{"lf-suggestion":{"description":"One proposed change to content the user has already seen, with accept and reject controls.","x-instructions":"Copy the current markup verbatim into lf-old and put the proposed markup in lf-new. Both slots replace, lf-new alone inserts, and lf-old alone deletes; a change to a widget also uses its complete old and new markup. Write new content directly, and use lf-draft for words the user owns. Suggestions cannot nest, contain a draft, or appear in a reply. Set `resolves` to the comment whose thread should close when the user accepts. To withdraw an undecided suggestion, replace the whole `lf-suggestion` with `lf-old`'s contents. Keeping `lf-new`'s contents instead would accept it without the user's decision.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"resolves":{"type":"string","pattern":"^[a-z0-9]+$"},"restated":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"x-content":"members","x-inline":true,"x-upgrade":true,"x-awaits":{"value":"decide","answered":{"decide":{}},"all":"accept"},"x-withdrawn-as":"reject","x-word":"module","x-state":{"decide":{"detail":{"type":"object","properties":{"outcome":{"enum":["accept","reject"]}},"required":["outcome"],"additionalProperties":false},"unit":"widget"}},"x-example":"<p>Refill rules for the season:</p>\n<lf-suggestion id=\"sug-refill\">\n  <lf-old><p id=\"refill-rule\">Refill every feeder each morning.</p></lf-old>\n  <lf-new><p>Refill a feeder when its camera shows it half-empty.</p></lf-new>\n</lf-suggestion>"},"lf-old":{"description":"The current markup a suggestion proposes to replace or delete.","x-instructions":"Copy the current markup verbatim, including its ids. Omit this slot for an insertion.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"additionalProperties":false,"x-owners":["lf-suggestion"],"x-content":"markup","x-inline":true,"x-upgrade":false,"x-retired-when":"accept"},"lf-new":{"description":"The proposed markup in a suggestion.","x-instructions":"Omit this slot for a deletion.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"additionalProperties":false,"x-owners":["lf-suggestion"],"x-content":"markup","x-inline":true,"x-upgrade":false,"x-retired-when":"reject"},"$languages":{"description":"The code languages this layer can color, and how a filename maps to one. `names` is the full list: an author may declare only these, validation refuses any other, and build/vendor.mjs builds a grammar for each. A widget marks an attribute as naming a language with x-language, and validation reads this list, so a new tag that takes a language needs only that declaration. `paths` maps a file extension to a language, for widgets with no attribute to name one: a diff spans several files, and a file editor shows one. A file whose extension is not listed shows uncolored.","why-diff-is-not-a-path":"`diff` is in `names` but not in `paths`. Coloring a .patch file inside a diff with the diff grammar would mark additions and deletions a second time, on top of the widget's own tints.","names":["bash","css","diff","go","html","java","javascript","json","markdown","python","rust","sql","toml","typescript","yaml"],"paths":{"bash":"bash","cjs":"javascript","css":"css","go":"go","htm":"html","html":"html","java":"java","js":"javascript","json":"json","jsx":"javascript","markdown":"markdown","md":"markdown","mjs":"javascript","py":"python","rs":"rust","sh":"bash","sql":"sql","toml":"toml","ts":"typescript","tsx":"typescript","yaml":"yaml","yml":"yaml"}},"$passages":{"description":"How Python (`leaf/passages.py`, `leaf/anchor_capture.py`) and the browser (`runtime/passage-facts.js`, generated from this entry by build/registry.mjs) turn a page into text, so `leaf thread open` can confirm any quote the browser captures. Python reads the running Leaf's copy and a page's runtime keeps the one it was vendored with, so a change here bumps `$events.protocol`.","collapse":"\t\n\u000b\f\r \u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff","why-collapse-is-spelled-out":"`collapse` lists the characters both readings fold to one space. JavaScript's \\s and Python's str.isspace() disagree on a few: U+FEFF is whitespace only to JavaScript, U+0085 only to Python. The browser captures every quote, so the list is JavaScript's set.","blocks":["p","li","h1","h2","h3","h4","h5","h6","td","th","pre","blockquote","dd","dt","figcaption","summary"],"why-blocks":"A text node's block decides spacing: runs of text in different blocks are joined with one space and runs in one block with none, so `<p>a</p><p>b</p>` reads \"a b\" and `set<em>up</em>` reads \"setup\". The browser also treats a block as the unit of prose a reader is in, and a version diff compares blocks.","context":24,"why-context":"How many characters of context a captured anchor keeps on each side of its quote. A quote read from the file must be unique. The browser knows which occurrence the user selected, and widens the context until the shared resolver finds that one."},"$data":{"description":"Reusable evidence from one guided website visual run.","contracts":{"measured-scalar":{"description":"The latest scalar emitted by a repeatable measurement source. Authored lf-num text freezes the value a version states; the source snapshot records whether that measurement ran again.","schema":{"type":["number","string"]}},"text-document":{"description":"UTF-8 text from a file or a selected line range.","schema":{"type":"string"}},"unified-diff":{"description":"A unified patch, either as one text value or as a file manifest whose patch fields Leaf delivers separately on demand.","instructions":{"producer":"Pipe the exact Git patch, with Git's default `a/` and `b/` prefixes, through this package's producer script into the source:\n\n```bash\ngit diff <base>...<head> | leaf package run diff patch_manifest.py | leaf data set \"$PAGE\" <source-id>\n```\n\nThe script preserves native Git evidence keyed by destination path. It leaves judgment to `lf-diff`: each file\u2019s patch is delivered and checked before its row appears, and textual hunks render when their file opens. A file the widget cannot present shows its refusal and reports it to you as the page's error."},"records":{"items":"files","key":"path","deferred":"patch"},"schema":{"type":["string","object"],"properties":{"files":{"type":"array","minItems":1,"items":{"type":"object","properties":{"path":{"type":"string","minLength":1},"patch":{"type":"string","minLength":1}},"required":["path","patch"],"additionalProperties":false}}},"required":["files"],"additionalProperties":false}},"visual-run":{"description":"An ordered set of aligned before-and-after website states captured against one base and one candidate.","instructions":{"producer":"Capture the same authored journey at the same viewport against immutable base and candidate revisions. Include a target URL only when that captured revision has a real replayable destination; omit it for archive-only captures. Wait on a product readiness fact, disable animation, and freeze seeded data and time. Authenticate the capture browser, not the visual run: store clean target URLs, and never put query keys, cookies, or headers into page data or media. Inspect every image for credentials or personal data, import it with `leaf page media`, then replace the complete source with `leaf data set`. Each case keeps a stable `id` across refreshes, a short action and observed result, both image paths, and the browser conditions and observation time under which that pair was captured. Keep each capture's observedAt with that case, so refreshing one case preserves the provenance of retained evidence. When a small change is hard to find in a large capture, give its case one optional `focus` rectangle, `x`, `y`, `width`, and `height` in captured CSS pixels from the image's top-left, shared by both images so movement stays visible; keep it inside both decoded images with enough surrounding context to show displacement. A second area that makes a separate claim is another case reusing the image pair, not a nested region. Use a new source id when the run changes meaning."},"records":{"items":"cases","key":"id"},"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"base":{"$ref":"#/$defs/target"},"candidate":{"$ref":"#/$defs/target"},"cases":{"type":"array","minItems":1,"items":{"$ref":"#/$defs/case"}}},"required":["title","base","candidate","cases"],"additionalProperties":false,"$defs":{"target":{"type":"object","properties":{"revision":{"type":"string","minLength":1},"url":{"type":"string","format":"uri","pattern":"^https?://\\S+$"}},"required":["revision"],"additionalProperties":false},"capture":{"type":"object","properties":{"observedAt":{"type":"string","format":"date-time"},"browser":{"type":"string","minLength":1},"browserVersion":{"type":"string","minLength":1},"viewport":{"type":"object","properties":{"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1}},"required":["width","height"],"additionalProperties":false},"deviceScaleFactor":{"type":"number","exclusiveMinimum":0},"colorScheme":{"enum":["light","dark"]},"locale":{"type":"string","minLength":1},"timezone":{"type":"string","minLength":1}},"required":["observedAt","browser","browserVersion","viewport","deviceScaleFactor","colorScheme","locale","timezone"],"additionalProperties":false},"focus":{"type":"object","properties":{"x":{"type":"number","minimum":0},"y":{"type":"number","minimum":0},"width":{"type":"number","exclusiveMinimum":0},"height":{"type":"number","exclusiveMinimum":0}},"required":["x","y","width","height"],"additionalProperties":false},"case":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"title":{"type":"string","minLength":1},"path":{"type":"string","pattern":"^/\\S*$"},"action":{"type":"string","minLength":1},"result":{"type":"string","minLength":1},"classification":{"enum":["changed","clean"]},"capture":{"$ref":"#/$defs/capture"},"focus":{"$ref":"#/$defs/focus"},"before":{"type":"string","pattern":"^/media/\\S+$"},"after":{"type":"string","pattern":"^/media/\\S+$"},"traceUrl":{"type":"string","format":"uri","pattern":"^https?://\\S+$"}},"required":["id","title","path","action","result","classification","capture","before","after"],"additionalProperties":false}}}},"playwright-trace":{"description":"A review index derived from one immutable Playwright format-9 trace archive. Times are native monotonic milliseconds within each stream; screenshots and saved accessibility trees have separate capture times.","instructions":{"producer":"Initialize a page with package playwright and bind an lf-trace widget to its source id. Import the native archive through the producer and Leaf canonical media writer: leaf package run playwright import_trace.py TRACE --page PAGE --leaf /absolute/path/to/bin/leaf --viewer-url URL | leaf data set PAGE SOURCE. The viewer URL must open the same unchanged trace.zip. Keep the original archive; its SHA-256 scopes every imported action, image and saved-tree node identity. Use a new source id for another recording. Format 9 only; other versions are refused explicitly. Review the recording for credentials and personal data before sharing. PNG checkpoints and accessibility trees are sequential captures: tree boxes describe the saved tree, not an exact pixel target in the neighboring image. Native method names and input selector, key, pointer coordinates and input-snapshot viewport dimensions are retained with action titles, timings and errors; filled values and other API parameters remain in the archive. Input may be absent, and keyboard input may have no pointer coordinates. Pointer coordinates use the native viewport, not raster-image dimensions; no point overlay is possible without that viewport. Native input events have no timestamp; the action phase records its snapshot time. DOM inspection, network, console, source, test-runner hierarchy, attachments and complete assertion results remain in the linked Playwright viewer."},"schema":{"type":"object","properties":{"archive":{"type":"object","properties":{"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"format":{"const":9}},"required":["sha256","format"],"additionalProperties":false},"viewerUrl":{"type":"string","format":"uri","pattern":"^https?://\\S+$"},"streams":{"type":"array","items":{"$ref":"#/$defs/stream"}},"pages":{"type":"array","items":{"$ref":"#/$defs/page"}},"actions":{"type":"array","items":{"$ref":"#/$defs/action"}},"images":{"type":"array","items":{"$ref":"#/$defs/image"}}},"required":["archive","viewerUrl","streams","pages","actions","images"],"additionalProperties":false,"$defs":{"box":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"width":{"type":"number"},"height":{"type":"number"}},"required":["x","y","width","height"],"additionalProperties":false},"node":{"type":"object","properties":{"path":{"type":"string"},"role":{"type":["string","null"]},"name":{"type":["string","null"]},"text":{"type":["string","null"]},"box":{"anyOf":[{"$ref":"#/$defs/box"},{"type":"null"}]}},"required":["path","role","name","text","box"],"additionalProperties":false},"tree":{"type":"object","properties":{"timestamp":{"type":"number"},"nodes":{"type":"array","items":{"$ref":"#/$defs/node"}}},"required":["timestamp","nodes"],"additionalProperties":false},"phase":{"type":"object","properties":{"pageId":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"timestamp":{"type":"number"},"imageId":{"type":["string","null"]},"tree":{"anyOf":[{"$ref":"#/$defs/tree"},{"type":"null"}]}},"required":["pageId","timestamp","imageId","tree"],"additionalProperties":false},"point":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"],"additionalProperties":false},"viewport":{"type":"object","properties":{"width":{"type":"number","exclusiveMinimum":0},"height":{"type":"number","exclusiveMinimum":0}},"required":["width","height"],"additionalProperties":false},"input":{"type":["object","null"],"properties":{"selector":{"type":["string","null"]},"key":{"type":["string","null"]},"point":{"anyOf":[{"$ref":"#/$defs/point"},{"type":"null"}]},"viewport":{"anyOf":[{"$ref":"#/$defs/viewport"},{"type":"null"}]}},"required":["selector","key","point","viewport"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"stream":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"callId":{"type":"string"},"pageId":{"type":["string","null"]},"title":{"type":"string"},"method":{"type":"string","minLength":1},"input":{"$ref":"#/$defs/input"},"startTime":{"type":"number"},"endTime":{"type":["number","null"]},"error":{"type":["string","null"]},"phases":{"type":"object","properties":{"before":{"$ref":"#/$defs/phase"},"action":{"$ref":"#/$defs/phase"},"after":{"$ref":"#/$defs/phase"}},"additionalProperties":false}},"required":["id","stream","callId","pageId","title","method","input","startTime","endTime","error","phases"],"additionalProperties":false},"image":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"pageId":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"stream":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"timestamp":{"type":"number"},"kind":{"enum":["frame","checkpoint"]},"url":{"type":"string","pattern":"^/media/[a-f0-9]+\\.(jpg|png)$"},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"callId":{"type":["string","null"]},"phase":{"enum":["before","action","after",null]}},"required":["id","pageId","stream","timestamp","kind","url","width","height","callId","phase"],"additionalProperties":false},"page":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"stream":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"pageId":{"type":"string"}},"required":["id","stream","pageId"],"additionalProperties":false},"stream":{"type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"origin":{"type":"string"},"playwrightVersion":{"type":["string","null"]},"wallTime":{"type":["number","null"]},"monotonicTime":{"type":["number","null"]}},"required":["id","origin","playwrightVersion","wallTime","monotonicTime"],"additionalProperties":false}}},"resources":["images[].url"]}}},"$events":{"protocol":8,"ownership":{"derived":["meaning","attention"],"browser_discard":["id","author","agent","session","ts","seq","attention"]},"description":"The kernel's event kinds. Each kind's `record` is the closed schema of the event as the log stores it, and a kind with a `browser` schema can also be posted to POST /api/event. Admission fills in the fields `ownership.derived` names; browser ingress drops those `ownership.browser_discard` names before validating. A layer extends widget behavior through x-state, but cannot add kinds or change who owns a field. Admission sets the boolean `attention`. Every report and error has it, and the agent's other events and the user's bookkeeping never do. The user's other input has it when it changes what is owed: an answer, an ask or to-do on the user, work the agent has started and its inputs, or a sign-off approval. Code that asks whether an event needs attention reads this field instead of switching on the kind. `protocol` is Leaf's only version number. It covers these kinds and the state the server sends a page's runtime, and every record Leaf keeps outside a page's log and document, such as a delivery or a browser draft, carries it in its `format`. A Leaf serves and writes only pages vendored at its own `protocol`, so a change that would break such a page, such as dropping a field or requiring a new one, bumps it. A `bookkeeping` kind (`read`, `reanchor`) records a fact about the user's view, never asks the agent for anything, and travels outside the queue of the user's updates. A `pickup` records that inputs reached their reader, or, with phase `failed`, that the harness gave up on them; it never means work has begun. A `comment` or `reply` with `token` instead of `text` is a reaction ($reactions). `handling` and `answering` hold the instructions delivered with each event, and a later layer may restate them one kind at a time. Each maps a kind (of event, or of the answer it owes: `reply` or `markup`) to an ordered list of clauses: a `text`, and an optional `when` JSON Schema matched against the event's record, the `answer` it owes and its thread's entry in the batch's `threads`. A delivered event carries its kind's matching clauses, then its answer's, so it is told only its own case. Instructions that differ by route are not clauses: the delivery says once who confirms receipt, and sets the answer's `writer` to `turn` where the turn carrying it writes the reply.","handling":{"comment":[{"when":{"required":["drawing"]},"text":"The user drew on the page. `drawing.says`, when present, is the page's text inside the ink's bounding box, from its first word to its last, so an arrow across a paragraph gives the whole paragraph; it is absent where the box covers no words, as over a picture. `drawing.strokes` are coordinates in one frame: the comment's target, or the visual inside it that the optional `drawing.frame` names (CSS pixels for HTML, user units for SVG, intrinsic pixels for an image, canvas or video), and `drawing.box` is that frame's size. To see what the mark covers, run `leaf page picture PAGE ID` with the comment's `id`: it prints the path of a PNG of that revision in the user's window size and color scheme, with the ink drawn over it. Any `text` explains the mark; otherwise answer it like any comment."},{"when":{"required":["text"],"properties":{"text":{"pattern":"\\]\\(/media/"}}},"text":"The message links an image in Markdown, as `/media/<digest>.<ext>` under the page directory the batch names. Open the image before answering; its alt text is only a label."},{"when":{"required":["suggestion"],"properties":{"suggestion":{"const":true}}},"text":"A suggestion proposes exact replacement text. Apply it verbatim, or reply with your reason for declining."},{"when":{"required":["about"],"properties":{"about":{"const":"design"}}},"text":"A design comment is about how the page looks or behaves, not what it says. Its anchor's `section` is an authored element's id or, if it starts `lf-`, a part of Leaf's chrome, such as `lf-banner`, `lf-threads` (the Threads panel), `lf-queue` (the On panel), `lf-versions` or `lf-composer`. `part`, when present, describes the control, region or picture the user clicked. Fix it in this page's source. If the behavior belongs to a package's widget, or the user asks for a wider fix, change the package as the Leaf skill's `references/packages.md` says, re-vendor, and note the re-vendor on the stamp. A fix to Leaf itself is the user's to raise (the Leaf skill's \"Improve Leaf through use\"). Your reply reports the stamped version that carries the fix."},{"when":{"required":["thread","answer"],"properties":{"thread":{"required":["title"],"properties":{"title":{"type":"null"}}},"answer":{"properties":{"kind":{"const":"reply"},"writer":{"const":"agent"}}}}},"text":"The thread has no title yet. Name it with `--title \"<a few words>\"` on your reply, so the Threads panel lists its subject instead of its opening words. If Leaf has already named it from its first message, that name stays."},{"when":{"required":["token"]},"text":"A reaction is a mark, not a question. Act on the token if it calls for a change; reply only if its meaning is unclear. Once the page reflects it, close it with `leaf thread resolve <page> <event-id>`. It never blocks publishing a version and waits on no answer."}],"reply":[{"when":{"not":{"required":["token"]}},"text":"The user answered in a thread. The batch's `threads` holds the thread's context, and `leaf page state <page> <thread-id>` reads its full history a page at a time."},{"when":{"required":["text"],"properties":{"text":{"pattern":"\\]\\(/media/"}}},"text":"The message links an image in Markdown, as `/media/<digest>.<ext>` under the page directory the batch names. Open the image before answering; its alt text is only a label."},{"when":{"required":["thread","answer"],"properties":{"thread":{"required":["title"],"properties":{"title":{"type":"null"}}},"answer":{"properties":{"kind":{"const":"reply"},"writer":{"const":"agent"}}}}},"text":"The thread has no title yet. Name it with `--title \"<a few words>\"` on your reply, so the Threads panel lists its subject instead of its opening words. If Leaf has already named it from its first message, that name stays."},{"when":{"required":["thread"],"properties":{"thread":{"required":["summary_hint"]}},"not":{"required":["token"]}},"text":"This thread's entry in the batch's `threads` has a `summary_hint`: an earlier range of messages worth summarizing. As you answer, follow the Leaf skill's `references/threads.md`, \"Summarize a long discussion\". The hint needs no separate answer."},{"when":{"required":["token"]},"text":"A reaction to your message. It needs no reply; Leaf already records whether it answers your question."}],"edit":[{"text":"The user rewrote their message `message`: `text` is the new wording and `was` the old, and the thread shows only the new. Answer it as it now reads. If your earlier answer or work depended on what changed, say what that changes and redo the work; if it didn't, say so. If `message` opens the thread and the title no longer fits, retitle it with `leaf thread edit <page> <message> --title \"<a few words>\"`."},{"when":{"required":["suggestion"],"properties":{"suggestion":{"const":true}}},"text":"The message is a suggestion, so `text` is now its exact replacement text. Apply it verbatim, or reply with your reason for declining."}],"resolve":[{"text":"The user closed the thread. You owe no reply there; a to-do you opened on it stays open until you end it."}],"unresolve":[{"text":"The user reopened a closed thread. Reopening needs no separate answer; if the thread's latest user message was never answered, `leaf page state <page> <thread-id>` shows the `answer` still owed."}],"todo_end":[{"text":"The user pressed Done on the to-do `todo`, which you opened with `--on user`. That ends it and owes no reply. Continue the work it was waiting for, reading the page if you need to see what they did; if you still need something from them, ask again."}],"done":[{"text":"The user approved the page's sign-off. The page stays open: keep watching it while you do the work the approval unblocks, and show that work as a to-do (`leaf task open <page> page \"<the work>\"`, then `leaf task start`)."}],"action":[{"text":"The user already sees the action applied."},{"when":{"allOf":[{"not":{"required":["answer"]}},{"not":{"required":["meaning"],"properties":{"meaning":{"required":["scope"],"properties":{"scope":{"const":"thread"}}}}}}]},"text":"The log carries the action onto every later version, so the page keeps it without an edit."},{"when":{"allOf":[{"required":["action"],"properties":{"action":{"const":"add"}}},{"not":{"required":["meaning"],"properties":{"meaning":{"required":["scope"],"properties":{"scope":{"const":"thread"}}}}}}]},"text":"Every later version keeps the added option in its group where the user put it, after the authored options, so leave it out of the markup."},{"when":{"required":["action"],"properties":{"action":{"const":"decide"}}},"text":"The user decided a suggestion; `detail.outcome` says which way: `accept` keeps the lf-new branch and `reject` the lf-old one. In the next version, write the kept branch in as plain prose with its ids and remove the suggestion."},{"when":{"not":{"required":["meaning"],"properties":{"meaning":{"required":["scope"],"properties":{"scope":{"const":"thread"}}}}}},"text":"If you need clarification, ask in a thread on the picked option. To override the pick in a later version, mark the element `restated` and say why in the version note."},{"when":{"not":{"required":["answer"]}},"text":"This action owes no answer of its own: it answers no ask, a later action on the same widget carries the answer, or the answer is not complete yet, as with a pick before the Done its group waits for."}],"undo":[{"text":"The user took back the gesture `undoes` names. Treat the two as cancelled: don't answer or record the withdrawn gesture. Undoing an action that answered or closed a thread reopens that thread."}],"report":[{"text":"A worker reported provisional state for a page widget, which the page shows until a stamped version answers it. Before the page ends, answer it in a stamped version: write the reported state into the markup, or mark the element `overruled` and say why in the version note. Until then the report stays in force."}],"error":[{"text":"The page's runtime reported a failure the user saw. Fix the page or widget and save the fix. Reply only if the user asked about it."}]},"answering":{"reply":[{"text":"If the event asks for work, first post one line in its thread saying what you will do, before any other command, even reading the source: `leaf response reply <answer.ref> --ephemeral --text \"<what you will do, in a line>\"`. It shows at once and starts the update, which reads Working until you answer. Do the work and put the result on the page, with what shows it (captures, a figure, the numbers). Then answer with `leaf response reply <answer.ref> --done < reply.md`: what changed, in a sentence or two, linking the section that shows it. If the event asks for no work, as a question may not, answer it with that reply at once. The page holds the work; the thread holds only the conversation about it. `leaf response reply` checks any saved page edit and makes it live before posting. If the revision removes the thread's anchor, move the thread in the same reply with `--section <id>` (narrowed by `--quote` or `--part`), or `--detach` it if its subject left the page. Each answer takes `--done` when it delivers what was asked, `--ask` when it asks the user something back, or `--todo \"<what you owe>\"` when it promises work beyond this turn, which stays on you until `leaf task end` (`references/conversation-loop.md`, \"Long-running work\").","when":{"properties":{"answer":{"properties":{"writer":{"const":"agent"}}}}}},{"text":"Leaf streams your opening message into the thread and posts your final message as the reply, unless an explicit reply already answered this input. Before your first tool call, tell the user briefly the answer or what you are about to do; later working messages stay in Codex. End with the answer, or what changed and where it shows. For widgets, an ask awaiting the user (`--ask`), work promised beyond this turn (`--todo`), a title or moving the thread, reply explicitly with `leaf response reply <answer.ref>` (`references/threads.md`); it posts at once, and your final message is then not posted.","when":{"properties":{"answer":{"properties":{"writer":{"const":"turn"}}}}}},{"text":"Your reply renders as Markdown in a narrow column: give each point its own short paragraph or list item, link a page section as `[its name](#section-id)`, and fence code or markup."},{"when":{"required":["meaning"],"properties":{"meaning":{"required":["scope"],"properties":{"scope":{"const":"thread"}}}}},"text":"The widget is in a thread message: continue the work the user's answer selects or unblocks, and answer in that thread."}],"markup":[{"text":"It answers the page's ask, which shows as waiting on you until the markup records the answer. Name the work it selects or unblocks with `leaf task start <page> <event-id> \"<the work, in a line>\"` before starting it; then do it, write the answer in, and stamp a version. An option the user added needs no writing in: the page keeps it where the user put it."}]},"kinds":{"comment":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"comment"},"seq":{"type":"integer","minimum":1},"revision":{"type":"integer","minimum":1},"text":{"type":"string","minLength":1},"token":{"type":"string","minLength":1},"anchor":{"type":"object","properties":{"section":{"type":["string","null"]},"quote":{"type":"string"},"datum":{"type":"string","minLength":1},"source":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"source_revision":{"type":"string","pattern":"^[0-9a-f]{16}$"},"identity":{"type":"string","minLength":1},"visual":{"type":"string","minLength":1},"prefix":{"type":"string"},"suffix":{"type":"string"},"detached":{"const":true},"part":{"type":"string"}},"anyOf":[{"required":["section"],"properties":{"section":{"type":"string","minLength":1}}},{"required":["quote"],"properties":{"quote":{"type":"string","minLength":1}}},{"required":["datum"],"properties":{"datum":{"type":"string","minLength":1}}}],"dependentRequired":{"datum":["section"],"source":["datum","source_revision"],"source_revision":["datum","source"],"identity":["datum"],"part":["section"],"detached":["quote"],"visual":["section"]},"additionalProperties":false},"drawing":{"type":"object","properties":{"strokes":{"type":"array","minItems":1,"maxItems":32,"items":{"type":"array","minItems":2,"maxItems":256,"items":{"type":"array","minItems":2,"maxItems":2,"prefixItems":[{"type":"number","minimum":-33554432,"maximum":33554432},{"type":"number","minimum":-33554432,"maximum":33554432}],"items":false}}},"box":{"type":"array","minItems":2,"maxItems":2,"prefixItems":[{"type":"number","exclusiveMinimum":0,"maximum":33554432},{"type":"number","exclusiveMinimum":0,"maximum":33554432}],"items":false},"frame":{"type":"object","properties":{"root":{"type":"string","maxLength":128,"pattern":"^[A-Za-z][A-Za-z0-9_.:-]*$"},"path":{"type":"array","maxItems":32,"items":{"type":"object","properties":{"tag":{"type":"string","maxLength":128,"pattern":"^[A-Za-z][A-Za-z0-9_.:-]*$"},"index":{"type":"integer","minimum":0,"maximum":65535},"siblings":{"type":"integer","minimum":1,"maximum":65536},"shadow":{"type":"boolean"}},"required":["tag","index","siblings"],"additionalProperties":false}}},"required":["root","path"],"additionalProperties":false},"says":{"type":"string","minLength":1,"maxLength":500},"viewport":{"type":"array","minItems":2,"maxItems":2,"prefixItems":[{"type":"number","exclusiveMinimum":0,"maximum":33554432},{"type":"number","exclusiveMinimum":0,"maximum":33554432}],"items":false},"scheme":{"enum":["light","dark"]}},"required":["strokes","box","viewport","scheme"],"additionalProperties":false},"suggestion":{"type":"boolean"},"about":{"const":"design"},"title":{"type":"string","minLength":1,"maxLength":80,"pattern":"\\S","not":{"pattern":"[\\r\\n]"}},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1},"markup":{"type":"string","minLength":1},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"},"holds":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","revision"],"additionalProperties":false,"oneOf":[{"required":["text"]},{"required":["token"]},{"required":["drawing"],"not":{"required":["text"]}}],"dependentSchemas":{"title":{"properties":{"author":{"const":"agent"}}},"token":{"not":{"anyOf":[{"required":["suggestion"]},{"required":["holds"]},{"required":["markup"]}]}},"drawing":{"required":["anchor"],"properties":{"anchor":{"not":{"anyOf":[{"required":["quote"]},{"required":["part"]}]}}},"not":{"anyOf":[{"required":["suggestion"]},{"required":["about"]},{"required":["holds"]},{"required":["markup"]}]}}}},"browser":{"required":["kind","revision"],"not":{"required":["markup"]}}},"reply":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"reply"},"seq":{"type":"integer","minimum":1},"parent":{"type":"string","minLength":1},"revision":{"type":"integer","minimum":1},"publication":{"type":"string","pattern":"^r[1-9][0-9]*-[a-f0-9]{16}$"},"text":{"type":"string","minLength":1},"token":{"type":"string","minLength":1},"anchor":{"type":["object","null"],"properties":{"section":{"type":["string","null"]},"quote":{"type":"string"},"datum":{"type":"string","minLength":1},"source":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"source_revision":{"type":"string","pattern":"^[0-9a-f]{16}$"},"identity":{"type":"string","minLength":1},"visual":{"type":"string","minLength":1},"prefix":{"type":"string"},"suffix":{"type":"string"},"detached":{"const":true},"part":{"type":"string"}},"anyOf":[{"required":["section"],"properties":{"section":{"type":"string","minLength":1}}},{"required":["quote"],"properties":{"quote":{"type":"string","minLength":1}}},{"required":["datum"],"properties":{"datum":{"type":"string","minLength":1}}}],"dependentRequired":{"datum":["section"],"source":["datum","source_revision"],"source_revision":["datum","source"],"identity":["datum"],"part":["section"],"detached":["quote"],"visual":["section"]},"additionalProperties":false},"title":{"type":"string","minLength":1,"maxLength":80,"pattern":"\\S","not":{"pattern":"[\\r\\n]"}},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1},"markup":{"type":"string","minLength":1},"ask":{"const":true},"todo":{"type":"string","minLength":1,"maxLength":80,"pattern":"\\S","not":{"pattern":"[\\r\\n]"}},"ephemeral":{"const":true},"start":{"type":"object","properties":{"item":{"type":"string","minLength":1},"turn":{"type":"string","minLength":1}},"required":["item"],"additionalProperties":false},"failure":{"type":"string","minLength":1},"responds":{"type":"string","minLength":1},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},"required":["attention","id","ts","author","kind","seq","parent"],"additionalProperties":false,"oneOf":[{"required":["text"]},{"required":["token"]}],"dependentSchemas":{"start":{"required":["ephemeral","text"],"properties":{"author":{"const":"agent"},"text":{"pattern":"\\S","not":{"pattern":"\\S\\s*[\\r\\n]\\s*\\S"}}}},"title":{"properties":{"author":{"const":"agent"}}},"publication":{"required":["revision"],"properties":{"author":{"const":"agent"}}},"ephemeral":{"required":["text"],"properties":{"author":{"const":"agent"}},"not":{"anyOf":[{"required":["responds"]},{"required":["ask"]},{"required":["todo"]},{"required":["markup"]},{"required":["failure"]},{"required":["anchor"]}]}},"token":{"not":{"required":["markup"]}},"ask":{"properties":{"author":{"const":"agent"}}},"todo":{"required":["text"],"properties":{"author":{"const":"agent"}},"not":{"anyOf":[{"required":["failure"]},{"required":["ask"]}]}},"failure":{"required":["text","responds"],"properties":{"author":{"const":"agent"}}},"anchor":{"required":["revision","text"],"properties":{"author":{"const":"agent"}}}}},"browser":{"required":["kind","parent","revision"],"not":{"anyOf":[{"required":["markup"]},{"required":["ask"]},{"required":["todo"]},{"required":["anchor"]},{"required":["responds"]},{"required":["failure"]},{"required":["ephemeral"]},{"required":["start"]},{"required":["title"]}]}}},"edit":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"enum":["agent","user"]},"kind":{"const":"edit"},"seq":{"type":"integer","minimum":1},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"},"message":{"type":"string","minLength":1},"text":{"type":"string","minLength":1},"base":{"type":"string","minLength":1},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","message","text"],"additionalProperties":false,"oneOf":[{"properties":{"author":{"const":"agent"}},"required":["agent","session"]},{"properties":{"author":{"const":"user"}},"not":{"anyOf":[{"required":["agent"]},{"required":["session"]}]}}]},"browser":{"required":["kind","message","text","base"]}},"summary":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"const":"agent"},"kind":{"const":"summary"},"seq":{"type":"integer","minimum":1},"thread":{"type":"string","minLength":1},"from":{"type":"string","minLength":1},"through":{"type":"string","minLength":1},"text":{"type":"string"},"label":{"type":"string","minLength":1},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","thread","from","through","text","agent","session"],"additionalProperties":false}},"read":{"bookkeeping":true,"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"const":"user"},"kind":{"const":"read"},"seq":{"type":"integer","minimum":1},"messages":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"object","properties":{"message":{"type":"string","minLength":1},"version":{"type":"string","minLength":1}},"required":["message","version"],"additionalProperties":false}},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},"required":["attention","id","ts","author","kind","seq","messages"],"additionalProperties":false},"browser":{"required":["kind","messages"]}},"thread_title":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"const":"agent"},"kind":{"const":"thread_title"},"seq":{"type":"integer","minimum":1},"thread":{"type":"string","minLength":1},"title":{"type":"string","minLength":1,"maxLength":80,"pattern":"\\S","not":{"pattern":"[\\r\\n]"}},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","thread","title","agent","session"],"additionalProperties":false}},"todo":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"const":"agent"},"kind":{"const":"todo"},"seq":{"type":"integer","minimum":1},"owner":{"enum":["agent","user"]},"subject":{"oneOf":[{"type":"object","properties":{"kind":{"enum":["widget","element"]},"id":{"type":"string","minLength":1}},"required":["kind","id"],"additionalProperties":false},{"type":"object","properties":{"kind":{"const":"page"}},"required":["kind"],"additionalProperties":false}]},"revision":{"type":"integer","minimum":1},"title":{"type":"string","minLength":1,"maxLength":80,"pattern":"\\S","not":{"pattern":"[\\r\\n]"}},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","owner","subject","title"],"additionalProperties":false}},"start":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"const":"agent"},"kind":{"const":"start"},"seq":{"type":"integer","minimum":1},"item":{"type":"string","minLength":1},"text":{"type":"string","minLength":1,"pattern":"\\S","not":{"pattern":"[\\r\\n]"}},"turn":{"type":"string","minLength":1},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","item","text"],"additionalProperties":false}},"put_down":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"const":"agent"},"kind":{"const":"put_down"},"seq":{"type":"integer","minimum":1},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq"],"additionalProperties":false}},"todo_end":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"enum":["agent","user"]},"kind":{"const":"todo_end"},"seq":{"type":"integer","minimum":1},"todo":{"type":"string","minLength":1},"outcome":{"enum":["done","failed","dropped"]},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"},"detail":{"type":"string","minLength":1,"maxLength":500,"pattern":"\\S"},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","todo","outcome"],"additionalProperties":false},"browser":{"required":["kind","todo","outcome"],"properties":{"outcome":{"const":"done"}},"not":{"required":["detail"]}}},"reanchor":{"bookkeeping":true,"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"const":"page"},"publication":{"type":"string","pattern":"^r[1-9][0-9]*-[a-f0-9]{16}$"},"kind":{"const":"reanchor"},"seq":{"type":"integer","minimum":1},"thread":{"type":"string","minLength":1},"revision":{"type":"integer","minimum":1},"anchor":{"type":["object","null"],"properties":{"section":{"type":"string","minLength":1}},"required":["section"],"additionalProperties":false}},"required":["attention","id","ts","author","kind","seq","thread","revision","anchor"],"additionalProperties":false}},"resolve":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"resolve"},"seq":{"type":"integer","minimum":1},"parent":{"type":"string","minLength":1},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},"required":["attention","id","ts","author","kind","seq","parent"],"additionalProperties":false},"browser":{"required":["kind","parent"]}},"unresolve":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"unresolve"},"seq":{"type":"integer","minimum":1},"parent":{"type":"string","minLength":1},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},"required":["attention","id","ts","author","kind","seq","parent"],"additionalProperties":false},"browser":{"required":["kind","parent"]}},"done":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"done"},"seq":{"type":"integer","minimum":1},"version":{"type":"integer","minimum":1},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},"required":["attention","id","ts","author","kind","seq","version"],"additionalProperties":false},"browser":{"required":["kind","version"]}},"action":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"action"},"seq":{"type":"integer","minimum":1},"widget":{"type":"string","minLength":1},"action":{"type":"string","minLength":1},"detail":{"type":"object"},"meaning":{"type":"object","properties":{"scope":{"enum":["page","thread"]},"unit":{"type":"string","minLength":1},"depends":{"type":"array","items":{"type":"string","minLength":1},"uniqueItems":true},"answer":{"type":["string","null"],"minLength":1},"creates":{"type":"string","pattern":"^lf-[a-z0-9]+(-[a-z0-9]+)*$"},"among":{"type":"array","items":{"type":"string","minLength":1}},"state":{"type":"object","properties":{"origin":{"type":"string","pattern":"^lf-[a-z0-9]+(-[a-z0-9]+)*$"},"unit":{"type":"string","minLength":1},"record":{"type":["object","null"]},"creates":{"type":["object","null"]},"detail":{"type":["object","boolean"]}},"required":["origin","unit","record","creates","detail"],"additionalProperties":false}},"required":["scope","unit","depends"],"additionalProperties":false},"revision":{"type":"integer","minimum":1},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},"required":["attention","id","ts","author","kind","seq","widget","action","detail","revision","meaning"],"additionalProperties":false},"browser":{"required":["kind","widget","action","detail","revision"]}},"pickup":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"const":"page"},"kind":{"const":"pickup"},"seq":{"type":"integer","minimum":1},"events":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"uniqueItems":true},"phase":{"enum":["queued","opened","failed"]},"session":{"type":["string","null"],"minLength":1},"turn":{"type":["string","null"],"minLength":1},"failure":{"type":"string","minLength":1},"refs":{"type":"object","additionalProperties":{"type":"object","properties":{"ref":{"type":"string","minLength":1},"claim":{"type":["string","null"],"minLength":1}},"required":["ref","claim"],"additionalProperties":false},"minProperties":1}},"required":["attention","id","ts","author","kind","seq","events","phase","session","turn"],"if":{"properties":{"phase":{"const":"failed"}}},"then":{"required":["failure"]},"else":{"not":{"required":["failure"]}},"additionalProperties":false}},"undo":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"undo"},"seq":{"type":"integer","minimum":1},"undoes":{"type":"string","minLength":1},"attempt":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},"required":["attention","id","ts","author","kind","seq","undoes"],"additionalProperties":false},"browser":{"required":["kind","undoes"]}},"report":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"report"},"seq":{"type":"integer","minimum":1},"widget":{"type":"string","minLength":1},"action":{"type":"string","minLength":1},"detail":{"type":"object"},"meaning":{"type":"object","properties":{"scope":{"enum":["page","thread"]},"unit":{"type":"string","minLength":1},"depends":{"type":"array","items":{"type":"string","minLength":1},"uniqueItems":true},"state":{"type":"object","properties":{"origin":{"type":"string","pattern":"^lf-[a-z0-9]+(-[a-z0-9]+)*$"},"unit":{"type":"string","minLength":1},"record":{"type":["object","null"]},"creates":{"type":["object","null"]},"detail":{"type":["object","boolean"]}},"required":["origin","unit","record","creates","detail"],"additionalProperties":false}},"required":["scope","unit","depends"],"additionalProperties":false},"revision":{"type":"integer","minimum":1},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","widget","action","detail","revision","meaning"],"additionalProperties":false}},"note":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"note"},"seq":{"type":"integer","minimum":1},"version":{"type":"integer","minimum":1},"revision":{"type":"integer","minimum":1},"publication":{"type":"string","pattern":"^r[1-9][0-9]*-[a-f0-9]{16}$"},"text":{"type":"string","minLength":1},"restated":{"type":"array","items":{"type":"string","minLength":1},"uniqueItems":true},"settles":{"type":"array","items":{"type":"object","properties":{"kind":{"enum":["report","todo"]},"id":{"type":"string","minLength":1}},"required":["kind","id"],"additionalProperties":false},"uniqueItems":true},"agent":{"type":"string","minLength":1},"session":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","version","revision","text"],"dependentSchemas":{"publication":{"properties":{"author":{"const":"agent"}}}},"additionalProperties":false}},"error":{"record":{"type":"object","properties":{"attention":{"type":"boolean"},"id":{"type":"string","minLength":1},"ts":{"type":"string","minLength":1},"author":{"type":"string","minLength":1},"kind":{"const":"error"},"seq":{"type":"integer","minimum":1},"revision":{"type":"integer","minimum":1},"text":{"type":"string","minLength":1}},"required":["attention","id","ts","author","kind","seq","text"],"additionalProperties":false},"browser":{"required":["kind","text"]}}}},"$keys":{"description":"The meaning of each x- key an element declaration may carry, one member per key. The registry lint admits exactly these keys: it refuses a member for a key it does not admit, and a missing member for one it does. A layer may override a member to describe its own reading of a key, but cannot add a key. The site's registry reference is generated from this entry, so authors, the lint and the site read the same text.","x-ask-context":"The element frames the asks inside it: its leading heading gives their prompt, and going to one of those asks lands on the element. `lf-ask` declares it; a widget that asks on its own needs no frame. Each ask keeps its own id, answer and completion, and where frames nest, it uses the nearest. Leaf calls the element a question unless its x-word module returns another word.","x-awaits":"The widget asks the user for input while its authored attributes match `when`. The ask's id is `widget:<source-id>` and never changes. `value` names the x-state verb whose state is the typed answer, and `answered` says when the ask is complete ($awaits); they are separate because a partial value can exist while the ask is open, and an empty value can be a complete answer. `all` names the outcome one banner control can give every ask of this kind at once. Once created, an ask stays answered or withdrawn after `when` stops matching; an element that never matched creates none, and neither does a quoted widget (x-exhibit). A `restated` event asks again. While the agent owes a reply in a thread about the ask, anchored inside the widget, or inside its x-ask-context but no other ask, the agent is its next actor and the ask stays unanswered. A widget in a thread message keeps its ask after the thread closes. Asks and to-dos are separate records, and the user's On me list reads asks directly.","x-thread-seat":"The module puts a thread box (`threadBox`) in each element that matches `when` on authored attributes, not on attributes an x-state record writes. The box shows, as text, the threads anchored exactly to that element; the Threads panel keeps the full view. An element inside thread markup or quoted content gets no box. On a widget that also asks (x-awaits), the box is where the user answers in words: while a thread there waits on the agent, the ask leaves the user's On me list, but it is still unanswered and the widget's controls still work. `hold` labels a second send button whose comment carries `holds`, naming the widget. The widget is held while that thread is open; resolving the thread releases it. Removing the widget removes only the box, not its threads.","x-content":"The required content: `markup` (the author's markup), `members` (only this element's declared member elements), `data` (one <pre> holding text in the notation the description names, with & < > escaped as &amp; &lt; &gt;), or `empty`.","x-data":"The widget's named external-data inputs. Each input names a `$data.contracts` contract and the string attribute whose authored value is the page's source id, and follows that source's current value; where an optional source attribute is absent, a widget reads null. A document binds each source to one contract, and a later document may rebind it; each document reads the value against its own contract and reports a mismatch as a source error. A module subscribes by widget and input name, never by a source name.","x-example":"Authored markup exhibiting the widget, valid against the merged registry: an agent reads it with the element declaration, writes from it, and the lint refuses one that does not validate.","x-exhibit":"The element shows quoted content: widgets inside it take no input, and their asks stay off the user's On me list. Modules check `quoted(el)` before enabling input.","x-instructions":"Instructions for an author using this widget, read after choosing it and before writing markup. One non-empty string, separate from the short `description` and the schema.","x-inline":"The element sits inline among the surrounding words. The render check therefore requires neither a width of its own nor a place where a block may stand.","x-language":"The attribute that names a code language. Its value must be one of `$languages.names`, so a new tag that takes a language needs only this declaration.","x-reading-role":"The structural role the element plays. The only role is `pane`: a reading region, named by its required `label`, whose body scrolls on its own while the workspace is full-height. A pane holds exactly one body element, optionally between a direct `header` and `footer`; a visible heading goes in the header. Validation reads this declaration, not tag names, so a package can contribute panes under its own tags.","x-measured":"A value in authored content tied to the data run that produced it. `input` names the widget's x-data input, and `run` its required receipt attribute. When the source holds a different run, `page check` warns that the measurement is stale, and `page state` reports it. Rewriting the source counts as a new run even with the same value; age alone never makes a measurement stale.","x-patch":"How a revision reaches an upgraded widget the user has open. By default any change to the widget's markup replaces the whole widget, rebuilding whatever the user had open in it. `members` says the module builds its controls beside its members, leaves the members where the author wrote them, and reads only their attributes; then, while a revision keeps the element's attributes and each member's tag and attributes in order, Leaf edits inside the members in place. Requires `x-content: members` and x-upgrade.","x-owners":"The element declarations that may directly own this element. An owner's direct children of these kinds are its members, and a gesture on the owner's whole box stops at them.","x-refers":"A map from each attribute whose value names another element to the contract its target must meet. An empty contract accepts any element id, as an option's `for` does. A typed contract names a shared registry map with `via` and an equality test with `where`, and `page check` requires a target whose tag's entry in that map passes the test, so a package can tell a goal reference from a worker reference without Leaf knowing either. With `owns: true` the referrer fills its target: `page check` requires the target in the referrer's own document, and requires each element there that the test selects to be named by exactly one referrer. A keyed contract `{tag, key}` names a member by an attribute instead of an id: the `tag` element whose `key` holds the value, inside the referrer's nearest owner in which `key` is unique (x-unique), as a playground preset's setting names a control by `name`. In the browser a module passes the attribute to `navigateToDatum`, or the experimental `indicate`, to reach the named widget; each looks in the referrer's own document (its message, for a widget in a reply) before the page.","x-resident":"How the element sits in a column page's first `aside.sidebar`. The only value is `map`, a contents map: where the margin has room and the pointer is precise, it shows as a spine in the left margin whose labels appear over the page. Delivery writes `data-lf-resident` into the served document, except in a thread message, which has no margin.","x-retired-when":"On a member: the outcome of its owner's decision that removes it from the page, as `accept` removes a suggestion's `lf-old`. Requires x-owners. The outcome is a value of the `outcome` field on the owner's one deciding verb. Leaf renders the decision itself, including its undo: it writes `data-lf-state=\"<outcome>\"` on the owner and `data-lf-retired` on the removed members, which one theme rule hides. A module may write the same attributes earlier during its own gesture (`renderRetired`), but code that needs the decision reads it from the widget's state, not the attributes. Once the log decides, `page check` lets a revision drop the member's ids, and `page check --render` reports a removed member that still shows words.","x-says":"Attributes whose values show as selectable text: `after` inside the element after its content, `before` at its start, in declaration order. The runtime writes real text nodes, unlike CSS `content: attr()`, so the user can select, quote and comment on the words.","x-shadow":"The module renders the page's words into an open shadow root, and Leaf's passage reading, selection capture and id lookups reach into it. The render check reports a shadow root on an element whose declaration lacks this key.","x-state":"Declares each verb of a widget that has state: the unit of state it changes, who writes it, and either its record (how the state reads in markup, $state.record) or the schema of its detail. A verb is the user's, sent from the page as `action` events, unless it declares `writer: \"agent\"`; the agent writes it with `leaf page report`, as `report` events. A user verb may create a child element (`creates`). An agent verb with `text: true` requires each report to carry a non-empty `detail.text`, a short note the report feed shows as written. The page marks a reported widget `data-lf-reported` until a version answers the report ($report). For each [widget, unit, verb] key, the latest action not taken back wins, and different verbs on one unit coexist. Leaf combines those actions with the authored values and hands the widget its complete state, keyed by verb, as `this.state`, which its `render()` reads. A past action keeps its key after the widget leaves the page. When an action makes the widget's x-awaits `answered` condition hold, Leaf records `meaning.answer` on it: the thread named by the widget's `resolves` attribute in the document the action came from, which the answer closes, or null. A decision whose outcome is the widget's x-withdrawn-as value also records null, and the page reads as if nothing had been proposed. The detail field `outcome` is reserved for the one user verb that decides which members leave the page (x-retired-when).","x-thread-surface":"The upgraded widget can show Leaf's comment box and threads inside itself, beside the data items they are about. On each pass, Leaf calls the element's `threadOutlets(targets, {signal, collection, onCommit})` with the targets anchored exactly to its items, in order, and the method returns for each an element to place it in (an outlet), or null. The widget reads its registration with `threadSurface(element)`: `update()` says its outlets changed, and `open(datum)` opens Comment on one item. Leaf still owns anchors, drafts, sending, thread rendering, replies, reactions and focus, and decides placement inside each outlet. An item that isn't shown (not loaded, filtered out, collapsed or outdated) gets no outlet, and its threads stay in the Threads panel and the margin.","x-text-format":"How the element's text is formatted. `inline-markdown` formats its direct text nodes; `markdown` renders its data body as safe block Markdown. A body record keeps the Markdown source, while passages read the visible words. Child elements stay HTML. In a generated child, the user's line breaks are hard breaks.","x-tone":"The attribute that names one of the layer's semantic tints, held to `$tones.names`, which the theme has a rule for.","x-unique":"A map from each attribute whose value must differ between members of one owner to that owner's tag. `page check` and message markup refuse a repeat inside the same nearest owner, such as two controls of one playground sharing a `name`. A keyed x-refers contract names members by such an attribute.","x-upgrade":"A module at `widgets/<tag>.js` enhances the element in the browser, loaded only where a page's markup uses the tag. `page init` refuses a layer that declares it without the module, and the render check refuses a module that defines no element for a widget on the page. Required.","x-verbatim":"The upgraded element keeps its authored words, and its nested upgraded widgets in authored order, so the passage reader can quote those words; each nested widget's own declarations cover the words it generates. Without this key the passage reader treats the widget as opaque, since its module may insert or replace words. The render check refuses a page where the wrapper's own words changed or a nested widget was removed or reordered.","x-initial":"The rooted path of a classic JavaScript bundle that registers the widget's synchronous first drawing with `document.documentElement.lfInitial.register(tag, render)`. Delivery inlines each used bundle once in the head and draws each element as soon as its source is complete, nested elements first. `render(host, {tabStore, offer, offerElement})` builds the instance's real markup from authored values and tab-local state, without network or asynchronous work, and returns the structure the behavior module adopts with `initialRender(host)`. For revisions and thread messages that arrive later, the widget loader imports the same bundle before the behavior module. Leaf keeps the original markup before drawing, so comparisons and readings of the source ignore the drawing. Requires `x-upgrade: true`; excludes x-prepaint.","x-prepaint":"Markup the element shows at first paint, before its module draws: one element with the structure the module will draw, holding words that give it the drawing's size. Delivery writes it into every occurrence as the element's first child, marked `data-lf-prepaint`, so the browser lays the widget out at its real size instead of reserving a computed height. The theme keeps the space but paints none of it. The module removes it in the same step that draws, so nothing moves, and draws by filling a copy of this markup, so the structure is stated only here. `{\"as\": tag}` reuses another widget's prepaint, for an element that first appears as that widget will inside it. Declare it on a widget whose drawn structure is fixed while its values come from the log; a widget whose rows depend on the log has no fixed structure to write here.","x-views":"`true`: the element shows one member at a time, as a tab set shows one panel. Its module opens the member the runtime names (`openingView`) and records each member it shows (`keepView`). The runtime opens the member holding the element the URL fragment names, else the member this tab last showed, else the first; a reload prefers the member last shown. Before first paint Leaf marks the member it will open `data-lf-opening`, so the package theme can show that member alone until the module upgrades.","x-visual":"How a rendered picture offers Comment targets. `whole` makes the picture one target. With `{parts: ATTR}` or `{prefixes: [PREFIX, \u2026]}`, the module calls `registerVisualParts(source, read)` once, and `read` returns the current list of `{id, element, label, surface?}`; a comment on a part stores its id as `anchor.visual`. Under `parts`, ATTR names an attribute of the widget, as in `<lf-diagram parts=\"all\">`: the registered parts become targets where the widget carries it, and without it the picture stays one target. Under `prefixes`, Leaf accepts any longer id starting with one of them, such as `commit:3f2a` under `commit:`. `surface` may name a descendant whose own paint, without decoration, gives the outline Leaf marks; `element` stays the target for hits and travel. A comment whose part is gone detaches on replay instead of widening to the whole picture. A visual that draws its parts over time also passes `{reveal}`: `reveal(id)` must synchronously show a state that holds that part, cancelling any pending change that would remove it, and Leaf calls it before going to the part from a thread or `navigateToDatum`. While a declared part is missing from the current state, its threads sit on the whole picture. Call the registration's `update()` after any change to rendering or geometry, including an attribute or style change in place. The render check validates each registered record.","x-space":"The width past the reading measure the element takes in a column or sidebar Layout: `wide` takes the shared, capped evidence width; `available` takes all the width the page shell can give. Without it the element fills its container, as every element does in other Layouts; an element read as lines of text keeps to the measure in its own stylesheet (`max-inline-size: var(--lf-measure)`). An authored element may override it with `data-width=wide|available`, which the theme applies without moving the prose.","x-bound":"The element has its own height and scrolls inside it, so a long log or feed never grows the page. `start` opens at the first line; `end` follows the newest entry while the user is at the end, and stays where the user scrolled back to otherwise. An authored element may set or override it with `data-bound=start|end`; delivery writes it as `data-lf-bound`.","x-height":"The height in CSS pixels the page reserves for the element before its module draws: the declared number, or an authored `data-height`, which overrides it; `true` reserves only where `data-height` is given. The theme holds the box to it from first paint until the module marks the element drawn (`lf-rendered`). Declare it on a widget whose drawing can't be sized from its markup. A module that can draw at any height, such as a chart's, draws at this one, so nothing moves; for content with its own height, the reserved height is the author's estimate of it.","x-history":"`true`: the module renders the page's history, so a page that contains one is served the `history` reading with its state. The reading is the newest 50 logged events, newest first, each with who acted, what they did, the id of the thread it was in, whether a later undo took it back, and, for a widget gesture, the words its ids had when it was made. The module reads it with `readHistory`.","x-withdrawn-as":"The deciding outcome that declines the proposal. It answers the ask without closing the widget's `resolves` thread. A revision may also remove an unanswered proposal outright, whether or not it has retirable members; ids from earlier versions don't prevent it.","x-within":"The regions (element declarations) inside which a member may sit at any depth instead of as its owner's direct child. It belongs to the nearest owner x-owners names around that region, and `page check` refuses it anywhere else. A playground control written inside `lf-playground-preview` stays where it is written, beside the item it changes, instead of in the rail.","x-name":"The attribute that holds the element's title, which the page uses to name the element elsewhere, as the activity feed does. Declare it only where an attribute is the title, as a column's or a tab's `label` is; a section is already titled by its heading, a disclosure by its summary, and a titled member by its leading <strong>. An attribute the element merely shows first, such as a metric's value, is not its title.","x-word":"The module gives a word for the widget's kind through `lfWord()`, as `lf-suggestion` returns \"insertion\", \"deletion\" or \"rewrite\" depending on its children. Leaf uses it when naming the widget in a panel row or comment anchor; without one, it calls an x-ask-context widget a question and anything else by its tag name without the prefix. The module may also describe the widget through `lfSays()`, where its text alone doesn't convey its structure, such as a rewrite's old and new text; otherwise Leaf reads the element's text.","x-work":"`true`: the agent may open its own to-do on this widget with `leaf task open` even when no update on it is open, and the to-do shows beside the widget. Only a block widget whose x-content is markup may declare it, and markup content does not imply it: markup can itself be a control, or sit in a hidden panel."},"$state":{"unit":"`\"widget\"` when one state value covers the whole widget, as `choose` on an option group does; otherwise a required string detail field that identifies the unit by element id or data key, as `add`'s `option` does. A position record always uses `unit`; a verb with no record names its own field.","creates":"An x-state verb that adds a child element declares `{child, words}`: `child` is the tag it creates, and `words` names the detail field holding the child's text; the verb's `unit` field holds the child's id. While the action is in force, the widget has that child; undoing or retracting the action removes it. Admission records the child's tag in `meaning.creates`, so a reader without the registry still knows what the action made, and refuses an id the sending document already uses. It also stores the verb's state definition in `meaning.state`, so a later incompatible definition doesn't change how the action reads.","record":"How the state reads in markup. `{kind: \"attribute\", attr}`: the elements inside the unit that carry `attr`, as the list of ids in `detail.value`, an array even where the widget allows one. `{kind: \"value\", attr}`: one scalar in the unit's own `attr`; `detail.value` takes that attribute's schema, so the log and the markup can't disagree. `{kind: \"body\"}`: the unit's own words. `{kind: \"position\", within}`: where the unit sits in a `within` container. `detail.unit` names the moved member (never the widget), `detail.value` the container, and `detail.rank` its sort key there: a base-36 fraction, digits 0-9a-z not ending in 0, compared as a string, ties broken by id. Authored members rank by authored order, and a widget computes a dropped member's rank between its new neighbours with `rankAt` from `runtime/widget-api.js`. The rank places the member in the same gap while later revisions author the container the same way. A revision that authors it differently absorbs the move: the member is written where the move left it, and the move can no longer be undone. Admission refuses a move made on an older revision whose container the newest one authors differently. Two tabs dropping into one gap get equal ranks, and the id order can put the later drop outside that gap. Leaf starts from the authored value (null for an absent value attribute or a verb with no record, the authored ids for an attribute set), applies the actions in force and the user's unsent updates, and renders the complete state without resetting or rebuilding the DOM on undo or refusal."},"$report":{"answering":"By explicit id. `page stamp` adds a report to the version note's `settles` list when the stamped revision writes in its reported state or marks its element `overruled`, and from that revision on the report no longer applies. A revision that changes nothing answers nothing, so the report stays shown.","overruled":"A boolean attribute on the reported element, declared by every widget with an agent-written x-state verb: this revision keeps its own state over the report in force. It belongs only to the revision whose stamp overrules; the stamp records the answer on the version note, so later revisions leave it off.","feed":"All reports form one feed, in log order. Each entry carries its target, action, detail, optional text, speaker, time and version, and one disposition: `effective` (part of current state), `outranked` (a newer report on the same key takes precedence), or `settled` (named in a version note). Work the agent has in hand is not a report: it is an update's Working stage or a started to-do.","wakes":"A report joins the watcher's batch: `leaf wait` prints it with the user's updates, the same `ack` confirms it, and `leaf status idle` is refused while one is unread. The user's banner doesn't count reports, which are news the agent owes the page."},"$settlement":{"description":"The `settles` list on a version note ends provisional facts the agent supplied. Each entry is `{kind, id}`, so ids of different kinds can't collide and a new kind needs no new note field. The list is explicit and permanent: time alone ends nothing, and a later note need not repeat an entry.","report":"The id is a report event. Stamping adds one for each report whose state the source writes in or explicitly overrules.","todo":"The id is an open to-do on a page widget. `page stamp --completes <widget>` adds one for each to-do on that widget opened before the stamped revision, ending it as `done`, and lets the revision remove the widget.","why-restated-is-separate":"`restated` is not a settlement. It retracts a user decision because the authored words or state it rested on changed, while `settles` completes provisional information the agent supplied. Merging the two would make finishing work look like taking back the user's action."},"$awaits":{"value":"The user-written x-state verb whose state is the ask's typed answer: a recorded verb's value, or a custom verb's full current detail, as a map by member id for a verb that keeps state per member.","when":"The authored attributes that make an element an ask: a map from each attribute to the values that make it one, `true` and `false` for a flag. Every attribute named must match. `lf-options` declares `{\"choose\": [true], \"settled\": [false]}`, so a group asks only while it takes picks and stops once it is `settled`. Without `when`, every element of the tag is an ask, as every `lf-suggestion` is.","answered":"When the ask is answered: a map from each answering x-state verb to a condition on its state, and the ask is answered while any one holds. Naming the answering verbs keeps other actions, such as adding an option, from answering. `{}` holds while the verb's state is set: a non-empty attribute or value record, read from the authored markup as well as the log, so a version that writes the answer in keeps it answered; for any other verb, an action of it in force. `when` limits a verb to instances whose attributes match, which is how a `multiple` group is answered by its Done (`answer`) and a single-choice group by its pick (`choose`). `empty: {within, when}` holds while the matching member container inside the widget has no members, which is how a queue is answered once its designated column is empty; it needs a position verb, and an answering verb whose unit is a member must use it. Admission marks the action that makes a condition hold in `meaning.answer` (x-state). A thread in the widget's thread box (x-thread-seat) is not an answer.","all":"The outcome a blanket yes gives, where one banner control answers every ask of this kind at once (`Accept all (3)`). It must be an `outcome` of the widget's deciding verb, which must be an answering verb, and the module must expose a method named for that verb taking the outcome, so each ask records its own decision. Without it, the user answers each ask where it is."},"$restated":{"description":"A boolean attribute saying this revision rewrote words the user already decided on, so the decision no longer applies and the user is asked again. Put it on the element the decision rests on: an `lf-draft` or `lf-suggestion`, or the `lf-card` or `lf-option` inside a board or group. It retracts every action that named that element: a rewritten card drops only that card's moves, while a rewritten option takes back the whole pick it was part of.","why":"Decisions are recorded against the revision the user saw and survive ordinary edits, so change presentation and wording directly. Use this attribute only when the decision itself should no longer apply; the log records the retraction and keeps the original answer.","when":"When a revision makes a decision no longer apply and needs a fresh answer, write the new content, mark the element the decision names, and say why in the stamp note. Changing decided wording or presentation alone needs no marker. An unused or repeated marker does no harm.","once":"Put the marker only on the revision that retracts the decision; stamping records the retraction. Leave it off later revisions unless they withdraw another decision.","example":"<lf-draft id=\"note-cli\" restated><pre>\nAdds --dry-run to every mutating command. It defaults on for `purge`.</pre></lf-draft>"},"$series":{"description":"The categorical colours this layer paints a chart's series in. The theme defines them as `--series-1` through `--series-N`, and `steps` is N: how many series a chart can tell apart, and the count the palette check holds the tokens to. A project that adds a step raises `steps` here and adds the token in its theme. A chart with more series than steps merges the small ones or splits into several charts, since two series in one colour mislead. The list stops at five because further steps can't stay distinct for users with colour-vision deficiency.","steps":5},"$reactions":{"description":"The reaction words: one-press marks a user can put on a passage, an element, a thread message or the whole page, each recorded as a `comment` or `reply` carrying `token` instead of `text`. The kernel declares none. The default package ships the working set, and each selected package edits it merge-patch style: a name replaces or adds a token, `null` removes one. A reaction opens no thread until someone replies to it, and while nothing answers it the user can withdraw it with an `undo`. `glyph` is the mark the page paints, at most four Unicode code points, such as one emoji. `settles: true` means a reaction of this kind on an agent message answers that message's question, so the thread stops waiting on the user. POST /api/event refuses a token outside the merged set. Reaction lists and their digit shortcuts follow this order.","tokens":{"keep":{"glyph":"\ud83d\udc4d","settles":true},"change":{"glyph":"\u274c"},"clarify":{"glyph":"\ud83e\udd14"},"shorten":{"glyph":"\u2702\ufe0f"},"support":{"glyph":"\ud83d\udd0e"},"prioritize":{"glyph":"\ud83c\udfaf"}}},"$tones":{"description":"The semantic tints this layer paints, and the full list an author may use: validation refuses any other word, and the theme has a rule for each. A widget marks an attribute as naming a tone with x-tone, and validation reads this list, so a new tag taking a tone needs only that declaration. The list is short on purpose: a page that can tint anything conveys nothing, and the palette supports three. The author decides which facts get a tint, since only the author knows whether a value is good news; `ok` on one page and `danger` on another may mark the same word.","names":["ok","warn","danger"]},"button.button":{"description":"A button styled like Leaf's controls, for an action your page module handles along with any state. For a toggle, set `aria-pressed`, and `true` draws it selected.","x-example":"<button type=\"button\" class=\"button\" aria-pressed=\"true\">Anchored threads</button>"},"select.field, input.field":{"description":"A labeled select or single-line text field for the page's own script, matching Leaf's buttons. Use the class rather than restyling the field in page CSS; page CSS only arranges the row.","x-example":"<label for=\"preview-case\">Conversation</label>\n<select id=\"preview-case\" class=\"field\"><option>Short exchange</option><option>Long exchange</option></select>"},".eyebrow":{"description":"A small-caps label above a heading.","x-example":"<p class=\"eyebrow\">design proposal</p>\n<h1>Widgets</h1>"},".lede":{"description":"The opening paragraph, set slightly larger.","x-example":"<p class=\"lede\">One paragraph saying what this page decides.</p>"},".tag":{"description":"An inline chip label. Add `ok`, `warn` or `danger` to draw it in that status tone.","x-example":"<span class=\"tag\">experimental</span>"},".callout":{"description":"An aside set off from the prose in a tinted, bordered box, for something the user must not miss; a note they can skip goes in the margin (aside.sidenote). Add `ok`, `warn` or `danger` when it reports a status, as `class=\"callout warn\"` for a paused release; the tint and the title take the tone, and the prose keeps the body's ink. The title is a `<strong>` written as the callout's first child; one opening a paragraph stays in the body's ink. In a flow wider than the column, such as a sidebar page's body, it keeps the prose width; one holding a wide chart or table takes `data-width`.","x-example":"<aside class=\"callout\" id=\"rollback-note\">Rollback is one flag flip; the backfill is idempotent.</aside>"},"section.panel":{"description":"A titled card on a sidebar page (`<main class=\"layout-sidebar\">`) holding one thing, such as a table, a log or a list of steps, under a short heading that names it. Build a dashboard's regions as panels so they all look alike, and keep the page's argument in the prose and the callout.","x-example":"<section class=\"panel\" id=\"checks\">\n  <h2>Checks</h2>\n  <table>\u2026</table>\n</section>"},"aside.sidebar":{"description":"Page-level supporting material in the left margin, such as local navigation, a compact legend, or reference facts the user needs throughout a long page. Write one, as a direct child of `main` near the start of the page; a note on one paragraph is an `aside.sidenote` instead. On a wide screen, the first sidebar of a column page sits left of the prose and stays in view, and with a mouse or trackpad an `lf-toc` there shows as a thin spine in the margin whose labels open over the page. Where the window has no room beside the column, in print, and for any second sidebar, it stays in the flow where it was written. Keep its content readable at about 240px wide.","x-example":"<aside class=\"sidebar\" id=\"page-route\">\n  <nav aria-label=\"On this page\"><strong>On this page</strong><ol><li><a href=\"#prepare\">Prepare</a></li><li><a href=\"#move\">Move</a></li></ol></nav>\n</aside>"},"aside.sidenote":{"description":"A note in the page's right margin, such as a caveat or a source, that the reader can skip without leaving the column. Write it just before the paragraph, list or block it annotates; it then sits level with that block's first line, or above a heading it precedes. A note inside a section, tab panel or disclosure still reaches the margin. Inside a box that clips, such as an `lf-options` group, a board or a table, it is not drawn at all, and `page check --render` fails the version. Where the window has no room beside the column, and in print, the note is a small indented block where it was written, so it must make sense there too. Keep a note to a few lines. The margin fits about fifty-six characters a line, and a long note pushes the next one below its own block. Put longer material in the column as a paragraph.","x-example":"<aside class=\"sidenote\" id=\"logout-frequency\">Support runs \"log out all devices\" during account-takeover response, about twice a month.</aside>\n<p>Logout must revoke immediately, which rules out any store whose invalidation is eventually consistent.</p>"},".facts":{"description":"A grid of labels and values for summary facts, written as a definition list. As a direct child of an `lf-option` titled with a `<strong>`, it floats right as a narrow column where the option is wide enough, so the options' figures line up.","x-example":"<dl class=\"facts\">\n  <dt>Owner</dt><dd>payments</dd>\n  <dt>Rollout</dt><dd>behind a flag</dd>\n</dl>"},"ol.steps":{"description":"An ordered procedure with numbered markers.","x-example":"<ol class=\"steps\">\n  <li>Backfill the new store.</li>\n  <li>Verify counts, then flip reads.</li>\n</ol>"},"svg.drawing":{"description":"A schematic the page draws itself as inline SVG, such as a layout or a mechanism, inside a `<figure>`, with `role=\"img\"` and a `<title>` stating its point. Paint its marks with these classes, whose colors follow the theme: `.frame` and `.frame-head` for a window or pane and its header; `.box`, with `.hot` for the one that matters; `.line` (`.soft`) for a line of text; `.highlight`; `.ghost` for where something would go; `.guide` and `.dim` for alignment and dimension lines; `.arrow`, with `.tip` (`.hot`) on its marker; `.mark` for an accent dot and `.glyph` for the character on it; and `.ok`, `.warn` and `.danger` fills. Text is muted; `.strong`, `.small` and `.mono` restyle it. Without a `width`, the drawing fills its figure; give a thumbnail one. For a mark particular to the subject, add a page-local class that uses the same tokens.","x-example":"<figure id=\"sidebar-width\">\n  <svg class=\"drawing\" viewBox=\"0 0 320 120\" role=\"img\" aria-labelledby=\"sidebar-width-t\">\n    <title id=\"sidebar-width-t\">The sidebar takes 240px left of the column</title>\n    <rect class=\"frame\" x=\"4\" y=\"4\" width=\"312\" height=\"112\" rx=\"6\"/>\n    <rect class=\"box hot\" x=\"16\" y=\"20\" width=\"72\" height=\"84\" rx=\"3\"/>\n    <rect class=\"line\" x=\"104\" y=\"24\" width=\"180\" height=\"6\" rx=\"3\"/>\n    <rect class=\"line soft\" x=\"104\" y=\"38\" width=\"150\" height=\"6\" rx=\"3\"/>\n    <text class=\"strong\" x=\"52\" y=\"66\" text-anchor=\"middle\">240</text>\n  </svg>\n  <figcaption>In a narrow window the sidebar returns to the column.</figcaption>\n</figure>"},"table":{"description":"Rows of one shape compared column by column, such as runs per configuration. Columns size to their content, and a table wider than the measure wraps its cells, or scrolls inside itself once they can wrap no further, so set no widths on it. Put identifiers such as test names and paths in `<code>`, which can break inside a cell; a bare identifier is one unbreakable word that holds its column wide and squeezes the others. `page check --render` warns when a table scrolls sideways while one of its cells wraps. A bare `<th>` is a column heading, drawn as a small muted label; `<th scope=\"row\">` names a row, in bold at the body's size. Add a `<caption>` when the section's heading doesn't say what the columns mean. For a few headline figures, put each figure in its own `dl` inside a `layout-tiles` block instead, and for alternatives the user picks between, use `lf-options`.","x-example":"<table id=\"tiers\">\n  <caption>Ceilings per plan, and what each is counted against.</caption>\n  <thead><tr><th>Plan</th><th class=\"num\">A minute</th><th>Counted against</th></tr></thead>\n  <tbody>\n    <tr><th scope=\"row\">Free</th><td class=\"num\">60</td><td>the token</td></tr>\n    <tr><th scope=\"row\">Team</th><td class=\"num\">600</td><td>the token</td></tr>\n  </tbody>\n</table>"},"td.num":{"description":"A table cell holding a quantity, right-aligned so the figures in a column line up on their last digit. Put `class=\"num\"` on the column's heading cell too, or the heading sits left of its figures. Add the class to each such cell yourself. Leaf doesn't infer it, since \"60\" and \"60 sessions\" look alike.","x-example":"<tr><th scope=\"row\">Enterprise</th><td class=\"num\">6,000</td><td class=\"num\">12,000</td></tr>"},"details":{"description":"Evidence: a claim as the <summary>, its backing collapsed beneath. Native disclosure; find-in-page reaches the collapsed content.","x-example":"<details>\n  <summary>The parser drops the slash on self-closed custom tags</summary>\n  <pre><code>document.querySelector(\"lf-code\").textContent\n// \u2192 \"rest of the paragraph\"</code></pre>\n</details>"},"pre > code[class*=\"language-\"]":{"description":"A literal the user can select and quote, such as a command, a config file or a snippet of output. To color it, add `class=\"language-NAME\"` with a name from `$languages`; leave the class off where the body isn't source. For a walkthrough with numbered lines, highlighted ranges or remarks at a line, use `lf-code` instead.","x-example":"<pre><code class=\"language-bash\">leaf page check ~/.local/state/leaf/pages/auth-diagnosis --render</code></pre>"},"lf-ask":{"description":"A heading and context for the asks inside it, each answered separately.","x-instructions":"Give it a heading that states the shared question or context without leaning on the prose around it, with any eyebrow beside it in an `<hgroup>`. Include the evidence the user needs to answer. Each widget inside that asks for input stays its own ask with its own answer. Wrap the context in a `section` when the document needs a section landmark.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"required":["id"],"additionalProperties":false,"x-content":"markup","x-ask-context":true,"x-upgrade":false,"x-example":"<section id=\"storage-section\">\n  <lf-ask id=\"storage-decision\">\n    <h2>What should a full store do?</h2>\n    <p>The beta never reached the cap. This decides what the first workspace at it sees; each option draws its document list once the store fills.</p>\n    <lf-options id=\"full-store\" choose>\n      <lf-option id=\"store-evict\"><small class=\"tag\">editing: continues</small><small class=\"tag ok\">recommended</small><strong>Drop the oldest documents</strong> Editing continues. <em>My take: this keeps work moving without losing server data.</em>\n        <figure id=\"store-evict-fig\">\n          <svg class=\"drawing\" width=\"240\" viewBox=\"0 0 240 56\" role=\"img\" aria-labelledby=\"store-evict-t\">\n            <title id=\"store-evict-t\">The oldest document leaves the device; the rest stay editable</title>\n            <rect class=\"frame\" x=\"1\" y=\"1\" width=\"238\" height=\"54\" rx=\"4\"/>\n            <rect class=\"line\" x=\"12\" y=\"12\" width=\"130\" height=\"6\" rx=\"3\"/><rect class=\"line\" x=\"12\" y=\"25\" width=\"130\" height=\"6\" rx=\"3\"/><rect class=\"ghost\" x=\"12\" y=\"38\" width=\"130\" height=\"6\" rx=\"3\"/>\n            <text class=\"small\" x=\"228\" y=\"44\" text-anchor=\"end\">server only</text>\n          </svg>\n        </figure>\n      </lf-option>\n      <lf-option id=\"store-stop\"><small class=\"tag\">editing: paused</small><strong>Pause offline editing</strong> Nothing leaves.\n        <figure id=\"store-stop-fig\">\n          <svg class=\"drawing\" width=\"240\" viewBox=\"0 0 240 56\" role=\"img\" aria-labelledby=\"store-stop-t\">\n            <title id=\"store-stop-t\">Every document stays on the device, read-only until it reconnects</title>\n            <rect class=\"frame\" x=\"1\" y=\"1\" width=\"238\" height=\"54\" rx=\"4\"/>\n            <rect class=\"line\" x=\"12\" y=\"12\" width=\"130\" height=\"6\" rx=\"3\"/><rect class=\"line\" x=\"12\" y=\"25\" width=\"130\" height=\"6\" rx=\"3\"/><rect class=\"line\" x=\"12\" y=\"38\" width=\"130\" height=\"6\" rx=\"3\"/>\n            <circle class=\"warn\" cx=\"224\" cy=\"28\" r=\"5\"/><text class=\"small\" x=\"212\" y=\"31\" text-anchor=\"end\">read-only</text>\n          </svg>\n        </figure>\n      </lf-option>\n    </lf-options>\n  </lf-ask>\n</section>"},"lf-gloss":{"description":"A short explanation the reader can open beside a phrase without leaving its sentence.","x-instructions":"Write a self-contained explanation at the first useful occurrence rather than on every repetition. Keep the phrase out of authored parentheses: print adds the explanation as a parenthetical note.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"tip":{"type":"string","minLength":1}},"required":["tip"],"additionalProperties":false,"x-content":"markup","x-inline":true,"x-says":{"tip":"after"},"x-upgrade":true,"x-verbatim":true,"x-example":"Deploy through a <lf-gloss tip=\"A thin, end-to-end path through the real system.\">walking skeleton</lf-gloss> before parallelizing."},"lf-num":{"description":"A measured number in prose, tied to the data run that produced it.","x-instructions":"Write the value with its unit as the element's text. Bind `source` to the feed that measures it, and set `run` to the receipt `leaf data set` returned. Add `via` when the source id doesn't say which command or query produced it.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"source":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"run":{"type":"string","minLength":1},"via":{"type":"string","minLength":1}},"required":["source","run"],"additionalProperties":false,"x-content":"markup","x-data":{"measurement":{"contract":"measured-scalar","source":"source"}},"x-inline":true,"x-measured":{"input":"measurement","run":"run"},"x-upgrade":false,"x-example":"The import now takes <lf-num source=\"import-latency\" run=\"a41f103e236c985b\" via=\"uv run bench-import\">184 ms</lf-num> at p95."},"lf-text-document":{"description":"A text file from page data with numbered lines, syntax coloring, and an optional Markdown or HTML preview.","x-instructions":"Bind `source` to the page's data source and name the file with `label`. Set `preview` to `markdown` or `html` to add Preview and Source tabs over the same text. `language` colors the source, and defaults to the preview's language. An HTML preview is a separate document that inherits no Leaf styles. With a preview, each tab scrolls inside a box `--lf-bound` tall, 28rem by default. To start it collapsed, put it inside `details`.","x-name":"label","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"source":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"label":{"type":"string","minLength":1},"preview":{"type":"string","enum":["markdown","html"]},"language":{"type":"string"}},"required":["id","source"],"additionalProperties":false,"x-content":"empty","x-data":{"document":{"contract":"text-document","source":"source"}},"x-language":"language","x-upgrade":true,"x-example":"<lf-text-document id=\"leaf-skill\" source=\"leaf-skill\" language=\"markdown\"></lf-text-document>"},"lf-toc":{"description":"An outline of the document\u2019s h2\u2013h6 headings for navigating its sections and showing the reader\u2019s position.","x-instructions":"Write it empty with a stable id. Set `max-level` to leave out deeper headings that are local detail; by default it lists h2 to h6. Give sections or headings ids of your own where a link must keep its target across versions, since the ids Leaf generates aren't stable.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"max-level":{"type":"string","pattern":"^[2-6]$"}},"required":["id"],"additionalProperties":false,"x-content":"empty","x-resident":"map","x-upgrade":true,"x-example":"<h1>Migration plan</h1>\n<aside class=\"sidebar\" id=\"plan-sidebar\">\n  <lf-toc id=\"plan-contents\"></lf-toc>\n</aside>\n<section><h2>Prepare</h2><p>Take a snapshot.</p><h3>Check capacity</h3><p>Leave headroom for the copy.</p></section>\n<section><h2>Move</h2><p>Shift one cohort at a time.</p></section>"},"lf-activity":{"description":"A newest-first feed of the page\u2019s comments, actions, reports, and published revisions.","x-instructions":"Write it empty with a stable id.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"required":["id"],"additionalProperties":false,"x-content":"empty","x-bound":"start","x-history":true,"x-upgrade":true,"x-initial":"/vendor/lf-activity-initial.js","x-example":"<section id=\"recent\">\n  <h2>Recent activity</h2>\n  <lf-activity id=\"page-activity\"></lf-activity>\n</section>"},"lf-options":{"description":"Alternatives the user can choose individually or as a set to answer a question.","x-instructions":"Keep shared premises and evidence with the group (lf-ask can frame its question and context), and each alternative's own case inside its lf-option. For an accept-or-reject proposal, a figure of today beside the change compares both answers, so it stays with the group. Use `multiple` when the picks form one answer because they depend on each other, such as a limit on how many; leave it off for mutually exclusive alternatives. Items the user can answer independently are separate asks (references/authoring-asks.md). The built-in Another option field takes unlisted answers, so add no catch-all option. Use `for` only to point at sections or work items that exist apart from the decision. An option the user adds stays in the group from the log, where the user put it; leave it out of revisions. A `multiple` ask needs the user's Done even when `chosen` is authored. `settled` collapses a decided group while keeping its options and anchors.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"choose":{"type":"boolean"},"multiple":{"type":"boolean"},"settled":{"type":"boolean"},"restated":{"type":"boolean"}},"dependentRequired":{"settled":["id"],"multiple":["choose"]},"additionalProperties":false,"x-content":"members","x-word":"module","x-upgrade":true,"x-awaits":{"value":"choose","when":{"choose":[true],"settled":[false]},"retired":"settled","answered":{"choose":{"when":{"multiple":[false]}},"answer":{"when":{"multiple":[true]}}}},"x-state":{"choose":{"unit":"widget","record":{"kind":"attribute","attr":"chosen"}},"add":{"detail":{"type":"object","properties":{"option":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"text":{"type":"string","minLength":1}},"required":["option","text"],"additionalProperties":false},"unit":"option","creates":{"child":"lf-option","words":"text"}},"answer":{"detail":{"type":"object","additionalProperties":false},"unit":"widget"}},"x-example":"<lf-ask id=\"run-status-decision\">\n  <h2>Where should run status appear?</h2>\n  <p>Both choices preserve the existing run detail.</p>\n  <lf-options id=\"run-status\" choose>\n    <lf-option id=\"rs-column\">\n      <small class=\"tag\">effort: low</small><small class=\"tag warn\">risk: med</small><small class=\"tag ok\">recommended</small>\n      <strong>Status on the run list</strong> One join; failures are visible without a click.\n      <figure id=\"rs-column-fig\">\n        <svg class=\"drawing\" width=\"240\" viewBox=\"0 0 240 56\" role=\"img\" aria-labelledby=\"rs-column-t\">\n          <title id=\"rs-column-t\">Each run row ends in its status</title>\n          <rect class=\"frame\" x=\"1\" y=\"1\" width=\"238\" height=\"54\" rx=\"4\"/>\n          <rect class=\"line\" x=\"12\" y=\"14\" width=\"150\" height=\"6\" rx=\"3\"/><circle class=\"ok\" cx=\"222\" cy=\"17\" r=\"5\"/>\n          <rect class=\"line\" x=\"12\" y=\"36\" width=\"150\" height=\"6\" rx=\"3\"/><circle class=\"danger\" cx=\"222\" cy=\"39\" r=\"5\"/>\n        </svg>\n      </figure>\n    </lf-option>\n    <lf-option id=\"rs-leave\">\n      <small class=\"tag\">effort: none</small><small class=\"tag ok\">risk: low</small>\n      <strong>Leave the list alone</strong> No work; failures stay one click away.\n      <figure id=\"rs-leave-fig\">\n        <svg class=\"drawing\" width=\"240\" viewBox=\"0 0 240 56\" role=\"img\" aria-labelledby=\"rs-leave-t\">\n          <title id=\"rs-leave-t\">Run rows carry no status</title>\n          <rect class=\"frame\" x=\"1\" y=\"1\" width=\"238\" height=\"54\" rx=\"4\"/>\n          <rect class=\"line\" x=\"12\" y=\"14\" width=\"150\" height=\"6\" rx=\"3\"/><circle class=\"ghost\" cx=\"222\" cy=\"17\" r=\"5\"/>\n          <rect class=\"line\" x=\"12\" y=\"36\" width=\"150\" height=\"6\" rx=\"3\"/><circle class=\"ghost\" cx=\"222\" cy=\"39\" r=\"5\"/>\n        </svg>\n      </figure>\n    </lf-option>\n  </lf-options>\n</lf-ask>"},"lf-option":{"description":"One alternative in a decision: a compact label, or a card showing what choosing it gives the user.","x-instructions":"Start a card with small.tag labels naming the facts that tell the alternatives apart, then a `<strong>` title and a sentence giving its consequence. Mark the option you recommend with `<small class=\"tag ok\">recommended</small>` after its labels, and give the reason in prose. `chosen` records the user's pick. Below, show what choosing it gives the user (references/authoring-asks.md): where options differ in arrangement, structure or mechanism, an svg.drawing thumbnail of each in the same frame, alike except where they differ; where they differ in how an existing interface looks, a capture of each; where they differ in behavior, that behavior working inside each; where they differ in wording, the words as they would appear. Add paragraphs or a fact rail only when that is not enough; a bare label suits an option that needs no case. Direct text takes inline Markdown; block content needs HTML children. A `for` target must stay useful whatever is decided, and does not supply the option's words. Rewriting a picked option needs `restated` ($restated).","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"for":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"chosen":{"type":"boolean"},"restated":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"x-owners":["lf-options"],"x-content":"markup","x-text-format":"inline-markdown","x-refers":{"for":{}},"x-upgrade":false},"lf-code":{"description":"A source-code excerpt with syntax coloring, highlighted lines, and line-anchored remarks.","x-instructions":"Write the exact code inside pre at column 0, HTML-escaping & before < and >. Set language for source code and omit it for plain transcripts or command output. For excerpts, set lines to the ascending source ranges quoted, such as 1505-1507,1520-1527; hi and lf-note at then use those source numbers. A note addressed to an omitted line captions the elided row.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"language":{"type":"string"},"hi":{"type":"string","pattern":"^[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*$"},"lines":{"type":"string","pattern":"^[1-9][0-9]*(-[1-9][0-9]*)?(,[1-9][0-9]*(-[1-9][0-9]*)?)*$"}},"required":["id"],"additionalProperties":false,"x-content":"data","x-language":"language","x-upgrade":true,"x-example":"<lf-code id=\"bracket-walk\" language=\"python\" hi=\"2\"><pre>\ndef bracket(temp):\n    if temp &lt; 0:\n        return \"steel\"\n    return \"cedar\"\n</pre>\n  <lf-note at=\"2\">Freezing is the only threshold that matters.</lf-note>\n</lf-code>"},"lf-note":{"description":"A prose remark anchored to a line or omitted range of its lf-code parent.","x-instructions":"Set at to the line number as the parent numbers it: 1-based by default, or the source number declared in lines.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"at":{"type":"string","pattern":"^[0-9]+$"}},"required":["at"],"additionalProperties":false,"x-owners":["lf-code"],"x-content":"markup","x-upgrade":false},"lf-chart":{"description":"An Observable Plot chart authored with Plot\u2019s API and sized to its place in the page.","x-instructions":"Inside a `<pre>`, write a JavaScript expression for the options object you would pass to `Plot.plot`, HTML-escaping & before < and >. `Plot` and `width` are the names in scope, and the data goes inline. The chart requires an `ariaLabel` describing it. Leave `width` and `height` out of the options: read `width` to fit the ticks to the room, and set a height other than the default with `data-height` on the element. Write dates as ISO strings on an explicitly typed time scale, `utc` for days and months, and give moments a time zone, such as 2026-06-01T14:00Z. Use `var(--series-N)` for constant or categorical colors; a continuous color scale needs a Plot scheme. Title the chart in the heading or prose around it rather than with Plot's `title`. Label on the chart each value the page's argument cites, such as a spike the prose explains, with a text mark beside the point. When `page check --render` reports overlapping labels, use fewer category ticks, choose them by `width`, or give the axis label more margin.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"required":["id"],"additionalProperties":false,"x-content":"data","x-upgrade":true,"x-visual":"whole","x-height":400,"x-example":"<lf-chart id=\"review-latency\"><pre>\n{\n  ariaLabel: \"Hours to first review by week: backend fell from 31 to 12, frontend from 18 to 11\",\n  x: {type: \"utc\", ticks: \"monday\", label: null},\n  y: {grid: true, label: \"hours to first review\"},\n  color: {legend: true, range: [\"var(--series-1)\", \"var(--series-2)\"]},\n  marks: [\n    Plot.lineY(\n      [\n        {week: \"2026-05-04\", team: \"backend\", hours: 31},\n        {week: \"2026-05-11\", team: \"backend\", hours: 26},\n        {week: \"2026-05-18\", team: \"backend\", hours: 12},\n        {week: \"2026-05-04\", team: \"frontend\", hours: 18},\n        {week: \"2026-05-11\", team: \"frontend\", hours: 21},\n        {week: \"2026-05-18\", team: \"frontend\", hours: 11},\n      ],\n      {x: \"week\", y: \"hours\", stroke: \"team\", marker: true},\n    ),\n  ],\n}\n</pre></lf-chart>"},"lf-shot":{"description":"A before-and-after pair of screenshots under a draggable divider, with optional outlines of what changed and a view of the changed pixels.","x-instructions":"Use it for two versions of an interface. Set `before` and `after` to the paths `leaf page media` prints, and describe the pair in `alt`. `authoring-evidence.md`, \"Source files and media\", covers making captures, laying out captures that vary along more than one axis in a table, and when to add `outlines` or `pixels`. Put explanation in the prose around the pair, not inside the element. When a decision turns on the change, put the pair inside the option that proposes it, or, for an accept-or-reject ask, with the group, where it shows both answers.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"before":{"type":"string","pattern":"^/media/\\S+$"},"after":{"type":"string","pattern":"^/media/\\S+$"},"alt":{"type":"string"},"outlines":{"type":"boolean"},"pixels":{"type":"boolean"}},"required":["id","before","after","alt"],"additionalProperties":false,"x-content":"empty","x-upgrade":true,"x-visual":"whole","x-example":"<h3>The option cards</h3>\n<p>The chips now sit above the title, so a scanning eye reads cost before prose.</p>\n<lf-shot id=\"shot-cards\" outlines alt=\"the decision page's option cards\" before=\"/media/0f2c91a4b7de3105.png\" after=\"/media/6b40ac7719ee5d82.png\"></lf-shot>"},"lf-board":{"description":"Cards grouped into columns for scanning work and status, with movement and reordering available.","x-instructions":"Use a board to show grouped work and status. When the user must make changes or decisions, give them explicit controls or `lf-options` rather than relying on moving cards. When revising, keep each card the user moved in the column they chose, unless the revision retracts that move by marking the card, not the board, `restated` (`authoring-revisions.md`, \"Honor user state\").","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"required":["id"],"additionalProperties":false,"x-content":"members","x-upgrade":true,"x-state":{"move":{"unit":"unit","record":{"kind":"position","within":"lf-column"}}},"x-space":"wide","x-example":"<lf-board id=\"feeder-board\">\n  <lf-column id=\"col-todo\" label=\"To do\">\n    <lf-card id=\"card-heater\"><strong>Heated perch</strong> Wire the south feeder.</lf-card>\n    <lf-card id=\"card-baffle\"><strong>Squirrel baffle</strong></lf-card>\n  </lf-column>\n  <lf-column id=\"col-doing\" label=\"Doing\">\n    <lf-card id=\"card-camera\"><strong>Camera mount</strong></lf-card>\n  </lf-column>\n  <lf-column id=\"col-done\" label=\"Done\"></lf-column>\n</lf-board>"},"lf-column":{"description":"One named board column, including empty columns the user can move a card into.","x-instructions":"Write a label that names the column on its own. Use tone when landing here carries a status judgment, such as blocked, needing review, or done; otherwise leave it neutral.","x-name":"label","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"label":{"type":"string"},"tone":{"type":"string"}},"required":["id","label"],"additionalProperties":false,"x-owners":["lf-board"],"x-content":"members","x-tone":"tone","x-upgrade":false,"x-says":{"label":"before"}},"lf-card":{"description":"One board card whose identity and comments survive user moves.","x-instructions":"Lead with a `<strong>` title and follow with prose. Keep its id stable across moves. Rewriting a card the user moved needs restated; read $restated.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"restated":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"x-owners":["lf-column"],"x-content":"markup","x-work":true,"x-upgrade":false},"lf-tabs":{"description":"Several views shown one at a time: page navigation, a tabbed box, or a queue beside its open item.","x-instructions":"The first `lf-tabs` written directly in `main` is the page's navigation; any other tab set is a framed box within the page. Put the page's title and lede before page tabs, and the main current view first. Make each `lf-tab` a self-contained view; history, threads, versions and sign-off belong to the whole page. When current work no longer needs a view, remove it. Move any context still needed, and any passage an open thread or an unretracted decision is anchored to, into a `details` in the relevant tab. Use `list=\"side\"` for a queue listed beside the item it opens.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"list":{"type":"string","enum":["side"]}},"required":["id"],"additionalProperties":false,"x-content":"members","x-upgrade":true,"x-patch":"members","x-views":true,"x-example":"<lf-tabs id=\"views\">\n  <lf-tab id=\"tab-implementation\" label=\"Implementation\">\n    <p id=\"rollout-plan\">Wire the first site this week.</p>\n  </lf-tab>\n  <lf-tab id=\"tab-vision\" label=\"Vision\">\n    <p id=\"product-vision\">Keep the original outcome and constraints in reach.</p>\n  </lf-tab>\n</lf-tabs>"},"lf-tally":{"description":"A count of the open asks in one region, such as the decisions left in a queue, with an optional control that goes to the next one.","x-instructions":"Write it empty with a stable id, and set `for` to the region whose asks it counts, such as a side-list `lf-tabs` queue. Place it where the reader looks for the queue's state, such as a workspace header beside its `.tag` chips. Add `next` for a Next on me control that steps through the asks waiting on the user. Don't also state the count in prose or chips; the tally keeps it current.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"for":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"next":{"type":"boolean"}},"required":["id","for"],"additionalProperties":false,"x-content":"empty","x-inline":true,"x-prepaint":"<span class=\"lf-tally-face\"><span class=\"lf-tally-count\"><span class=\"lf-tally-room\">00 of 00 to answer</span><span class=\"lf-tally-room\">Nothing to answer</span><span class=\"lf-tally-words\"></span></span><button class=\"lf-btn lf-tally-next lf-ui lf-ui-face\" type=\"button\">Next on me</button></span>","x-refers":{"for":{}},"x-upgrade":true,"x-example":"<header>\n  <h1>Release triage</h1>\n  <p><lf-tally id=\"triage-left\" for=\"triage-queue\" next></lf-tally></p>\n</header>\n<lf-tabs id=\"triage-queue\" list=\"side\">\n  <lf-tab id=\"triage-retries\" label=\"Retry storm\">\n    <lf-ask id=\"retries-ask\">\n      <h3>Ship the retry cap?</h3>\n      <lf-options id=\"retries-choice\" choose>\n        <lf-option id=\"retries-ship\">Ship it</lf-option>\n        <lf-option id=\"retries-hold\">Hold for a canary</lf-option>\n      </lf-options>\n    </lf-ask>\n  </lf-tab>\n  <lf-tab id=\"triage-flag\" label=\"Stale flag\">\n    <lf-ask id=\"flag-ask\">\n      <h3>Remove the flag?</h3>\n      <lf-options id=\"flag-choice\" choose>\n        <lf-option id=\"flag-remove\">Remove it</lf-option>\n        <lf-option id=\"flag-keep\">Keep it a release</lf-option>\n      </lf-options>\n    </lf-ask>\n  </lf-tab>\n</lf-tabs>"},"lf-tab":{"description":"One labeled view in a tab set, optionally summarized and grouped in a side-list queue.","x-instructions":"In a side-list queue each item's `summary` shows under its label, so the user can choose an item without opening it. Start the summary with what the item is about, such as the problem a ticket reports, unless the label already says so, then what sets it apart from its neighbours, such as its age or suggested outcome. Leave out the item's group, which its heading shows. Where items fall into kinds the user works through in turn, such as merge, close and FYI, give each item its kind as `group` and place each kind's items together in the order to take them; adjacent tabs with the same group share one heading. Keep ids distinct across tabs, which share the page's id space.","x-name":"label","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"label":{"type":"string"},"summary":{"type":"string"},"group":{"type":"string"}},"required":["id","label"],"additionalProperties":false,"x-owners":["lf-tabs"],"x-content":"markup","x-upgrade":false},"lf-draft":{"description":"A block of text the user owns and can rewrite in place, with recorded revision history.","x-instructions":"Write the exact Markdown source as `<pre>`, one newline, the HTML-escaped source (& before < and >), then `</pre>` right after it. HTML drops that first newline; every later character, indentation and trailing newlines included, is part of the draft. For a change you propose to existing prose, use a suggestion instead. With `needed`, a draft asks the user for an edit; without it, it is an optional editing surface. Use lf-ask when the request needs its own heading and evidence, or page sign-off to approve the whole page. Keep the user's exact source on revision (authoring-revisions.md, \"Honor user state\"); to replace an edited passage on purpose, write the new text and mark the draft `restated` ($restated).","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"needed":{"type":"boolean"},"restated":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"x-content":"data","x-word":"module","x-awaits":{"value":"edit","when":{"needed":[true]},"answered":{"edit":{}}},"x-upgrade":true,"x-verbatim":true,"x-text-format":"markdown","x-state":{"edit":{"unit":"widget","record":{"kind":"body"}}},"x-example":"<lf-draft id=\"note-cli\"><pre>\nAdds --dry-run to every mutating command.</pre></lf-draft>"},"lf-sample":{"description":"A quotation of page content, either static or an operable child Leaf page.","x-instructions":"For a live child page, put its main content in one direct template[data-sample] with a stable id. Use window for a whole Leaf window including its chrome; chrome=\"floating\" or chrome=\"classic\" shows it in that chrome rather than the reader's own. Keep invented content visibly fictional. Read live-samples.md for child-page interaction, reset, and isolation.","x-name":"label","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"label":{"type":"string"},"chrome":{"enum":["classic","floating"],"description":"For a window sample, the chrome its child page reads with; without it, the reader's own preference."},"window":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"x-content":"markup","x-says":{"label":"before"},"x-exhibit":true,"x-upgrade":true,"x-example":"<lf-sample id=\"spec-gear\" label=\"next season's kit\">\n  <lf-options>\n    <lf-option id=\"sp-paper\"><small class=\"tag\">effort: low</small><strong>Paper maps</strong> Nothing to charge.</lf-option>\n    <lf-option id=\"sp-gps\"><small class=\"tag\">effort: med</small><small class=\"tag ok\">recommended</small><strong>Dedicated GPS</strong> Offline maps, week-long battery. <em>My take: this is the better field tool.</em></lf-option>\n  </lf-options>\n</lf-sample>"},"lf-pane":{"description":"A reading region with an optional header and footer, independently scrollable inside a full-height workspace.","x-instructions":"For independent scrolling, place the pane as a full-height workspace\u2019s body or a direct cell; elsewhere the page scrolls. Wrap multiple body blocks in one div or section. Use label to name the region accessibly and its header for the visible heading. Put action widgets in the direct footer when they should remain reachable as the body scrolls.","x-name":"label","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"label":{"type":"string","minLength":1}},"required":["id","label"],"additionalProperties":false,"x-content":"markup","x-reading-role":"pane","x-upgrade":true,"x-verbatim":true,"x-example":"<lf-pane id=\"detail\" label=\"Selected record\"><p>Read the selected record.</p></lf-pane>"},"lf-diagram":{"description":"A Mermaid diagram with optional comment targets on its named boxes.","x-instructions":"Write Mermaid source inside the `<pre>`, HTML-escaping & before < and >. Give each diagram an `accTitle` naming its subject and an `accDescr` describing its relationships, for a reader who can't see it. Draw a chain of more than three steps top-down (`flowchart TD`), since a long horizontal chain runs past the page's edge. Give a node that needs its own tone a Mermaid class styled in page CSS with theme tokens. Without `parts`, the whole diagram is one comment target; with `parts=\"all\"`, each named box, such as a flowchart node or a sequence participant, is a target of its own. Edges and messages never are.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"parts":{"const":"all"}},"required":["id"],"additionalProperties":false,"x-content":"data","x-upgrade":true,"x-visual":{"parts":"parts"},"x-space":"available","x-height":true,"x-example":"<lf-diagram id=\"checkout-flow\" data-height=\"368\" parts=\"all\"><pre>\nflowchart TD\n  accTitle: Checkout from cart to receipt\n  accDescr: The cart reaches a payment decision; a paid order produces a receipt.\n  Cart([Cart]) --> Pay{Paid?}\n  Pay --> Receipt[(Receipt)]\n</pre></lf-diagram>"},"lf-diff":{"description":"A unified patch with per-file navigation and commentable source lines.","x-instructions":"Without `source`, write the exact Git patch in the `<pre>` at column 0, HTML-escaped (& before < and >), or entity text in the patch will change silently. Keep Git's file headers and metadata, and make each hunk's `@@` counts match its lines. Keep the leading space on context lines, and write a context line that is only a space as `&#32;` so HTML parsing keeps it. With `source`, bind a page-owned patch feed or files manifest and leave the `<pre>` empty. Add `collapsed` to start every file closed.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"source":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"collapsed":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"x-content":"data","x-data":{"document":{"contract":"unified-diff","source":"source"}},"x-upgrade":true,"x-shadow":true,"x-thread-surface":true,"x-height":true,"x-example":"<lf-diff id=\"mount-diff\" data-height=\"151\"><pre>\ndiff --git a/feeders/mount.py b/feeders/mount.py\n--- a/feeders/mount.py\n+++ b/feeders/mount.py\n@@ -1,2 +1,2 @@\n def bracket():\n-    return \"plastic\"\n+    return \"steel\"\n</pre></lf-diff>"},"$diff":{"widgets":{"lf-diff":{"role":"patch"}}},"lf-call-diff":{"description":"A commentable call-tree diff, linked to the `lf-diff` that holds its patch.","x-instructions":"Set `diff` to the id of the `lf-diff` holding the exact patch. Store CallDiff's plain-text output, unedited, as the source's string value:\n\n```bash\njq -Rs . calldiff.txt | leaf data set \"$PAGE\" <source-id>\n```\n\nKeep the unchanged items in the tree as landmarks. In a large repository, give each widget one file or entry point. Don't copy the output into markup, add attribute reads as calls, or draw separate before and after diagrams.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"source":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"diff":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"required":["id","source","diff"],"additionalProperties":false,"x-content":"empty","x-data":{"document":{"contract":"text-document","source":"source"}},"x-refers":{"diff":{"via":"$diff.widgets","where":{"role":"patch"}}},"x-upgrade":true,"x-height":true,"x-example":"<lf-call-diff id=\"request-calls\" data-height=\"480\" source=\"request-call-diff\" diff=\"request-patch\"></lf-call-diff>"},"lf-playground":{"description":"A preview with controls, where the user tunes one configuration and sends it.","x-instructions":"Frame the question with `lf-ask` when its context lives outside the playground. Structured editors use `registerContributor(name, defaults)` and its immutable get/set handle; views use `subscribe(paint)` through the playground\u2019s LeafElement lifecycle. The playground package\u2019s \u201cStateful previews\u201d section owns initialization and connection lifetimes. One optional `registerInstructionProvider(values => text)` writes the instruction. For contributor state, redeclare the complete `lf-playground` entry in `page/registry.json` with an exact schema for `detail.values`.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"submit-label":{"type":"string","minLength":1},"restated":{"type":"boolean"}},"required":["id"],"additionalProperties":false,"x-content":"members","x-upgrade":true,"x-awaits":{"value":"choose","answered":{"choose":{}}},"x-state":{"choose":{"detail":{"type":"object","properties":{"values":{"type":"object","minProperties":1,"propertyNames":{"pattern":"^[a-z][a-z0-9-]*$"},"additionalProperties":{}},"instruction":{"type":"string","minLength":1}},"required":["values","instruction"],"additionalProperties":false},"unit":"widget"}},"x-example":"<lf-ask id=\"notification-ask\"><h2>Which notification should we build?</h2><lf-playground id=\"notification-playground\" submit-label=\"Create notification\"><lf-playground-control name=\"format\" label=\"Format\" kind=\"choice\" value=\"banner\"><lf-playground-choice value=\"banner\" label=\"Banner\"></lf-playground-choice><lf-playground-choice value=\"status strip\" label=\"Status strip\"></lf-playground-choice></lf-playground-control><lf-playground-control name=\"radius\" label=\"Corner radius\" kind=\"range\" value=\"10\" min=\"0\" max=\"24\" step=\"1\" unit=\"px\"></lf-playground-control><lf-playground-preset label=\"Status strip\"><lf-playground-setting for=\"format\" value=\"status strip\"></lf-playground-setting><lf-playground-setting for=\"radius\" value=\"4\"></lf-playground-setting></lf-playground-preset><lf-playground-preview><section aria-label=\"Notification candidates\"><article data-candidate=\"banner\"><h3>Banner</h3><p>The real banner responds to the shared controls.</p></article><article data-candidate=\"status strip\"><h3>Status strip</h3><p>The real status strip responds to the same controls.</p></article></section></lf-playground-preview><lf-playground-output>Build the <lf-playground-value for=\"format\"></lf-playground-value> notification with <lf-playground-value for=\"radius\"></lf-playground-value> corners. Replace the notification component and show me its browser test.</lf-playground-output></lf-playground></lf-ask>","x-initial":"/vendor/lf-playground-initial.js"},"lf-playground-control":{"description":"One typed input in a playground.","x-instructions":"Use a stable `name` for the submitted field and a `label` for the control. Write its initial `value` as a string: a finite number for range, true or false for toggle, one child's value for choice, a six-digit hex color for color, or any text for text. A range needs `max`; `min`, `step` and `unit` are optional. Only a choice control contains lf-playground-choice children. A control that changes the whole preview, as most do, is a direct child of lf-playground and appears in its rail. When the preview holds several items that each take their own settings, write each item's controls inside lf-playground-preview beside that item, where they appear as written.","x-name":"label","type":"object","properties":{"name":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"label":{"type":"string","minLength":1},"kind":{"enum":["range","toggle","choice","color","text"]},"value":{"type":"string"},"min":{"type":"string","pattern":"^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?$"},"max":{"type":"string","pattern":"^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?$"},"step":{"type":"string","pattern":"^(?:0\\.[0-9]*[1-9][0-9]*|[1-9][0-9]*(?:\\.[0-9]+)?)$"},"unit":{"type":"string"},"placeholder":{"type":"string"}},"required":["name","label","kind","value"],"allOf":[{"if":{"properties":{"kind":{"const":"range"}},"required":["kind"]},"then":{"properties":{"value":{"pattern":"^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?$"}},"required":["max"]}},{"if":{"properties":{"kind":{"const":"toggle"}},"required":["kind"]},"then":{"properties":{"value":{"enum":["true","false"]}}}},{"if":{"properties":{"kind":{"const":"color"}},"required":["kind"]},"then":{"properties":{"value":{"pattern":"^#[0-9a-fA-F]{6}$"}}}}],"additionalProperties":false,"x-unique":{"name":"lf-playground"},"x-owners":["lf-playground"],"x-within":["lf-playground-preview"],"x-content":"members","x-upgrade":false},"lf-playground-choice":{"description":"One labeled value offered by a playground choice control.","x-instructions":"Use value for the submitted value and label for the words the user sees.","x-name":"label","type":"object","properties":{"value":{"type":"string","minLength":1},"label":{"type":"string","minLength":1}},"required":["value","label"],"additionalProperties":false,"x-unique":{"value":"lf-playground-control"},"x-owners":["lf-playground-control"],"x-content":"empty","x-upgrade":false},"lf-playground-preset":{"description":"A named partial playground configuration the user can apply at once.","x-instructions":"Include settings only for values the preset changes; unspecified controls keep their current values.","x-name":"label","type":"object","properties":{"label":{"type":"string","minLength":1}},"required":["label"],"additionalProperties":false,"x-owners":["lf-playground"],"x-content":"members","x-upgrade":false},"lf-playground-setting":{"description":"One control value applied by a playground preset.","x-instructions":"Set for to a control in the same playground and write value in that control's authored string form.","type":"object","properties":{"for":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"value":{"type":"string"}},"required":["for","value"],"additionalProperties":false,"x-refers":{"for":{"tag":"lf-playground-control","key":"name"}},"x-unique":{"for":"lf-playground-preset"},"x-owners":["lf-playground-preset"],"x-content":"empty","x-upgrade":false},"lf-playground-preview":{"description":"The live preview the user operates in a playground, such as the candidates being compared.","x-instructions":"For an A/B comparison, mount both candidates here and drive them from one state, as the playground package\u2019s author instructions describe. Page CSS can read the `--playground-NAME` properties and `data-playground-NAME` attributes. Page modules read the immutable `values` aggregate, subscribe to draw updates, and replace structured slices through contributor handles.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"additionalProperties":false,"x-owners":["lf-playground"],"x-content":"markup","x-upgrade":false},"lf-playground-output":{"description":"The task instruction displayed by a playground and sent with the chosen configuration.","x-instructions":"Write a self-contained task rather than a value dump. Insert lf-playground-value where scalar selections make it more precise; use a registered instruction provider for prose that depends on structured or conditional values.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"additionalProperties":false,"x-owners":["lf-playground"],"x-content":"markup","x-upgrade":true},"lf-playground-value":{"description":"A live scalar value embedded in a playground instruction.","x-instructions":"Set for to a control in the enclosing playground. Numeric values already include the control's unit.","type":"object","properties":{"for":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"}},"required":["for"],"additionalProperties":false,"x-refers":{"for":{"tag":"lf-playground-control","key":"name"}},"x-owners":["lf-playground-output"],"x-within":["lf-playground-output"],"x-content":"empty","x-inline":true,"x-upgrade":false},"lf-visual-review":{"description":"A guided review of a visual run, with before-and-after captures and the user's verdict on each case.","x-instructions":"Write it empty with a stable id, and bind `source` to the visual run. To open a case on its changed area, give it a `focus` rectangle in the run. Tie each case's id to the run, not to the user's inspection choices.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"source":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"}},"required":["id","source"],"additionalProperties":false,"x-content":"empty","x-data":{"run":{"contract":"visual-run","source":"source"}},"x-state":{"review":{"detail":{"type":"object","properties":{"case":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"disposition":{"enum":["looks-right","needs-work"]}},"required":["case","disposition"],"additionalProperties":false},"unit":"case"}},"x-thread-surface":true,"x-upgrade":true,"x-space":"available","x-height":true,"x-example":"<lf-visual-review id=\"docs-review\" data-height=\"720\" source=\"docs-visual-run\"></lf-visual-review>"},"lf-trace":{"description":"A commentable Playwright recording with action phases, native captured frames and saved accessibility elements.","x-instructions":"Bind it to an imported playwright-trace source. Say what the recording shows, and make each result under review directly reachable with a named lf-trace-bookmark, preferably a successful expectation's After checkpoint, using imported ids and a label naming the result. The viewer supplies its own controls and opens at the earliest authored moment it can resolve. Native input records no timestamp or held duration, so the timeline places inputs at their calls; describe input timing at that resolution. Equal elapsed times in two recordings don't mean equal states. A comment on an image pins that image; one on a saved element pins the labeled checkpoint and tree path, which can be at a different time. Keep the linked Playwright viewer running for DOM snapshots, element picking, source, console and network. To pair results across recordings, put the viewers in one lf-trace-compare and give matching bookmarks the same key: choosing a keyed moment then selects each recording's own target, while manual seeking moves each one independently.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"},"source":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"},"label":{"type":"string","minLength":1}},"required":["id","source"],"additionalProperties":false,"x-content":"members","x-data":{"trace":{"contract":"playwright-trace","source":"source"}},"x-upgrade":true,"x-space":"available","x-visual":{"prefixes":["trace-"]},"x-example":"<lf-trace id=\"recorded-checkout\" source=\"checkout-trace\"></lf-trace>","x-prepaint":"<p class=\"lf-trace-waiting\">Waiting for a Playwright recording.</p>"},"lf-trace-bookmark":{"description":"A labeled link to one captured image or action phase in its trace.","x-instructions":"Set `target` to a capture in the trace: `trace-ARCHIVE_SHA256-image-IMAGE_ID` or `trace-ARCHIVE_SHA256-phase-ACTION_ID-PHASE`, where PHASE is before, action, after, start or end. Read the ids from the imported source. A target the recording lacks shows as unavailable. In an `lf-trace-compare`, give the bookmarks for the same result in each recording the same `key`; Leaf never pairs them by time or label.","type":"object","properties":{"label":{"type":"string","minLength":1},"target":{"type":"string","pattern":"^trace-[a-f0-9]{64}-(image|phase)-[a-z0-9-]+$"},"key":{"type":"string","pattern":"^[a-z][a-z0-9-]*$"}},"required":["label","target"],"additionalProperties":false,"x-content":"empty","x-owners":["lf-trace"],"x-name":"label","x-example":"<lf-trace id=\"recorded-checkout\" source=\"checkout-trace\"><lf-trace-bookmark label=\"Popup closes\" target=\"trace-0000000000000000000000000000000000000000000000000000000000000000-image-demo\"></lf-trace-bookmark></lf-trace>","x-upgrade":false},"lf-trace-compare":{"description":"Several Playwright recordings inspected together, with their results paired by key.","x-instructions":"Put one `lf-trace` per recording inside it, each with a `label` naming its recording, and give the bookmarks for the same result the same `key`. Choosing a keyed result then shows each recording's own capture of it; seeking by hand moves each recording separately.","type":"object","properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}},"required":["id"],"additionalProperties":false,"x-content":"markup","x-upgrade":true,"x-views":true,"x-space":"available","x-example":"<lf-trace-compare id=\"paired-recordings\"><lf-trace id=\"before\" label=\"Before\" source=\"before-recording\"></lf-trace><lf-trace id=\"after\" label=\"After\" source=\"after-recording\"></lf-trace></lf-trace-compare>"},"nav.sitenav":{"description":"The product site's compact route bar, written as the first child of main.","x-example":"<nav class=\"sitenav\" aria-label=\"Site\"><a class=\"brand\" href=\"/\">leaf</a><a href=\"/examples/\">Examples</a></nav>"},"header.hero":{"description":"A product-page opening with extra room and one larger headline.","x-example":"<header class=\"hero\" id=\"top\"><h1>Generative UI for your agent.</h1><p class=\"lede\">The agent builds the page your task needs.</p></header>"},"footer.site-footer":{"description":"The product site's quiet route and license colophon.","x-example":"<footer class=\"site-footer\" id=\"colophon\"><p><a href=\"/\">Home</a> \u00b7 <a href=\"/examples/\">Examples</a></p></footer>"},"$decisions":{"lf-suggestion":{"verb":"decide","retires":{"accept":["lf-old"],"reject":["lf-new"]}}},"$states":{"lf-suggestion":{"decide":{"writer":"user","definition":{"origin":"lf-suggestion","unit":"widget","record":null,"creates":null,"detail":{"type":"object","properties":{"outcome":{"enum":["accept","reject"]}},"required":["outcome"],"additionalProperties":false}}}},"lf-options":{"choose":{"writer":"user","definition":{"origin":"lf-options","unit":"widget","record":{"kind":"attribute","attr":"chosen"},"creates":null,"detail":{"type":"object","properties":{"value":{"type":"array","items":{"type":"string","minLength":1},"uniqueItems":true}},"required":["value"],"additionalProperties":false}}},"add":{"writer":"user","definition":{"origin":"lf-options","unit":"option","record":null,"creates":{"child":"lf-option","words":"text"},"detail":{"type":"object","properties":{"option":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1},"text":{"type":"string","minLength":1}},"required":["option","text"],"additionalProperties":false}}},"answer":{"writer":"user","definition":{"origin":"lf-options","unit":"widget","record":null,"creates":null,"detail":{"type":"object","additionalProperties":false}}}},"lf-board":{"move":{"writer":"user","definition":{"origin":"lf-board","unit":"unit","record":{"kind":"position","within":"lf-column"},"creates":null,"detail":{"type":"object","properties":{"value":{"type":"string","minLength":1},"unit":{"type":"string","minLength":1},"rank":{"type":"string","pattern":"^(?:[0-9a-z]*[1-9a-z])$"}},"required":["value","unit","rank"],"additionalProperties":false}}}},"lf-draft":{"edit":{"writer":"user","definition":{"origin":"lf-draft","unit":"widget","record":{"kind":"body"},"creates":null,"detail":{"type":"object","properties":{"value":{"type":"string"}},"required":["value"],"additionalProperties":false}}}},"lf-playground":{"choose":{"writer":"user","definition":{"origin":"lf-playground","unit":"widget","record":null,"creates":null,"detail":{"type":"object","properties":{"values":{"type":"object","minProperties":1,"propertyNames":{"pattern":"^[a-z][a-z0-9-]*$"},"additionalProperties":{}},"instruction":{"type":"string","minLength":1}},"required":["values","instruction"],"additionalProperties":false}}}},"lf-visual-review":{"review":{"writer":"user","definition":{"origin":"lf-visual-review","unit":"case","record":null,"creates":null,"detail":{"type":"object","properties":{"case":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1},"disposition":{"enum":["looks-right","needs-work"]}},"required":["case","disposition"],"additionalProperties":false}}}}},"$marks":{"x-content":{"paint":"data-lf-content","message":true},"x-verbatim":{"paint":"data-lf-verbatim","message":true},"x-space":{"paint":"data-lf-space","authored":"data-width","authored_on":"content","message":false},"x-inline":{"paint":"data-lf-inline","message":true},"x-exhibit":{"paint":"data-lf-exhibit","message":true},"x-bound":{"paint":"data-lf-bound","authored":"data-bound","authored_on":"content","message":true},"x-height":{"paint":"data-lf-height","authored":"data-height","authored_on":"declared","message":true},"x-reading-role":{"paint":"data-lf-reading-role","message":true},"x-resident":{"paint":"data-lf-resident","message":false},"x-views":{"paint":"data-lf-views","message":true}},"$layer":{"generation":"6815907daf868fb4556dd017a32a896a","fingerprint":"sha256:aa2515062217586f7a2c066f5f7624fd21e3fd89d3e5f5748e5bafbb90e83e70","server":"sha256:624b26e792a64798161dcfa3be4e25c19be7395f75c5838348cac142ac859c06","packages":["code-review","diagram","diff","playground","monitoring","visual-review","playwright","./docs/package"],"producer":{"commit":"7f2e83475eb7","committed":"2026-10-16T13:43:08-07:00","dirty":false}}}