The schema commons.

Nine small ATProto lexicons under the com.cultureblocs.* namespace — anchored to this domain, which is what makes them citable. The same shapes describe a record on a device, in a self-hosted String, or published to the open network; privacy is a property of where a record lives, not of its schema. Status: published and resolvable — these schemas are live protocol infrastructure, in daily use by the reference apps.

resolve it yourself: _lexicon.cultureblocs.com → did:plc:l3726um33xesakwqhjkkpoet → e.g. at://cultureblocs.com/com.atproto.lexicon.schema/com.cultureblocs.bead

personal record: bead · annotation · strand
creative identity: creative.profile · creative.work · creative.connection · Linked Data terms
venues: venue.profile · venue.lineup · venue.listing (deprecated) · shared defs — fields marked ✱ are required

com.cultureblocs.bead

An atomic cultural memory: a visit, a dwell, an encounter, a screening. Minted on-device or by hand; annotated later.

record · key: tid

An atomic cultural memory: a visit, a dwell, an encounter, a screening. Minted on-device or by hand; annotated later.

fieldtypenotes
✱ createdAtstring · datetime
✱ kindstringWhat kind of cultural moment: bloc is the neutral default (a marked moment); read/listen/watch cover at-home culture; visit/dwell/screening/performance cover being out; encounter is a mutual mint. Known values: bloc, visit, dwell, encounter, read, listen, watch, screening, performance, note.
subjectunion: com.cultureblocs.defs#placeRef | com.cultureblocs.defs#strongRefWhere the bead happened, or the published record (event, exhibition) it belongs to. Works, people and concepts go in `refs`.
notestring · ≤3000
refsarray of ref → com.cultureblocs.defs#ref (max 50)What this record is about (role subject) and what it reaches for (role mention). Anchors index into `note`.
presentationref → com.cultureblocs.defs#presentation
tagsarray of string · ≤64 (max 8)Freeform tags: the CultureBloc mask worn at mint time, ad-hoc event tags (emfcamp26), etc.
georef → com.cultureblocs.defs#geo
mediaarray of ref → com.cultureblocs.defs#mediaRef (max 10)
prevref → com.cultureblocs.defs#strongRefPrevious bead in the day's chain, if any.
provenanceref → com.cultureblocs.defs#provenance
linksarray of ref → com.cultureblocs.defs#linkRef (max 8)Event page, venue page, etc.
imagesarray of ref → com.cultureblocs.defs#imageRef (max 10)Published images as imageRefs. Tier 0 records use `media` (local refs); the promoter uploads the bytes and maps alt + aspectRatio across at publish time.

com.cultureblocs.annotation

A bookmark/note about a specific work, typically minted by the AR gallery app at the moment of recognition. Meaningful entirely on its own — no bead required.

record · key: tid

A bookmark/note about a specific work, typically minted by the AR gallery app at the moment of recognition. Meaningful entirely on its own — no bead required.

fieldtypenotes
✱ createdAtstring · datetime
✱ workref → com.cultureblocs.defs#workRef
notestring · ≤3000
refsarray of ref → com.cultureblocs.defs#ref (max 50)What this record is about (role subject) and what it reaches for (role mention). Anchors index into `note`.
mediaarray of ref → com.cultureblocs.defs#mediaRef (max 10)
georef → com.cultureblocs.defs#geo
contextref → com.cultureblocs.defs#strongRefOptional exhibition or event record this annotation was made within.
matchConfidencestringHow the work was identified: cosine embedding match, ORB geometric verification, or manual entry. Known values: embedding, geometric, manual.
provenanceref → com.cultureblocs.defs#provenance
imagesarray of ref → com.cultureblocs.defs#imageRef (max 10)Published images as imageRefs. Tier 0 records use `media` (local refs); the promoter uploads the bytes and maps alt + aspectRatio across at publish time.

com.cultureblocs.strand

A curated, ordered string of beads and annotations — typically one day's cultural path. The publishable story unit.

record · key: tid

A curated, ordered string of beads and annotations — typically one day's cultural path. The publishable story unit.

