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.
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.
| field | type | notes |
|---|---|---|
| ✱ createdAt | string · datetime | |
| ✱ kind | string | What 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. |
| subject | union: com.cultureblocs.defs#placeRef | com.cultureblocs.defs#strongRef | Where the bead happened, or the published record (event, exhibition) it belongs to. Works, people and concepts go in `refs`. |
| note | string · ≤3000 | |
| refs | array 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`. |
| presentation | ref → com.cultureblocs.defs#presentation | |
| tags | array of string · ≤64 (max 8) | Freeform tags: the CultureBloc mask worn at mint time, ad-hoc event tags (emfcamp26), etc. |
| geo | ref → com.cultureblocs.defs#geo | |
| media | array of ref → com.cultureblocs.defs#mediaRef (max 10) | |
| prev | ref → com.cultureblocs.defs#strongRef | Previous bead in the day's chain, if any. |
| provenance | ref → com.cultureblocs.defs#provenance | |
| links | array of ref → com.cultureblocs.defs#linkRef (max 8) | Event page, venue page, etc. |
| images | array 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.
| field | type | notes |
|---|---|---|
| ✱ createdAt | string · datetime | |
| ✱ work | ref → com.cultureblocs.defs#workRef | |
| note | string · ≤3000 | |
| refs | array 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`. |
| media | array of ref → com.cultureblocs.defs#mediaRef (max 10) | |
| geo | ref → com.cultureblocs.defs#geo | |
| context | ref → com.cultureblocs.defs#strongRef | Optional exhibition or event record this annotation was made within. |
| matchConfidence | string | How the work was identified: cosine embedding match, ORB geometric verification, or manual entry. Known values: embedding, geometric, manual. |
| provenance | ref → com.cultureblocs.defs#provenance | |
| images | array 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.
| field | type | notes |
|---|---|---|
| ✱ createdAt | string · datetime | |
| title | string · ≤300 | |
| narrative | string · ≤10000 | |
| refs | array 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`. |
| ✱ items | array of ref → com.cultureblocs.defs#strongRef (max 200) | Ordered refs to bead and annotation records. |
| day | string · datetime | The day this strand covers (date portion significant). |
| links | array of ref → com.cultureblocs.defs#linkRef (max 8) | |
| place | ref → com.cultureblocs.defs#placeRef | Where 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.
| field | type | notes |
|---|---|---|
| ✱ name | string · ≤300 | The name to be credited under. One profile per persona; a creative may hold several. |
| bio | string · ≤2000 | |
| disciplines | array of string · ≤64 (max 8) | Freeform, e.g. 'sculpture', 'sound design', 'dark goth techno'. No controlled vocabulary by design. |
| based | ref → com.cultureblocs.defs#placeRef | Where the creative is based, at whatever precision they choose to publish. |
| links | array of ref → com.cultureblocs.defs#linkRef (max 8) | Website, portfolio, label page, socials. |
| externalIds | array 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. |
| ✱ createdAt | string · datetime | When 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.
| field | type | notes |
|---|---|---|
| ✱ title | string · ≤300 | Titles can change; history is preserved in repository commits. |
| referenceUrl | string · uri | Where the work currently lives online — gallery page, Bandcamp, Instagram post, own site. Expected to change over a career. |
| completionDate | string · ≤100 | Freeform: '2024', 'Spring 2019', 'ongoing'. Not a datetime: creative chronology is rarely precise. |
| description | string · ≤2000 | |
| credits | array 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. |
| externalIds | array 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. |
| links | array of ref → com.cultureblocs.defs#linkRef (max 8) | Other contexts for the work: press, a Flickr set, the Instagram post, a review. |
| tags | array of string · ≤64 (max 8) | |
| images | array 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. |
| ✱ createdAt | string · datetime | When 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.
| field | type | notes |
|---|---|---|
| ✱ subject | union: com.cultureblocs.defs#didRef | com.cultureblocs.defs#strongRef | Who or what this claim is about: a party by DID, or a specific record (pin the CID to make the attestation tamper-evident). |
| ✱ relationship | string · ≤64 | Advisory vocabulary: new relationship types need no schema change. Known values: created, collaborated_on, performed, exhibited, curated, released, represented_by, attests_to, references, member_of. |
| role | string · ≤100 | Freeform role within the relationship, e.g. 'mastering engineer', 'lighting design'. Industry role vocabularies are external layers, not core schema. |
| note | string · ≤500 | |
| ✱ createdAt | string · datetime | When 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.
| field | type | notes |
|---|---|---|
| ✱ name | string · ≤300 | |
| description | string · ≤2000 | |
| place | ref → com.cultureblocs.defs#placeRef | Where it is. Venues are public places: geo precision here is normally 'exact'. |
| address | string · ≤500 | |
| capacity | integer | Approximate standing/seated capacity. Small venues are repeatedly asked for this by funders and licensing. |
| accessibility | string · ≤1000 | Freeform access notes: step-free entry, accessible toilet, hearing loop, quiet room. |
| links | array of ref → com.cultureblocs.defs#linkRef (max 8) | Website, socials, ticketing, listings page. |
| externalIds | array of ref → com.cultureblocs.defs#externalId (max 20) | Wikidata, MusicBrainz place, charity or company number. |
| tags | array of string · ≤64 (max 8) | |
| ✱ createdAt | string · datetime | When this record was first stamped. The only immutable field: everything else may be revised by publishing a new commit. |
| location | union: community.lexicon.location.address | community.lexicon.location.geo | community.lexicon.location.fsq | community.lexicon.location.hthree | Where 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.
| field | type | notes |
|---|---|---|
| ✱ event | ref → com.cultureblocs.defs#strongRef | The event this describes — normally a community.lexicon.calendar.event record. Pin the CID so the attachment is tamper-evident. |
| billing | array of ref → com.cultureblocs.defs#creditRef (max 20) | Who is on: performers, artists, speakers, DJs. `did` links to a creative profile where one exists. |
| works | array of ref → com.cultureblocs.defs#workRef (max 20) | Works performed or shown, where the programme is specific about them. |
| venue | ref → com.cultureblocs.defs#strongRef | The venue profile record, when the event happens at a venue that publishes one. |
| note | string · ≤2000 | |
| tags | array of string · ≤64 (max 8) | |
| ✱ createdAt | string · 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.
| field | type | notes |
|---|---|---|
| ✱ title | string · ≤300 | |
| description | string · ≤2000 | |
| ✱ start | string · datetime | |
| end | string · datetime | |
| venue | union: com.cultureblocs.defs#placeRef | com.cultureblocs.defs#strongRef | The venue profile record, or a named place when the venue has no CultureBlocs identity. |
| billing | array of ref → com.cultureblocs.defs#creditRef (max 20) | Who is on: performers, artists, speakers, DJs. `did` links to a creative profile where one exists. |
| works | array of ref → com.cultureblocs.defs#workRef (max 20) | Works shown or performed, where the listing is specific about them. |
| event | ref → com.cultureblocs.defs#strongRef | Interop hook: a general-purpose event record elsewhere that this listing corresponds to. Prefer pointing over duplicating. |
| status | string · ≤32 | Known values: scheduled, cancelled, postponed, soldout. |
| links | array of ref → com.cultureblocs.defs#linkRef (max 8) | Tickets, event page, the venue's own listing. |
| externalIds | array of ref → com.cultureblocs.defs#externalId (max 20) | |
| tags | array of string · ≤64 (max 8) | |
| ✱ createdAt | string · datetime | When 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] }.
| field | type | notes |
|---|---|---|
| wikidata | string | Wikidata QID, e.g. Q1892745 |
| accession | ref → #accessionRef | |
| linkedArt | string · uri | Linked Art object URI |
| title | string · ≤500 | |
| creator | string · ≤300 | |
| date | string · ≤100 | Freeform creation date, e.g. '1972' or 'c. 1889' |
| image | ref → #mediaRef | |
| creatorDid | string · did | DID of the creative who made this work, when known. The `creator` string remains the descriptive fallback. |
object · #accessionRef
| field | type | notes |
|---|---|---|
| ✱ institution | string · did | DID of the holding institution |
| ✱ id | string · ≤200 | Accession/inventory number |
object · #placeRef
A venue with an ATProto identity, or an ad-hoc named place.
| field | type | notes |
|---|---|---|
| did | string · did | Venue DID if it has an ATProto account |
| name | string · ≤300 | |
| geo | ref → #geo |
object · #geo
| field | type | notes |
|---|---|---|
| ✱ lat | number | |
| ✱ lng | number | |
| ✱ precision | string | Declared 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.
| field | type | notes |
|---|---|---|
| ✱ uri | string · uri | |
| mime | string · ≤100 | |
| alt | string · ≤1000 | |
| aspectRatio | ref → #aspectRatio |
object · #aspectRatio
Pixel dimensions, so a reader can reserve layout space before the image bytes arrive. Shape matches app.bsky.embed.images#aspectRatio.
| field | type | notes |
|---|---|---|
| ✱ width | integer | |
| ✱ height | integer |
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.
| field | type | notes |
|---|---|---|
| ✱ image | blob | |
| alt | string · ≤2000 | What the image shows. Absent means absent — readers must not substitute a title. |
| aspectRatio | ref → #aspectRatio |
object · #provenance
| field | type | notes |
|---|---|---|
| ✱ app | string · ≤100 | Producing app id, e.g. 'culturebloc', 'ar-gallery' |
| device | string · ≤100 | Device identifier, e.g. StickS3 id |
| ✱ mintedAt | string · datetime | |
| mutualMint | boolean | True if created by a mutual-press ceremony |
| mintId | string · ≤64 | Device-generated mint identifier (hex). Shared between both parties' beads on a mutual mint — the encounter join key. |
| timeAnchored | boolean | False 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
| field | type | notes |
|---|---|---|
| ✱ uri | string · uri | |
| cid | string |
object · #linkRef
External link attached to a bead or strand: event page, venue page, ticket listing.
| field | type | notes |
|---|---|---|
| ✱ uri | string · uri | |
| title | string · ≤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.
| field | type | notes |
|---|---|---|
| ✱ scheme | string · ≤64 | Known values: isni, ipi, ipn, orcid, wikidata, musicbrainz, auracle, isrc, iswc, isan, doi, viaf, discogs, rsl, isbn, olid, tmdb, linkedArt, accession. |
| ✱ id | string · ≤200 | |
| uri | string · uri | Resolvable 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.
| field | type | notes |
|---|---|---|
| ✱ type | string · ≤32 | Known values: person, work, event, venue, concept. |
| ✱ role | string · ≤32 | subject: what the record is about. mention: invoked, compared, gestured at. Readers treat any other value as mention. Known values: subject, mention. |
| ✱ descriptor | ref → #refDescriptor | |
| did | string · did | DID of the referent itself (a person, a venue with an account). A work's maker goes in descriptor.creatorDid. |
| externalIds | array of ref → #externalId (max 20) | |
| index | ref → #byteSlice |
object · #refDescriptor
The portable description of a referent: enough to cluster on when no identifier exists. Deliberately has no free-text note.
| field | type | notes |
|---|---|---|
| ✱ label | string · ≤500 | Title of a work, name of a person, venue, event or concept. |
| creator | string · ≤300 | |
| creatorDid | string · did | |
| date | string · ≤100 | Freeform, 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.
| field | type | notes |
|---|---|---|
| ✱ byteStart | integer | |
| ✱ byteEnd | integer |
object · #presentation
How the work was encountered: the manifestation, as distinct from the work. Two beads can share a work ref and differ here.
| field | type | notes |
|---|---|---|
| format | string · ≤100 | Known values: IMAX 70mm, 70mm, 35mm, digital, streaming, broadcast, hardback, paperback, ebook, audiobook, vinyl, live. |
| venueRef | ref → #ref | A reference to a venue, never a location: carries no coordinates. |
| eventRef | ref → #ref | The screening or performance attended. |
object · #didRef
A person or organisation by DID, with a descriptive fallback name.
| field | type | notes |
|---|---|---|
| ✱ did | string · did | |
| name | string · ≤300 |
object · #creditRef
A named contributor. `role` is deliberately freeform: role vocabularies differ per industry and belong in referencing layers, not in this schema.
| field | type | notes |
|---|---|---|
| ✱ name | string · ≤300 | |
| did | string · did | |
| role | string · ≤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.