- commit
- a8fea1c6dca23447fe190a69cf0bf0861c619e00
- parent
- aececfdb208124448ddaa599bd7691047d32162f
- author
- Dami <dami.etoile@gmail.com>
- kind
- docs risk score 0.1 of 3, Jev's estimate
| M | ROADMAP.md | 13 | +-- |
| M | docs/ | 1 | + |
| A | docs/ | 224 | ++++++++++++++++++++++++++++++ |
| M | docs/ | 4 | +- |
| M | docs/ | 58 | ++++++-- |
| M | docs/ | 10 | +- |
| M | docs/ | 1 | + |
| M | docs/ | 2 | + |
| M | docs/ | 7 | + |
| M | e2e/ | 2 | +- |
| M | e2e/ | 2 | +- |
@@ -36,18 +36,6 @@ completed by nu as they're written.
3636 |---|---|---|3737 | A command's signature and description for the word at the caret, on the context line, through `nu --ide-hover` or `nu --lsp` | Writing a cell without leaving for `help` | S |3838 39-### 3. Agents40-41-Agents work on workbooks through the same operations people do (the42-`Batch`/`Change` path), so their edits are undoable, attributed and43-shown by `012 diff`, under the same trust rules as macros. Live mode is44-`012 serve`'s shared editing with an agent as one participant45-([Architecture](docs/contributing/architecture.md#shared-workbooks)).46-47-| Step | Result | Size |48-|---|---|---|49-| Live mode: `012 --listen` and `012 mcp --attach`; the agent's cursor and name in the grid, its changes arriving as a suggestion (marked cells, accepted or rejected whole or by cell) unless direct edits are allowed, its own undo, a scope (sheet, range, read-only), elicitation to ask the person | Coworking with an agent in the grid | M to L |50-5139 ## Shelved5240 5341 Explored, not scheduled; the fit is still open.@@ -151,6 +139,7 @@ needs cgo.
151139 - `012 describe`, results as JSON with stable schemas, `012 set --dry-run` as a diff, and a Claude Code skill installed by `012 agent --install-skill`: [Agents](docs/agents/README.md)152140 - `012 mcp`, an MCP server on the workbooks in its folders, each tool taking a path, added to hosts by `012 agent --install-mcp`: tools that read, evaluate, write, sort, filter, chart, pivot and run notebook cells through the same checks as `012 set`, resources and prompts: [MCP server](docs/agents/mcp.md)153141 - Views: ranges read and charts made drawn in the chat from the HTML export, in MCP Apps hosts and the OpenAI Apps SDK's: [MCP server](docs/agents/mcp.md#views-in-the-chat)142+- Live mode: `012 --listen` and `012 mcp --attach`, the agent a participant in the session's room, its cursor and name in the grid, its changes suggestions accepted or rejected whole or by cell unless direct edits are allowed, its own undo, a scope, and questions on the context line: [Live mode](docs/agents/live.md)154143 155144 **Upkeep**156145 @@ -16,6 +16,7 @@ started with the flags that allow it, as for scripts.
1616 |---|---|1717 | This page | Agents with a shell: the commands, their JSON, and the Claude Code skill |1818 | [MCP server](mcp.md) | `012 mcp`, for any MCP host: tools, resources, prompts, views in the chat, and adding it to Claude Code, Codex and Claude Desktop with `012 agent --install-mcp` |19+| [Live mode](live.md) | The agent working in your running 012 with you: its pointer in the grid, its changes as suggestions you accept or reject, a scope, questions on the context line |1920 | [JSON output](../reference/json.md) | The schemas of what commands write with `--format json`, and what the MCP tools return |2021 2122 ## With a shell@@ -0,0 +1,224 @@
1+---2+title: "Live mode"3+sidebar_position: 34+---5+6+# Live mode7+8+In live mode the agent works in your running 012 with you, as one more9+person in the workbook: its pointer and name show in the grid, it reads10+the workbook as it is on your screen, and what it changes arrives as a11+suggestion you accept or reject, whole or cell by cell. Here claude12+suggests March's food and power bills; the cells it would change carry13+a ◇, and the context line says what it would put in the one under the14+pointer, and why:15+16+17+18+19+It is [`012 serve`'s shared editing](../terminal/ssh.md#sharing-a-workbook)20+with the agent as a participant: the session's workbook sits in a room,21+every change goes through the workbook's one mutation path in the order22+the room takes them, each attributed to whoever made it, so undo takes23+back only your own and `012 diff` shows everyone's. The agent uses the24+[MCP server's](mcp.md) tools, on this one workbook.25+26+## Starting27+28+Let agents in when you start, or from a session already running:29+30+```sh31+012 --listen budget.01232+```33+34+**File > Invite an agent** asks what the agent may change (its <!-- doclint:allow: the menu item's title -->35+[scope](#scope)), and starts listening if the session wasn't;36+`--listen` lets it suggest changes to the whole workbook. **File > Stop37+inviting agents** closes the socket: agents attached leave, and their38+suggestions stay for you to settle.39+40+The agent's host runs `012 mcp --attach` as its MCP server, which joins41+the session:42+43+```sh44+claude mcp add --scope user 012-live -- 012 mcp --attach # Claude Code45+012 mcp --attach # the only session listening46+012 mcp --attach budget # the session with budget.012 open47+```48+49+With no name, `--attach` joins the only session listening, or lists50+them when there are several; a name picks the session by its workbook51+(`budget`, `budget.012`) or its process id, and a path ending in52+`.sock` names a socket. The agent's name in the grid is its host's53+(`Claude Code`), as its MCP `initialize` request gives it.54+55+```mermaid56+sequenceDiagram57+ participant H as MCP host (the agent)58+ participant A as 012 mcp --attach59+ participant S as 012 --listen (your session)60+ participant R as the room61+ H->>A: initialize (its name)62+ A->>S: the socket: hello, the agent's name63+ S->>R: a seat for the agent64+ S-->>A: welcome: the workbook, the scope65+ H->>S: tools/call write_cells (through A)66+ S->>R: a turn: the change made on a copy, checked against the scope67+ R-->>S: a suggestion on the board; your screen marks its cells68+ S-->>H: the suggestion's number69+ Note over S: you accept (Ctrl+Alt+A, Enter)70+ S->>R: your turn: the cells set, one step in the agent's name71+ R-->>H: the suggestions resource updated72+```73+74+## In the grid75+76+The agent shows as the others in a shared workbook do, with a ◆ where77+a person has their initial: on the header of the row its pointer is on,78+before its name on the status line, and in **File > Who's here**, which79+lists it with the word agent. Its pointer's cell is in its color, double80+underlined. The agent moves it with the `focus` tool as it works, and81+each change it makes or suggests puts it on the cells changed, so you82+see where it's looking.83+84+## Suggestions85+86+What the agent changes waits as a suggestion unless you87+[let agents edit directly](#direct-edits). A cell it would change has a88+◇ in its top-left corner; with the pointer on one, the context line89+says whose suggestion it is, what it would put there, what the cell90+holds and the agent's message. The status line counts the suggestions91+waiting.92+93+**Review suggestions** (Ctrl+Alt+A, or File > Review suggestions) lists94+them at the right of the grid, by agent and message, each with its95+cells; the grid shows the cell of the row highlighted:96+97+98+99+100+| Key | On a suggestion | On one of its cells |101+|---|---|---|102+| Enter, A, or click ✓ | Accept all it has waiting | Accept the cell |103+| R, Del, or click ✗ | Reject all it has waiting | Reject the cell |104+| Shift+A, Shift+R | Accept or reject every suggestion | |105+106+What you accept is made as one step, in the agent's name: its cells107+show as changed by it, the agent's `undo` takes it back, and your own108+undo passes it by, as it passes by another person's step. A change that109+does more than set cells (inserting rows, adding a sheet, a chart, a110+filter) is listed with what else it does and is accepted whole, by111+making it again on the workbook; a change of cells alone sets the cells112+it showed you. Rejecting changes nothing. Either way the agent hears113+of it: the `suggestions` resource is updated for hosts subscribed to114+it, and its next write lists what became of its earlier ones.115+116+### Direct edits117+118+**File > Let agents edit directly** skips suggestions: agents' changes119+are made at once, each its own step, still theirs to undo. It is off120+when a session starts, holds for the session, and applies to every121+agent in it.122+123+## Scope124+125+When you invite the agent you pick what it may change:126+127+| Scope | The agent may change |128+|---|---|129+| The whole workbook | Anything, as you could |130+| This sheet | The shown sheet's cells, lines, charts, rules and filters; no other sheet, and not the sheet list, names or settings |131+| The selection | The cells of the selected range only |132+| Read only | Nothing: it reads, points and asks |133+134+A change outside the scope is refused before it reaches you, with the135+reason, and the agent's pointer stays inside it. The scope bounds136+changes, not reading: formulas in the scope read cells outside it, so137+the agent reads the whole workbook. Invite it again to change the scope.138+139+## Notebook cells and JEV140+141+What reaches beyond the workbook needs your leave each time, or for the142+session, as an [untrusted macro](../sheets/macros.md) does. The agent's143+`run_notebook_cell` asks before your session runs the cell with nu as144+you, with your files; with the whole workbook in scope only, as its145+output goes to the sheets it's sent to. With direct edits on, a change146+that enters [JEV formulas](../formulas/jev.md), which send cells' values147+over the network with your API key, asks first; a suggestion doesn't,148+as accepting it is your leave. The question takes the context line:149+Enter allows once, A allows for the session, Esc denies.150+151+## Questions152+153+The agent's `ask` tool puts a question on your context line and waits154+for your answer:155+156+157+158+159+It takes what an MCP elicitation request takes, a message and a flat160+object schema, and returns what an elicitation returns: `accept` with161+the values, `decline` or `cancel`. MCP's elicitation goes from a server162+to the user of its host; here you are on the server's side, so the163+agent asks through a tool shaped like one. A question without a schema164+is a yes or no (Enter, N, Esc); otherwise each property is asked in165+turn: a boolean with Y and N, a choice (`enum`, or `oneOf` consts, up166+to nine) with its number, a string, number or integer typed and167+entered. Esc cancels. The question waits until you're in READY with168+nothing open, and goes away if the agent stops waiting.169+170+## Tools171+172+The agent has the [MCP server's](mcp.md) tools, working on the one173+workbook: `path` is left out. Writes return the suggestion's number,174+or with direct edits the change as saved, and the news of earlier175+suggestions. `create_workbook` isn't offered. Live mode adds:176+177+| Tool | Does |178+|---|---|179+| `focus` | Moves the agent's pointer to a cell or range, in its scope |180+| `undo` | Takes back the agent's latest step that was made (accepted, or made directly); refused when someone changed the same cells since |181+| `ask` | Asks you a question and waits for the answer |182+| `suggestions` | The agent's suggestions and what became of each, and its scope |183+| `run_notebook_cell` | Has your session run a notebook cell, once you allow it |184+185+The resource `o12://live/suggestions` lists the same as `suggestions`;186+hosts subscribed to it are told when you settle one.187+188+## 012 serve189+190+[`012 serve`](../terminal/ssh.md) listens the same way when sharing is191+on, and the agent on the server, run by the server's user, joins a file192+someone has open by naming it: `012 mcp --attach budget.012`. It may193+change the whole workbook, as a suggestion anyone in the room accepts194+or rejects; its questions go to whoever is free first.195+196+## Security197+198+- A session listens on a Unix socket only you can reach: the socket is199+ `0600`, in a folder that is `0700`, `$XDG_RUNTIME_DIR/012` or else200+ `agents` in [012's config folder](../reference/config.md). Nothing201+ listens on the network.202+- The session asks the kernel who connected (`SO_PEERCRED` on Linux,203+ `LOCAL_PEERCRED` on macOS and FreeBSD) and refuses any other user.204+ `012 mcp --attach` refuses a socket or folder another user owns or205+ can reach.206+- On Windows the socket is in your profile's folder, whose permissions207+ keep other users out; there is no kernel check of who connected.208+- The agent can do what the scope and your grants allow, as you, in209+ this workbook only: it opens no files, runs nothing and reaches no210+ network without your leave.211+- A process of yours can attach, as it could already read and write212+ your files; stop inviting agents to close the socket.213+214+## Limits215+216+- A change is made on a copy of the workbook first, to show it and217+ check its scope, so a suggestion costs a save and an open of the218+ workbook: quick for everyday workbooks, seconds near the219+ [`max-cells` budget](../contributing/limits.md#sheet-size).220+- The agent's changes are made in the order the room takes them, as221+ anyone's; accepting a suggestion sets the cells it showed, over what222+ anyone typed in them since.223+- The agent attaches to the workbook it was invited to: opening another224+ file in the session stops inviting agents.@@ -23,7 +23,9 @@ flowchart LR
2323 ```2424 2525 A file is opened afresh for every call, so what the screen, a script26-or git saved meanwhile is what the next call sees.26+or git saved meanwhile is what the next call sees. To work in a running27+012 instead, on the workbook on your screen with its changes as28+suggestions, attach with `012 mcp --attach`: [Live mode](live.md).2729 2830 ## Adding it to a host2931 @@ -490,7 +490,7 @@ draw. The components:
490490 | edit line | `lineedit.Line` | the one-line editor shared by cell entries, prompts and search fields (package `lineedit`) |491491 | cell entry | `entry`, `suggest.List` | typing into a cell, pointing at references, other sheets while pointing (`entry.go`, `assistsheets.go`); formula suggestions and signatures (package `suggest`, with `assist.go`) |492492 | prompt | `prompt` | a question on the context line, typed or pointed at (`prompt.go`) |493-| overlays | `overlay.Overlay` | whatever has taken over input: menus (`menuoverlay.go`), the palette and pickers (package `picker`, with `palette.go`, `names.go`), the command line (package `cmdline`), the theme picker (package `themepicker`), the find bar (package `findbar`), the filter picker (package `filterpick`, with `filter.go`), the sort bar (package `sortbar`, with `sort.go`), choice bars (package `choicebar`, with `dialog.go`), the chart editor and selection (`charteditor.go`, `chartsel.go`), the pivot editor (`pivoteditor.go`, `pivotactions.go`), the rules panel (package `rules`, with `rules.go`), the shortcuts (package `shortcuts`, with `help.go`), Evaluate formula (package `evalview`, with `evaluate.go`) |493+| overlays | `overlay.Overlay` | whatever has taken over input: menus (`menuoverlay.go`), the palette and pickers (package `picker`, with `palette.go`, `names.go`), the command line (package `cmdline`), the theme picker (package `themepicker`), the find bar (package `findbar`), the filter picker (package `filterpick`, with `filter.go`), the sort bar (package `sortbar`, with `sort.go`), choice bars (package `choicebar`, with `dialog.go`), the chart editor and selection (`charteditor.go`, `chartsel.go`), the pivot editor (`pivoteditor.go`, `pivotactions.go`), the rules panel (package `rules`, with `rules.go`), the shortcuts (package `shortcuts`, with `help.go`), Evaluate formula (package `evalview`, with `evaluate.go`), the agents' suggestions (package `review`, with `agents.go`) |494494 | sheet tabs | `tabstrip.Strip` | where each sheet was left, the tab strip's scroll and layout (package `tabstrip`); what clicks on it do (`tabstrip.go`) |495495 | mouse | `mouseState` | drags, hover, double clicks, the fill handle (`mouse.go`, `fill.go`) |496496 | import | `transfer.Transfer`, `pipeState` | the import in progress, its progress display and cancelling (package `transfer`); choosing and placing imports (`transfer.go`, `importplace.go`); standard input read as a sheet, and what a pipeline gets on quitting (`pipe.go`) |@@ -525,6 +525,7 @@ methods off `ui.Model`'s exported API:
525525 | `cmdline` | `cmdline.Host` | theme, size, the edit line, close, the commands to complete, run a line, fail, the session's history (8) |526526 | `nbview` | `nbview.Host` | theme, locale, the cells, a cell's output, how its run stands, run a command, keep a cell's new source (7); the language's highlighter, completer and checker are `nbview.Providers`, small interfaces of their own |527527 | `suggest` | `suggest.Host` | theme, size, the edit line, whether an entry is being typed, the entry's sheet, the formula as parsed, where the formula bar's text starts (7) |528+| `review` | `review.Host` | theme, size, close, the agents' suggestions waiting, accept, reject, show a cell (7) |528529 | `themepicker` | `themepicker.Host` | a picker's host, and the current theme, the themes directory, preview, keep, whether keys can be held (10) |529530 | `rules` | `rules.Host` | theme, size, the edit line, close, the sheet and selection, save a conditional format or a validation rule, follow a rule removed or moved (each recorded as the commands that do it), the terminal's palette colors (10) |530531 | `findbar` | `findbar.Host` | theme, size, the edit line, the workbook, the trace, the sheet and cell shown, show a cell, note, run a replacement (recorded as Find and replace), leave keeping the search, pass a click to the grid (11) |@@ -570,7 +571,7 @@ hints) are what every overlay is drawn with.
570571 **Packages.** `theme`, `rowtext`, `formula`, `overlay` and `lineedit`571572 depend on nothing in `ui`, so they can be tested and measured alone. The572573 components in `picker`, `cmdline`, `nbview`, `themepicker`, `findbar`, `rules`,573-`sortbar`, `filterpick`, `choicebar`, `shortcuts`, `evalview`, `suggest`, `tabstrip`574+`sortbar`, `filterpick`, `choicebar`, `shortcuts`, `evalview`, `suggest`, `review`, `tabstrip`574575 and `transfer` build on them and reach the model only through their575576 hosts, with unit tests of their own against fake hosts. A component moves out of package576577 `ui` when its host stays small (about ten methods or fewer); one that@@ -857,8 +858,9 @@ changed; everything else it does, it does through its seat:
857858 858859 | `room.Participant` | What it is |859860 |---|---|860-| `Name()` | who they are to the others: the SSH user |861+| `Name()` | who they are to the others: the SSH user, or the agent's MCP host |861862 | `Notify()` | the room changed; called with the room locked, so it only schedules a turn (a session sends its program a `roomMsg`) |863+| `Agent()`, optional (`room.Agent`) | the participant is one of the agents: marked as one, never the keeper, and the room closes when its last person leaves |862864 863865 | `room.Seat` | What it does |864866 |---|---|@@ -868,15 +870,6 @@ changed; everything else it does, it does through its seat:
868870 | `Saved`, `SetSaved`, `Value`, `Keeper`, `Post`, `Take` | what the room shares: its file's saved state, values such as the notebook runs, and messages for whoever keeps it |869871 | `Leave` | the seat given up; reports whether the room closed |870872 871-The interface stays this small so an MCP client attached to the872-server can be a participant beside sessions (ROADMAP.md, Agents):873-`internal/mcp`'s tools stand on a `Backend` of `View`, `Scratch` and874-`Change`, and a room's would be a seat, `View` and `Change` its turns875-(the change one `Batch`, attributed to the client's seat, so its own876-undo and the others' marks follow), `Scratch` a copy of the workbook877-taken in a turn, and `Notify` what tells the client the workbook878-changed.879-880873 **Unsaved work.** `Server.Shutdown` closes a channel every session881874 watches; a session quitting on it, or on its idle timeout, asks its882875 model `Unsaved` and `Recover`, which writes the workbook to@@ -892,6 +885,47 @@ root (the local app) uses them as they are, a served session's root
892885 keeps them inside its directory. Every open, save, import, download and893886 file listing goes through `Model.path` or the root.894887 888+### Live mode889+890+Agents take part in rooms as participants ([Live mode](../agents/live.md)),891+through `internal/cowork`. A local session invited to (`012 --listen`,892+File > Invite an agent) takes its workbook into a room of its own as it <!-- doclint:allow: the menu item's title -->893+is (`enterLocal`: its steps adopted as its person's, `Workbook.Adopt`),894+runs under `ui.Shared` as served sessions do, waits for its room's895+changes itself (`waitRoom`), and listens on a Unix socket896+(`cowork.Listen`); `012 serve` listens beside its rooms. `012 mcp897+--attach` is a pipe between the host's standard input and output and898+that socket, after a line each way naming the agent and the workbook.899+In the session, each connection is a seat (`cowork.Agent`, which900+implements `room.Agent`) and an `mcp.Server` whose `Options.Live` is901+that agent: `internal/mcp`'s tools stand on a `Backend` of `View`,902+`Scratch` and `Change`, and the agent's are its seat's turns, `Scratch`903+a copy taken in one, and changes go through `mcp.Live.Make`:904+905+```mermaid906+flowchart TD907+ tool[a write tool] --> make[Agent.Make, a turn]908+ make --> propose[sheet.Propose: the change on a copy; its cells and what else it does]909+ propose --> scope{Scope.Check}910+ scope -->|outside| refuse[refused, with the reason]911+ scope -->|direct edits| apply[Proposal.Apply: a step in the agent's name]912+ scope -->|otherwise| board[a Suggestion on the room's Board; Seat.Touch]913+ board --> screen[the person's frame: cells marked, the review panel]914+ screen -->|accept| apply915+ screen -->|reject| told[marked rejected]916+ apply --> notify[the agent's Notify: the suggestions resource updated]917+ told --> notify918+```919+920+The board (`cowork.Board`, a room value) holds the suggestions, the921+scope, direct edits, the grants and the agent's questions, so it's read922+and changed in turns like the workbook. A proposal of cells alone is923+applied as the cells it made on the copy, cell by cell if the person924+picks; one that does more is applied whole by running the change again925+(`sheet/proposal.go`). Questions and grants wait on the board until the926+person asked is free (`agentask.go`); a notebook run the agent is927+allowed is posted to the room's keeper, as other runs are.928+895929 ## Configuration and secrets896930 897931 `internal/config` reads one Ghostty-style file (`key = value`, `#`@@ -51,7 +51,9 @@ shared, as a room of `012 serve` holds it, then has them undo their own
5151 steps in turns drawn from the seed, out of order wherever the rule5252 allows: someone can always undo, an undo redone at once gives back the5353 file it undid, and once every step is undone the workbook is back where54-it started.54+it started. A fourth author stands for the agent of live mode: its edits are55+proposals made on a copy, accepted whole, cell by cell or not at all as56+the seed draws, and its accepted steps are undone with the rest.5557 5658 The UI is tested by sending5759 Bubble Tea messages (keys, mouse, paste, window size) to the model and@@ -104,7 +106,11 @@ restores the terminal and keeps the work; release builds have no such key.
104106 is tested as a user sees it (skipped when `ssh` isn't installed). `e2e/share_test.go` has two people105107 reach one `012 serve` that way, each in a terminal of their own, and106108 share a file; screens of a shared workbook start the others' sessions107-first (`screen.peers`).109+first (`screen.peers`). `e2e/live_test.go` runs `012 --listen` and a real110+`012 mcp --attach`, spoken to in MCP's JSON-RPC as a host would: the111+agent reads, suggests and asks, and the person accepts in the grid;112+live mode's screens attach it first (`screen.live`). Live mode's unit113+tests (`internal/cowork`) attach the SDK's client over the socket.108114 109115 `make e2e` builds libghostty-vt from source with Zig into `.deps/` on first110116 use. It is its own Go module so cgo never reaches the main binary.@@ -113,6 +113,7 @@ there.
113113 | Protected ranges | A question in words before an edit (`A1:B2 is protected.`) |114114 | Notes | A `▝` in the cell's top-right corner |115115 | Others in a shared workbook (012 serve) | Their pointer's cell double-underlined, their initial on its row's header, their name on the status line, `▘` in a cell they changed in the last 30 seconds, and `Changed by`, `is here` or their warnings in words on the context line |116+| Agents in the workbook (live mode) | A `◆` for their initial on the row header and before their name on the status line, `agent` in Who's here; a `◇` in a cell their suggestion would set, what they suggest in words on the context line, and the count on the status line |116117 | Macro recording | `REC` beside the mode indicator |117118 | Mode | The mode indicator's word (`READY`, `ENTER`, `POINT`, `MENU`, and on a notebook `NOTEBOOK`, `EDIT` or `OUTPUT`) |118119 | Search matches, traced cells | Reverse video, with a count or the list on the context line; dependents also bold |@@ -14,6 +14,7 @@ like a command (`get`, `diff`) opens as `./get`.
1414 |---|---|1515 | `012 [flags] [file]` | Opens a `.012` workbook (created on saving when it doesn't exist), or imports another format: [Files](../files/README.md) |1616 | `012 [flags] -` | A table from standard input: [Pipelines](../nushell/pipelines.md) |17+| `012 [flags] --listen [file]` | Lets agents work in the session with you, attached with `012 mcp --attach`: [Live mode](../agents/live.md) |1718 | `012 [flags] --pipe [--to nuon\|json\|csv\|tsv] [--send ask\|selection\|sheet] [file]` | On quitting, sends a table to standard output: [Pipelines](../nushell/pipelines.md) |1819 | `012 nu [flags] [file]` | A nushell notebook, at its prompt: [Notebooks](../nushell/notebooks.md) |1920 | `012 serve [flags] [dir]` | Serves the sheets in a directory over SSH: [Serving over SSH](../terminal/ssh.md) |@@ -30,6 +31,7 @@ The flags are the options' flags, listed in [Configuration](config.md#options).
3031 | `012 export file.012 out [ref]` | Writes the workbook, a sheet or a range in another format: [Scripts](../files/scripts.md#export) |3132 | `012 describe file.012` | Lists the sheets and what's on them: [Agents](../agents/README.md#with-a-shell) |3233 | `012 mcp [file.012]` | Serves the workbooks in the folders open to it to MCP hosts over standard input and output: [MCP server](../agents/mcp.md) |34+| `012 mcp --attach [name\|socket]` | Joins a running 012 listening for agents, as the agent's MCP server: [Live mode](../agents/live.md#starting) |3335 | `012 diff a.012 b.012` | Lists what changed, cell by cell: [Diff and merge in git](../files/git.md#012-diff) |3436 | `012 diff --textconv file.012` | Writes a workbook as lines, for git's textconv: [Diff and merge in git](../files/git.md#git) |3537 | `012 merge-driver base ours theirs [path]` | Merges theirs into ours, for git: [Diff and merge in git](../files/git.md#merging) |@@ -195,6 +195,13 @@ once for everyone, and notebook cells run once: any session may run or
195195 stop them, everyone sees them running and their outputs, and they go on196196 when the one who started them leaves, until the last one does.197197 198+**Agents.** With sharing on, the server also listens for agents run by199+its own user on its machine: `012 mcp --attach budget.012` joins the200+room of a file someone has open, where the agent shows with a ◆ and its201+changes wait as suggestions for anyone in the room to accept202+([Live mode](../agents/live.md#012-serve)). The room closes when its203+last person leaves, whatever agents are still in it.204+198205 ## Each session199206 200207 Besides the shared workbook, every session is a separate 012 with@@ -131,7 +131,7 @@ func (a *agent) tool(name string, args map[string]any) map[string]any {
131131 }132132 133133 // startLive starts 012 --listen on a new budget.012 with 40, 2 and134-// their sum in A1:A3, and attaches an agent called claude.134+// their sum in A1:A3, and attaches the agent, claude.135135 func startLive(t *testing.T, o options) (*session, *agent) {136136 t.Helper()137137 run := runDir(t)@@ -32,7 +32,7 @@ type screen struct {
3232 user string3333 peers []peer3434 args []string // 012's command line, e.g. --pipe35- // live starts 012 --listen on budget.012 and attaches an agent35+ // live starts 012 --listen on budget.012 and attaches the agent3636 // called claude (s.agent) before setup: live mode's screens.3737 live bool3838 setup func(s *session)