SUZENT / Docs
THE SUZENT HANDBOOK

ACP — Suzent in Someone Else's Editor

Suzent speaks ACP (Agent Client Protocol) in both directions : Direction Role Entry point What it means --- --- --- --- Outbound Suzent is the client suzent.acp.client Suzent drive

Suzent speaks ACP (Agent Client Protocol) in both directions:

DirectionRoleEntry pointWhat it means
OutboundSuzent is the clientsuzent.acp.clientSuzent drives Claude Code, Codex, … as subagents
InboundSuzent is the agentsuzent acpZed, enoxian, any ACP client drives your geist

This page covers the inbound half. See a2a.md for A2A, which reaches agents over the network; ACP is local and process-scoped — the client spawns the agent and speaks JSON-RPC on its stdin/stdout.

1. What the client gets

suzent acp

That command is not meant to be typed. An ACP client spawns it, keeps the pipe, and passes its workspace as the session cwd:

client -> agent:  initialize
client -> agent:  session/new       (cwd = the client's workspace)
client -> agent:  session/prompt
agent  -> client: session/update    (message chunks, thoughts, tool calls)
agent  -> client: session/request_permission
client -> agent:  session/cancel

Implemented methods: initialize, authenticate, session/new, session/load, session/prompt, session/cancel. Advertised capabilities: loadSession: true, text prompts with embedded context. Images and audio are declined at the handshake rather than silently dropped.

2. It is a translator, not a second agent

suzent acp runs no model. Every turn is posted to the already-running backend over the loopback API and its AG-UI event stream is translated back into ACP:

Suzent stream eventACP session update
TEXT_MESSAGE_CONTENTagent_message_chunk
THINKING_TEXT_MESSAGE_CONTENTagent_thought_chunk
TOOL_CALL_START / _ARGS / _ENDtool_call, then tool_call_update with rawInput
TOOL_CALL_RESULTtool_call_update (completed)
tool_approval_requestsession/request_permission
RUN_ERRORJSON-RPC error on the prompt turn

That indirection is the point. One process owns the database, so an ACP session is a real chat: it appears in the desktop UI, uses the same memory, skills, model config, and permission rules, and survives a restart. suzent serve (or suzent start) must be running; without it the first session fails with a connect error rather than quietly starting a second agent stack.

An ACP session id is a chat id. session/load therefore resumes a real conversation — and refuses any chat this surface did not create, so a client cannot address one of your local conversations by guessing an id.

3. Where the files are

session/new binds the client's cwd to the session as a custom volume mounted at /mnt/workspace, and pins the agent's working directory to the path the active execution mode can actually use:

ModeMountAgent cwd
Sandbox<client cwd>:/mnt/workspace/mnt/workspace
Hostsame mapping, resolved on the hostthe real client cwd

The binding rides along with every prompt, the same way the desktop UI sends a chat's config on every turn, so a session/load that arrives with a different cwd rebinds immediately. The mount is also announced in the system prompt (host path, mount point, and whether it is a Git repo), so the model knows where it is working.

Because edits land on the real files through a bind mount, a client that tracks workspace changes — enoxian's proposal engine, an editor's diff view — sees them as ordinary file writes.

4. Approvals stay yours

By default an ACP session runs in default permission mode, so a tool call that needs approval becomes a session/request_permission request and the turn blocks on the client's answer. The options offered are built from the backend's own decision contract, so a client sees exactly the authority Suzent is willing to grant:

Suzent actionACP option kind
allow_onceallow_once
allow_session / allow_globalallow_always
rejectreject_once

Choosing an allow_always option persists the rule the label promised (a command prefix such as git log …, or a whole tool), because the selected option id is handed back to the backend as the action to resolve. A cancelled outcome stops the turn.

To skip prompting entirely — for an unattended client — start the agent with --permission-mode auto or --permission-mode full_access.

5. Flags

FlagDefaultPurpose
--server-urlthe running local backendBridge to a specific backend URL
--permission-modedefaultdefault, auto, or full_access
--log-levelWARNINGDiagnostics level on stderr

stdout carries protocol traffic only. Logging is forced to stderr before anything can write, -v included.

6. Registering with a client

enoxian — Suzent is a built-in agent there, so enabling it downloads nothing; it only points the @suzent handle at your installed CLI. Mentions launch it once this device's reaction policy is push:

enox agent install suzent

Any other client — register suzent acp wherever it configures external agent servers (command suzent, args ["acp"]), and it will be spawned with the workspace as the process cwd and the session cwd. Check the client's own docs for where that configuration lives.

Edit this page on GitHub ↗

On this page