yamlover 0.3.55 → 0.3.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -5
- package/bin/yamlover.js +41 -4
- package/dist/agent-docs/AGENTS.md +20 -330
- package/dist/agent-docs/AGENTS.yo +621 -0
- package/dist/builtin-taxonomy/$defs/.yo/meta.yo +0 -2
- package/dist/builtin-taxonomy/$defs/annotation +3 -1
- package/dist/builtin-taxonomy/$defs/decision +34 -0
- package/dist/builtin-taxonomy/$defs/edit +60 -0
- package/dist/builtin-taxonomy/$defs/edit-answer +21 -0
- package/dist/builtin-taxonomy/$defs/edit-batch +31 -0
- package/dist/builtin-taxonomy/$defs/envelope +169 -0
- package/dist/builtin-taxonomy/$defs/event +85 -0
- package/dist/builtin-taxonomy/$defs/fragment +7 -9
- package/dist/builtin-taxonomy/$defs/link +58 -0
- package/dist/builtin-taxonomy/$defs/task +28 -19
- package/dist/builtin-taxonomy/$defs/workflow +3 -0
- package/dist/builtin-taxonomy/ontos/.yo/body.yo +7 -1
- package/dist/client/assets/{decoded-DYF3m3qY.js → decoded-Bj1qJCo_.js} +1 -1
- package/dist/client/assets/{djvu--bwAI3Ad.js → djvu-lnurzbzN.js} +1 -1
- package/dist/client/assets/{docx-rhrp57OA.js → docx-DpN_PtM8.js} +1 -1
- package/dist/client/assets/{heic-CNvQbH_2.js → heic-BqJutS0N.js} +1 -1
- package/dist/client/assets/imagemap-rdhcPlWy.js +1 -0
- package/dist/client/assets/index-0ALNONIF.js +962 -0
- package/dist/client/assets/index-BiETmvLO.css +1 -0
- package/dist/client/assets/map-Btm4SlVs.js +1 -0
- package/dist/client/assets/paged-Cjy3svw2.js +1 -0
- package/dist/client/assets/{openable-CaZBG8d8.js → panzoom-BXEAw479.js} +2 -2
- package/dist/client/assets/{pdf-CJhbTDg_.js → pdf-DvC2sbDN.js} +1 -1
- package/dist/client/assets/psd-BKmCWsdC.js +11 -0
- package/dist/client/assets/{spreadsheet-B71fTduw.js → spreadsheet-Coy5sooG.js} +1 -1
- package/dist/client/assets/tiff-IcWiNdYs.js +1 -0
- package/dist/client/assets/video-YC-ZvXg7.js +1 -0
- package/dist/client/assets/xyflow-CFNcu5cT.js +23 -0
- package/dist/client/index.html +2 -2
- package/dist/server.js +9228 -5278
- package/dist/wire/openapi.yo +935 -0
- package/package.json +6 -1
- package/dist/agent-docs/CLAUDE.md +0 -7
- package/dist/builtin-taxonomy/$defs/board +0 -15
- package/dist/client/assets/imagemap-BHOOud3m.js +0 -1
- package/dist/client/assets/index-D7Uc99a8.css +0 -1
- package/dist/client/assets/index-DDCohDX6.js +0 -759
- package/dist/client/assets/map-DRUkC_pT.js +0 -1
- package/dist/client/assets/paged-CKzW-eq6.js +0 -1
- package/dist/client/assets/psd-CPdDl_Gy.js +0 -11
- package/dist/client/assets/tiff-D6Ts7aAc.js +0 -1
- package/dist/client/assets/xyflow-DWUupXDf.js +0 -23
- /package/dist/client/assets/{openable-CIGW-MKW.css → panzoom-CIGW-MKW.css} +0 -0
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
!!<*yamlover: $defs: chapter>
|
|
2
|
+
Working with this yamlover project - a guide for AI agents
|
|
3
|
+
description: how to read, write, and co-edit the .yo files of this directory without corrupting the data or the human's live view
|
|
4
|
+
- >
|
|
5
|
+
This project stores structured knowledge as **yamlover** files. You (an AI coding agent) and a
|
|
6
|
+
human are editing the **same directory** at the same time: the human browses the tree in the
|
|
7
|
+
yamlover web UI (`npx yamlover .`) while you read and edit the files on disk. This document is
|
|
8
|
+
itself a yamlover chapter - the format it describes - and tells you how to manipulate these files
|
|
9
|
+
**correctly**.
|
|
10
|
+
- >
|
|
11
|
+
It is self-contained, but not the spec. The authoritative reference is the online documentation
|
|
12
|
+
book at <"yamlover.inthemoon.net/docs"| -: "https://yamlover.inthemoon.net/docs"> - the
|
|
13
|
+
<"language"| -: "https://yamlover.inthemoon.net/docs/language">, the
|
|
14
|
+
<"documents"| -: "https://yamlover.inthemoon.net/docs/documents"> (chapters, marklower, tables,
|
|
15
|
+
lists), the <"annotations"| -: "https://yamlover.inthemoon.net/docs/annotations">, the
|
|
16
|
+
<"meta language"| -: "https://yamlover.inthemoon.net/docs/meta">, the
|
|
17
|
+
<"foreign formats"| -: "https://yamlover.inthemoon.net/docs/formats">, and the
|
|
18
|
+
<"server"| -: "https://yamlover.inthemoon.net/docs/server">. The worked
|
|
19
|
+
<"examples"| -: "https://yamlover.inthemoon.net/examples/"> are browsable live, and the source is
|
|
20
|
+
on <"GitHub"| -: "https://github.com/dims12/yamlover">. This file is regenerated by the UI's
|
|
21
|
+
"Install LLM agent guide" action - keep project-specific rules in `AGENTS.md` (outside its fenced
|
|
22
|
+
block), not here. The bundled guide was checked against the implementation on 2026-09-07.
|
|
23
|
+
- What yamlover is
|
|
24
|
+
- >
|
|
25
|
+
yamlover is a **distinct, YAML-like language** - close to YAML and mostly readable as it, but
|
|
26
|
+
**not a superset**: `*` and `&` carry different meanings (a `*` is a path pointer, **not** a
|
|
27
|
+
YAML alias), so a YAML document with aliases does not round-trip, and these files need the
|
|
28
|
+
yamlover parser. **Never "fix" a `.yo` file with a generic YAML formatter** - it will destroy
|
|
29
|
+
the pointers, the bookmarks, the inline tags, and the mixed ordering.
|
|
30
|
+
- >
|
|
31
|
+
On top of a YAML-style surface it adds a small **pointer layer**, so data forms a graph rather
|
|
32
|
+
than a tree:
|
|
33
|
+
- !!<*yamlover: $defs: bullets>
|
|
34
|
+
- '`*path` - a **reference** (the pull): this value *is* the node over there - a ref edge, never a copy.'
|
|
35
|
+
- '`&path` - a **bookmark** (the push): this node *also* lives over there - it grafts a real key.'
|
|
36
|
+
- '`!!<...>` - an inline **schema tag**; `!!yo` marks a data island, `!!set` a by-identity container.'
|
|
37
|
+
- >
|
|
38
|
+
File extensions: `.yo` is the yamlover surface (the legacy `.yamlover` reads forever).
|
|
39
|
+
`.json5p` is its brace twin - the same pointer layer in JSON5 syntax, pointers written as
|
|
40
|
+
quoted strings (`*": pets: 1"`). Plain `.yaml`/`.json`/`.json5`/`.md`/`.adoc`/images/PDFs
|
|
41
|
+
in the tree are read as what they are; yamlover overlays them, it does not rewrite them.
|
|
42
|
+
- The one omni node
|
|
43
|
+
- >
|
|
44
|
+
YAML forces a node to be a sequence **or** a mapping. yamlover has **one ordered container**:
|
|
45
|
+
every entry has an integer **position** (0, 1, ...) and **may also** carry a string key.
|
|
46
|
+
Keyless and keyed entries coexist, in author order - and a node may carry a **scalar
|
|
47
|
+
self-value and fields at once**:
|
|
48
|
+
- !!<format: text/x-yamlover> |
|
|
49
|
+
playlist:
|
|
50
|
+
- Intro # position 0 keyless
|
|
51
|
+
- Verse # position 1 keyless
|
|
52
|
+
title: Greatest Hits # position 2, key=title keyed - AND still positioned
|
|
53
|
+
- Chorus # position 3
|
|
54
|
+
encore: *: pets: 0 # position 4, key=encore a keyed pointer, still in order
|
|
55
|
+
rating: 5 # the node's own SELF-VALUE ...
|
|
56
|
+
- solid # ... plus a positional field
|
|
57
|
+
scale: 10 # ... plus a keyed field
|
|
58
|
+
- >
|
|
59
|
+
**Order is data**: the position of every entry, keyed ones included, is part of the value. A
|
|
60
|
+
bare integer key **pins** a position (`10: ten` is a keyless entry at position 10); the numeric
|
|
61
|
+
*string* key stays quoted (`'10': v`). `!!mix` is a no-op readability marker for these shapes
|
|
62
|
+
(mixing is the default) - never add or remove it to change meaning. `!!yo` (deprecated
|
|
63
|
+
aliases `!!var`, `!!omni`) is **semantic**: it marks a **data island**, plain yamlover exempt
|
|
64
|
+
from the enclosing document's schema (inside a chapter it renders as data, never as prose).
|
|
65
|
+
- Omni flow syntax
|
|
66
|
+
- >
|
|
67
|
+
Flow containers may carry a self-value using postfix `value|`, anywhere among their
|
|
68
|
+
entries: `{a: 12, 12|}` and `[12, 12|]` each have one entry plus scalar self-value 12.
|
|
69
|
+
`{Earth| diameter: 12742, -: satellite}` mixes a self-value, keyed and keyless entries.
|
|
70
|
+
The self-value consumes no position; duplicate self-values are errors. Quote literal
|
|
71
|
+
pipes in flow strings and keys. Use `-: value` with separation for explicit keyless
|
|
72
|
+
entries. Unquoted `~`, `null`, `Null` and `NULL` in data key position mean the null
|
|
73
|
+
key; quote them to author string keys. `:value` stays a string, and `{:value}` is an
|
|
74
|
+
omitted-value string-key entry. These extensions do not change JSON/json5p or YAML.
|
|
75
|
+
- Paths use colons
|
|
76
|
+
- >
|
|
77
|
+
A path chains keys with **colons**: `a: b: c` is key `a`, then `b`, then `c`. Canonical style
|
|
78
|
+
writes `: ` (colon, space) between steps; the compact `a:b:c` also parses and is what you
|
|
79
|
+
write *inside prose*. `/` is an ordinary character (`text/html`, `01/02/2026` ride bare); the
|
|
80
|
+
old slash-separated paths are dead - `*/pets` dangles on the literal key "/pets".
|
|
81
|
+
- >
|
|
82
|
+
**The scope ladder** - more colons, wider scope. There is no implicit search up the ancestors:
|
|
83
|
+
a bare name is the current mapping only, reach outward explicitly.
|
|
84
|
+
- !!<*yamlover: $defs: table>
|
|
85
|
+
header:
|
|
86
|
+
- Form
|
|
87
|
+
- Base
|
|
88
|
+
width: 2
|
|
89
|
+
- Example
|
|
90
|
+
- ['`*name`, `*..: x`', 'the **current mapping** / its parent', '`*cat`, `*..: ..: pets: 1`']
|
|
91
|
+
- ['`*: path`', 'this **document** root (the nearest `.yo` file or overlay)', '`*: pets: 1`']
|
|
92
|
+
- ['`*:: path`', 'this **project** root (the directory yamlover was served)', '`*:: ontos: genre`']
|
|
93
|
+
- ['`*::: authority: path`', 'the **world** - another project by name, never fetched', '`*::: yamlover.inthemoon.net: $defs: onto`']
|
|
94
|
+
- >
|
|
95
|
+
**What a segment means** - every portion is typed by its own form:
|
|
96
|
+
- !!<*yamlover: $defs: table>
|
|
97
|
+
header:
|
|
98
|
+
- Segment
|
|
99
|
+
- Meaning
|
|
100
|
+
width: 2
|
|
101
|
+
- ['`abc`, `"two words"`', 'a **string key** (bare, or quoted when the bare form would read as something else)']
|
|
102
|
+
- ['`0`, `17`', 'a **position** - bare digits; `''17''` quoted is the numeric string key']
|
|
103
|
+
- ['`~`', 'the **null key** (quote `"null"` in data for that string key)']
|
|
104
|
+
- ['`..`', 'the **parent**; the literal keys `..` / `...` are escaped `\.\.` / `\.\.\.`']
|
|
105
|
+
- ['`-`', 'the **keyless segment** - a trailing `-` on a bookmark appends; in a query, any position']
|
|
106
|
+
- ['`.`, `.len-(1)`, `3+(3)`, `.-(1)`', '**position arithmetic** - my own position, the last entry, position 6, the previous sibling']
|
|
107
|
+
- >
|
|
108
|
+
A key that would read as something else **must be quoted**: pure digits, an empty key, `~`,
|
|
109
|
+
`-`, a position-shaped token (`-1`, `0-3`, `.len`), or a key containing a space. In a document
|
|
110
|
+
a plain `1:` is a **pin**, `'1':` the string key. The retired bracket index (`*pets[1]`,
|
|
111
|
+
`[.-1]`) reads forever but is **written never** - author the bare integer or the arithmetic;
|
|
112
|
+
the old `[]` append and `[?]` brackets were removed, both are the `-` segment now.
|
|
113
|
+
- References and bookmarks
|
|
114
|
+
- >
|
|
115
|
+
`*path` **pulls**: the value lives there. Resolution is lazy, cycle-safe, and yields a **ref
|
|
116
|
+
edge** - editing the target changes everything that points at it. Walking *through* a pointer
|
|
117
|
+
pulls implicitly: a path never stops halfway at "a pointer".
|
|
118
|
+
- !!<format: text/x-yamlover> |
|
|
119
|
+
humans:
|
|
120
|
+
- name: Alice
|
|
121
|
+
manager: *: pets: 1 # Alice.manager IS the node at root -> pets -> position 1
|
|
122
|
+
feline: *pets: 1 # a sibling key, by position
|
|
123
|
+
topDog: *: pets: 0
|
|
124
|
+
- >
|
|
125
|
+
`&path` **pushes**: this node *also* lives there. A bookmark grafts a **real key** - there is
|
|
126
|
+
no anchor namespace, so any plain pointer reaches it. Bookmarks ride the node's own row
|
|
127
|
+
ahead of the value, each chain closed by a colon, or stand on their own lines under the key
|
|
128
|
+
when the value is a container or a block scalar. Bookmarks are **not entries**: a scalar with
|
|
129
|
+
bookmarks is still a scalar.
|
|
130
|
+
- !!<format: text/x-yamlover> |
|
|
131
|
+
boss: &: chief: Rex # ALSO the document-root key `chief`; the value is Rex
|
|
132
|
+
team:
|
|
133
|
+
lead: *: chief # the same node - a ref edge
|
|
134
|
+
adam:
|
|
135
|
+
cain:
|
|
136
|
+
&: eve: cain # "eve holds me as cain" - a reverse relation, as a bookmark
|
|
137
|
+
fan:
|
|
138
|
+
name: Bob
|
|
139
|
+
&: favorites: - # a trailing `-`: Bob APPENDS himself to `favorites`
|
|
140
|
+
- >
|
|
141
|
+
A bookmark path must be **unambiguous**: no wildcards, no position claim (`&: list: 3` and
|
|
142
|
+
`&: list: .len-(1)` are rejected - use the trailing `-`), no null key. A forward `k: *me` and a
|
|
143
|
+
reverse `&: P: k` are **two authorings of one edge** - both at once is legal, merely
|
|
144
|
+
redundant; `normalize` folds them. Bookmark-created members project **after** the
|
|
145
|
+
container's own entries. The legacy `~key: *path` back-edge syntax reads but is deprecated.
|
|
146
|
+
- Partial documents and flat rows
|
|
147
|
+
- >
|
|
148
|
+
A partially loaded graph is valid yamlover. **Pins** state which positions are held
|
|
149
|
+
(`10: ten`, `11: eleven` - positions 0-9 are **gaps**, reported as *not loaded*, never as a
|
|
150
|
+
typo); pins must strictly increase. A reference to itself **postpones** a branch - the key
|
|
151
|
+
is known, the value is not loaded: `a: *a`, normalized to the dot `a: *.`; as a keyless
|
|
152
|
+
entry `- *.` holds one postponed position, and a trailing `- *.` says **more follows** - the
|
|
153
|
+
node's tail is open and its length unknown. You will meet this spelling in the engine's
|
|
154
|
+
own answers; author it only when you mean it.
|
|
155
|
+
- !!<format: text/x-yamlover> |
|
|
156
|
+
a:
|
|
157
|
+
10: value10 # positions 0-9 are gaps
|
|
158
|
+
- value11 # position 11
|
|
159
|
+
- *. # position 12 postponed, the tail open
|
|
160
|
+
- >
|
|
161
|
+
A **flat row** folds a chain of single-pair lines onto one line: `key1: key2: key3: value`
|
|
162
|
+
reads exactly as the nested spelling, and the nested form is the normalized one. A `-`
|
|
163
|
+
segment at the end of a flat path **appends** (`list: -: 1`), in the middle it addresses the
|
|
164
|
+
**last** keyless element. Positions never appear in a flat spine. The editor also preserves
|
|
165
|
+
supported flat-row authoring; use the native editor, not a YAML formatter.
|
|
166
|
+
- Schemas - tags and $defs
|
|
167
|
+
- >
|
|
168
|
+
`!!<...>` binds a node to a schema by a pointer path (the leading `*` is implied):
|
|
169
|
+
`!!<*yamlover: $defs: chapter>`. The project-hosted schemas sit under `$defs` at the project
|
|
170
|
+
root; the built-in taxonomy ships with yamlover and is grafted into **every** served root
|
|
171
|
+
under the self-import key `yamlover`, so `*:: yamlover: $defs: chapter` and
|
|
172
|
+
`*:: yamlover: ontos: colors: yellow` resolve anywhere. Inside a project the self-import is
|
|
173
|
+
absorbed: `*:: $defs: onto` is the same path. Always the **all-colon** spelling after `::`.
|
|
174
|
+
- !!<*yamlover: $defs: table>
|
|
175
|
+
header:
|
|
176
|
+
- Schema
|
|
177
|
+
- What it marks
|
|
178
|
+
width: 3
|
|
179
|
+
- ['`$defs: chapter`', 'a document page - self-value title, keyed `description`, a positional body of chunks and subchapters']
|
|
180
|
+
- ['`$defs: chunk`', 'one renderable block (string or binary); default format `text/marklower`']
|
|
181
|
+
- ['`$defs: table`, `$defs: bullets`, `$defs: numbered`', 'the structures marklower delegates - enter a body only by their explicit tag']
|
|
182
|
+
- ['`$defs: task`', 'a chapter plus planning fields (`priority`, `due`, `assignee`, `estimate`, optional `workflow`); its keyless task members are SUBTASKS - a task with subtasks is a board']
|
|
183
|
+
- ['`$defs: workflow`', 'a state machine as a tag whose sub-tags are the states; `initial:` and per-state `next:` are ref edges']
|
|
184
|
+
- ['`$defs: onto`', 'an entity of an ontology (a tag): optional `color`, sub-ontos to any depth']
|
|
185
|
+
- ['`$defs: fragment`', 'a selected region of a node, under the node''s `.yo: fragments:`']
|
|
186
|
+
- ['`$defs: config`', 'the project settings file `.yo/settings.yo`']
|
|
187
|
+
- >
|
|
188
|
+
A schema is **metadata** (typing, format, presentation), never data storage, and it
|
|
189
|
+
**propagates**: a chapter tagged at its root makes every nested container a chapter and every
|
|
190
|
+
prose leaf marklower - no per-node tags. A per-chunk override is an inline facet tag:
|
|
191
|
+
`!!<format: text/x-latex>`, `!!<format: text/x-yamlover>`, `!!<format: text/plain>`.
|
|
192
|
+
- Concretes - how a node is stored on disk
|
|
193
|
+
- !!<*yamlover: $defs: bullets>
|
|
194
|
+
- '**A single file** - one `.yo` (or `.json5p`) document is one node with everything inside it.'
|
|
195
|
+
- '**A directory** - the directory *is* the node: its files and subdirectories are its members (keyed by file name - member keys keep their extension, `merge-op.yo`), and an **instance overlay** supplies its self-value, tag, ordering, pointers and extra entries: `index.yo` for `dir/index.yo`, or `.yo/body.yo` for `dir/.yo`. An optional `.yo/meta.yo` supplies the schema overlay. Use the existing flavor; never create both instance overlays.'
|
|
196
|
+
- >
|
|
197
|
+
To give "a folder" a title, a tag, a pointer, or an order, edit (or create) its instance overlay
|
|
198
|
+
(`index.yo` or `.yo/body.yo`). A body that is a pointer array (`- *: intro`, `- *: chapter-two`)
|
|
199
|
+
is the **order overlay**: it grants positions to the members it names; a member it never names
|
|
200
|
+
is keyed-only and sorts after the ordered block. The two concretes are **interconvertible**:
|
|
201
|
+
`child.yo` (collapsed) and `child/` with an instance overlay (expanded) are the same node.
|
|
202
|
+
File/directory conversion is a structural operation requiring pointer rewrites, not a plain
|
|
203
|
+
filesystem rename. Ordinary edits do not automatically convert existing file tasks or directory
|
|
204
|
+
tasks.
|
|
205
|
+
- >
|
|
206
|
+
When creating a member, choose its concrete explicitly when storage matters. The edit API
|
|
207
|
+
supports inline values, files and directory concretes, with `name` for a new file or
|
|
208
|
+
directory. A materialized body member is referenced from the instance overlay; tables,
|
|
209
|
+
lists and prose can stay inline. A task born from the board's + is `task-N/index.yo`;
|
|
210
|
+
agents should supply a descriptive slug. Existing members are never automatically renamed
|
|
211
|
+
or converted because their content changes. The body order, not the filename, determines
|
|
212
|
+
the document's order.
|
|
213
|
+
- >
|
|
214
|
+
Inside `.yo/` you also meet `settings.yo` (project configuration - where new ontos and fragments
|
|
215
|
+
are created; edit only when asked), `.trash/` (the archive of removed members - storage-backed
|
|
216
|
+
removal archives there), and **`index.db`** with its `-wal`/`-shm` companions - the server's
|
|
217
|
+
generated SQLite index. **Never edit, copy, or delete `index.db`**; it regenerates from the
|
|
218
|
+
sources. Any key or file whose name starts with `.` is hidden from the TOC but browsable by
|
|
219
|
+
direct path. Hidden entries still occupy their original absolute indexes; do not compact indexes
|
|
220
|
+
when hiding them.
|
|
221
|
+
- Marklower - the prose format
|
|
222
|
+
- >
|
|
223
|
+
**Marklower** is the format of a chapter's prose chunks: a markup deliberately a notch *below*
|
|
224
|
+
Markdown. The current renderer is **inline-only**: it styles prose and displays complete
|
|
225
|
+
yamlover insertions, links and scalar references. It currently has no block syntax: no headings,
|
|
226
|
+
no `- ` lists, no `|---|` tables, no fenced code, no `> ` quotes, no `![]()` images. Structure
|
|
227
|
+
is the chapter body's job: a heading is a subchapter, a table is a `$defs: table` node, a figure
|
|
228
|
+
is a pointer body element. A `##` or a pipe grid typed into a chunk renders as **literal text**.
|
|
229
|
+
- !!<*yamlover: $defs: table>
|
|
230
|
+
header:
|
|
231
|
+
- Syntax
|
|
232
|
+
- Meaning
|
|
233
|
+
width: 2
|
|
234
|
+
- ['`**bold**`, `__bold__`', 'strong']
|
|
235
|
+
- ['`*italic*`, `_italic_`', 'emphasis (an intra-word `_` is literal - `snake_case` stays plain)']
|
|
236
|
+
- ['`~~strike~~`', 'struck through']
|
|
237
|
+
- ['`` `code` ``', 'code span - **atomic**']
|
|
238
|
+
- ['`$$...$$`', 'math, typeset with KaTeX - **atomic**, may span lines']
|
|
239
|
+
- ['`<Earth| diameter: 12742>`', 'complete yamlover flow insertion; literal scalar plus retained fields']
|
|
240
|
+
- ['`<Earth| -: *:: planets: earth>`', 'scalar label and one keyless link target']
|
|
241
|
+
- ['`<*: earth>`', 'insert only the target scalar, without recursive markup']
|
|
242
|
+
- ['`[value](fields)`', 'the **fragment token** - a link when the parens hold one pointer or URL']
|
|
243
|
+
- >
|
|
244
|
+
**Atomic** means the contents are never re-read as markup: a `*` inside a code span or `$$`
|
|
245
|
+
is a literal asterisk - which is why every pointer spelling in this guide sits in backticks.
|
|
246
|
+
A **single newline is a soft break** (hard-wrapped source rejoins into one paragraph); a
|
|
247
|
+
blank line inside a block scalar stays a paragraph gap. Nothing else is special - any
|
|
248
|
+
other character passes through verbatim.
|
|
249
|
+
- >
|
|
250
|
+
**Links** use complete angle insertions: `<the spec| -: *::language:pointers>` is project-rooted
|
|
251
|
+
and `<site| -: "https://example.org">` external. Use a block scalar when inserting spaced
|
|
252
|
+
key/value syntax into prose. `<*: earth>` substitutes only the target scalar. Angle scalars
|
|
253
|
+
display literally; extra fields survive editor round trips. A scalar explicitly tagged
|
|
254
|
+
`!!<format: text/marklower>` can style a label. Escape literal angles as `\<` and `\>` and a
|
|
255
|
+
literal backslash as `\\`; do not escape code/math contents. Missing scalar targets and
|
|
256
|
+
ambiguous multiple link targets are visibly marked. Existing bracket links remain readable and
|
|
257
|
+
source preserved. Structural continuations such as `<| -:>` and `<}>` can now be decomposed into
|
|
258
|
+
chapter nodes through the browser source editor or the shared gather/decompose CLI. Ordinary .yo
|
|
259
|
+
prose scalars, including tagless | blocks, now project those structures as queryable nodes. No
|
|
260
|
+
separate extension or format tag is needed. Explicit plain/code formats and !!yo data islands
|
|
261
|
+
remain literal. The optional .marklower exchange reader also remains supported. Save gathered
|
|
262
|
+
source with an external editor; the browser keeps them read-only until source write routing is
|
|
263
|
+
ready. The chapter editor is WYSIWYG and must never execute typed or pasted structural source.
|
|
264
|
+
Gathering refuses bookmarks/comments, position gaps, binary and separately stored members; use
|
|
265
|
+
native yamlover for those. Full grammar: docs/documents/marklower/gathered.
|
|
266
|
+
- >
|
|
267
|
+
**Fragment tokens** spell a text fragment inline:
|
|
268
|
+
`<&"::yamlover:ontos:topic:math:-" "LaTeX">` files the words "LaTeX" under an onto - the
|
|
269
|
+
angle content is a yamlover scalar with membership bookmarks. Explicit fragment members
|
|
270
|
+
preserve arbitrary fields on existing authored insertions. Bracket tokens are recognized only
|
|
271
|
+
by the explicit migrate-links command; normal readers treat them as prose.
|
|
272
|
+
- >
|
|
273
|
+
**Embedding** is structural: a body element that is a pointer to an image or media member
|
|
274
|
+
(`- *: diagram.png`, `- *: talk.mp4`), or a chunk whose **entire text is one media URL**
|
|
275
|
+
(YouTube, Vimeo, a direct `.mp4`/`.mp3`/`.png` - an allowlist; anything else stays prose).
|
|
276
|
+
A URL inside a sentence is just a link - to embed, give it its own chunk.
|
|
277
|
+
- Chapters - the document model
|
|
278
|
+
- >
|
|
279
|
+
A chapter is a **fully omni** node: its scalar **self-value is the title** (there is no
|
|
280
|
+
`title:` key), `description` is an optional keyed field, and every keyless entry is a body
|
|
281
|
+
element read top to bottom - a **chunk** (a leaf: prose, a format-tagged block, a file
|
|
282
|
+
pointer) or a **subchapter** (a container: a titled one is a scalar with body entries; an
|
|
283
|
+
untitled one a bare container). Tell them apart by **shape**, not tags. A bare string body
|
|
284
|
+
element is both "a chunk" and "a title-only subchapter" - the same thing, by design.
|
|
285
|
+
- !!<format: text/x-yamlover> |
|
|
286
|
+
!!<*yamlover: $defs: chapter>
|
|
287
|
+
Getting Started # the SELF-VALUE - the title
|
|
288
|
+
description: the shortest tour # optional, keyed
|
|
289
|
+
- yamlover is a YAML layer over the filesystem. # a chunk - marklower by default
|
|
290
|
+
- >
|
|
291
|
+
A longer paragraph - with **bold**, `code`, a [link](*:1) to the first chunk - folds
|
|
292
|
+
its hard-wrapped lines into one run.
|
|
293
|
+
- !!<format: text/x-latex> | # a chunk overriding its format
|
|
294
|
+
e^{i\pi} + 1 = 0
|
|
295
|
+
- *: diagram.png # a pointer chunk - the image inlines
|
|
296
|
+
- !!<*yamlover: $defs: bullets> # a typographical list - by explicit tag
|
|
297
|
+
- first point
|
|
298
|
+
- - a nested sub-point # an untagged container = a sublist of the same kind
|
|
299
|
+
- A subchapter # a TITLED subchapter: self-value + its own body
|
|
300
|
+
- its first chunk
|
|
301
|
+
- - an untitled sub-subchapter
|
|
302
|
+
- with two chunks
|
|
303
|
+
- *: appendix # a subchapter stored as its own directory/file
|
|
304
|
+
- !!yo # a data island - rendered as data, not prose
|
|
305
|
+
sensor: 42
|
|
306
|
+
- >
|
|
307
|
+
**Writing prose safely.** Author chunks as block scalars (`- >` folded, `- |` literal): a
|
|
308
|
+
chunk's text then never collides with the parser - a sentence beginning with `*`, `&`, `!`, `[`,
|
|
309
|
+
`-` or containing `: ` is harmless inside a block. A one-line chunk may ride bare when it starts
|
|
310
|
+
with a plain word. Apply only marklower literal escapes inside the block; marklower reads the
|
|
311
|
+
scalar afterwards.
|
|
312
|
+
- >
|
|
313
|
+
**Subchapters on disk.** An inline subchapter is a nested container in the same file. A
|
|
314
|
+
**materialized** one is its own document - `name.yo` beside the parent, or a subdirectory with
|
|
315
|
+
its own `index.yo` or `.yo/body.yo` - referenced from the parent's body by a pointer element
|
|
316
|
+
`- *: name` (member keys keep the extension: `- *: name.yo` for a file). The TOC lists
|
|
317
|
+
subchapters in **body order**; a directory never named by the body sorts after the named ones. A
|
|
318
|
+
**task** member (`- *: engine`, a `$defs: task` file or directory - a board is a task with
|
|
319
|
+
subtasks) lays out as one card linking to the task; its own page holds the lanes.
|
|
320
|
+
- >
|
|
321
|
+
**Addressing body elements.** A chapter at path `P` addresses its elements by **absolute
|
|
322
|
+
entry index** on the node: `:P:0` is the first entry. Keyed entries consume indexes too - a
|
|
323
|
+
chapter with a `description:` has its first body element at `:P:1` - while the **title
|
|
324
|
+
consumes no index** (it is the self-value). This is the same index `/api/edit` uses.
|
|
325
|
+
- >
|
|
326
|
+
**Unlisted files and Other.** With an authored directory body, files not listed in that body
|
|
327
|
+
appear as thumbnail cards in Other rather than trailing chunks, in both render and edit mode.
|
|
328
|
+
The parent chapter collects unlisted files from its own nested subchapters in source order into
|
|
329
|
+
one pane. It does not collect another task's board or unrelated linked chapters. Other is docked
|
|
330
|
+
outside the document scroll area, collapsible and resizable; cards wrap. Empty chapter trays
|
|
331
|
+
start collapsed. A collapsed tray leaves only its divider and expand knob. In both chapter and Tag
|
|
332
|
+
board Other panes, the ± tag menu filters by the conjunction of selected tags. This selection is
|
|
333
|
+
browser-only, scoped by served base and node and shared between renderers; it never retags the
|
|
334
|
+
files. Active badges use the same navigation and appearance as other tag bars.
|
|
335
|
+
- >
|
|
336
|
+
**Drop destinations.** External files dropped on a TOC section or Other become members of
|
|
337
|
+
that section: unlisted on disk-backed directories, keyed references for inline containers.
|
|
338
|
+
A chapter-body drop places a reference chunk at the indicated position. Internal drags
|
|
339
|
+
reuse existing items rather than uploading copies; returning an item to Other unlists its
|
|
340
|
+
placement. Missing reference chunks remain visible and atomically deletable in the editor.
|
|
341
|
+
- >
|
|
342
|
+
**References after edits.** References retain path semantics, including authored citation
|
|
343
|
+
bookmarks. Use mediated structural edits to preserve references through moves and rekeys.
|
|
344
|
+
Positional references follow positions after unmanaged edits, and reusing a deleted path
|
|
345
|
+
or bookmark key makes old references resolve to its new occupant. Trash redirection,
|
|
346
|
+
deletion warnings and permanent memory stubs are not yet a general reference guarantee.
|
|
347
|
+
- Tables and lists
|
|
348
|
+
- >
|
|
349
|
+
A table is a body element tagged `!!<*yamlover: $defs: table>`: its keyless entries are the
|
|
350
|
+
**rows** (top to bottom), each an array of **cells** (left to right, marklower); the row
|
|
351
|
+
keyed `header` is the header row, `title` the caption. The column count comes from the first
|
|
352
|
+
row. A header cell may be an omni scalar carrying a `width` weight. A **merged** cell is a
|
|
353
|
+
pointer to its adjacent neighbor using position arithmetic: `*.-(1)` "I am the cell to my
|
|
354
|
+
left" (colspan), `*..: .-(1): .` "I am the cell above" (rowspan); the merged region must be
|
|
355
|
+
a filled rectangle, and every row keeps its full cell count.
|
|
356
|
+
- !!<format: text/x-yamlover> |
|
|
357
|
+
- !!<*yamlover: $defs: table>
|
|
358
|
+
title: Who does what
|
|
359
|
+
header:
|
|
360
|
+
- Name
|
|
361
|
+
width: 2 # a proportional column weight
|
|
362
|
+
- Class
|
|
363
|
+
- *.-(1) # "Class" spans two columns
|
|
364
|
+
- [Whiskers, mammal, '**manager**'] # a flow row; a cell starting with * must be quoted
|
|
365
|
+
- [Rex, *..: .-(1): ., security] # "mammal" spans down
|
|
366
|
+
- - Bubbles # a block row
|
|
367
|
+
- fish
|
|
368
|
+
- # an UNTAGGED container cell is a CHAPTER again
|
|
369
|
+
- night shift **only**
|
|
370
|
+
- >
|
|
371
|
+
The table schema spends exactly **two** nesting levels (rows, cells); an untagged container
|
|
372
|
+
cell switches back to a chapter, and a nested table or list enters a cell only by its own
|
|
373
|
+
tag. Lists (`$defs: bullets`, `$defs: numbered`) are plain yamlover lists of marklower items;
|
|
374
|
+
an untagged nested container inside one is a sublist of the **same kind**, at any depth.
|
|
375
|
+
Tag a list when the bullets are *content*; a chapter body's own `- ` elements are structure,
|
|
376
|
+
not typography.
|
|
377
|
+
- Annotations - ontos and fragments
|
|
378
|
+
- >
|
|
379
|
+
An **ontology** is an ordinary subtree of things that exist to be pointed at - colors,
|
|
380
|
+
topics, workflow states - each node an **onto** (`$defs: onto`, optional `color`). The
|
|
381
|
+
project's own live under `ontos/` at the project root (the `.yo/settings.yo` location);
|
|
382
|
+
the built-in palette and workflows ship with yamlover: `::yamlover:ontos:colors:yellow`
|
|
383
|
+
(also green, sky, mauve, pink, peach) and `::yamlover:ontos:workflow:dev`.
|
|
384
|
+
- >
|
|
385
|
+
Filing a node under an onto (tagging) is **one bookmark line on the target** - a
|
|
386
|
+
membership edge, no annotation object:
|
|
387
|
+
- !!<format: text/x-yamlover> |
|
|
388
|
+
!!<*yamlover: $defs: chapter>
|
|
389
|
+
A Pinch of Math
|
|
390
|
+
&:: ontos: genre: brevity: shortest-paper: - # a project onto
|
|
391
|
+
&:: yamlover: ontos: colors: yellow: - # a built-in color
|
|
392
|
+
- >
|
|
393
|
+
Membership is additive (two ontos, two lines); the onto sees its members as keyless entries
|
|
394
|
+
after its own. To **untag**, delete the line. The applied onto's color drives display. A
|
|
395
|
+
**fragment** is a selected region of a node - a text span, an image/PDF rectangle, a map
|
|
396
|
+
box - stored as a member of the node's **`.yo: fragments:`** key (the legacy `yo:` spelling
|
|
397
|
+
is read forever - reuse it where a file already has it, never add a second overlay key).
|
|
398
|
+
Each fragment is an omni: its self-value is the principal content (the selected text), the
|
|
399
|
+
selector fields sit beside it, and its own memberships ride it. In marklower prose the
|
|
400
|
+
bracket writer can spell plain selections inline; angle selections use explicit fragment
|
|
401
|
+
members to retain all insertion fields.
|
|
402
|
+
- !!<format: text/x-yamlover> |
|
|
403
|
+
- |
|
|
404
|
+
Mathematics likes to hide, but a standalone LaTeX block gives it away.
|
|
405
|
+
.yo: fragments:
|
|
406
|
+
mq1abc-x2: # a slug key (the UI generates them)
|
|
407
|
+
LaTeX # the fragment's self-value - the text
|
|
408
|
+
type: text
|
|
409
|
+
prefix: ', a standalone '
|
|
410
|
+
suffix: ' block'
|
|
411
|
+
&:: yamlover: ontos: topic: math: - # the fragment's membership
|
|
412
|
+
- >
|
|
413
|
+
For a binary file (`paper.pdf`) the keys go in the enclosing directory's instance overlay
|
|
414
|
+
under the `"paper.pdf":` key. Prefer the UI or the API (`POST /api/annotate`,
|
|
415
|
+
`POST /api/fragment`) over hand-writing selectors; if you must, keep the key names exact and
|
|
416
|
+
never renumber or reorder fragment slugs.
|
|
417
|
+
- Tasks, workflows, and boards
|
|
418
|
+
- >
|
|
419
|
+
A **task** is a chapter plus planning fields - `!!<*yamlover: $defs: task>`, the title as
|
|
420
|
+
self-value, keyed `description`, `priority` (low/normal/high/urgent, advisory), `due`,
|
|
421
|
+
`assignee`, `estimate`, an optional `workflow` - and a body of chunks and **subtasks**. It
|
|
422
|
+
carries **no state field**: its lifecycle position is one membership bookmark into a workflow
|
|
423
|
+
onto. There is no separate board schema: **a board is a task with subtasks** (the retired
|
|
424
|
+
`$defs: board` tag still reads as a task).
|
|
425
|
+
- !!<format: text/x-yamlover> |
|
|
426
|
+
!!<*yamlover: $defs: task>
|
|
427
|
+
Fix the leaky tap
|
|
428
|
+
description: The bathroom tap drips overnight - replace the washer, or the cartridge.
|
|
429
|
+
priority: high
|
|
430
|
+
assignee: dims
|
|
431
|
+
estimate: 2h
|
|
432
|
+
- *..: buy-washers.yo # a BLOCKER - a link to a sibling task (up to the board dir): a subtask here
|
|
433
|
+
- Turn the water off at the valve under the sink FIRST.
|
|
434
|
+
- A half-inch washer kit is in the garage toolbox.
|
|
435
|
+
&::yamlover:ontos:workflow:dev:ready:- # the STATE - one bookmark line
|
|
436
|
+
- >
|
|
437
|
+
**Subtasks** are body elements that are tasks BY THEIR OWN TAG: an inline container tagged
|
|
438
|
+
`!!<*yamlover:$defs:task>` (an untagged container is a plain section of the task, as in a
|
|
439
|
+
chapter), a pointer to the task's OWN child (`- *: slug.yo`, a file or directory under it
|
|
440
|
+
whose document carries the tag), or a link to a task **elsewhere**
|
|
441
|
+
(`- *..: slug.yo`, `- *:: …`) - a BLOCKER is a subtask of the task it blocks; the link is the
|
|
442
|
+
DAG edge, the linked task keeps its own storage (so one card may sit in several tasks' lanes).
|
|
443
|
+
Every subtask is a card of the task's lanes, by its state, and a row of its TOC - a keyless
|
|
444
|
+
pointer is a positional member of its node, the general rule. Keys keep their `.yo`.
|
|
445
|
+
- >
|
|
446
|
+
The built-in **`dev` workflow** (`$defs: workflow` - a tag whose sub-tags are the states) has
|
|
447
|
+
`backlog` -> `ready` -> `in-progress` -> `review` -> `done` | `cancelled`; `initial:` and each
|
|
448
|
+
state's `next:` are advisory ref edges - the engine permits any transition. A **board** is a
|
|
449
|
+
task whose subtasks are files (or inline elements) - a directory tagged in its `index.yo` (or a
|
|
450
|
+
legacy `.yo/body.yo`, read forever):
|
|
451
|
+
- !!<format: text/x-yamlover> |
|
|
452
|
+
# engine/index.yo (or engine/.yo/body.yo)
|
|
453
|
+
!!<*yamlover:$defs:task>
|
|
454
|
+
Engine # the board's title (self-value)
|
|
455
|
+
description: the work board
|
|
456
|
+
workflow: *::yamlover:ontos:workflow:dev # optional: EMPTY lanes for states no card has yet
|
|
457
|
+
- >
|
|
458
|
+
Every task member of the directory is a **card**. Lanes come from the task's own
|
|
459
|
+
workflow or the nearest ancestor task's workflow, excluding its initial state; they do
|
|
460
|
+
not come from whichever tags the cards happen to carry. Initial-state and unmatched cards
|
|
461
|
+
wait in **Other**. Without a workflow or explicit layout there are no lanes.
|
|
462
|
+
Saved layouts live in `.yo: lanes:`; missing workflow lanes are completed on reconcile,
|
|
463
|
+
and terminal states may share a column. Reads reconcile the display in memory without
|
|
464
|
+
writing files; board mutations persist the layout. **Tags are the truth** for membership.
|
|
465
|
+
On a chapter page a task is one card; on its own page it shows its planning strip,
|
|
466
|
+
its foldable board, and its prose.
|
|
467
|
+
- >
|
|
468
|
+
**Operating a board from the files.** To **create a subtask**: add `slug.yo` with the tag, a
|
|
469
|
+
title line, optional fields, and a state bookmark - it is a card on the next reindex (name it in
|
|
470
|
+
the parent's body with `- *: slug.yo` to give it a position; an untagged file is not a task
|
|
471
|
+
card). To **move a card**: change its state bookmark line (`...:dev:ready:-` to
|
|
472
|
+
`...:dev:in-progress:-`); the lanes follow. To **reorder or restructure lanes**, or to move a
|
|
473
|
+
card as the UI does (`POST /api/board` with `op: "move"`), go through the API - it re-tags and
|
|
474
|
+
rewrites `.yo: lanes:` together. Do not hand-edit `.yo: lanes:` to move a card: the tag on the
|
|
475
|
+
card wins, and the next reconcile undoes you. A board's LANES are its workflow's states beyond
|
|
476
|
+
the initial one - its own `workflow:` or the nearest ancestor task's - never derived from the
|
|
477
|
+
cards' tags; the initial state IS the `other` pane; a card tagged otherwise waits there too; an
|
|
478
|
+
empty tagless compartment is forgotten on reconcile. An inline subtask drags too - its state
|
|
479
|
+
bookmark lands on its own line under the element's head. States BUBBLE UP: a task whose subtask
|
|
480
|
+
(member or linked blocker, transitively) is in a further non-terminal state stands in that lane
|
|
481
|
+
on its parent's board, its card saying via which subtask; its own terminal state never moves,
|
|
482
|
+
and the file keeps only the task's own bookmark. And THE PARENT FOLLOWS: when a subtask reaches
|
|
483
|
+
the workflow's active state (`in-progress`), every host still behind it (no state, backlog,
|
|
484
|
+
ready) is written to that state, forward only - review and done stay the host's own call. To
|
|
485
|
+
**declare a blocker**: add `- *..: slug.yo` as a body element of the blocked task - it joins
|
|
486
|
+
that task's lanes and its TOC. **Storage**: a task born from the board's `+` is a DIRECTORY
|
|
487
|
+
member of its host, `task-N/index.yo` (the smallest unused N), **named at birth and never
|
|
488
|
+
renamed by the machine**; rename it yourself with `POST /api/rekey` (`{ path, key }` - it moves
|
|
489
|
+
the directory and rewrites every pointer). Nothing converts a file task to a directory or back:
|
|
490
|
+
a legacy `slug.yo` file task keeps working as it is.
|
|
491
|
+
- Working the tickets - the process for an agent
|
|
492
|
+
- >
|
|
493
|
+
A yamlover project runs its work as **tickets**: task files under a tickets directory
|
|
494
|
+
(`docs/server/todo/*.yo`, say), **sessions** (a task per working session - a directory
|
|
495
|
+
with an `index.yo` - whose body links the tickets it works, `- *:: server: todo: x.yo`,
|
|
496
|
+
so each is a card on the session's board), and **subtasks** born under a ticket or a
|
|
497
|
+
session (`task-N/index.yo`). The `dev` workflow's lanes ARE the process; the state of a
|
|
498
|
+
ticket is the one bookmark line in ITS OWN file, and moving a card means rewriting that
|
|
499
|
+
line (or `POST /api/board` `op: move`, or `POST /api/annotate`) - never a hand edit of a
|
|
500
|
+
board's `.yo: lanes:`. Tag the NODE, never a walked slot (`:session:5`): a bookmark written
|
|
501
|
+
at the slot lands in the session's file, not the card's.
|
|
502
|
+
- !!<*yamlover: $defs: bullets>
|
|
503
|
+
- '**The card moves with you - first.** Before the first edit for a ticket, move its card to `in-progress` - THE TAG IS THE MOVE: rewrite the card''s own state line (`&::yamlover:ontos:workflow:dev:in-progress:-`), or `POST /api/board` with `op: "move"` on a live server, and let the lanes follow. Never hand-edit `.yo: lanes:` to move a card (the tag wins and the next reconcile undoes you). The human watches the board to see what you are on: a card still in `backlog` or `ready` while you work on it is a bug in your process.'
|
|
504
|
+
- '**Titles and slugs.** Every ticket you create has a TITLE - its first line, a sentence a human reads on a card - and a proper SLUG: the file or directory name is the title''s slug (lowercase, hyphenated, the key words: `rename-leaves-the-menu-open.yo`, `the-key-cell/`), never a serial. `task-N` is only what the board''s + births for a human to name; a card you were handed under a serial name gets its slug through `POST /api/rekey` before you work it.'
|
|
505
|
+
- '**Refine before you build.** Read the card, write what you understood and the law you will implement into its body (a dated `- >` note), and birth subtasks (descriptive slug directories under the card, each with its own tag, title, `assignee: agent`, and `&...:dev:ready:-`) when the work has parts; each subtask moves to `in-progress` as you take it, to `review` as it lands.'
|
|
506
|
+
- '**Review means green.** When the code and its pins pass, write a dated "In review" note - what changed, where it is pinned, the suite counts - and move the card to `review`. A UI change waits there for the human''s hands-on check.'
|
|
507
|
+
- '**Done only with the commit.** A card goes to `done` in the same commit that lands its work (the commit message names the cards); never before. A card the human closes by drag is theirs.'
|
|
508
|
+
- '**`assignee` says whose call it is.** `agent`: yours to take from `ready`. `user`: the human''s - a question, a check, a decision; you do not move it.'
|
|
509
|
+
- '**A decision record** (`!!<*::yamlover:$defs:decision>` - a task subtype with `question`, `options`, `decision`, `decided`) is how you hand a question to the human without stalling: birth it under the section where the question arose, `assignee: user`, state `ready`; LINK it from the ticket it blocks (`- *:: session: decide`) - a blocker card on that ticket''s board, waiting; then go on with everything that does not depend on the answer and name it in your report. The human writes `decision:` and moves it to done.'
|
|
510
|
+
- '**Never move a card as a side effect.** No bulk retagging, no "tidying" of lanes, no state written into a file the human did not name. The server logs every state write on its console (`[state] <op> <node> +tag` / `-tag`) - a card that moved has a line there.'
|
|
511
|
+
- '**A commit closes the loop.** Commit what you did with a message that tells the law, the fix, the pins and the cards; the human decides where it is pushed. Stage only your task changes unless the human asks to commit the whole state; preserve concurrent edits.'
|
|
512
|
+
- Operating the running server
|
|
513
|
+
- >
|
|
514
|
+
The server **watches the filesystem**: every save reindexes and pushes the diff to the
|
|
515
|
+
human's browser over SSE within a moment, and their edits appear to you on disk. Everything
|
|
516
|
+
a client does goes through the HTTP API; it is yours to use too, and the safest way to do
|
|
517
|
+
anything structural.
|
|
518
|
+
- !!<*yamlover: $defs: table>
|
|
519
|
+
header:
|
|
520
|
+
- Endpoint
|
|
521
|
+
- Use
|
|
522
|
+
width: 3
|
|
523
|
+
- ['`GET /api/tree?path=:a:b&depth=3`', 'the TOC subtree - labels, types, formats, `hasChildren`']
|
|
524
|
+
- ['`GET /api/content/a/b`', 'THE WIRE - a node as a yamlover envelope (`source`, `side`, `relations`); the path is slash-spelled here, digits are positions, `~` the null key']
|
|
525
|
+
- ['`GET /api/source?path=:a:b`', 'the raw yamlover text of a document (or a re-serialized subtree)']
|
|
526
|
+
- ['`GET /api/query?q=...&path=:`', 'evaluate a colon-grammar query (`humans: ?: name`, `...: !!<format: x-yamlover-onto>`); `shape=paths` / `tree` / `filter`']
|
|
527
|
+
- ['`GET /api/dangling`, `GET /api/doctor`', 'pointers that did not resolve; the whole-tree layout-rule sweep - **run both after a batch of edits**']
|
|
528
|
+
- ['`GET /api/board?path=:engine`', 'the reconciled board and card stubs; `seeded: true` means no saved layout exists; `backlog` contains cards no compartment holds (Other)']
|
|
529
|
+
- ['`POST /api/edit`', 'THE SURGICAL EDITOR: `{ path, op, yamlover }` with `op` = `emplace` (replace only the facets the payload carries), `replace`, `insert` (at the index `path` names), `remove` (storage-backed members are archived), `unlist` (remove a listed reference while retaining its target); `yamlover` is inline source, validated then spliced verbatim - comments elsewhere survive; `{ edits: [...] }` batches']
|
|
530
|
+
- ['`POST /api/mv` `{ from, to }`', 'move/rename a file or directory **and rewrite every inbound pointer** - prefer it over `mv`']
|
|
531
|
+
- ['`POST /api/rekey` `{ path, key }`', 'rename a key - storage-routed: on disk for a file or directory member (every pointer rewritten), in place for an inline entry; a positional path takes a key, `key: null` drops one - the entry never moves']
|
|
532
|
+
- ['`POST /api/paste`', 'file upload with `{ path, filename, contentBase64, placement, at }`: `placement: "member"` adds an unlisted directory member or an inline keyed reference; `"body"` inserts a chunk at absolute index `at`. Duplicate names receive a suffix. Text and rich HTML modes also exist']
|
|
533
|
+
- ['`POST /api/annotate` `{ target, tag }` / `DELETE`', 'apply / remove a membership bookmark on a node or fragment']
|
|
534
|
+
- ['`POST /api/fragment` `{ target, selector }`', 'mark a region under the target''s `.yo: fragments:`']
|
|
535
|
+
- ['`POST /api/board` `{ path, op }`', '`move` (the drag: re-tag + restructure), `structure` (rewrite the lanes), `reconcile`']
|
|
536
|
+
- ['`POST /api/reindex`', 'force a reconcile when the watcher missed something']
|
|
537
|
+
- >
|
|
538
|
+
**Concurrent edits and retries.** Read `/api/content/…?editing=1` and retain its
|
|
539
|
+
`X-Yamlover-Revision` header. Mutation requests can include
|
|
540
|
+
`safety: { revision, operationId }`, where the operation identifier is
|
|
541
|
+
`<milliseconds-since-epoch>:<UUID>`. Retry an uncertain request with its exact original
|
|
542
|
+
payload and identifier; do not mint a new one and duplicate the action. A conflict needs
|
|
543
|
+
a fresh read and reconciliation with the unsaved work. Requests without safety remain
|
|
544
|
+
compatible but lack this concurrency protection.
|
|
545
|
+
- >
|
|
546
|
+
**Generated metadata.** Reconcile removes computed thumbnail metadata for missing files
|
|
547
|
+
and prunes empty metadata containers. Authored fragments and other meaningful metadata
|
|
548
|
+
must be preserved. Do not erase `.yo:` wholesale to repair a stale thumbnail.
|
|
549
|
+
- >
|
|
550
|
+
With `--read-only` every writing route answers 403 - then the files are the only way in, and
|
|
551
|
+
your saves still show up live.
|
|
552
|
+
- >
|
|
553
|
+
**Safety rules for co-editing:**
|
|
554
|
+
- !!<*yamlover: $defs: bullets>
|
|
555
|
+
- '**Make small, valid saves.** A half-written file reindexes as broken and shows the human a parse-error banner. Prefer complete edits; check `GET /api/dangling` afterwards.'
|
|
556
|
+
- '**Never touch `.yo/index.db`** (nor `-wal` / `-shm`). It is the generated index. Instance and schema overlays are source files; logical `.yo:` metadata is engine-managed through annotation, fragment and board APIs, with settings the authoring exception.'
|
|
557
|
+
- '**Renames and moves break inbound pointers.** A plain `mv` leaves every `*: old: path` dangling. Use `POST /api/mv` (it rewrites them at the source) or search the project for pointers to the old path and fix them yourself.'
|
|
558
|
+
- '**Distinguish unlisting from deletion.** `/api/edit` with `op: "unlist"` removes a keyless reference placement, keeping its target. Removing storage-backed members archives their files or directories into the parent''s `.yo/.trash/`; removing inline source is a source edit. Filesystem deletion bypasses that archive. Do not promise reference redirection or memory stubs: those remain future work.'
|
|
559
|
+
- '**Do not reformat with a generic YAML/JSON tool.** It mangles `*`, `&`, `!!<...>`, colon paths, pins, and the mixed keyed/keyless order. Edit the text and preserve the author''s style.'
|
|
560
|
+
- '**Confirm a path before you point at it** - `GET /api/query` or `/api/tree` - and read a chapter''s absolute indexes off `/api/content` before an `/api/edit`.'
|
|
561
|
+
- '**Settings** (`.yo/settings.yo`) say where things are *created*, never constrain reading; change them only when asked.'
|
|
562
|
+
- Escaping
|
|
563
|
+
- >
|
|
564
|
+
A literal metacharacter inside a key is **backslash-escaped**, per character: `cat\:dog`
|
|
565
|
+
is the key "cat:dog", `*\.\.` the literal key "..", `\*boss` the key "*boss". The
|
|
566
|
+
metacharacters are `: [ ] * & ~ # \` and the query characters `? ! ( ) < > = |`. A key
|
|
567
|
+
whose **whole** bare form reads as something else is **quoted** instead: a space inside
|
|
568
|
+
(`'дорожный знак'`), pure digits (`'1'`), `'~'`, `'-'`, an empty key, a position-shaped
|
|
569
|
+
token (`'2024-01'` - the bare form is a range; `2024-01-15` rides bare). In `.json5p` the
|
|
570
|
+
same pointer is a quoted string: `*'..: ..: pets: 1'`.
|
|
571
|
+
- Quick reference
|
|
572
|
+
- !!<format: text/x-yamlover> |
|
|
573
|
+
# references (pull) - colon paths, the scope ladder
|
|
574
|
+
sibling: *pets: 1 # current mapping, position 1
|
|
575
|
+
rooted: *: humans: 0: name # document root -> position 0 -> key name
|
|
576
|
+
strkey: *: counts: '1' # QUOTED digits = the numeric STRING key
|
|
577
|
+
nullkey: *: doc: ~ # the null key
|
|
578
|
+
project: *:: ontos: genre # this project's root
|
|
579
|
+
world: *::: yamlover.inthemoon.net: $defs: onto
|
|
580
|
+
last: *items: .len-(1) # position arithmetic
|
|
581
|
+
previous: *.-(1) # my previous sibling
|
|
582
|
+
later: *. # postponed - known, not loaded
|
|
583
|
+
|
|
584
|
+
# bookmarks (push) - "I also live there"; real keys; unambiguous only
|
|
585
|
+
here: &: chief: Rex # also the document-root key `chief`, value Rex
|
|
586
|
+
rev: &: parent: child # parent holds me as `child`
|
|
587
|
+
mem: &: favorites: - # appended keyless member of `favorites`
|
|
588
|
+
&:: yamlover: ontos: colors: yellow: - # own-line: file THIS node under an onto
|
|
589
|
+
|
|
590
|
+
# schema tags
|
|
591
|
+
!!<*yamlover: $defs: chapter> # a document; task / table / bullets likewise
|
|
592
|
+
- !!<format: text/x-latex> | # a chunk's format override
|
|
593
|
+
e^{i\pi}+1=0
|
|
594
|
+
- !!yo # a data island inside a document
|
|
595
|
+
k: v
|
|
596
|
+
|
|
597
|
+
# partial
|
|
598
|
+
10: ten # a pin - positions 0-9 are gaps
|
|
599
|
+
- *. # the tail is open
|
|
600
|
+
|
|
601
|
+
# escaping
|
|
602
|
+
lit: *weird: cat\:dog # a literal colon in a key
|
|
603
|
+
space: *: ontos: 'two words' # a spacey key is quoted
|
|
604
|
+
- Where to read more
|
|
605
|
+
- !!<*yamlover: $defs: table>
|
|
606
|
+
header:
|
|
607
|
+
- Topic
|
|
608
|
+
- Online chapter
|
|
609
|
+
width: 2
|
|
610
|
+
- ['the language - principles, the logical graph, the concretes, YAML differences', '<"yamlover.inthemoon.net/docs/language"| -: "https://yamlover.inthemoon.net/docs/language">']
|
|
611
|
+
- ['pointers, paths, scopes, bookmarks, position arithmetic, escaping, queries', '<"docs/language/pointers"| -: "https://yamlover.inthemoon.net/docs/language/pointers">']
|
|
612
|
+
- ['partial documents - pins, gaps, postponed branches', '<"docs/language/partial"| -: "https://yamlover.inthemoon.net/docs/language/partial">']
|
|
613
|
+
- ['flat rows', '<"docs/language/flattening"| -: "https://yamlover.inthemoon.net/docs/language/flattening">']
|
|
614
|
+
- ['storage - files, directories, overlays, member encoding', '<"docs/language/concretes"| -: "https://yamlover.inthemoon.net/docs/language/concretes">']
|
|
615
|
+
- ['the meta language - `type`, `format`, `members`, `$defs`', '<"docs/meta"| -: "https://yamlover.inthemoon.net/docs/meta">']
|
|
616
|
+
- ['chapters, tasks, addressing body elements', '<"docs/documents/chapter"| -: "https://yamlover.inthemoon.net/docs/documents/chapter">']
|
|
617
|
+
- ['marklower - grammar, link targets, embeds, tables, lists', '<"docs/documents/marklower"| -: "https://yamlover.inthemoon.net/docs/documents/marklower">']
|
|
618
|
+
- ['annotations - fragments, ontos, membership, storage', '<"docs/annotations"| -: "https://yamlover.inthemoon.net/docs/annotations">']
|
|
619
|
+
- ['foreign formats - Markdown, AsciiDoc, office, images, media, maps', '<"docs/formats"| -: "https://yamlover.inthemoon.net/docs/formats">']
|
|
620
|
+
- ['the server - UI, editors, endpoints', '<"docs/server"| -: "https://yamlover.inthemoon.net/docs/server">']
|
|
621
|
+
- ['worked examples (a table, a chapter, a board - a task with subtasks, marklower links, a deep book)', '<"yamlover.inthemoon.net/examples"| -: "https://yamlover.inthemoon.net/examples/">']
|