fieldtypenotes
✱ createdAtstring · datetime
titlestring · ≤300
narrativestring · ≤10000
refsarray of ref → com.cultureblocs.defs#ref (max 50)What this record is about (role subject) and what it reaches for (role mention). Anchors index into `narrative`.
✱ itemsarray of ref → com.cultureblocs.defs#strongRef (max 200)Ordered refs to bead and annotation records.
daystring · datetimeThe day this strand covers (date portion significant).
linksarray of ref → com.cultureblocs.defs#linkRef (max 8)
placeref → com.cultureblocs.defs#placeRefWhere this strand happened (e.g. Tate Modern).

com.cultureblocs.creative.profile

A creative's self-asserted identity. Self-assertion is the normal state, not a deficient one: the record lives in the creative's own repository, which is the claim. Third-party attestation (com.cultureblocs.creative.connection) is an optional overlay some records acquire. This is a join layer, not a registry: externalIds carry ISNI/IPI/ORCID/Auracle/Wikidata and any future scheme so identifiers held elsewhere keep their value here.

record · key: literal:self

A creative's self-asserted identity. Self-assertion is the normal state, not a deficient one: the record lives in the creative's own repository, which is the claim. Third-party attestation (com.cultureblocs.creative.connection) is an optional overlay some records acquire. This is a join layer, not a registry: externalIds carry ISNI/IPI/ORCID/Auracle/Wikidata and any future scheme so identifiers held elsewhere keep their value here.

fieldtypenotes
✱ namestring · ≤300The name to be credited under. One profile per persona; a creative may hold several.
biostring · ≤2000
disciplinesarray of string · ≤64 (max 8)Freeform, e.g. 'sculpture', 'sound design', 'dark goth techno'. No controlled vocabulary by design.
basedref → com.cultureblocs.defs#placeRefWhere the creative is based, at whatever precision they choose to publish.
linksarray of ref → com.cultureblocs.defs#linkRef (max 8)Website, portfolio, label page, socials.
externalIdsarray of ref → com.cultureblocs.defs#externalId (max 20)Identity in other systems. A bridge service may later register some of these on the creative's behalf; CultureBlocs does not.
✱ createdAtstring · datetimeWhen this record was first stamped. The only immutable field: everything else may be revised by publishing a new commit.

com.cultureblocs.creative.work

A minimal, self-asserted marker: 'I made this' / 'we made this'. Deliberately tiny. It proves that this claim was made on this date by the holder of this repository — nothing more, which is exactly the claim that can honestly be made. Everything else (industry metadata, scene layers, commercial registrations, licensing terms) belongs in other namespaces that REFERENCE this record's URI rather than adding fields to it.

record · key: tid

A minimal, self-asserted marker: 'I made this' / 'we made this'. Deliberately tiny. It proves that this claim was made on this date by the holder of this repository — nothing more, which is exactly the claim that can honestly be made. Everything else (industry metadata, scene layers, commercial registrations, licensing terms) belongs in other namespaces that REFERENCE this record's URI rather than adding fields to it.

fieldtypenotes
✱ titlestring · ≤300Titles can change; history is preserved in repository commits.
referenceUrlstring · uriWhere the work currently lives online — gallery page, Bandcamp, Instagram post, own site. Expected to change over a career.
completionDatestring · ≤100Freeform: '2024', 'Spring 2019', 'ongoing'. Not a datetime: creative chronology is rarely precise.
descriptionstring · ≤2000
creditsarray of ref → com.cultureblocs.defs#creditRef (max 20)Self-asserted collaborators. Asymmetric by design: no approval inbox. If a collaborator publishes a matching claim, readers may compute a verified collaboration from the closed loop.
externalIdsarray of ref → com.cultureblocs.defs#externalId (max 20)ISWC, ISRC, DOI, Wikidata and so on, once they exist. Registering them is a separate, often paid, workflow — this field is the hook a bridge service would write back into.
linksarray of ref → com.cultureblocs.defs#linkRef (max 8)Other contexts for the work: press, a Flickr set, the Instagram post, a review.
tagsarray of string · ≤64 (max 8)
imagesarray of ref → com.cultureblocs.defs#imageRef (max 10)The work itself, as published images (small / optionally watermarked). For image-based works this is the work, not metadata. Full-resolution originals need not leave the creator's machine.
✱ createdAtstring · datetimeWhen this record was first stamped. The only immutable field: everything else may be revised by publishing a new commit.

