Editor integration¶
Two ways in, both spawned by the editor over stdio: ACP drives whole runs, and agent6 mcp serve exposes a few tools to another agent (see As an MCP server).
Agent Client Protocol¶
agent6 acp runs agent6 as an Agent Client Protocol agent: an editor spawns it, sends prompts, and renders the run as it happens.
It uses the same engine, config, and jail as agent6 run.
// Zed: settings.json
{
"agent_servers": {
"agent6": { "type": "custom", "command": "agent6", "args": ["acp"] }
}
}
What the editor sees¶
Every run writes one event journal; the CLI, TUI, web UI, and ACP all render it the same way.
An editor sees what agent6 attach shows: reasoning, each tool call and its outcome, auto-commits, and how the run ended.
ACP carries a tool call as two messages.
tool_call(in_progress) when the run dispatches it,tool_call_update(completedorfailed, with the output) when its result lands- a call names its tool (
name) beside the call's title; built-in calls carry their ACP kind, and an edit result carries each journaled path as an absolute follow-along location - a call waiting on an approval or an
ask_useranswer is updated topendingwhile its prompt is open, and back toin_progressonce answered - a long verify shows as in progress while it runs; a call the run never returned from settles as
failedwhen the run'ssession.stopis written, or when the tail ends without one (a worker killed mid-call) toolCallIdis<run id>:<execution id>:<call>, unique for the life of the session; the dispatcher numbers each execution's calls from 1
Worker text and thinking arrive as they stream; side-role output stays out of the conversation.
Inspect persisted line-origin evidence with /findings, agent6 sessions findings <id> or the web Findings card.
Three more updates ride the journal.
session_info_update: the task's headline as the session title, the lineagent6 sessions listshowsavailable_commands_update:/pin <text>and the review commands./pinreaches the run as steering text; review commands are handled by the front end, not the model. The composer's other directives (/compact,/btw,/task, ...) are refused, except/paralleland/undo./parallelstarts no children through ACP.abort,exit,detachand/undoare task text over ACP, not terminal commands. The editor cancels throughsession/cancel.usage_updateafter each model call: the last call's whole prompt over the model's context window (thectx N%rule), and the run's cumulative USD when it spent any and every call was priced (a plan-metered run carries none); nothing while the window is unknown
Review findings¶
Findings and dispositions appear as [agent6] transcript notices, not native review threads.
The advertised commands act on the conversation's recorded run:
/findings [--all]lists open findings, or also resolved findings with--all./answer <question-id> <text>...answers a pending question, with options or without; a queued question's answer reaches the run at its next turn, and an ended run's is delivered by the next prompt, which resumes it./fix ID [ID...] --resumeconfirms Resume to fix as a follow-up prompt when the session is idle;/fix --all --resumetakes every open finding without a queued Fix. It uses the stored reports, leaves the findings open, and refuses a missing resume point rather than starting a new run./resolve ID --as DISPOSITION --reason "TEXT" [--duplicate-of ID]records the operator's conclusion./reopen ID --reason "TEXT"reopens a finding.
Live disposition actions use the worker's IPC queue; their notices arrive when recorded. Fix does not support mid-run steering through ACP.
Receipts¶
The advertised /receipt command reads testing, review and reversal evidence without calling the worker or rerunning checks.
Ask for a reversal in a subsequent prompt or a new isolated run; displayed git commands are explanations, not executable actions.
Code-review rule sources¶
See Code-review rules for discovery and limits.
Approvals¶
session/request_permission carries every approval the CLI would prompt for.
- a command under
run_commands = "ask" - an MCP tool call the server's
approvedoes not cover - a
fetchto a host outside the allow-list - an unsandboxed autorun
- a new run on another run's branch
The editor renders the buttons; the request names the tool call it gates and carries the prompt as that call's title.
A prompt that gates no call (a pre-run question) announces a tool call of its own and closes it with the answer.
The prompt and its answer go through the same gate every front-end answers through, so agent6 attach and the web show the run as waiting; the answer journals source: "acp", "frontend" when another surface answered it, or "headless" when the client cannot answer it.
- an unanswered request denies after five minutes, and the run continues without it
- a command or an MCP tool call offers the four answers every front-end shares: "allow" (
allow_once) and "deny" (reject_once) answer the one call, "allow all" (allow_always) grants that scope's later calls for the session, "deny all" (reject_always) withdraws the scope's tools for the session - an off-list
fetchhost is offered asallow_onceonly, so an editor's "always allow" cannot cover a different host later - a standing "allow all", from the editor or an earlier front-end, answers that scope's later prompts without asking the editor (
source: "session")
Sessions¶
A session is one conversation in one directory.
session/newcarries an absolutecwd, a git repository, whose own layered config applies Each execution uses that directory without changing the connection process's cwd.- the first prompt starts an
agent6 run; every later prompt resumes it with the text as its steering instruction (an execution that died before its first checkpoint leaves nothing to resume: the next prompt starts a new run, and the editor is told) After an undo on another surface, the next prompt follows the run's continuation. - a busy session refuses a prompt rather than queueing it; one connection runs one prompt at a time across its sessions, and a prompt on another session queues and says for which session it waits
session/list(cwdoptional, absolute) names the repository's resumable runs, newest first: agent6's run id assessionId, the task astitle, the last activity asupdatedAt; one page, no cursor. A runagent6 resumewould refuse (a child, a run whose worktree is gone, a run with no checkpoint) is left out. Withoutcwdit covers every repository the connection has a session open in.session/resumeopens a conversation on a recorded run by that id, so an editor reopens its thread after a restart.session/resumerefuses a plan, an ask, a run whose worker is alive, or a runagent6 resumewould refuse. It also refuses a run this connection has open for another directory or with a prompt in flight.session/loadopens the recorded run likesession/resume, replays its journal as orderedsession/updatenotifications, then returns.session/closeends a conversation; a prompt in flight is cancelled first and answerscancelled.session/cancelcuts a model call in flight and ends a running foreground command at once, without waiting for or signalling the worker (the ACP server itself). The prompt answerscancelled(ACP's word) and the run's record readsstopped, as every operator stop does; what it had not yet committed stays in the tree for the next prompt, which resumes it. A prompt still queued answerscancelledat once. Cancellation releases an open permission wait without waiting for the client's reply. A late permission reply is ignored and cannot grant permission to a later prompt.
Not implemented¶
session/delete: the operator removes a run's record (agent6 sessions remove).- Mid-run steering: ACP has no message for a prompt while the previous prompt is running.
fs/*andterminal/*: ACP lets the client own the filesystem and the terminal, and agent6 keeps both behind the jail the operator configured.- Free-text answers to a waiting
ask_userquestion: the editor gets option buttons only, so a waiting question without options is unanswered and not queued (see the frontend cases);/answertakes any text. - Embedded resources in a prompt: text and
resource_linkblocks are read (a link rides in as its uri; the workspace boundary still decides what it reaches)- images and embedded resources are dropped;
promptCapabilities.embeddedContextsays so
- images and embedded resources are dropped;
Troubleshooting¶
- stdout is the protocol stream: nothing but JSON-RPC
- everything agent6 would print goes to stderr (the editor's agent logs)
- a wrapper echoing to stdout before exec'ing
agent6breaks the connection irrecoverably; write to stderr
As an MCP server¶
agent6 mcp serve speaks MCP over stdio, so another agent (an editor's own, or a second agent6 with [mcp.servers]) can use agent6's jail and run state.
The cwd's config decides everything: the sandbox the commands run in, and which tools exist at all.
Five tools, of which a default config publishes two:
| Tool | Withheld when |
|---|---|
get_task_graph (a run's task graph) |
never |
list_sessions (this repository's sessions) |
never |
run_verify_command (the configured gate, jailed) |
no [harness] verify_command, or [sandbox] run_commands is not allow |
run_in_sandbox (an argv, jailed) |
[sandbox] run_commands is not allow |
apply_patch_in_sandbox (a patch, then the gate) |
either of the two above |
run_commands = "ask" withholds the command tools: the MCP boundary has no operator to prompt.
// Zed: settings.json -- agent6's jail as another agent's tool surface
{
"context_servers": {
"agent6": { "command": "agent6", "args": ["mcp", "serve"] }
}
}
The tools reach the repository the server was started in, under that repository's sandbox policy; list_sessions and get_task_graph read its state dir and nothing else.