open source is social v-it.org
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add org.v-it.cap lexicon and architecture doc

Define the cap record type as an ATProto Lexicon v1 schema mirroring
app.bsky.feed.post (minus deprecated fields) under the custom NSID
org.v-it.cap. Document the three-record-type strategy: custom cap,
reused like (app.bsky.feed.like), reused follow (app.bsky.graph.follow).

+168
+76
ARCHITECTURE.md
··· 1 + # Architecture 2 + 3 + ## Record Types 4 + 5 + vit uses ATProto records stored in each user's PDS repository. Three record types are used: 6 + 7 + | Record type | NSID | Custom? | Key | Purpose | 8 + |---|---|---|---|---| 9 + | Cap | `org.v-it.cap` | Yes | `tid` | Structured change description | 10 + | Like | `app.bsky.feed.like` | No (reused) | `tid` | Endorse a cap | 11 + | Follow | `app.bsky.graph.follow` | No (reused) | `tid` | Subscribe to a handle | 12 + 13 + ### Why caps use a custom NSID 14 + 15 + Caps are structurally similar to Bluesky posts (`app.bsky.feed.post`) but serve a different purpose. Using a custom NSID (`org.v-it.cap`) ensures: 16 + 17 + - Caps live in their own collection (`org.v-it.cap`) and never appear in a user's Bluesky post feed. 18 + - Bluesky AppViews and feed generators ignore cap records (unknown collection). 19 + - vit tooling can query caps independently without filtering out posts. 20 + - The cap schema can evolve independently of `app.bsky.feed.post`. 21 + 22 + ### Why likes and follows are reused 23 + 24 + `app.bsky.feed.like` and `app.bsky.graph.follow` are generic enough to use as-is: 25 + 26 + - A like's `subject` is a `strongRef` (URI + CID) — it works for any record, including caps. 27 + - A follow's `subject` is a DID — it works regardless of what record types the followed account publishes. 28 + - Reusing official lexicons means likes and follows are visible in Bluesky clients, which is acceptable and useful for cross-network discoverability. 29 + 30 + ## Cap Lexicon 31 + 32 + The cap lexicon (`lexicons/org/v-it/cap.json`) mirrors `app.bsky.feed.post` with these differences: 33 + 34 + - **NSID**: `org.v-it.cap` instead of `app.bsky.feed.post`. 35 + - **Deprecated fields removed**: `entities` and `textSlice` are not carried over. 36 + - **Self-referencing replies**: `reply` references `org.v-it.cap#replyRef`, so cap threads are self-contained. 37 + - **Descriptions updated**: All description strings reference "cap" instead of "post". 38 + 39 + Fields carried over from `app.bsky.feed.post` and their cap-context meaning: 40 + 41 + | Field | Type | Cap meaning | 42 + |---|---|---| 43 + | `text` | string (max 3000 bytes / 300 graphemes) | Primary cap content | 44 + | `facets` | array of `app.bsky.richtext.facet` | Rich text annotations (mentions, URLs, hashtags) | 45 + | `reply` | `org.v-it.cap#replyRef` | Thread structure (parent + root refs) | 46 + | `embed` | union of `app.bsky.embed.*` | Attached media, links, or record embeds | 47 + | `langs` | array of language strings (max 3) | Content language hints | 48 + | `labels` | `com.atproto.label.defs#selfLabels` | Content warnings | 49 + | `tags` | array of strings (max 8) | Additional hashtags | 50 + | `createdAt` | datetime | Client-declared creation timestamp | 51 + 52 + ### Relationship to VOCAB.md 53 + 54 + VOCAB.md defines a cap as a structured record with fields like intent, scope, risk, and provenance. The current lexicon does not include these fields — it establishes structural parity with `app.bsky.feed.post` so caps can thread, embed, use rich text, and be liked. 55 + 56 + Cap-specific fields (intent, scope, risk, kind, evidence, artifacts, provenance) are planned as future lexicon extensions. The `text` field and `tags` can carry some of this information informally until dedicated fields exist. 57 + 58 + ## Directory Layout 59 + 60 + Lexicon JSON files follow the NSID-to-path convention: 61 + 62 + ``` 63 + lexicons/ 64 + org/ 65 + v-it/ 66 + cap.json # org.v-it.cap 67 + ``` 68 + 69 + This mirrors the convention used in the atproto repository. 70 + 71 + ## Future Work 72 + 73 + - Custom lexicons for vouch (`org.v-it.vouch`), evidence, and other vit record types. 74 + - Cap-specific fields (intent, scope, risk, kind, beacon, provenance) as lexicon properties. 75 + - Runtime lexicon validation (currently `validate: false` in pds-record.js). 76 + - Migration of `org.v-it.hello` references to `org.v-it.cap` in CLI commands.
+92
lexicons/org/v-it/cap.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "org.v-it.cap", 4 + "defs": { 5 + "main": { 6 + "type": "record", 7 + "description": "Record containing a vit cap.", 8 + "key": "tid", 9 + "record": { 10 + "type": "object", 11 + "required": ["text", "createdAt"], 12 + "properties": { 13 + "text": { 14 + "type": "string", 15 + "maxLength": 3000, 16 + "maxGraphemes": 300, 17 + "description": "The primary cap content. May be an empty string, if there are embeds." 18 + }, 19 + "facets": { 20 + "type": "array", 21 + "description": "Annotations of text (mentions, URLs, hashtags, etc).", 22 + "items": { 23 + "type": "ref", 24 + "ref": "lex:app.bsky.richtext.facet" 25 + } 26 + }, 27 + "reply": { 28 + "type": "ref", 29 + "ref": "lex:org.v-it.cap#replyRef", 30 + "description": "Reference to the parent and root caps when this cap is a reply in a thread." 31 + }, 32 + "embed": { 33 + "type": "union", 34 + "description": "Embedded content: images, video, external links, or record references.", 35 + "refs": [ 36 + "lex:app.bsky.embed.images", 37 + "lex:app.bsky.embed.video", 38 + "lex:app.bsky.embed.external", 39 + "lex:app.bsky.embed.record", 40 + "lex:app.bsky.embed.recordWithMedia" 41 + ] 42 + }, 43 + "langs": { 44 + "type": "array", 45 + "description": "Indicates human language of cap primary text content.", 46 + "maxLength": 3, 47 + "items": { 48 + "type": "string", 49 + "format": "language" 50 + } 51 + }, 52 + "labels": { 53 + "type": "union", 54 + "description": "Self-label values for this cap. Effectively content warnings.", 55 + "refs": ["lex:com.atproto.label.defs#selfLabels"] 56 + }, 57 + "tags": { 58 + "type": "array", 59 + "description": "Additional hashtags, in addition to any included in cap text and facets.", 60 + "maxLength": 8, 61 + "items": { 62 + "type": "string", 63 + "maxLength": 640, 64 + "maxGraphemes": 64 65 + } 66 + }, 67 + "createdAt": { 68 + "type": "string", 69 + "format": "datetime", 70 + "description": "Client-declared timestamp when this cap was originally created." 71 + } 72 + } 73 + } 74 + }, 75 + "replyRef": { 76 + "type": "object", 77 + "required": ["root", "parent"], 78 + "properties": { 79 + "root": { 80 + "type": "ref", 81 + "ref": "lex:com.atproto.repo.strongRef", 82 + "description": "The root cap of the thread." 83 + }, 84 + "parent": { 85 + "type": "ref", 86 + "ref": "lex:com.atproto.repo.strongRef", 87 + "description": "The direct parent cap being replied to." 88 + } 89 + } 90 + } 91 + } 92 + }