extracted spec from an ADR for implementing an atproto client and public lexicon
livtet_lexicon.md
1### ATProto Lexicons
2
3ATProto lexicons use JSON with NSID identifiers. The lexicon format includes `lexicon`, `id`, `defs`, and record/query/procedure types. Custom lexicons are stored as JSON and embedded via `include_str!`.
4
5Domain: `livtet.app` (user owns this domain). Not a full PDS implementation—just a minimal lexicon server.
6
7**`app.livtet.work`** - Work record (literary work like "Frankenstein"):
8
9```json
10{
11 "lexicon": 1,
12 "id": "app.livtet.work",
13 "defs": {
14 "main": {
15 "type": "record",
16 "description": "A literary work tracked by Livtet.",
17 "key": "tid",
18 "record": {
19 "type": "object",
20 "required": ["name", "language", "datePublished"],
21 "properties": {
22 "name": { "type": "string", "description": "Title of the work" },
23 "language": { "type": "string", "description": "ISO 639-1 language code" },
24 "datePublished": { "type": "string", "format": "datetime" },
25 "description": { "type": "string" },
26 "series": { "type": "ref", "ref": "app.livtet.defs#seriesRef" },
27 "identifiers": {
28 "type": "array",
29 "items": { "type": "ref", "ref": "app.livtet.defs#identifier" }
30 }
31 }
32 }
33 }
34 }
35}
36```
37
38**`app.livtet.edition`** - Edition record (specific form of a work):
39
40```json
41{
42 "lexicon": 1,
43 "id": "app.livtet.edition",
44 "defs": {
45 "main": {
46 "type": "record",
47 "description": "A specific edition of a work.",
48 "key": "tid",
49 "record": {
50 "type": "object",
51 "required": ["work", "format"],
52 "properties": {
53 "work": { "type": "ref", "ref": "com.atproto.repo.strongRef" },
54 "format": {
55 "type": "union",
56 "refs": ["app.livtet.defs#physicalFormat", "app.livtet.defs#virtualFormat", "app.livtet.defs#audiobookFormat"]
57 },
58 "datePublished": { "type": "string", "format": "datetime" },
59 "seriesIndex": { "type": "integer" },
60 "url": { "type": "string", "format": "uri" },
61 "identifiers": {
62 "type": "array",
63 "items": { "type": "ref", "ref": "app.livtet.defs#identifier" }
64 }
65 }
66 }
67 }
68 }
69}
70```
71
72**`app.livtet.readProgress`** - Reading progress record:
73
74```json
75{
76 "lexicon": 1,
77 "id": "app.livtet.readProgress",
78 "defs": {
79 "main": {
80 "type": "record",
81 "description": "Reading progress for a specific edition.",
82 "key": "tid",
83 "record": {
84 "type": "object",
85 "required": ["edition", "progress", "updatedAt"],
86 "properties": {
87 "edition": { "type": "ref", "ref": "com.atproto.repo.strongRef" },
88 "progress": { "type": "integer", "minimum": 0, "maximum": 100 },
89 "lastPosition": { "type": "string" },
90 "updatedAt": { "type": "string", "format": "datetime" },
91 "highlights": { "type": "array", "items": { "type": "ref", "ref": "#highlight" } }
92 }
93 }
94 },
95 "highlight": {
96 "type": "object",
97 "properties": {
98 "text": { "type": "string" },
99 "location": { "type": "string" },
100 "note": { "type": "string" },
101 "createdAt": { "type": "string", "format": "datetime" }
102 }
103 }
104 }
105}
106```
107
108Supporting definitions in `app.livtet.defs`:
109- `seriesRef`: `{ seriesId: string }`
110- `identifier`: `{ type: string, value: string }` (e.g., `{"type": "isbn", "value": "978-0-123456-78-9"}`)
111- `physicalFormat`: `{ pages: integer }`
112- `virtualFormat`: `{ size: integer }` (bytes)
113- `audiobookFormat`: `{ duration: integer }` (seconds)