com.cultureblocs.creative.connection

A directional claim from this repository's holder about another party or record: 'we exhibited this', 'I performed on this', 'this is my work'. One-way and unapproved by default — the counterparty is never asked to accept anything. When two parties independently point at each other, any reader can compute a verified relationship from the closed loop; this is the mutual-mint primitive at professional scale. Pointing at a record with a CID pins the exact content attested to: if the target is silently rewritten the loop visibly breaks.

record · key: tid

A directional claim from this repository's holder about another party or record: 'we exhibited this', 'I performed on this', 'this is my work'. One-way and unapproved by default — the counterparty is never asked to accept anything. When two parties independently point at each other, any reader can compute a verified relationship from the closed loop; this is the mutual-mint primitive at professional scale. Pointing at a record with a CID pins the exact content attested to: if the target is silently rewritten the loop visibly breaks.

fieldtypenotes
✱ subjectunion: com.cultureblocs.defs#didRef | com.cultureblocs.defs#strongRefWho or what this claim is about: a party by DID, or a specific record (pin the CID to make the attestation tamper-evident).
✱ relationshipstring · ≤64Advisory vocabulary: new relationship types need no schema change. Known values: created, collaborated_on, performed, exhibited, curated, released, represented_by, attests_to, references, member_of.
rolestring · ≤100Freeform role within the relationship, e.g. 'mastering engineer', 'lighting design'. Industry role vocabularies are external layers, not core schema.
notestring · ≤500
✱ createdAtstring · datetimeWhen this record was first stamped. The only immutable field: everything else may be revised by publishing a new commit.

com.cultureblocs.venue.profile

A venue or organiser as a publishing party: the small amount a grassroots space needs to be findable and pointable-at. Publishing this does not make the venue an audience-data platform — audiences publish their own beads referencing the venue's listings, and the venue reads public references. Nothing about an attendee is ever collected here. Events at this venue are published as community.lexicon.calendar.event records; this profile carries what a venue needs that an event does not — capacity and access, which funders and licensing ask for.

record · key: literal:self

A venue or organiser as a publishing party: the small amount a grassroots space needs to be findable and pointable-at. Publishing this does not make the venue an audience-data platform — audiences publish their own beads referencing the venue's listings, and the venue reads public references. Nothing about an attendee is ever collected here. Events at this venue are published as community.lexicon.calendar.event records; this profile carries what a venue needs that an event does not — capacity and access, which funders and licensing ask for.

fieldtypenotes
✱ namestring · ≤300
descriptionstring · ≤2000
placeref → com.cultureblocs.defs#placeRefWhere it is. Venues are public places: geo precision here is normally 'exact'.
addressstring · ≤500
capacityintegerApproximate standing/seated capacity. Small venues are repeatedly asked for this by funders and licensing.
accessibilitystring · ≤1000Freeform access notes: step-free entry, accessible toilet, hearing loop, quiet room.
linksarray of ref → com.cultureblocs.defs#linkRef (max 8)Website, socials, ticketing, listings page.
externalIdsarray of ref → com.cultureblocs.defs#externalId (max 20)Wikidata, MusicBrainz place, charity or company number.
tagsarray of string · ≤64 (max 8)
✱ createdAtstring · datetimeWhen this record was first stamped. The only immutable field: everything else may be revised by publishing a new commit.
locationunion: community.lexicon.location.address | community.lexicon.location.geo | community.lexicon.location.fsq | community.lexicon.location.hthreeWhere the venue is, using the shared location objects of the open social web so other apps understand it. Preferred over the legacy `place`/`address` fields.

com.cultureblocs.venue.lineup

