{"lf-suggestion":{"description":"One proposed change to content the user has already seen, with accept and reject controls.","x-space":"column","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 proposed widget change uses complete old and new markup too. Write fresh 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 acceptance should resolve. To withdraw an undecided proposal, retain lf-old\u2019s contents and remove both wrappers and lf-new; dropping the wrapper must not silently accept the proposal.","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 languages this page's layer can color, and what a filename means. `names` is the whole vocabulary: what an author may declare, what the lint refuses a word outside, and what the shared syntax grammars in build/vendor.mjs are built from. It is a property of the page rather than of any widget, which is why it lives here and not under the schema of whichever tag happens to take a `language` \u2014 a widget declares that one of its attributes names a language (x-language) and the lint reads the list from here, so a second tag taking one costs a declaration and no new reader. `paths` is the half nobody writes: the one place a language is derived rather than declared, because a unified diff spans files and a file editor names one file, so neither has an attribute to carry one. An extension is the filename's own statement about what a file holds, which is a declaration like any other; an extension absent here leaves that file plain.","why-diff-is-not-a-path":"`diff` is in `names` and deliberately not in `paths`: a .patch inside a diff would be colored by the diff grammar, whose addition and deletion ink is the same statement the widget's own tints already make \u2014 said twice, in two channels, about the same line.","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 the file's reading (`leaf/passages.py`, `leaf/anchor_capture.py`) and the browser's (`runtime/passage-facts.js`, generated from this entry by build/registry.mjs) turn a page into text, so a quote the browser captures is one `leaf thread open` can confirm. Python reads it from the running Leaf's registry, while a page's runtime carries the copy it was vendored with, so changing it 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 a whitespace run is made of, which both readings fold to one space. JS's \\s and Python's str.isspace() disagree at the edges \u2014 U+FEFF is whitespace to JS alone, U+0085 and U+001C\u2013001F to Python alone \u2014 and a page carrying one of those in prose would read differently on the two sides. The browser captures every quote, so this is its set: the characters JS's \\s and trim() treat as whitespace.","blocks":["p","li","h1","h2","h3","h4","h5","h6","td","th","pre","blockquote","dd","dt","figcaption","summary"],"why-blocks":"A text node's block: one space goes between two runs of text in different blocks and none between runs that share one, so `<p>a</p><p>b</p>` reads \"a b\" and `set<em>up</em>` reads \"setup\". The browser also reads a block as one unit of prose: the passage a reader is in, where a walk over the user's On me list starts, and what a version diff compares.","context":24,"why-context":"The characters of context a captured anchor starts with on each side of its quote. The file requires a unique quote; the browser knows which occurrence the user selected and may widen the context until the shared resolver identifies that exact span."},"$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":6,"ownership":{"derived":["meaning","attention"],"browser_discard":["id","author","agent","session","ts","seq","attention"]},"description":"Leaf's fixed kernel event contract. Each kind carries the closed `record` schema for the complete event read from the log. Admission stamps the server-owned boolean `attention` from the change to canonical answers, work in hand (a started update or an open to-do on a thread or widget) and its inputs, or sign-off approval; reports and errors always carry it. Carriers select this recorded meaning rather than classifying event kinds. A `browser` schema opts that kind into POST /api/event and adds the browser writer's assertions. `ownership.derived` names fields admission supplies; `ownership.browser_discard` names fields browser ingress removes before validation. Layers extend widget behavior through x-state; they cannot change transport kinds or field ownership. `protocol` numbers this contract together with the reading the server serves the page's runtime, and is the one version Leaf has: each 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 a page whose vendored `protocol` is its own, admitting the page's events against its own kinds, so a change a page vendored at the same number would break on, such as a dropped or newly required field, bumps it. A kind declaring `bookkeeping` records a fact about the user's view of the page rather than an update: it never asks the agent for anything, and the browser sends it outside the ordered gesture queue, so it neither waits behind a gesture nor holds one back. A `pickup` is the page-owned durable transport fact that named attention-bearing inputs reached their next consumer, or with phase `failed` and a harness `failure` code that the harness gave up on them with no answer coming; it is never a claim that work has begun. Its optional `refs` maps each input its delivery owed an answer to the exact `answer.ref` that delivery gave it and the `claim` the delivery was captured under. A `comment` or `reply` carrying `token` instead of `text` is a reaction \u2014 one word from $reactions, aimed where the comment's anchor or the reply's parent points, or with neither at the page whole. It starts as a mark rather than a thread: no thread opens until someone replies to it, `resolve` on it is the floor after which it stops painting, and while nothing has answered it the user takes it back with an ordinary `undo` naming it. `handling` and `answering` remain layer-owned. `handling` holds, per kernel kind, an ordered list of clauses, each a `text` and an optional `when` JSON Schema; `answering` holds the same per answer kind (`reply`, `markup`), for the event that owes that answer. A `when` matches the delivered event: its record plus the `answer` it owes and its `thread`'s entry in the batch's digest, each if any, so a clause states one case plainly rather than naming a condition the delivery already settles. What differs by route is not a clause: the delivery states once who acknowledges it, and names its `writer` as `turn` where the turn carrying it writes the reply. Each delivered event carries its kind's matching clauses and then its answer's, so an event is told only its own case and only the answer it owes, and a later layer may restate one kind at a time.","handling":{"comment":[{"when":{"required":["drawing"]},"text":"The user drew on the page. `drawing.says`, when present, holds the page's words from the first to the last inside the ink's extents: the neighbourhood of the mark rather than the mark, so an arrow across a paragraph says the whole paragraph. It is absent where the extents hold no words, as over a picture or in a margin. `drawing.strokes` are local coordinates in one frame: HTML CSS pixels, SVG user units, or intrinsic image, canvas and video pixels. Optional `drawing.frame` identifies that visual inside the semantic comment target by a structural path; `drawing.box` is the frame's size. Prefer `leaf page picture PAGE ID`, given the comment's `id`, to see what the mark covers: it prints the path of a PNG of the comment's revision laid out in their window and color scheme (`drawing.viewport`, `drawing.scheme`), with the ink over it. Any `text` explains the mark. Otherwise it is an ordinary comment, answered the same way."},{"when":{"required":["text"],"properties":{"text":{"pattern":"\\]\\(/media/"}}},"text":"The message carries an image as a Markdown link to `/media/<digest>.<ext>`, a path under the page directory the batch names. Open the image itself before answering: its alt text is a label, not a description of what it shows."},{"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 rather than what it says. Its anchor's `section` is an authored element's id or, when it starts `lf-`, a part of Leaf's own 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 click landed on. Find the source that produces what it names and fix it in this page's own source, unless the behavior belongs to a package's widget or the user asks for a wider fix: then change the package as the Leaf skill's `references/packages.md` says, re-vendor, and note the re-vendor on the stamp. A fix that belongs in Leaf itself is the user's to raise, as the Leaf skill's \"Improve Leaf through use\" says. The stamped version that carries the fix is the result the reply reports."},{"when":{"required":["thread","answer"],"properties":{"thread":{"required":["title"],"properties":{"title":{"type":"null"}}},"answer":{"properties":{"kind":{"const":"reply"},"writer":{"const":"agent"}}}}},"text":"This event's thread has no title yet: name it by adding `--title \"<a few words>\"` to the reply that answers it, so the thread panel lists its subject rather than its opening words. If Leaf has named it from its opening message by then, that name stands."},{"when":{"required":["token"]},"text":"A reaction is a mark, not a question. Read the token and act on it 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 it does not wait on an answer."}],"reply":[{"when":{"not":{"required":["token"]}},"text":"The user answered in a thread; the batch's `threads` carries the thread's context, and `leaf page state <page> <thread-id>` reads its history in pages."},{"when":{"required":["text"],"properties":{"text":{"pattern":"\\]\\(/media/"}}},"text":"The message carries an image as a Markdown link to `/media/<digest>.<ext>`, a path under the page directory the batch names. Open the image itself before answering: its alt text is a label, not a description of what it shows."},{"when":{"required":["thread","answer"],"properties":{"thread":{"required":["title"],"properties":{"title":{"type":"null"}}},"answer":{"properties":{"kind":{"const":"reply"},"writer":{"const":"agent"}}}}},"text":"This event's thread has no title yet: name it by adding `--title \"<a few words>\"` to the reply that answers it, so the thread panel lists its subject rather than its opening words. If Leaf has named it from its opening message by then, that name stands."},{"when":{"required":["thread"],"properties":{"thread":{"required":["summary_hint"]}},"not":{"required":["token"]}},"text":"This thread's entry in the batch's `threads` carries a `summary_hint`, a suggested earlier range to review. Follow the Leaf skill's `references/threads.md`, \"Summarize a long discussion\", as you answer this input. The hint adds no separate response obligation."},{"when":{"required":["token"]},"text":"A reaction on your message. It needs no reply, and Leaf already records whether it answers what you asked."}],"edit":[{"text":"The user rewrote their message `message` in place: `text` is how it reads now and `was` how it read before, and the thread shows only the new wording. Answer the message as it now reads. Where your earlier answer or work rested on what changed, say what that changes and redo the work it requires; where it changes nothing you did, say so. If `message` opens the thread and the thread's title no longer fits what it now asks, retitle the thread with `leaf thread edit <page> <message> --title \"<a few words>\"`, so the thread panel names what the thread is about now."},{"when":{"required":["suggestion"],"properties":{"suggestion":{"const":true}}},"text":"The message is a suggestion, so `text` is now the exact replacement it proposes. Apply it verbatim, or reply with your reason for declining."}],"resolve":[{"text":"The user closed the thread. You owe no reply in it; a to-do you opened on it still stands until you end it."}],"unresolve":[{"text":"The user reopened a closed thread. The reopening owes nothing of its own; if the thread's latest user message was never answered, `leaf page state <page> <thread-id>` shows the `answer` its workflow still owes."}],"todo_end":[{"text":"The user pressed Done on a to-do you put on them: `todo` names the to-do you opened with `--on user`. It ends that to-do and owes no reply of its own. Carry on with whatever the to-do was waiting for, reading the page where 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 it watched while you do what the approval unblocks, and show that work on the page 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, and `detail.outcome` says which way: `accept` keeps the lf-new branch and `reject` keeps the lf-old branch. The next version writes the kept branch in as settled prose with its ids and drops 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 it does not finish the answer yet, such as a pick before the Done its group waits for."}],"undo":[{"text":"The user took back the gesture that `undoes` names. Treat the two as cancelling out: do not 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. Answer it in a stamped version before the page ends: write the reported state into the markup, or mark the element `overruled` and say why in the version note. A version that leaves the widget as it was leaves the report in force, and `page check` refuses one whose markup contradicts the report without answering it."}],"error":[{"text":"The page's runtime reported a failure the user saw. Fix the page or widget and save the fix. It is a diagnostic: reply only if the user asked about it."}]},"answering":{"reply":[{"text":"When the event asks for work, say in its thread what you will do before any other command, including reading the source it concerns: `leaf response reply <answer.ref> --ephemeral --text \"<what you will do, in a line>\"`. The user reads it in the thread at once, and it takes the update in hand: the update reads Working, and the line stands in the banner until you answer. Do the work and put its result on the page, with whatever 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. When the event asks for no work, as a question may not, answer it with that reply at once. The page carries the work, and the thread only the conversation about it. `leaf response reply` checks any saved page edit and makes it live before posting. If a revision removes what the thread is anchored on, move the thread in the reply that reports it with `--section <id>` (narrowed by `--quote` or `--part` if needed), or `--detach` it if its subject has left the page. Every answer says what it leaves: `--done` when it delivers what was asked, `--ask` when its prose asks the user something back, or `--todo \"<what you owe>\"` when it promises work that outlasts this turn, which then stays on you, under the reply's id, until `leaf task end` (`references/conversation-loop.md`, \"Long-running work\").","when":{"properties":{"answer":{"properties":{"writer":{"const":"agent"}}}}}},{"text":"Leaf streams your opening into the thread and commits your completed final unless an explicit successful reply already answered this input. Before your first tool call, open with a short message to the user: the answer, or what you are about to do. Later working messages stay in Codex. Finish with the answer or what changed and where it appears. For an explicit answer, including widgets, an ask awaiting the user (`--ask`), work promised beyond this turn (`--todo`), a title or relocation, use `leaf response reply <answer.ref>` and the rich options in `references/threads.md`; it validates saved edits and commits immediately. Your later final yields to that recorded answer.","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, so the page shows it as waiting on you until the markup records it. 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 it 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":"What each x- key an element declaration may carry means, one member per key. The lint admits only these keys: it refuses a registry whose $keys has a member for a key the lint does not admit, or lacks a member for one it does. A layer may override a member to document its own reading of a key, but cannot declare a new key. Authors query this entry beside element declarations, and the site's table of keys is generated from it, so authors, the lint and the site read the same text.","x-ask-context":"The element frames the asks nested in it. Its leading direct heading supplies their prompt text, and travel to one of those asks lands on the element. It never changes an ask's identity, answer or completion, and never merges asks from different sources. Where frames nest, an ask uses the nearest. One frame may hold several asks, each keeping its own widget:<source-id> identity. lf-ask is one element that declares this key; a widget that asks on its own needs no frame. When Leaf names the element's kind, it calls it a question, unless the element's x-word module returns another label.","x-awaits":"The widget asks the user for input while its authored attributes match `when`. The ask's id is widget:<source-id> and does not change; a framing x-ask-context supplies only the prompt words and where travel to the ask lands. `value` names the x-state verb whose state is the typed answer: the verb's record value, or, where it has no record, the detail of its latest action still in force. A verb that keeps state per member unit gives a map from each unit to its value. `answered` declares when the ask is complete, separately from `value`: a partial value can exist while the ask is open, and a completed empty value is still an answer. Core publishes one record per ask with source, prompt, answer {value, event}, status and next_actor. An ask once registered stays answered or withdrawn after `when` stops holding; an element that never matched `when` creates no ask. A `restated` event starts a fresh request. An open ask's next actor is the agent, and the ask stays open and unanswered, while the agent owes a reply about it: to a thread anchored inside the widget, or inside its x-ask-context and no other ask; or, for a widget frozen into a thread, to a user turn after the message that asked. A widget frozen into a thread keeps its ask after that thread closes, with no next actor. A quoted widget (x-exhibit) registers no ask. `all` names the outcome one banner control can give every ask of this kind at once. Asks and to-dos are separate records, and the user's On me list reads asks directly.","x-thread-seat":"The module places a thread box (threadBox) in each matching Leaf element, chosen by the authored, static attributes in `when`; an attribute that an x-state value record writes cannot satisfy `when`. The box shows, as text, the threads anchored exactly to that element, read from the whole log; the Threads panel keeps the full interactive view. A matching element inside thread markup or quoted content gets no box. If the widget also asks a question (x-awaits), the box is where the user answers it in words: while a thread there waits on the agent, the ask leaves the user's On me list, so the user does not see it twice. That comment does not answer the ask. The widget's state is unchanged, its controls still work, and the ask still reads as unanswered. `hold` is the label of a second send control in the box, whose comment carries `holds`, naming this widget. A held comment starts a thread like any other comment in the box, and the control stays available after other threads have started there. The widget is held while that thread is unresolved; resolving the thread releases it, and undoing the resolution restores the hold in one step. Removing the widget removes only the box, not its threads.","x-content":"The required content model: `markup` (the author's markup), `members` (only this element's declared member elements), `data` (one <pre> containing text in the notation the description names), or `empty`. A data body uses <pre> to preserve whitespace without CSS, with & < > escaped as &amp; &lt; &gt;.","x-data":"The widget's named external-data inputs. Each input names a `$data.contracts` contract and the declared canonical string attribute whose authored value is this page's source id. The input follows the source's current value. An optional source attribute leaves that input absent; `watchData` delivers null. Several widgets may bind the same source to the same contract. A document binds a source to one contract. Later documents may replace that binding; each captured document reads the current value against its own declared contract and reports incompatible values as source errors. A module subscribes by widget and input name, never by a package-owned 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 displays quoted content: nested widgets are not interactive, and nested asks do not enter the user's On me list. Modules check `quoted(el)` before enabling input. The theme suppresses interactive styling inside quoted content.","x-instructions":"Author instructions for using this widget, read after selecting it and before writing markup. A flat nonempty string, separate from its short discovery description and its structured schema.","x-inline":"The element sits inline among the words around it. The render gate therefore does not require it to have a width of its own, and does not apply the rule that a block widget must stand where a block is allowed.","x-language":"The attribute that names a code language. Its value must be one of `$languages.names`, the one list of languages the page highlights, so a new tag that takes a language needs only this declaration and no code of its own to read the attribute.","x-reading-role":"The structural role an element supplies. The only role is `pane`: a labeled reading region whose body scrolls on its own while the workspace is full-height. A pane holds exactly one body element, optionally preceded by a direct native `header` and followed by a direct native `footer`. Validation of roles reads this declaration rather than tag names, and a pane's content stays markup, so packages can contribute panes under their own tag names without a fixed list of allowed parents and children. A pane requires a string `id` and a string `label`; the label names its accessible region, and a visible heading belongs in its authored header.","x-measured":"A scalar in authored content pinned to one x-data input's run receipt. `input` names the widget's data input and `run` its required nonempty receipt attribute. When that source holds a different run, `page check` warns that the authored measurement is stale and `page state` reports it too. A source rewritten with the same value counts as a new run; a measurement's age alone does not make it stale.","x-patch":"How a revision reaches an upgraded widget the user has open. By default its module owns everything under the element, so a revision that changes any of the widget's markup replaces the whole widget and rebuilds whatever the user had open in it. `members` says the module builds its own controls beside its members, leaves them where the author wrote them, and reads nothing of them but their attributes: while a revision keeps the element's attributes and each member's tag and attributes, in order, it edits inside the members in place and the widget stays. Requires `x-content: members` and x-upgrade.","x-owners":"The element declarations that may directly own a Leaf element. Read from an owner, this defines which direct child Leaf elements are its members rather than nested elements it merely contains; a gesture the owner takes on its whole box stops at those members.","x-refers":"A map from attributes whose values name another element to their target contracts. An empty contract accepts any element id (an option's `for`). A typed contract names a shared registry map with `via` and an equality predicate with `where`; `page check` then requires both an existing id and a target tag whose declaration in that package-owned map matches the predicate. This lets a package distinguish a goal, worker, or evidence reference without Leaf knowing those roles or tags. A typed contract with `owns: true` says the referrer fills its target, as a command fills the readings seat it names: `page check` requires the target in the referrer's own document, and every element there that the predicate selects named by exactly one referrer. A keyed contract `{tag, key}` names a member by an attribute rather than an id: the `tag` element whose `key` attribute holds the value, inside the referrer's own nearest owner of the tag `key` is unique within, which `tag` declares in x-unique (a playground preset's setting names a control of its own playground by `name`); `page check` and message markup refuse one naming no such member. In the browser a declared attribute is what a module hands `navigateToDatum` and the experimental `indicate` to reach the named widget, which each resolves in that same owner for a keyed contract, and otherwise in the owner's own authored document first (its message's markup, for a widget in a reply) and then in the page.","x-resident":"How an element sits in the margin when it is the only occupant, or one occupant, of a column page's first `aside.sidebar`. The only value is `map`, a contents map: where the margin has room and the pointer is fine, such as a mouse or trackpad, it shows as a spine in the left margin and reveals its labels over the page. Delivery writes the declaration into the served document as `data-lf-resident`, so the margin layout reads it rather than a widget's tag. A thread message has no margin, so delivery does not write it there.","x-retired-when":"On a member: the outcome of its owner's decision that removes this element from the page, as `accept` removes a suggestion's `lf-old`. Requires x-owners. The outcome is a value of the `outcome` detail field on the owner's one deciding verb, so only one decision can be in force. The layer renders the decision itself and follows the log in both directions. Reconciliation writes data-lf-state=\"<outcome>\" on the owner and data-lf-retired on the members that outcome removes, and takes both off when undo or a retraction withdraws the deciding action; one theme rule hides the marked members. No module has to do any of this, though a module may write the same attributes earlier as part of its own gesture (renderRetired). These attributes are rendered output for CSS, export, and checks; code that needs the decision reads the publisher's explicit outcome rather than the attributes. The file-side reading takes the decision from the log, and once the log decides it, `page check` allows a revision to drop the member's ids. `page check --render` reports a removed member that still shows words, and a mark the log never decided.","x-says":"Attributes whose values render as selectable text, and where that text appears. `after` places the text inside the element, after its content and before trailing controls. `before` places it at the start, before content and controls; multiple `before` attributes render in declaration order. The runtime creates text nodes so the user can select, quote, and comment on these words; CSS `content: attr()` cannot provide that.","x-shadow":"The module renders the page's words into an open shadow root. Leaf's passage reading, selection capture, and every lookup by id reach into it. The render gate reports a shadow root on an element whose declaration lacks this key.","x-state":"What x-state declares, once per widget that has state: for each verb, the unit of the widget's state it changes, who writes it, and either its recorded effect or the schema of its unrecorded detail. A recorded effect's payload follows from the effect kind and the destination attribute, so it declares no detail schema or field mapping of its own. A verb is the user's unless it declares `writer: \"agent\"`. The user writes a user verb through the page, as `action` events; the agent writes an agent verb with `leaf page report`, as `report` events, so each [widget, unit, verb] key has one writer. A user verb may declare a child element it creates (`creates`). An agent verb needs a record form other than `body`, because a report changes declared state and never the page's words, so it never changes what the passage reader reads. An agent verb may declare `text: true`, which requires each report to carry non-empty `detail.text`. That text is the report's short news for a person, and the report feed shows it as written instead of composing it from the widget, verb, or field names. The runtime marks a report on the page as soon as it is in force (data-lf-reported); it stays only until a version answers it, as $report says. Each verb holds its own state: for each [widget, unit, verb] key, the latest action that has not been taken back replaces earlier ones, and different verbs on the same unit coexist. The framework combines those latest actions with the typed authored values and gives each widget its complete state through renderState, keyed by verb. The same declaration drives POST validation, replay of the complete state, inspection, the runtime's readings of user actions and reports, and the state half of a version diff. When an admitted action makes the widget's x-awaits `answered` condition hold, Leaf records meaning.answer on the event. Its value is the thread named by the widget's authored `resolves` attribute in the document the action was sent from, which the answer closes, or null when the answer closes no thread. A decision whose outcome is the widget's x-withdrawn-as value also records null, and the page then reads as if nothing had been proposed. A past action keeps the [widget, unit, verb] key it was admitted under, even after the widget leaves the page. One detail field name is reserved: `outcome`, on the one user verb that decides which retirable members leave the page (x-retired-when). $state documents units, `creates`, and record forms.","x-thread-surface":"The upgraded widget can show Leaf's comment box and threads inside itself, beside the exact data items (datums) they are about. Leaf registers the widget when it upgrades and retires it when it leaves the page. On each reconciliation pass Leaf calls the element's own `threadOutlets(targets, {signal, collection, onCommit})` with one ordered batch of the admitted targets anchored exactly to its items, and the method returns for each target an element to place it in (an outlet), or null. Leaf maps each outlet to its thread or to the open comment box and controls where it is placed and how long it stays. The widget reads its registration with `threadSurface(element)`: `update()` says its seats changed, and `open(datum)` opens Comment on one of its items. Leaf owns anchors, drafts, response modes, sending, thread rendering, reply and reaction state, settlement, focus, receipts, and the fallback to the margin. A placement holds that comment box or thread in the widget for the current reconciliation pass only. An item that is not loaded, filtered out, collapsed, outdated, or otherwise not shown gets no placement; its threads stay in the Threads panel and fall back to the margin as usual.","x-text-format":"Text format: inline-markdown formats this element's direct text nodes; markdown renders its exact data body as safe block Markdown. A body record retains Markdown source while passages read visible words. Its existing element children remain HTML. The browser formats those words with the shared safe Markdown parser, while file-side passage and revision readings use the same visible words. A generated child with this declaration interprets the user's line breaks as hard breaks; source HTML line wraps remain ordinary whitespace.","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 attributes whose values no two members share within one owner to that owner's tag. `page check` and message markup refuse a member whose value repeats another's inside the same nearest enclosing owner of that tag, as two controls of one playground sharing a `name` or two choices of one control sharing a `value`. A keyed x-refers contract names members by such an attribute, so it always names one.","x-upgrade":"A module at widgets/<tag>.js enhances the element in the browser, imported where a page's markup carries the tag rather than for the whole layer. `page init` refuses a layer declaring it with no module beside it, and the render gate a module that defines no element for a widget the page contains. Required.","x-verbatim":"The upgraded element keeps its authored words, and keeps nested upgraded widgets in their authored order with their identity, so the passage reader can quote those words. Each nested upgraded widget keeps its own declarations about its words and boundaries, so what it generates is not a claim made by the wrapper. Without this declaration the passage reader treats the widget as opaque, since its module may insert or replace words. The render gate 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 captured classic JavaScript bundle registering the widget's synchronous initial renderer with document.documentElement.lfInitial.register(tag, render). Delivery inlines each used bundle once in the head, buffers each outer host in an inert template until its source is complete, and inserts and draws it in one synchronous turn, nested hosts deepest-first. render(host, {tabStore, offer, offerElement}) builds the instance's real markup using authored values and tab-local mechanical state; it performs no network or asynchronous work and returns the structure the behavior module adopts with initialRender(host). The widget loader imports that same bundle before the behavior module for later revision and thread arrivals, only where it has not already registered. The coordinator preserves the original authored markup and node routes before rendering, so source comparisons and semantic readings do not consume the drawing. Requires x-upgrade: true and excludes x-prepaint.","x-prepaint":"Markup an upgraded element shows at its first paint, before its module draws: one element with the structure the module will draw, holding words that give it the size the drawing will have. Delivery writes it into every occurrence in the served document, as the element's first child marked data-lf-prepaint, so the browser lays the widget out from its real structure and wraps it as the drawing will, instead of reserving a height computed from line heights. The theme keeps that space and paints none of the prepaint markup, and a reading without the runtime hides it. The module removes it in the same step that draws its replacement, so nothing moves, and draws by filling in a copy of the same markup, so this declaration is the only statement of that structure. `{\"as\": tag}` takes the named widget's prepaint, for an element that first paints as that widget will appear inside it, as a command with no readings seat draws one at its head. Write the markup exactly as the parser reads it back, with every element closed, because delivery inserts it as written and an unclosed element would take in the occurrence's own children. It carries no id, no custom element, and no script, since every occurrence gets a copy. Declare it on a widget whose drawn structure is fixed while its values come from the log, as a command's outcome and count tiles are; a widget whose rows depend on the log has no fixed structure to write here.","x-views":"`true`: the element shows one of its members at a time, as a tab set shows one panel, and its module opens it on the member the runtime names (`openingView`) and records each member it shows (`keepView`). The runtime opens it on the member holding the element the address's fragment names, else on the member this browser tab last showed, else on the first; a reload puts the member last shown before the fragment's. Delivery paints it into the served document as data-lf-views, and before the 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 the element.","x-visual":"How a rendered picture exposes stable Comment targets. `whole` anchors the picture on the authored widget. Every declared provider also supplies its own visual surface for whole-widget aim and marks, so chrome paint stays above the widget's drawing. For `{parts: ATTR}` or `{prefixes: [PREFIX, \u2026]}`, its module calls `registerVisualParts(source, read)` once; `read` returns the complete current `{id, element, label, surface?}` inventory. When ATTR is present, core admits the complete registered inventory; omitting it keeps one whole-picture target. Under `prefixes`, core admits any longer id one of them begins, such as `commit:3f2a` under `commit:`. Core derives token lookup and deepest-part hit testing from that inventory. `surface` defaults to `element` and may name one descendant whose native paint excludes decoration from the contour. It changes paint only: `element` remains the semantic hit and travel target. Marks and aim follow an SVG surface's painted geometry primitives; a surface with none, and every other element, uses the shown box. Targeting a mapped part stores its id as `anchor.visual` while the widget remains the semantic seat. A missing token or registration detaches on replay rather than widening to the whole picture. A visual that draws its parts over time passes `registerVisualParts(source, read, {reveal})`: `reveal(id)` synchronously settles on a state whose inventory holds that declared part, even when it is already visible, cancelling any pending replacement that would retire it. A declared part absent from the current state then places its threads on the whole picture, and travel to the part, whether a thread anchored there or a module's `navigateToDatum`, calls `reveal` before landing on it. The registration's `update()` signals any rendering or geometry change, including an in-place attribute or style change. The render gate validates every registered record and refuses a registered id its prefixes do not admit.","x-space":"The default width an element takes in a flow wider than the prose measure: `column` keeps that measure and starts where the prose does, for an element or idiom whose content is read as lines of text or that frames prose (an ask, `.callout`), and it widens to the widest allocation among its own blocks; `wide` takes the vocabulary's shared capped evidence width; `available` takes all room the page shell can give after enclosing frames, chrome, and actual margin residents. An element that declares none fills the box it stands in, as every element does outside the column and sidebar Layouts, which alone allocate it. The declaration says nothing about how the package arranges content inside that allocation. An authored occurrence may override the default with data-width=wide|available; delivery paints that choice into the served document as data-lf-space and the theme allocates it without moving the prose axis.","x-bound":"The element holds its own height and scrolls inside it, so a long log or feed never grows the page: `start` opens at its first line and `end` follows its newest entry while the user is at the end, and stays where the user scrolled back to otherwise. An authored occurrence may state or override it with data-bound=start|end; delivery paints it into the served document as data-lf-bound.","x-height":"The height, in CSS pixels, the page reserves for the element before its module draws: the declaration's number, or an authored occurrence's data-height, which overrides it; `true` declares no number, so only an occurrence's data-height reserves. Delivery paints it into the served document as data-lf-height, and wherever the runtime runs the theme holds the box to it from the first paint until the module marks the element drawn (`lf-rendered`), when the box becomes the drawing's own. Declare it on a widget whose drawing cannot be sized from its markup before the module draws. A module that can draw to any height, as a chart's can, draws at the stated one, so nothing moves when the reservation ends; one whose content has a height of its own draws that, and the reservation is the author's estimate of it. A failure takes the height of the message it shows.","x-history":"`true`: the module renders the page's history, so a page whose markup holds one is served the `history` reading beside its state and a page without one does not pay for it. The reading is the newest 50 logged events, newest first, each naming who acted, what they did, the thread it belongs to and that thread's title, whether a later undo took it back, and for a widget gesture the words its ids had in the document it was made in, so a later version rewording or removing what was chosen leaves the row as made. The module reads it through `readHistory`.","x-withdrawn-as":"A declared 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 directly, whether or not it has retirable slots; historical ids do not veto the edit.","x-within":"The regions, each an element declaration, where a member may also stand at any depth rather than as an 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` stands where it is written, beside the item it changes, rather than in the rail.","x-name":"The attribute whose value is this tag's title: what the page calls one of these elements when it names it away from itself, as the activity feed does for where something happened. Leave it off where the authoring contract already titles the element: a section by its heading, a disclosure by its summary, a titled member by its leading <strong>. Declare it where an attribute is the title instead, as a column's or a tab's `label` is. An attribute the element merely shows first, such as a metric's value or a chronology entry's time, is not its title.","x-word":"The module supplies the widget's type label through `lfWord()`. For example, `lf-suggestion` returns \"insertion\", \"deletion\", or \"rewrite\" according to its children. Leaf uses this label when referring to the widget in a panel row or comment anchor. If the widget has not upgraded, returns no label, or does not declare x-word, Leaf calls an x-ask-context widget a question; otherwise it uses the tag name without its prefix. The same declaration lets the module supply descriptive text through `lfSays()`, for widgets whose text nodes alone do not convey their structure, such as a rewrite's old and new text. If no description is returned, 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 the widget holds no unsettled update, and the runtime shows the to-do beside the widget's authored markup. Only a block widget whose x-content is markup may declare it. Once opened, a to-do on a page widget shows at the page edge through its target's margin entry, even if a later layer drops x-work. Markup content does not imply x-work, because markup can itself be a control its owner uses, or sit in a hidden panel."},"$state":{"unit":"\"widget\" for a verb absolute across the group (choose toggles every sibling), or the detail field naming the element the verb is absolute per. Recorded positions use \"unit\"; custom commands name their own field.","creates":"An optional created-child contract `{child, words}` on an x-state verb. The verb's fold unit names the detail field carrying the new child's canonical element id, and `words` names the detail field carrying its non-empty prose; the detail holds exactly those two required fields and the verb declares no record form. While the action is in force, the sender has a direct `child` with that id and words, on the action's own owner-unit-verb coordinate: an action of another verb leaves it in force, and undoing or retracting the action removes it. Admission stamps the child tag in `meaning.creates`, so registry-free readers keep the action resting on its child before any markup holds it. The append door refuses an id the sending document already holds. Admission also captures the semantic state definition in meaning.state. A later incompatible definition does not reinterpret that historical action as current state.","record":"How the state reads in markup: {kind: \"attribute\", attr} \u2014 every element inside the unit carrying attr, sorted, vs the ids `detail.value` lists, which is why that field is an array however many the widget allows at once; {kind: \"position\", within} \u2014 the enclosing `within` element and the nearest unit both documents list before it there, with `detail.unit` naming the moved item, `detail.value` its destination and `detail.rank` its rank among its container's siblings: a base-36 fraction key, digits 0-9a-z not ending in 0, that sorts as a string, so a container lists its units by rank (ties by id) and a unit's placement stands whichever other moves stand or are undone. Authored units rank by authored index, and a widget computes a dropped unit's rank between its new neighbours' with `rankAt` from `runtime/widget-api.js`. A rank lies among the container's authored units on the revision the move was made on, which admission records as `meaning.among`. While a later revision authors that container the same way, the rank lands in the same gap and places the unit; a revision that authors it differently absorbs the move, writing the unit where the fold left it, which becomes its authored position, and its markup places the unit from then on. Later revisions may change that placement, and an absorbed move can no longer be undone; a new move changes where the unit stands. The append door refuses a move made on an older revision whose container the newest one authors differently. Equal ranks are a known limit: two tabs dropping into one gap tie, and the id order can put the later drop outside the gap it was dropped into. A position record's unit is always a part (a widget cannot place itself), because only the widget holding the container can read the neighbours a rank lies between; {kind: \"body\"} \u2014 the unit's own words; {kind: \"value\", attr} \u2014 the unit's own attr holding one scalar, whose `detail.value` carries the attribute's own schema so the log's contract and the markup's cannot drift. Within one tag and unit, body and position are each one physical slot; value slots are keyed by their host attr, and attribute-set slots by their descendant attr. Distinct verbs cannot claim the same slot. A node has one place across tags as well: the nearest recording widget above it places it. Recorded verbs declare no `detail` schema or input-field mappings: the effect defines a closed object requiring `value`, plus `unit` and `rank` for positions. An agent verb with `text: true` also requires a non-empty string `text`. The framework captures the typed initial value once, composes it with surviving winners and local gestures, and renders the resulting complete widget state. An absent value attribute starts at null, an attribute set at its authored ids, and a recordless verb at null (undecided). Position records compose ordered containers before rendering, so undo and refusal do not reset or rebuild the DOM."},"$report":{"answering":"Explicit, by typed id. `page stamp` puts a report target in the note's settles relation when the stamped revision absorbs its recorded state or marks its element overruled. Replay stops a settled report at that revision. An unchanged baseline settles nothing, so the report keeps painting. Changing authored content never requires a historical-state permission gate.","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 to the revision whose stamp does the overruling \u2014 stamping records the answer on the note, so later revisions leave it off.","feed":"Reports share one derived report feed in log-causal order. Every entry has a typed target (`widget` or `thread`), source (`report`), action, structured detail, optional declared text, speaker, timestamp, version, sequence, and one closed disposition: `effective` contributes to current state on its semantic coordinate, `outranked` still awaits settlement but a newer report on its coordinate takes precedence, and `settled` has been answered by a version note that names it. The work the agent has in hand is no report: it is the workflows' Working stage and the open to-dos' running start.","wakes":"A report joins the watcher's batch: `leaf wait` prints it beside user events, the same `ack` acknowledges it, and idling is refused over one nobody read. The user's banner counts none of this \u2014 a report is news the agent owes the page, not something the user owes an answer."},"$settlement":{"description":"The typed `settles` relation on a version note ends provisional agent facts. Each target is `{kind, id}` so independently allocated id namespaces cannot collide and adding a kind does not add another parallel note field. The relation is explicit and durable: chronology alone ends nothing, and a later note need not repeat a settlement.","report":"The id is a report event. Stamping derives these targets from reported state the source absorbs or explicitly overrules.","todo":"The id is an open to-do on a page widget. `page stamp --completes <widget>` writes this target for every open to-do on that widget opened before the stamped revision, which ends it `done` citing the version, and licenses the revision to remove the widget.","why-restated-is-separate":"`restated` is not a settlement. It retracts a user decision because authored words or state invalidated what the decision rested on, while `settles` completes provisional information supplied by the agent. Conflating them would make ending work look like taking back the user's action."},"$awaits":{"value":"The user-written x-state verb supplying the ask\u2019s typed answer independently of completion. A record verb supplies its recorded value; a custom verb supplies its complete current detail. Member-unit values form a map by unit id, and positions retain their container-to-ordered-unit mapping.","when":"The attribute condition that registers a local Leaf element as an ask: each attribute maps to the values that require an ask, a flag attribute's values being true and false. Every named condition must match. A group takes picks only with `choose` and stops requiring an ask once it is `settled`. An entry with no `when` is an ask on every Leaf element, which is what a pending suggestion is.","answered":"When a local ask is answered, as a map from each answering x-state verb to the condition its current state meets; the ask is answered while any one holds. `{}` holds while the verb's state stands: an attribute or value record that is not empty, read through authored markup as well as the fold so a version that honors the answer keeps it answered and a cleared value opens the ask again, and otherwise an action of the verb in force on the widget. `when` narrows a verb to instances whose attributes match, which is how a `multiple` group is answered by its Done press (`answer`) while a single-choice group is answered by its pick (`choose`). `empty: {within, when}` holds while the one member container of that tag and static authored attributes inside the widget holds no members under the positions in force, which is how a queue is answered once its designated column is empty; it needs a verb with a position record, and a verb folding on a part needs it. The action whose admission makes a condition hold is the answer, and admission marks it in meaning.answer (x-state). Naming the answering verbs keeps orthogonal actions, such as adding an option, from answering. A thread in the widget's own seat (x-thread-seat) is not an answer; it only takes the ask off the user's list while the next word there is the agent's.","all":"The outcome a blanket yes takes, where one banner control can answer every ask of this kind at once (`Accept all (3)`). It is one of the `outcome` values of the widget's deciding verb, which must be one of its answering verbs, and the widget's module exposes a method named for that verb taking the outcome, so the control records each decision separately rather than one blanket consent. Leave it off and the ask is answered where the user is, one at a time."},"$restated":{"description":"A boolean attribute saying this revision has rewritten words the user already decided on, so what they decided no longer applies and they are being asked again. It goes on the element the decision rests on \u2014 a lf-draft or lf-suggestion, or the lf-card or lf-option inside a board or group \u2014 and retracts every action that named it: a move names one card, so a rewritten card drops that card's moves, leaving the rest of the board arranged as the user left it; a pick names every option chosen at once, so a rewritten option takes back the whole answer it was part of.","why":"Decisions are recorded against the revision the user saw and survive ordinary edits. Change presentation and wording directly when needed. Use this attribute when the decision itself should no longer apply; the log records the retraction without erasing the original answer.","when":"When a revision invalidates a decision and needs a fresh answer, write the new content, mark the element the decision names, and explain the retraction in the stamp note. Revisions do not require this attribute merely to change decided wording or presentation. An unused or repeated marker is harmless.","once":"The marker belongs to the revision that retracts the decision. Stamping records the retraction; leave it off later revisions unless another decision is being withdrawn.","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 steps this layer paints a chart's series in, and how many of them there are. It is a property of the page rather than of any widget: the colours are --series-1 through --series-N in the theme, so a project that restates the palette with a step more says so once, here and beside the tokens, and every consumer reads the same number. `steps` is how many series a chart can colour apart, and what the palette's own check counts the tokens against. A chart with more series than steps folds the small ones together or splits, since two series in one colour is worse than either. The list is short on purpose: past five, the steps stop clearing the separation a user with colour-vision deficiency needs, and a sixth is a chart that lies to some users and to no others.","steps":5},"$reactions":{"description":"The reaction vocabulary: the one-press words a user can put on a passage, an element, a message in a thread, or the page whole, each recorded as a `comment` or `reply` carrying `token` in place of `text` ($events). The kernel declares the namespace and no word; the default package ships the working set, and any selected package reshapes it merge-patch style: an entry under a token's name replaces that token, a new name adds one, `null` removes one. Core never names or interprets a token. Everything a consumer needs rides the entry: `glyph` is the mark of at most four Unicode code points the page paints for it \u2014 including one emoji \u2014 in the margin, in the reaction list, and on a thread's strip; `settles`, where true, says a reaction of this kind in force on an agent message answers the question that message asks, and only that one, so the thread no longer waits on the user for it \u2014 a projection rule the server reads, never a second event. POST refuses a token outside the merged set, the way $languages gates a language name. Tokens stand independently on one target; reaction lists and their optional digit accelerators follow this declared order, so a digit survives any layer's renaming without changing a chip's label.","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 whole vocabulary an author may declare: what the lint refuses a word outside, and what the theme has a rule for. It is a property of the page rather than of any widget, which is why it lives here and not under the schema of whichever tag happens to take a `tone` \u2014 a widget declares that one of its attributes names one (x-tone) and the lint reads the list from here, so a second tag taking a tone costs a declaration and no new reader. The list is short on purpose: a page that can paint anything paints nothing, and three is what the palette already answers for. Which facts earn a tint is never the theme's to decide \u2014 `ok` on one page's chip and `danger` on another's may be the same word, because the author is the only one who knows whether the answer is good news.","names":["ok","warn","danger"]},"button.button":{"description":"A page-local action button. The button class supplies the layer's control typography, frame, hover and focus treatment. A toggle states its selection with aria-pressed; true draws the selected face. These classes supply presentation; the page module owns the action and state.","x-example":"<button type=\"button\" class=\"button\" aria-pressed=\"true\">Anchored threads</button>"},"select.field, input.field":{"description":"A labeled page-local select or single-line text field, using the same typography, frame and height as the layer's buttons. Use the existing control face rather than rebuilding it in page CSS; page CSS 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 \u2014 a tinted field with a hairline border. For something the user must not miss; a note they lose nothing by skipping goes in the margin (aside.sidenote). Add `ok`, `warn` or `danger` when the callout reports a status, as `class=\"callout warn\"` for a paused release; its tint and title take the tone and its prose stays in the body's ink. In a flow wider than the column, such as a sidebar page's body, it keeps the prose's width; one holding a chart or table that needs more takes `data-width`.","x-space":"column","x-example":"<aside class=\"callout\" id=\"rollback-note\">Rollback is one flag flip; the backfill is idempotent.</aside>"},"section.panel":{"description":"One titled region of a sidebar page (`<main class=\"layout-sidebar\">`): a card holding one surface, such as a table, a log or a list of steps, with a short heading that names it. Lay a dashboard out as panels in the Layout's tracks so every region is drawn alike; the page's argument stays 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: local navigation, a compact legend, or stable reference facts that remain useful while the user moves through a long page. Use one, as a direct child of main near the page's opening, rather than beside the one paragraph it concerns; that local annotation is an aside.sidenote. On a roomy live screen the first such child of a column page sits left of the prose and sticks beneath Leaf's banner, the column moving right to make the room; with a fine pointer, a contents map (an element declaring `x-resident: map`, such as lf-toc) can use that margin as a fixed reading map instead. Where the window has no room for the strip beside the column and its rail, and on paper, the sidebar returns to ordinary flow where it was authored. An accidental second sidebar also stays in flow instead of occupying the first. Keep the contents compact enough to scan in about 240px. The wrapper supplies placement, not a visual panel, so what it holds keeps its own voice; an lf-toc is the usual navigation occupant, but the idiom reads the declaration, not that widget. Its content remains part of the page and may be selected or commented on unless the occupant itself declares apparatus.","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: a caveat, a provenance, a figure the sentence had no room for. It is read where it stands and skipped at no cost, where a .callout sits in the column the user is reading down and a <details> asks for a click. Write it immediately before the paragraph, list or block it annotates, and it comes out level with that block's first line; before a heading it sits above the heading instead, a heading carrying more room over it than the block before it leaves. A second note written soon after the first stacks under it, so a long note pushes the next one down the margin and away from its own block. It reaches the margin through any box that doesn't clip \u2014 a section, a tab panel, a disclosure; written inside one that does, a choose group or a board or a table, it is drawn nowhere at all, and `page check --render` refuses the version rather than letting it ship. It stands there where the window holds the strip beside the column, and beside a sidebar, which takes the margin first; the column moves left to make the room. Elsewhere, and on paper, it is a small indented block where it was written, so nothing it says rests on the margin being there. These are the page's own words, so the user can select, quote and comment on one. A stable id lets Alt-click point at the whole note. The margin holds about fifty-six characters to the line; a note running past a few lines wants to be a paragraph in the column instead.","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 label/value grid for summary facts, as a definition list. Inside a card that stands for one alternative in a group, it docks right as a fixed-width rail instead, aligning each item's scalars down the group.","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 drawing the page makes itself \u2014 a layout, a mechanism, alternatives compared in one frame \u2014 as inline SVG inside a `<figure>`, with `role=\"img\"` and a `<title>` stating its claim. Its marks take classes whose paint is theme tokens, so the drawing follows the light and dark palettes: `.frame` and `.frame-head` for a window or pane and its header, `.line` (`.soft`) for a line of text, `.box` (`.hot` for the one that matters), `.highlight`, `.ghost` for where something would be, `.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, `.ok`, `.warn` and `.danger` fills, and `.strong`, `.small` and `.mono` for text, which is muted otherwise. Without a `width` it fills its figure; give a thumbnail one. A mark particular to the subject takes a page-local class on 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: ceilings per plan, runs per configuration. Columns take the width of what they hold, and a table wider than the measure wraps its cells or, failing that, scrolls inside itself \u2014 so nothing in one needs a width. An identifier \u2014 a test name, a path \u2014 is one word to the line breaker: in `<code>` it breaks inside its cell where it must, so a column of them takes a share of the measure beside the prose; bare, it holds its column to its own width and squeezes the rest to a word a line, and `page check --render` advises on a table that scrolls sideways with a cell in it wrapped at any width from a 360px phone to a wide desktop. `<th scope=\"row\">` names a row in the page's own voice; a bare `<th>` is a column heading, set in small caps as one. A `<caption>` above the rows says what the columns mean where the section's heading doesn't. Reach for a KPI widget when the numbers are a handful of headline figures rather than a grid, and a decision widget when the rows are alternatives the user picks between.","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 cell holding a quantity, right-aligned so a column of them lines up on its last digit \u2014 the comparison a column of figures is there for. Say it on the column's heading cell too, or the heading hangs left of its own figures. Nothing is guessed from the text: \"60\" and \"60 sessions\" are the same shape and different things.","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: a command to run, a config file, a snippet of output. Name the language to color it \u2014 one of $languages, the same list a widget's own language attribute is held to; a language outside it stays uncolored. Leave the class off where the body isn't source; nothing is guessed from the text. Reach for an annotated code block instead when the block is a walkthrough: numbered lines, highlighted ranges, remarks anchored at a line.","x-example":"<pre><code class=\"language-bash\">leaf page check ~/.local/state/leaf/pages/auth-diagnosis --render</code></pre>"},"lf-ask":{"description":"Prompt context and an arrival region shared by the independent asks nested within.","x-space":"column","x-instructions":"Begin with a direct heading that names the shared question or context without relying on surrounding prose. Include the evidence needed to answer. Each nested widget declaring x-awaits registers its own ask and keeps its source identity and answer. Keep an ordinary semantic section around the context 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 scalar embedded in prose, tied to the snapshot that established it.","x-instructions":"Write the displayed value with its unit as the element text. Bind source to the repeatable measurement feed and use the run receipt returned by leaf data set. Use via when the source id alone leaves the command or query unclear.","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 file-backed text document with optional syntax coloring and rendered Markdown or HTML previews.","x-instructions":"Bind source to the page-owned feed. Use label to name the file. Set preview to markdown or html for Preview and Source tabs over the same text; language optionally overrides the source syntax. HTML is a separate document: its provider owns typography, spacing, and responsive CSS; it inherits no Leaf styles. Both readings share a scrollable viewport sized by --lf-bound (28rem by default). Compose ordinary lf-tabs for other kinds of preview. Put it inside details when it should begin collapsed.","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":"Set max-level when deeper headings are local detail rather than navigation destinations; omit it to include h2\u2013h6. Use stable authored section, title-group, or heading ids for links that must keep their target across versions; generated heading ids are not addresses for comments or page state. Write the element empty with a stable id.","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-space":"column","x-instructions":"Keep shared premises and evidence with the group; lf-ask can frame its question and context. Keep each alternative's case and decision-relevant evidence inside its lf-option; an accept-or-reject proposal's figure of today beside the change compares both answers, so it stays with the group. Use multiple when the selections form one answer because they depend on each other, such as a limit on how many; leave it off for mutually exclusive alternatives. Items each answerable on its own are separate asks (references/authoring-asks.md). The built-in Another option field accepts unlisted answers, so author the alternatives you mean without a catch-all option. Use for only to select sections or work items that exist independently of the decision; do not create sections solely to hold alternatives. A user-added option stays in the group from the log, where the user put it; leave it out of revisions. A multiple-choice ask still needs the user's Done even when chosen is authored. Use settled to collapse a retired decision while preserving 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":{"choose":["id"],"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":"Lead a card with matching small.tag comparison labels naming the facts that distinguish the alternatives, then a `<strong>` title and a sentence naming its consequence. Mark the option you recommend with `<small class=\"tag ok\">recommended</small>` after its comparison labels, and give the reason in prose. chosen records the user's pick. Under them, show what choosing it gives the user (references/authoring-asks.md): where alternatives 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 how something behaves, that behavior working inside each option; where they differ in wording, the words as they would appear. Add paragraphs or a fact rail when the face alone cannot support the choice. A bare label suits an alternative needing no further case. Direct text uses inline Markdown; use HTML children for block content. A for target must remain useful independently of the decision and does not supply the option's words. Rewriting a picked option needs restated; read $restated for when to rewrite instead of correcting beside the ask.","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":"Write a JavaScript expression for Plot.plot's options inside pre, HTML-escaping & before < and >; give the options object rather than calling Plot.plot. Plot and width are the only names in scope, and data stays inline. Use ISO date strings on an explicitly typed time scale; use utc for days and months, and include a timezone on moments, such as 2026-06-01T14:00Z. Supply ariaLabel describing the chart for users who cannot see it. Leave width and height out of the options: use width to adapt ticks, and data-height on the element for a nondefault height. Where page check --render reports overlapping labels, reduce category ticks, choose them by width, or reserve more margin for the axis label. Use var(--series-N) for constant or categorical colors; continuous color scales need a Plot scheme because CSS variables cannot be interpolated. Name the chart in the surrounding heading or prose rather than Plot's title. Label each value the page's argument cites on the chart itself, such as the spikes its prose explains, for example with a text mark beside the point, so the reader sees the evidence without opening a table.","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 screenshot pair with an operable divider, optional change outlines and changed-pixel view, and component-owned comparison, overlay, scaling and focus-crop presentation.","x-instructions":"Use for two versions of an interface, current and proposed. Use served image paths printed by leaf page media for before and after, and describe the pair in alt. Read authoring-evidence.md, Source files and media, for captures, the table that sets captures varying along other axes, and when to use outlines or pixels. Write explanations in surrounding prose rather than element content. When a decision turns on the change, put the pair inside the proposing option, or with the group of an accept-or-reject ask, where it compares 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 primarily to display grouped work and status. Prefer explicit controls or lf-options when the user needs to make changes or decisions; the board is not the primary interaction surface. When revising, keep each moved card in the column the user chose unless the revision explicitly retracts that decision with restated on the card. Read authoring-revisions.md, Honor user state. A rewrite that invalidates a move restates the card, not the board.","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 of one artifact, as page navigation, a local tabbed section, or a side-list queue.","x-instructions":"Place the first set directly in main for page navigation; other placements make a framed local tabbed section. Put the shared title and lede before page tabs and the primary current view first. Each lf-tab is a self-contained view, while history, Threads, the On panel, versions, and sign-off belong to the whole page. Retire obsolete views once current work no longer depends on them, preserving needed context and passages anchoring open threads or decisions in force in details within the relevant tab. Use list=\"side\" for a queue beside its selected item; it remains framed and its list does not stick.","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 asks a region still holds open, such as a queue's decisions left to make, with an optional control to the next one.","x-instructions":"Name the region whose asks it counts with for, such as a side-list lf-tabs queue, and 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 region's asks waiting on the user. Write it empty with a stable id; it counts asks the page already poses, so state no count of them in prose or chips.","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":"A side-list queue shows summary under each label, so the user can choose an item without opening it. Start it with what the item is about in a few words, such as the problem a ticket reports, unless the label already says so, then add what sets the item apart from its neighbours, such as its age or suggested outcome. Leave out the item's group, which its heading already shows. Where a queue's 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 the user should take them; neighbouring tabs with the same group stand under one heading. Keep ids distinct across tabs: they share the page's one 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-space":"column","x-instructions":"Write exact Markdown source as <pre> followed by one newline, the HTML-escaped source, and </pre> immediately after the source. HTML consumes that first newline; every subsequent character, including indentation and trailing newlines, belongs to the draft. HTML-escape & before < and >. Use a suggestion for an agent-proposed change to existing prose. A draft asks for an edit when needed is present; otherwise it is an optional editing surface. Use lf-ask when that request needs its own heading and supporting evidence, or page sign-off to approve the whole page. Preserve the user\u2019s exact source on revision; read authoring-revisions.md, Honor user state. To replace an edited passage deliberately, write the new text and mark the draft restated; read $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 page-authoring.md, Live samples, 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 explaining its relationships for a reader who cannot see it. Draw a chain of more than three steps top-down (flowchart TD), since a long horizontal chain scrolls past the page edge. Use Mermaid classes and page CSS with theme tokens where a node needs a distinct tone. Omit parts for one whole-diagram comment target. Set parts=\"all\" to make every named flowchart node/subgraph, state/composite state, sequence participant, class/namespace, and ER entity a comment target. Edges, sequence messages, and chart marks have no stable source id.","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":"Add collapsed when every file should start closed. Bind source to a page-owned patch feed or files manifest; the bound form keeps an empty pre. With no source, write the exact Git patch in pre at column 0. Keep native file headers and metadata; text hunks need @@ counts matching their lines. Preserve context-line leading spaces; encode a space-only context line as &#32; so HTML parsing keeps it. HTML-escape an inline patch, & before < and >, or entity text in the source will change silently.","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 unified call-tree diff with links to its exact patch evidence.","x-instructions":"Point diff at the lf-diff holding the exact patch. Supply authentic CallDiff plain-text output as the source\u2019s string value:\n\n```bash\njq -Rs . calldiff.txt | leaf data set \"$PAGE\" <source-id>\n```\n\nKeep unchanged tree items as stable comparison landmarks. Prefer one focused file or entry point per widget for a large repository. Do not transcribe the output into markup, invent attribute reads as calls, or redraw 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":"An interactive playground for exploring one configuration in an operable preview and choosing it.","x-instructions":"Use lf-ask to frame the configuration question and context when they live outside the playground. A page module can add structured values with registerContributor(name, defaultSnapshot, {read, apply}); call the returned notifier after its gestures. Use one optional registerInstructionProvider(values => text) for prose derived from structured or conditional values. Give the page's complete lf-playground declaration an exact action schema for its task-specific 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 its control. Author its initial value as a string: a finite number for range, true or false for toggle, one child value for choice, a six-digit hex colour for color, or arbitrary text for text. Range controls need max; min, step, and unit are optional. Only choice controls contain lf-playground-choice children. A control that changes the whole preview, as most do, is a direct child of lf-playground and stands in its rail. Where the preview holds several items that each take their own settings, write each item's controls inside lf-playground-preview beside that item; they stand where they are 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 operable artifact inside a playground.","x-instructions":"For an A/B comparison, mount both candidates here and read the playground package's author instructions for driving them from one state. Page CSS can bind the playground's reflected values. A page module can consume its public values and change event, own gestures and computed state, and load vendored or page-media assets from the page's origin.","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-content":"empty","x-inline":true,"x-upgrade":false},"lf-visual-review":{"description":"A guided review of a typed visual run, with before-and-after evidence and recorded case dispositions.","x-instructions":"Author an empty element with a stable id and bind source to the visual run. Supply focus rectangles when a case should open on its changed area; keep case identities tied to the run rather than the user's temporary 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 to an imported playwright-trace source. Introduce what the recording shows and make the results under review directly reachable with named lf-trace-bookmark members, preferably successful expectations\u2019 After checkpoints; use imported ids and labels naming the result. The viewer supplies its controls. It opens at the earliest resolvable authored moment in the first stream holding one, otherwise the first saved tree, then the first image. Its timeline places calls and inputs as bars spanning their recorded calls; native input carries no timestamp or held duration, so describe input timing at call resolution. Its chronology includes action checkpoints and intermediate frames at native times, with page filters for multi-page recordings and separate clocks for streams. Matching elapsed times across recordings do not establish matching states. Image comments pin the actual image; saved-element comments pin the labeled checkpoint and tree path. These captures can have different times. A first-image preview before its capture time is explicitly labeled. Keep the linked Playwright viewer running for DOM snapshots, element picking, source, console and network inspection. To pair named results across recordings, put the viewers in one lf-trace-compare and give their corresponding bookmarks the same key. Choosing a keyed moment selects each recording\u2019s own target; manual seeking keeps independent positions.","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":"An authored, labeled jump to an exact captured image or action phase in its trace.","x-instructions":"Set target to an existing trace visual coordinate: trace-ARCHIVE_SHA256-image-IMAGE_ID or trace-ARCHIVE_SHA256-phase-ACTION_ID-PHASE. Read those ids from the imported source; phase is before, action, after, start or end. The widget derives elapsed time from the capture. A target absent from the recording is shown as unavailable. A key explicitly pairs this semantic result with bookmarks in the owner\u2019s compare group; elapsed times and label text are never used to infer correspondence.","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":"One shared inspection workspace for recordings with explicitly paired named results.","x-instructions":"Put independent lf-trace viewers inside this container, each with a label naming the recording. Give corresponding lf-trace-bookmark members the same key. Selecting a keyed result chooses each recording\u2019s own captured target; switching the Recording chooser retains the shared inspection position and each image view. Manual seeking remains independent.","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,"idiom":true},"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":"2a483b8a572f2e0046529097f9349ccf","fingerprint":"sha256:da76c66fdee83f75febaa6a8449d1b38ce226abb80186e1d22062cc59de5d7dd","server":"sha256:0e5046aad618dd3ef22cc4ba1b585add9e74ff4059192e3f7f4abd5ae61e1dcc","packages":["code-review","diagram","diff","playground","monitoring","visual-review","playwright","./docs/package"],"producer":{"commit":"6fd22dbd16cc","committed":"2026-10-14T08:24:34Z","dirty":false}}}