Labels #
Contrail can subscribe to AT Protocol labelers and attach their labels to records and profiles.
Configure #
export default {
namespace: "com.example",
collections: {
event: { collection: "community.lexicon.calendar.event" },
},
labels: {
sources: [
{ did: "did:plc:ar7c4by46qjdydhdevvrndac" },
],
},
};
Normal contrail backfill, Worker cron ingestion, and runPersistent() include configured labelers automatically.
Author self-labels #
Records and profile views expose author declarations separately as
selfLabels: [{ val: "nudity" }]. Contrail reads only the root canonical
labels: { $type: "com.atproto.label.defs#selfLabels", values: [...] }
container; the original value is unchanged. At most 10 entries are admitted,
with nonempty values of at most 128 UTF-8 bytes. Malformed entries are skipped,
exact duplicates are removed, and oversized containers are ignored.
Self-labels are normalized at read time, including relation/reference previews,
feeds, pipeline queries, cached/fetched profiles, and private moderator previews.
They require no labeler configuration, database migration, backfill or extra
queries. Removing them in a new record version removes them from the next
response. Custom handlers can use the exported extractSelfLabels(value) helper.
These are author declarations, not trusted labeler claims: no synthetic
src, timestamp, signature or expiry is added, and they never affect backend
visibility, counts or pagination. Profile declarations belong to that profile
record, not all posts from its author. They are not selected by
Atproto-Accept-Labelers or reported in Atproto-Content-Labelers.
@atmo-dev/ui/moderation accepts them through
moderate({ labels: record.labels, selfLabels: record.selfLabels, subject: record.uri, subjectCid: record.cid, author: { did: record.did } }).
Pass the rich decision to ModerationGate. Built-in porn, sexual, nudity
and graphic-media declarations cover media with author attribution; custom
values are informational. Operator ! values cannot create takedowns or
sign-in restrictions. Use a profile's own URI/decision with kind: "profile"
for profile media/avatar gates; never flatten profile declarations into posts.
Regenerate Lexicons/types after upgrading. Generated views include the standard
self-label dependency, with a bundled offline fallback when the project has no
local com.atproto.label.defs document. Project-provided documents win.
Select labelers #
A request chooses labelers with the standard header:
Atproto-Accept-Labelers: did:plc:ar7c4by46qjdydhdevvrndac
Use ?labelers=did:plc:... when setting a header is inconvenient. Without either, Contrail uses labels.defaults, or all configured sources when defaults are omitted. Set defaults: [] to require callers to opt in.
Selected labels appear as record.labels. Account labels appear on hydrated profile entries. The response's Atproto-Content-Labelers header reports which configured labelers were applied.
Contrail drops expired labels, applies CID-pinned labels only to the matching record version, treats newer neg: true labels as retractions, and rejects labels whose cts is more than five minutes in the future.
Per-source values filters stored label values; subjects: "known" restricts
subjects to indexed identities and schedules durable first-seen queryLabels
backfill. Stored retractions always pass admission. backfill: false starts a
new stream from now rather than replaying its entire history.
Set enforce: true to enforce !hide and !takedown independently of caller
labeler selection. Account labels are included on returned records as well as
profiles, including hydrated relation/reference previews. Moderator action
records, overrides, account lifecycle and private reports are documented in
Moderation. @atmo-dev/ui/moderation provides presentation
helpers; Contrail itself does not publish a signed label stream. Label
signatures are stored but are not currently verified.