Cultural detail attached to an event that the shared calendar record does not carry: who is on, and what is performed or shown. A layer, not a replacement — it references an event by strongRef and never duplicates it. The same discipline as the creative namespace: layers reference the core claim rather than growing it. If these fields prove generally useful they belong upstream in the community calendar lexicon, not here.

record · key: tid

Cultural detail attached to an event that the shared calendar record does not carry: who is on, and what is performed or shown. A layer, not a replacement — it references an event by strongRef and never duplicates it. The same discipline as the creative namespace: layers reference the core claim rather than growing it. If these fields prove generally useful they belong upstream in the community calendar lexicon, not here.

fieldtypenotes
✱ eventref → com.cultureblocs.defs#strongRefThe event this describes — normally a community.lexicon.calendar.event record. Pin the CID so the attachment is tamper-evident.
billingarray of ref → com.cultureblocs.defs#creditRef (max 20)Who is on: performers, artists, speakers, DJs. `did` links to a creative profile where one exists.
worksarray of ref → com.cultureblocs.defs#workRef (max 20)Works performed or shown, where the programme is specific about them.
venueref → com.cultureblocs.defs#strongRefThe venue profile record, when the event happens at a venue that publishes one.
notestring · ≤2000
tagsarray of string · ≤64 (max 8)
✱ createdAtstring · datetime

com.cultureblocs.venue.listing

DEPRECATED — do not write new records. Use community.lexicon.calendar.event instead: it is the shared event record of the open social web, so a venue's nights appear in every calendar app on the network rather than only in CultureBlocs. Cultural extras that the community event does not carry (who is on, works performed) live in com.cultureblocs.venue.lineup, which references the event. This schema remains published so existing records stay resolvable.

record · key: tid

DEPRECATED — do not write new records. Use community.lexicon.calendar.event instead: it is the shared event record of the open social web, so a venue's nights appear in every calendar app on the network rather than only in CultureBlocs. Cultural extras that the community event does not carry (who is on, works performed) live in com.cultureblocs.venue.lineup, which references the event. This schema remains published so existing records stay resolvable.

fieldtypenotes
✱ titlestring · ≤300
descriptionstring · ≤2000
✱ startstring · datetime
endstring · datetime
venueunion: com.cultureblocs.defs#placeRef | com.cultureblocs.defs#strongRefThe venue profile record, or a named place when the venue has no CultureBlocs identity.
billingarray of ref → com.cultureblocs.defs#creditRef (max 20)Who is on: performers, artists, speakers, DJs. `did` links to a creative profile where one exists.
worksarray of ref → com.cultureblocs.defs#workRef (max 20)Works shown or performed, where the listing is specific about them.
eventref → com.cultureblocs.defs#strongRefInterop hook: a general-purpose event record elsewhere that this listing corresponds to. Prefer pointing over duplicating.
statusstring · ≤32Known values: scheduled, cancelled, postponed, soldout.
linksarray of ref → com.cultureblocs.defs#linkRef (max 8)Tickets, event page, the venue's own listing.
externalIdsarray of ref → com.cultureblocs.defs#externalId (max 20)
tagsarray of string · ≤64 (max 8)
✱ createdAtstring · datetimeWhen this record was first stamped. The only immutable field: everything else may be revised by publishing a new commit.

com.cultureblocs.defs

object · #workRef

DEPRECATED: use #ref with type 'work'. Reference to an artwork/creative work. At least one resolvable ID or a descriptive fallback (title). Readers map it to #ref as { type: work, role: subject, descriptor: { label: title, creator, creatorDid, date }, externalIds: [wikidata, linkedArt, accession] }.

fieldtypenotes
wikidatastringWikidata QID, e.g. Q1892745
accessionref → #accessionRef
linkedArtstring · uriLinked Art object URI
titlestring · ≤500
creatorstring · ≤300
datestring · ≤100Freeform creation date, e.g. '1972' or 'c. 1889'
imageref → #mediaRef
creatorDidstring · didDID of the creative who made this work, when known. The `creator` string remains the descriptive fallback.

