Using a page
Using a Leaf page
An agent hands the user a page about its work. The user reads it, comments on exact passages, makes the choices it asks for, and follows what the agent is doing, by keyboard, pointer or touch.
This guide is for the person working on a page. Pages is for the page's author, and How it works explains the mechanism behind both. Leaf is experimental software. Browser support gaps lists what is known to differ in Chrome, Edge, Firefox and Safari and their mobile versions.
In this topic
Panel, rail and thread cards
Leaf adds controls around the authored HTML. This interface is called chrome: the Leaf panel floating at the window's foot, comment and decision markers, and thread cards. At rest the panel is one row: the leaf, coloured by the agent's state; the comment field, which shows the agent's status while it is empty; and the On Me mark, counting what waits on the user, with a dot while a thread holds a reply they haven't read. The leaf opens a small menu of the page's other controls. Pressing the On Me mark opens its view above the row. A ✕ replaces the mark while the view is open and closes it when pressed. A folded panel shows only the leaf in the window's corner.
The On view shows one list at a time, under a tab named for its actor, with completed items under Done, and a Threads tab listing the open threads under Open, then the resolved ones under Resolved. On Me and the agent’s list defines their membership. Opening a view preserves the page’s text wrapping and reading position.
The page reserves space at the bottom for the panel's row, so the last lines can scroll above it. A view opens above the row and overlays the page without moving its content. Escape or a press on the page closes the view. Phones and touch screens describes the panel on a touch screen.
The rail is the strip to the right of main where
Leaf places comment and decision markers. It appears when the window has
enough space: about 960px on a column page or about 1920px on a sidebar
page. data-rail="right" keeps it visible above 640px, except
on a workspace, whose panes scroll on their own. Where no rail fits, and
inside a scrolling pane, a small pin appears beside the target on the
page. Leaf places it clear of text and controls when space permits. The
o shortcut hides pins and passage highlights.
A thread card opens beside its marker in the margin. If the margin is narrower than the card, it overlaps the text's edge. Threads, a thread opened from it, the On view and All pages open as views above the panel's row, one at a time.
Who can open a page
A page's URL carries an access key, which the browser keeps in a cookie. One key covers every Leaf page on the machine that serves it, so anyone with one page's URL and a network route to that machine can read and act on all of them. A page served on loopback opens only on that machine; one served on an SSH destination or another hostname opens from that network. Leaf opens no public tunnel.
On leaf.page, each browser works on a private copy of a page. Its comments, choices and the hosted agent's revisions are visible to no other browser (The leaf.page website).
Data lifetime
Accepted events and external data survive closing a tab or restarting the server. Browser stores preserve drafts and interface arrangements with the scopes shown below. An update the server has not yet accepted has not reached durable storage; while the status says the connection is lost or the update is not through yet, keep its tab open until it is.
| What | Reload | Close the tab | Server restarts | Another browser |
|---|---|---|---|---|
| Picks, drags, and comments accepted into the log | ✓ | ✓ | ✓ | ✓ |
| External values, until the next write replaces them | ✓ | ✓ | ✓ | ✓ |
| Words the user has typed and not sent | ✓ | ✓ | ✓ | ✗ |
| Arrangements of Leaf controls | ✓ | ✓ | ✓ | ✗ |
| Reading position, the open tab or panel, design mode | ✓ | ✗ | ✓ | ✗ |
Draft text is shared between tabs showing the same page; arranged controls are shared across pages in that browser. Reading position, the active tab or panel, and design mode belong to one browser tab. Comment text awaiting acceptance remains in the draft store; pending widget actions have no durable browser queue.
Offline exports
leaf page export PAGE -o FILE captures a stamped version, its
resources and the decisions recorded on its widgets in one HTML file. The
file holds none of the conversation with the agent, on screen or in its
source: no threads or their attachments, to-dos, plan or changelogs.
Reading controls and page-owned code work offline; new Leaf choices,
comments and Undo need the served page. An agent need not be running to
record a choice on a live server. Pages containing live samples cannot
export.
In this topic
Try a thread
This fictional exchange shows an agent's reply after revising the importer policy. Open the marker beside the sentence to read the exchange, or open Threads in the sample's top row. Select the sentence to try a comment. The sample has its own temporary log; no agent answers its practice comments. Reset restores the fictional exchange.
Importer queue policy
When the queue is full, the importer discards the oldest queued job and admits the new one.
Anchors
A thread's anchor is the place on the page it is about. The first comment records it in the event log, and that record never changes; a reply or a revision can later move the thread to a new anchor. A comment can be anchored in these ways:
| Anchor | How the user makes it | What the log stores |
|---|---|---|
| Passage | Select words, then press c |
section, the id of the nearest element around the
words; quote, the words; and prefix and
suffix, up to 24 characters on each side
|
| Element | ⌥-click (Alt-click) an element, such as an image or a table, or press s and choose one | section alone |
| Part of a picture | ⌥-click a box that a diagram declares commentable | section and visual, the part's name |
| Data value | Select words inside one value a widget drew from a data source |
section and datum, the value's key, and
for a value from an external source, that source's revision
|
| Drawing | Draw on the page in Draw mode (w) | An element anchor, plus the strokes |
| None | Press c with nothing selected, or write in the Threads panel's comment box | No anchor: the thread is about the whole page |
An agent opens threads with the same anchors, using
leaf thread create with --quote,
--section, --part, or none of them.
How a thread ends
The user usually closes a thread with Resolve thread once they have read the answer. Its marker and ink leave the page, and it moves from Threads' Open list to Resolved. Reopen brings it back, as does z when resolving was the user's latest action.
The agent resolves a thread only when the user asks, or when no review could change the outcome; the thread then reads “Resolved by” and the agent's name. A new message from either side reopens a resolved thread. A reaction, a progress message or a failure notice does not.
z takes back the user's latest action, a message they just sent
included: a comment, reply or reaction. A reaction's mark also has an undo
control of its own. The log gains an undo naming the message,
and the message leaves the page, with any thread it started. Where
something has already answered it, it stays in its place instead and reads
Deleted. To delete an older message, the user rewrites it to no words.
Words typed but not sent are kept after their box closes. If a new version removes the content they were about, Resume writing (g i) opens them, unsent, in Comment on the page, after any words already there.
In this topic
Progress on an update and the page
Leaf distinguishes progress on one update from the page’s status. A busy agent has not necessarily started every comment. The agent names the update or to-do it is handling and the work it is doing, in one line. That line appears beside the relevant thread or widget and in the panel; replies carry the results.
A session is the agent conversation attached to the page; a turn is one run within it. A watcher receives updates between turns. The illustrative sequence below follows a request to shorten a lede; its times are examples, not delivery guarantees.
- observation Queued for Claude The comment appears in its thread immediately, reading Queued for Claude until the agent has it.
- observation Delivered The hook puts the comment into the agent’s turn, and Claude Code's transcript then confirms it reached the agent. Until the agent names its work, the panel shows its leaf in the working tone and no words.
- intervention On it The agent says what it is doing: Cutting the lede to two sentences. The comment reads On it, and the same sentence becomes the page’s status.
- intervention Each new phase gets a new line When the work moves from editing to checking, the agent starts the same update again: checking the page at phone width.
- observation Answered The revision goes live, the agent's reply reports it, and the status returns to Ready — select text to comment.
Stages of an update
A label beside each comment or widget update records its delivery and handling. Leaf changes it only on recorded evidence and clears it when the required answer arrives. Harnesses skip stages they do not report. Only On it, Replying and Answered relay an act of the agent's own, so only they read in its voice; every other label is what Leaf observed of the update, set in italic.
| Label | Evidence |
|---|---|
| Queued for Claude | No harness has queued the update or put it into the agent's turn. The label is the same while the browser is still sending it and once the server has added it to the page's event log. It names the page's agent and is set in italic, as Leaf's own words are, since the agent can't yet be saying anything about the update. |
| Up next | Codex accepted the update's delivery as the task's next message. |
| Delivered | The agent's harness put the update into the agent's turn. What confirms that differs by harness (Harness connections and receipt); Claude Code can deliver an update again if the turn ends before its transcript shows it. |
| On it |
The agent started work on the update and named the work in one line,
as a progress message in its thread or with
leaf task start, or started a to-do on the update's
widget.
|
| Replying | On Codex App Server, the turn's answer is streaming into the thread. |
| Answered (label clears) | The answer the update needs is recorded: a reply in its thread, or a version whose markup records the decision. |
| Delayed, interrupted, or unanswered | |
| Still queued for Claude | The update is still queued two minutes after the user sent it. |
| Stopped | The turn the update was delivered into ended, or was interrupted, before the agent answered it. |
| Gone quiet | The agent's start on the update is 15 minutes old, or the turn that wrote it has ended with no background work Claude Code reports still running, and the agent has not started the update again since. A Delivered update reads the same once nothing shows its turn still running (no status, start, or step for 15 minutes), or once the agent is in a later turn. On Codex App Server, so does a Replying update whose stream disconnects. |
| Interrupted | Codex App Server stopped the turn before it answered. |
| Not answered | The harness gave up on the update: its turn failed, or Leaf could not confirm that the delivery reached a turn. The leaf.page website and the Codex adapter record this. |
A comment needs a thread reply; a page-widget obligation needs a version recording its answer. Resolving a thread, editing a draft, or moving a card requires no answer, but the agent still receives the event. A draft edit or card move’s label clears when a version records or replaces it; inside a thread message, it clears when the agent next writes there or the thread resolves. A choice with a Done button gets no label until Done submits it.
Thread readings
A thread appears in several places at once: its card in Threads, its entry in the margin, its row in the Page Map, its row in On Me, and its line in an activity feed. Each place says the same thing about it, so a thread never goes by two names or shows two statuses.
| What it says | Where it shows |
|---|---|
| Its name: the title, else the words of its opening message, else Drawing | Threads, On Me, the margin, the Page Map, an activity feed |
| Its status: Your turn, On it, Still to do, Waiting, or how far the agent has got with the latest update | Threads and the floating panel, as the card's status; the margin and the Page Map, beside its name |
| How far the agent has got with an update: Queued for Claude, Up next, Replying, Not answered | the message itself; the margin and Page Map entries |
| How many of the agent's messages the user has not read | Threads, the margin, the Page Map |
| An unsent reply or rewrite | its box, wherever the thread is open |
On Me and the agent’s list
The On view gathers outstanding work across the page, using the obligations, to-dos and workflows defined in How it works. A status sentence alone creates no obligation.
| List | What belongs there |
|---|---|
| On Me |
Open obligations: each widget that asks, on the page or in a thread
message; each agent message sent with --obligation; and
each update the user needs to send again.
|
| On Claude (or the attached agent’s name) | Updates still owed a reply or a stamped revision, and open agent to-dos. |
| Done | Each list’s finished records: answered or withdrawn obligations and ended to-dos. User decisions appear under On Me; answered conversations under the agent’s list. A decision recorded in a revision finishes the widget’s record, without a duplicate update in Done. |
On the page, an item On Me is answered only in the widget or thread that
asks it, and Leaf adds no control of its own to end one. A widget’s
obligation is answered by the actions its
x-awaits declaration names, such as a pick, or the Done a
multi-select choice offers as its own control. A question in a thread is
answered by the user’s reply there or a settling reaction, such as 👍. The
agent ends its to-dos with leaf task end, and records the
same way an answer the user gave elsewhere, such as in chat. Done history
records the outcome, including withdrawn obligations and failed or dropped
to-dos.
A thread’s attention identifies which side it awaits, using its updates, questions, and to-dos. The page-wide lists collect that work across threads and widgets. While a thread about a decision awaits the agent, its unanswered update represents the work on the agent’s list; the decision returns to On Me when it needs the user again.
What the panel's line says
The panel's comment field, while empty, is Leaf's one line of words about the page. It says one thing at a time, the first of these that applies:
| Reading | Example |
|---|---|
| An error about no particular box, until the user next types | Couldn't load v3 |
| Where words go, while the caret is in the field | Comment on the page, Reply in this thread |
| Words selected on the page, which a press on the field or c comments on | “the queue fills” |
| A notice, or a walk's position while the user stays on its stop | Updated to v4, Thread 2 of 5 |
| The mode the user is in, which the ✕ at the row's end leaves | In Draw mode |
| The page's status | running the browser suite |
With a thread open, the field is that thread's reply box. It says whose turn it is beside the leaf, such as Your turn, and Reply with the key that enters it at the line's end; a notice takes their place for its four seconds, and a walk's position follows whose turn it is.
A middle dot joins separate facts, as in In Draw mode · Thread 2 of 5, and a dash attaches a detail to the fact before it. Only words the agent wrote, such as the line it gave its work, read in its voice; what Leaf says itself, such as Stopped 3m ago, is set in italic. Words the user is writing hide the line, while screen readers still hear notices and changes of status. A press the line offers, Reply or the selected words, reads in full ink with the key that makes it, and everything else reads dimmer. The leaf and the tab's icon keep the status's colour throughout, and the leaf's menu holds the status's full sentence. A folded panel shows notices beside the leaf.
Status readings
The server combines the agent’s latest start or status with observed
session, turn, and watcher activity. Browser tabs and
leaf page state read that same result. All pages uses each
serving page’s published activity summary.
- The turn. The harness integration records when a turn starts and ends. Leaf treats it as active while its opening, a start, a status declaration, or a reported step is less than 15 minutes old. Claude Code also reports the session's activity directly, including permission dialogs and interrupted turns. An interruption can therefore mark the turn ended as soon as the user presses Escape.
-
The watcher. Claude Code's watch hook,
leaf wait, or Codex's adapter registers with Leaf while watching for updates. Leaf treats the agent as available for updates while a watcher runs. A running Claude Code turn can also receive updates through its hooks. With no watcher after a turn ends, Leaf messages a Claude Code session when the next update arrives, so the agent is available too where that message starts a turn: a background job whose worker has retired is resumed with it, and a running session takes it at once where Claude Code'scrossSessionInboundsetting isaccept. - The start. A start stops counting as active once it is 15 minutes old, or once the turn that wrote it is seen to end, unless Claude Code reports the session still busy with background work, such as subagents it started.
flowchart TD accTitle: Activity status by first matching condition accDescr: Test each rule from top to bottom and stop at the first match. Otherwise continue to the next rule. An idle page is done, a stopped owner is not on this page, active work is working, stale input is stopped or last checked in, available input is awaits, stalled input needs a terminal nudge, otherwise the agent is away. Idle["Page idle<br/>Status: Done with this page"] -->|otherwise| Owner["Owner stopped<br/>Status: Not on this page right now"] Owner -->|otherwise| Work["Work active<br/>Status: Working"] Work -->|otherwise| Stale["Takes input, start stale<br/>Status: Stopped /<br/>Last checked in"] Stale -->|otherwise| Input["Takes input<br/>Status: Awaits"] Input -->|otherwise| Stalled["Input stalled<br/>Nudge in the terminal"] Stalled -->|otherwise| Away["Status: Away"]
Leaf shows work as active when a start is still current, when the harness reports a step in an active turn, or when that turn has received input requiring an answer. The freshness rules above determine when a start or turn stops counting as active. Input is stalled if it remains queued for two minutes, or if the turn that received it ends without answering. The status doesn't date the agent's line: its hooks remind it to restate a line that has stood two minutes, and the menu's full status says when the line was written.
| Status | What Leaf knows |
|---|---|
| The leaf alone, in the working tone | The agent is working, or the user's update was delivered into its running turn, and the agent has not yet said what it is doing. The update's own label says Delivered. |
| Approval needed in the terminal | A wait for the user, for input, or for approval is a dialog in the harness's own window, so the status says to answer it in the terminal, ahead of the agent's line. A step the harness reports, such as Thinking or Using a tool, shows in the menu's full status. |
| Ready — select text to comment | The agent is taking input. An update still on its way to the agent says so on its own label, and the menu's full status counts it. |
| Stopped 3m ago | The turn that wrote a start has ended without a new start. The integration is still available for updates. Pointing at the status shows the start's line. |
| Last checked in 20m ago | The agent has not renewed its start for 15 minutes. The integration is still available to receive updates. |
| Away | No integration is currently receiving updates. Comments remain saved for the next agent turn. The message Leaf sends a Claude Code session as a comment arrives may wait there behind a prompt to accept it. |
| Not answering — nudge the terminal | No integration is receiving updates, and an update has stalled. Sending a message in the agent's terminal starts another turn. |
| Not on this page right now | The session attached to the page has exited. Another session can resume the page by starting its server. |
| Done with this page | The agent wrote leaf page close …. |
Notices
A notice stands in the panel's line for four seconds and is announced to screen readers. Simultaneous news shares one notice, such as Not answered · New On Me. Some news is only announced, since something on the page already shows it: an agent message the user hasn't read, which the On Me mark's dot and its margin marker show, and the user's own gesture, which the widget draws where it was made. Opening a page announces only unread agent messages, not its existing activity. The agent starting or stopping work is no notice: the status in the same line says it.
| Notice | When |
|---|---|
| I shortened the lede., Edited: …, 3 replies in 2 threads | Announced only: an agent message the user hasn't read arrives, or one is edited. One message speaks for itself in its opening words, including anything it asks of the user. |
| New On Me, 2 new On Me | Something new waits on the user, such as a question a reply asks or a decision a revision adds. |
| Not answered, Interrupted mid-answer | The harness reports that a response failed or was interrupted. |
| Updated to v4 | A new revision replaces the page in place. |
| Moved to Done, Undid: Moved to Done | The log accepted the user's gesture, which is announced only, or its undo. |
In this topic
Phones and touch screens
Touch users can read, comment and operate widgets. Leaf’s page commands have direct gestures or visible controls; authored widgets supply their own routes. Narrow windows describes how page regions stack.
The panel and its menu
The panel fits a narrow window with space at its edges. Its row holds the leaf, a comment field showing agent status, and the On Me count beside its icon. A temporary notice replaces the status words.
Comments, threads and widgets
Select words to quote them in the panel’s field; tap the field to open a comment below the block. For a whole table, figure or other element, use Select mode.
Where the margin cannot hold a rail, markers appear as pins on their blocks. Tapping a pin highlights its passage and opens its thread card. Threads opens above the panel’s row. Hide annotations hides the pins.
On a touch screen, a board at most 640px wide shows a Move to row on each card, reaching offscreen columns without dragging.
Touch coverage and testing
- Whole elements. Open the leaf’s menu → Annotations → Select mode, then tap the target. This opens its comment composer without activating the target’s controls.
- Commands. Menu commands and direct controls provide touch routes; the panel and reply fields suppress keyboard hints for a coarse pointer.
- Exits. The panel’s ✕ leaves an active mode, search or target picker. Within the picker it first removes a typed hint prefix.
- Hover detail. Authored hover explanations need a touch-accessible alternative; keyboard and hover behavior alone do not establish a touch route.
- Layout. Page-authored controls and diagrams still need review at narrow widths for target size, legibility and reachable content.
- Device coverage. Automated touch journeys use browser emulation; they do not establish real-device behavior.
Comments and replies
Select a passage, then use the comment control or press c to write a comment. The thread keeps that passage as its anchor. Its marker opens the conversation beside the passage, where the agent's reply and the reply box appear.
The Threads tab of Leaf's On view, which the panel's On Me mark opens, lists the threads above the panel's row. Select a thread to read its messages and reply in the panel's comment field. Its passage link returns to the anchor on the page.
A reaction records brief feedback on a passage or agent reply without opening a thread. The default reactions request keeping, changing, clarifying, shortening, supporting, or prioritizing content. Packages can declare additional reactions.