object · #accessionRef

fieldtypenotes
✱ institutionstring · didDID of the holding institution
✱ idstring · ≤200Accession/inventory number

object · #placeRef

A venue with an ATProto identity, or an ad-hoc named place.

fieldtypenotes
didstring · didVenue DID if it has an ATProto account
namestring · ≤300
georef → #geo

object · #geo

fieldtypenotes
✱ latnumber
✱ lngnumber
✱ precisionstringDeclared coordinate fuzzing level. Coordinates MUST already be fuzzed to this precision before the record leaves Tier 0. Known values: exact, 100m, 1km, city.

object · #mediaRef

Tier 0/1 media reference. Replaced by an imageRef at promotion time; alt text and aspectRatio carry across unchanged.

fieldtypenotes
✱ uristring · uri
mimestring · ≤100
altstring · ≤1000
aspectRatioref → #aspectRatio

object · #aspectRatio

Pixel dimensions, so a reader can reserve layout space before the image bytes arrive. Shape matches app.bsky.embed.images#aspectRatio.

fieldtypenotes
✱ widthinteger
✱ heightinteger

object · #imageRef

A published image and the two things a reader needs to present it honestly: what it shows, and how much room it takes. Field names match app.bsky.embed.images#image and the community standalone-image proposal, so this can become a ref to a shared lexicon without changing the published payload.

fieldtypenotes
✱ imageblob
altstring · ≤2000What the image shows. Absent means absent — readers must not substitute a title.
aspectRatioref → #aspectRatio

object · #provenance

fieldtypenotes
✱ appstring · ≤100Producing app id, e.g. 'culturebloc', 'ar-gallery'
devicestring · ≤100Device identifier, e.g. StickS3 id
✱ mintedAtstring · datetime
mutualMintbooleanTrue if created by a mutual-press ceremony
mintIdstring · ≤64Device-generated mint identifier (hex). Shared between both parties' beads on a mutual mint — the encounter join key.
timeAnchoredbooleanFalse when the device knew only the time-of-day or nothing; createdAt is then a best guess

object · #strongRef

Local stand-in for com.atproto.repo.strongRef

fieldtypenotes
✱ uristring · uri
cidstring

object · #linkRef

External link attached to a bead or strand: event page, venue page, ticket listing.

fieldtypenotes
✱ uristring · uri
titlestring · ≤300

object · #externalId

An identifier for this subject in another system. Registries are peers: no scheme is privileged, and knownValues is advisory so new schemes need no schema change.

fieldtypenotes
✱ schemestring · ≤64Known values: isni, ipi, ipn, orcid, wikidata, musicbrainz, auracle, isrc, iswc, isan, doi, viaf, discogs, rsl, isbn, olid, tmdb, linkedArt, accession.
✱ idstring · ≤200
uristring · uriResolvable URL for this identifier, where one exists.

object · #ref

What an entry is about, or reaches for, as data beside the text. Modelled on app.bsky.richtext.facet: the text is never rewritten, and `index` is a UTF-8 byte range into the record's own text (strand.narrative; bead.note; annotation.note). Identity is descriptor + did + externalIds. No AppView cluster id is ever part of a ref.

fieldtypenotes
✱ typestring · ≤32Known values: person, work, event, venue, concept.
✱ rolestring · ≤32subject: what the record is about. mention: invoked, compared, gestured at. Readers treat any other value as mention. Known values: subject, mention.
✱ descriptorref → #refDescriptor
didstring · didDID of the referent itself (a person, a venue with an account). A work's maker goes in descriptor.creatorDid.
externalIdsarray of ref → #externalId (max 20)
indexref → #byteSlice

object · #refDescriptor

The portable description of a referent: enough to cluster on when no identifier exists. Deliberately has no free-text note.

fieldtypenotes
✱ labelstring · ≤500Title of a work, name of a person, venue, event or concept.
creatorstring · ≤300
creatorDidstring · did
datestring · ≤100Freeform, e.g. '1972' or 'c. 1889'.

object · #byteSlice

Same shape as app.bsky.richtext.facet#byteSlice: zero-indexed UTF-8 byte offsets, end exclusive. Text length limits elsewhere are in graphemes; these are bytes.

fieldtypenotes
✱ byteStartinteger
✱ byteEndinteger

object · #presentation

How the work was encountered: the manifestation, as distinct from the work. Two beads can share a work ref and differ here.

fieldtypenotes
formatstring · ≤100Known values: IMAX 70mm, 70mm, 35mm, digital, streaming, broadcast, hardback, paperback, ebook, audiobook, vinyl, live.
venueRefref → #refA reference to a venue, never a location: carries no coordinates.
eventRefref → #refThe screening or performance attended.

object · #didRef

A person or organisation by DID, with a descriptive fallback name.

fieldtypenotes
✱ didstring · did
namestring · ≤300

object · #creditRef

A named contributor. `role` is deliberately freeform: role vocabularies differ per industry and belong in referencing layers, not in this schema.

fieldtypenotes
✱ namestring · ≤300
didstring · did
rolestring · ≤100

Design notes

Self-assertion is the normal state. A creative's profile and work claims live in their own repository; that is the claim. A work record proves one narrow, honest thing — this claim was made on this date by the holder of this repository — which is enough to tag work as yours and to be referenced by everything further up the stack. Industry metadata, scene-specific layers and commercial registrations belong in other namespaces that reference these records rather than growing them. Attestation is an optional overlay: when two parties independently point at each other, a reader can compute a verified relationship; unattested records are ordinary, not deficient.

Venues stay small — and we do not own the event. Nights are published as community.lexicon.calendar.event, the shared event record of the open social web, so a venue's programme appears in every calendar app that speaks it rather than only in ours. Our own venue.lineup is a layer over that shared record, carrying only what it does not — who is on, works shown — and referencing it by strongRef. venue.listing is deprecated and kept published so old records stay resolvable. An RSVP on an event says I'm going; a bead pointing at the same event says I was here — two tenses, one record, different apps.

What an entry is about is data, not prose. A narrative can say that the book was Ben Pester’s The Expansion Project, that it rhymes with Severance, and that its ancestry runs back through the SF New Wave — all of it legible to a reader and invisible to everything else. Prose does not join: two people write two paragraphs about the same film and there is no common key in either record. refs is that key — a small array beside the text naming what the entry is about (role: subject) and what it reaches for (role: mention). The text is never rewritten: no wikilinks, no inline markup, and a reader that ignores refs renders the entry correctly. The anchor into the text is a UTF-8 byte range with the same field names as app.bsky.richtext.facet, because anyone who has implemented facets has implemented most of this. Subject versus mention is the whole relation vocabulary, deliberately: influencedBy and friends are where twenty years of semantic web effort went, and the cheap distinction captures nearly all of the value — a mention is not a watch, not a read, not an attendance.

The work and the manifestation are different things. Two people log the same film; the work ref is what connects them, and presentation — IMAX 70mm against a streaming rip, a Peckhamplex screening against a living room — is often why they disagree. Record at the level the person knew: “I read The Left Hand of Darkness” is a complete claim and nobody should be made to pick an edition, but capture the edition when they do know it, because an index can generalise upward and never downward. presentation.venueRef is a reference to a venue and carries no coordinates; subject’s place ref remains where-you-were, with geo, stripped to its name on the way out. The two can name the same building; only one can ever carry a coordinate.

Records reference artworks by stable external identity (Wikidata QIDs, institution accession numbers, Linked Art URIs, ISBNs) with a descriptive fallback — works are referenced, never owned. A person ref publishes only when it already carries a DID or a public identifier, so no one is ever matched by name alone. Coordinate fuzzing is a schema concept (geo.precision), not an app afterthought. knownValues on kind is advisory, so the vocabulary can grow without breaking old records. defs#workRef is deprecated in favour of defs#ref and stays published so old records resolve. Event and calendar shapes are deliberately absent: for those we interoperate with the Lexicon Community calendar work rather than fork it.