Harness Notes

JSON

ACP

5 records ยท Updated 2026-10-15

The Agent Client Protocol (ACP) lets an editor such as Zed or a JetBrains IDE run a coding agent in its own panel. How to connect each harness, what carries over from its terminal app, and how much of the work the editor sees and controls.

Getting connected

QuestionCodex CLIchecked at codex-acp 2.2.2, Codex 0.162.1Claude Codechecked at claude-agent-acp 0.90.0Cursor Agentchecked at 2026.10.12OpenCodechecked at 2.0.29pichecked at pi-acp 0.0.34
Run it as an ACP agent

Codex has no ACP mode of its own; run the adapter npx -y @agentclientprotocol/codex-acp (binary codex-acp), which starts codex app-server and translates between the two protocols. It bundles Codex 0.160.1; set CODEX_PATH=/path/to/codex to use your own Codex.

The older Rust zed-industries/codex-acp repository is archived; the current adapter lives at agentclientprotocol/codex-acp.

A @preview npm tag tracks unreleased main.

Source

Claude Code has no ACP mode of its own; run the adapter npx @agentclientprotocol/claude-agent-acp (binary claude-agent-acp), built on the Claude Agent SDK. It bundles Claude Code 2.1.296; set CLAUDE_CODE_EXECUTABLE to use your own claude.

The package was formerly @zed-industries/claude-code-acp (repo zed-industries/claude-code-acp); that name is deprecated at 0.16.2.

claude-agent-acp --cli <args> runs the bundled Claude Code CLI directly, e.g. for login.

Set CLAUDE_AGENT_ACP_EXPERIMENTAL_V2=1 to also serve the draft ACP v2 to clients that ask for it.

Source

Run agent acp; ACP is native to the Cursor Agent CLI, so no adapter package is needed. It speaks newline-delimited JSON-RPC 2.0 over stdio and logs to stderr.

Source

Run opencode acp; ACP is built into OpenCode, no adapter package is needed. It speaks newline-delimited JSON-RPC (protocol version 1) on stdin/stdout, starts its own private OpenCode server and exits when stdin closes.

Add --print-logs before acp (opencode --print-logs acp) to send logs to stderr when debugging; stdout carries only ACP messages.

1.x (opencode-ai) uses the same opencode acp command.

Source

pi has no ACP mode of its own; run the community adapter npx -y pi-acp (svkozak/pi-acp). It starts pi --mode rpc for each session, so pi must be on PATH (or set PI_ACP_PI_COMMAND).

pi-acp 0.0.34 documents pi v0.81.0+ and was released before pi 1.0; 1.x compatibility is tracked in the adapter's issue #159.

pi --mode rpc is pi's own JSON-over-stdio protocol, not ACP; pi-acp translates between the two.

Other community adapters exist (@automatalabs/pi-acp, which embeds pi through its SDK in-process; @wbline/pi-acp-jetbrain for JetBrains), but only pi-acp is in the ACP registry.

Source
Add it to Zed, JetBrains or another editor

The ACP registry lists it as codex-acp (npx @agentclientprotocol/codex-acp@2.2.2), so Zed and JetBrains install it from their registry UI. Zed users start a Codex thread from the Agent Panel; for a custom build add an agent_servers entry with "command": "/path/to/codex-acp" and optional "env": {"CODEX_PATH": "/path/to/codex"}.

Source

The ACP registry lists it as claude-acp ("Claude Agent"), launched with npx @agentclientprotocol/claude-agent-acp@0.90.0, so registry-aware editors such as Zed (zed: acp registry, or Agent Settings > External Agents > Install from Registry) and JetBrains install it in one step. Other clients can configure it as a custom stdio agent running npx @agentclientprotocol/claude-agent-acp.

The registry also carries a preview channel (0.90.1-preview.12) built from every push to main.

Source

Cursor is in the ACP registry as cursor, which downloads the CLI package and launches cursor-agent acp, so registry-aware clients such as Zed and JetBrains can install it directly. Cursor documents JetBrains IDEs, Zed and Neovim via avante.nvim (cursor provider, auth_method = "cursor_login"); any other client can spawn agent acp.

Source

OpenCode is in the ACP registry (id opencode), so Zed can install it via zed: acp registry. For a custom binary, add "agent_servers": {"OpenCode": {"command": "opencode", "args": ["acp"]}} to Zed's settings.json or JetBrains' acp.json; Avante.nvim and CodeCompanion.nvim are also documented.

The registry entry downloads the 1.x release binary (currently v1.19.0), not the 2.x @opencode/cli. To use 2.x in an editor, point command at your 2.x opencode binary.

If a GUI editor cannot find opencode, use the absolute path from which opencode.

Source

pi-acp is listed in the ACP registry as pi ACP, so in Zed run zed: acp registry and pick it, which adds "agent_servers": {"pi-acp": {"type": "registry"}}. Without the registry, add a custom server with "command": "npx", "args": ["-y", "pi-acp"].

Development targets Zed; other ACP clients may work with varying compatibility.

Source
Signing in

initialize advertises api-key (reads CODEX_API_KEY, then OPENAI_API_KEY) and chat-gpt (browser login, hidden when NO_BROWSER is set). Clients that support URL elicitation also get chat-gpt-device-code, and clients that opt in get a gateway method for a custom OpenAI-compatible endpoint. Existing codex login credentials in ~/.codex are reused, and /logout or authentication/logout signs out.

Source

Sign-in reuses Claude Code's own credentials (claude auth login, ANTHROPIC_API_KEY, or Bedrock/Vertex env), and the agent pushes the current identity on _auth/status_update. When the client declares auth.terminal, initialize advertises terminal auth methods claude-ai-login (Claude subscription) and console-login (Anthropic Console), which run claude-agent-acp --cli auth login --claudeai|--console; over SSH it offers claude-login instead. Clients that declare auth._meta.gateway also get gateway/gateway-bedrock methods, and logout is supported.

Launch with --hide-claude-auth to hide the subscription login and refuse turns a claude.ai subscription would pay for.

Source

The only advertised auth method is cursor_login. Sign in beforehand with agent login, or launch with --api-key/CURSOR_API_KEY or --auth-token/CURSOR_AUTH_TOKEN; the client then calls authenticate with methodId: "cursor_login". Session calls made without credentials fail with an auth-required error telling the user to run agent login.

Source

OpenCode advertises one auth method, opencode-login, and uses the provider credentials already stored by opencode auth login. If the client sets clientCapabilities.auth.terminal, the method becomes a terminal auth method with args --login, so the editor runs opencode acp --login in a terminal; a prompt that needs credentials fails with ACP's auth_required error.

authenticate does not collect credentials; it just accepts opencode-login.

Clients that set _meta["terminal-auth"] get the login command (opencode auth login) in the method's _meta. Provider API keys can also come from the environment or OpenCode config as usual.

Source

Partly

The adapter advertises one terminal auth method, pi_terminal_login, which runs pi-acp --terminal-login to open interactive pi so you can log in or set API keys. There is no in-protocol API-key method; credentials come from pi's own configuration or provider env vars.

If no models are available, session/new fails with an auth-required error carrying the same method.

Source

Sessions and settings

QuestionCodex CLIchecked at codex-acp 2.2.2, Codex 0.162.1Claude Codechecked at claude-agent-acp 0.90.0Cursor Agentchecked at 2026.10.12OpenCodechecked at 2.0.29pichecked at pi-acp 0.0.34
Resume, list or fork past sessions

loadSession is true and sessionCapabilities advertises list, resume, fork, close and delete, so editors can list, reload (with history replay), resume and fork sessions. Listing reads Codex's own thread store across cli, vscode, exec and appServer sources, so sessions started in the terminal codex show up in the editor and vice versa.

session/list is filtered to the active model provider and, when given, the cwd.

Source

It implements session/list, session/load (with history replay), session/resume, session/fork, session/close and session/delete. Sessions are Claude Code's own transcripts, so conversations started in the editor show up in claude --resume and vice versa.

session/list can be filtered by cwd and is paged with a cursor.

Subagent child sessions are replayed from their own transcripts when the client declares subagents.

Source

Partly

session/list (optional cwd filter, no pagination) and session/load work, and loading replays the conversation history to the editor. There is no session/resume or session/fork. ACP sessions are stored separately under ~/.cursor/acp-sessions/, so terminal chats from agent --resume are not listed or loadable, and the other way round.

Source

session/list (100 per page, cwd filter, cursor), session/load (replays history), session/resume, session/fork, session/close and session/delete are all supported. Sessions live in OpenCode's normal session store, so sessions started in the terminal app appear in the editor and vice versa.

Load, resume and fork must pass the session's original directory as cwd; a different cwd is rejected.

1.x supports list, load, resume, fork and close but not session/delete or additionalDirectories.

Source

session/list, session/load and session/delete work over pi's own session files in ~/.pi/agent/sessions/ (or the configured sessionDir), so sessions started in the editor can be /resumed in the pi terminal and vice versa. session/resume and fork are not implemented.

session/delete removes the pi session file from disk.

Without a cwd filter, the list defaults to the last session's working directory, like pi's /resume picker.

Source
Switch mode or model from the editor

session/set_mode and config options switch between read-only, workspace-write, agent (Auto review, the default) and agent-full-access; INITIAL_AGENT_MODE picks the starting mode. Config options also cover model, reasoning_effort, fast-mode (where the model supports it) and collaboration_mode (Default or Plan).

Source

session/set_mode switches among default (Manual), acceptEdits, plan, auto and, unless disabled by settings or running as root outside a sandbox, bypassPermissions. Model, effort (thought_level) and Fast mode are session config options changed with session/set_config_option; there is no separate session/set_model handler.

The mode is also exposed as a config option, so clients that only use config options can switch it too.

Source

session/new returns modes agent, plan and ask plus the full model list, and exposes both as configOptions (mode, model). Switch them with session/set_mode, session/set_config_option or session/set_model. Model ids carry Cursor's bracketed parameters, such as claude-opus-4-8[thinking=true,context=300k,effort=high,fast=false].

Source

Each session exposes config options model (enabled models as provider/model, optional /variant), effort (model variants, when the model has them) and mode (visible primary agents such as build and plan). Change them with session/set_config_option; session/set_mode also switches the agent.

2.x has no session/set_model; use the model config option. 1.x also implements the unstable session/set_model.

OpenCode sends config_option_update when available models or agents change or another client changes the session's model or agent.

Source

Sessions expose two config options: Model (all models pi can use) and Thinking (pi's thinking levels), via session/set_config_option. The legacy session/set_mode and session/set_model map to the thinking level and model respectively; there are no plan/ask-style modes.

Some clients that expect a mode-category option (e.g. JetBrains) may not handle the thinking-level selector correctly.

Source
Slash commands and skills

The adapter sends available_commands_update with built-ins /plan, /mcp, /skills, /status, /review, /review-branch, /review-commit, /compact, /goal, /rename and /logout, plus every Codex skill found for the session's roots as $skill-name.

Codex custom prompts are not listed; skills are.

Source

After session setup the agent sends available_commands_update with Claude Code's slash commands, including custom commands, skills and MCP prompts. A few terminal-only commands such as /clear, /cost, /login, /logout and /todos are withheld, and /mcp is answered by the adapter itself.

Source

After session/new or session/load, the agent sends available_commands_update listing Cursor commands and skills (built-in, global and project, e.g. create-skill, loop, rename-chat). Sending /name args as prompt text runs the matching command or skill.

Source

After a session is created or loaded OpenCode sends available_commands_update with the project's custom commands plus the built-in compact, and resends it when commands change. A prompt starting with /name runs that command with the rest of the text as arguments.

Built-in TUI commands such as /undo and /redo are not available over ACP.

Source

Partly

After session/new and session/load the adapter sends available_commands_update with pi prompt templates (~/.pi/agent/prompts, .pi/prompts), skill commands as /skill:<name> when enabled in pi settings, and adapter built-ins such as /compact, /session, /name, /export. Commands registered by pi extensions are not exposed.

/model and /clear are not implemented; use the editor's model selector and new-session command instead.

Source

Working with the editor

QuestionCodex CLIchecked at codex-acp 2.2.2, Codex 0.162.1Claude Codechecked at claude-agent-acp 0.90.0Cursor Agentchecked at 2026.10.12OpenCodechecked at 2.0.29pichecked at pi-acp 0.0.34
Approving tool calls

Codex approval requests become session/request_permission with options such as Yes, proceed (allow_once), Yes, and don't ask again for this command in this session or for a command prefix (allow_always), network-host allow/block, and No, and tell Codex what to do differently (reject_once). Approval and sandbox policy come from the ACP mode sent on every turn, not from approval_policy/sandbox_mode in config.toml; Codex exec-policy rules still apply, and prefix approvals are saved as rules.

Source

Whenever Claude Code would prompt, the adapter sends session/request_permission with options such as allow_once ("Yes"), allow_always ("Yes, and don't ask again for ...", which saves a Claude Code permission rule) and reject_once ("No"). Claude Code's own permissions allow/deny rules from user, project and local settings, and the current permission mode, still apply, so only undecided calls reach the editor.

Exiting plan mode is offered as a permission request whose options pick the next mode (auto, accept edits, bypass, or manual).

Source

Shell, write, delete, read, MCP and web tool calls go through session/request_permission with the options allow-once, allow-always and reject-once. Choosing allow-always adds the command, path or MCP tool to the CLI's permission allowlist. Existing permissions.allow entries and Run Everything (--force/--yolo) skip the prompt.

Cursor also asks multiple-choice questions and plan approvals through its own cursor/ask_question and cursor/create_plan methods. The question flow falls back to session/request_permission options.

Source

When OpenCode's permission rules say ask, it sends session/request_permission with three options: once (allow_once), always (allow_always) and reject (reject_once). Your opencode.json permission settings still apply, so allow and deny rules never reach the editor; edit requests include a diff preview when one can be built.

Cancelling a prompt rejects any pending permission requests. Requests from subagent (child) sessions carry _meta["opencode/child-session"].

Source

Partly

pi does not ask for approval before tool calls, so tool runs never trigger session/request_permission. The adapter only uses session/request_permission to forward pi extension confirm (Yes/No) and select prompts, so a permission-gate extension installed in pi can ask through the editor.

In RPC mode pi cannot show its project-trust prompt; project resources load only if defaultProjectTrust is always or a saved decision applies.

Source
Edits through the editor's buffers

Not supported

Codex reads and writes files itself on disk; the adapter never calls fs/read_text_file or fs/write_text_file, so unsaved editor buffers are not seen. Edits are reported back as tool calls with ACP diff content, so the editor still shows the change.

Source

Not supported

Claude Code's built-in Read, Edit and Write tools work directly on disk, and the adapter never calls fs/read_text_file or fs/write_text_file, so unsaved editor buffers are not seen. Edits are still reported to the editor as tool calls with diffs.

Source

Not supported

Files are read and written directly on disk, even when the client advertises fs.readTextFile/fs.writeTextFile, so unsaved editor buffers are not seen. Edits still reach the editor as diff content (path, old text, new text) on the permission request and tool call.

Source

Not supported

2.x reads and writes files straight to disk with its own tools and never calls fs/read_text_file or fs/write_text_file, so unsaved editor buffers are not seen. Edit diffs show up in permission requests instead.

1.x (opencode-ai) writes an approved edit back through fs/write_text_file after the permission is granted, so the editor sees the change; it still reads from disk.

Source

Not supported

pi reads and writes files directly on disk; the adapter does not call fs/read_text_file or fs/write_text_file, so unsaved editor buffers are not seen. Edits are still shown in the editor as ACP diff tool-call content built from before/after snapshots.

Source
Commands in the editor's terminal

Not supported

Commands run in Codex's own sandboxed shell; the adapter never calls terminal/create. Output streams into the tool call as terminal content with _meta.terminal_output / terminal_output_delta chunks for clients that declare them (the Zed convention), otherwise as text.

Source

Not supported

Commands run in Claude Code's own Bash tool, and the adapter never calls terminal/create. Clients that opt in with _meta.terminal_output (or terminal_output_delta) get the command output rendered as a terminal via _meta.terminal_info/terminal_output/terminal_exit on the tool call.

Source

Not supported

Commands run in Cursor's own shell, even when the client advertises terminal: true. The agent never calls terminal/create, so output streams back only as tool call updates.

Source

Not supported

Shell commands run in OpenCode's own shell; the ACP layer never calls terminal/create or other client terminal methods. Command output streams back as tool call content.

Source

Not supported

Commands run in pi's own shell via its bash tool; the adapter does not use terminal/create or other editor terminal methods.

Source
MCP servers from the editor

Partly

Servers passed in session/new are added to the session's Codex config for stdio (command) and http transports; sse and acp transports are rejected (mcpCapabilities.sse: false). Codex also keeps loading its own mcp_servers from config.toml, and a requested server whose name already exists there is skipped (set DISABLE_MCP_CONFIG_FILTERING=true to turn that off).

Source

MCP servers passed in session/new are used, with stdio, http and sse transports (mcpCapabilities.http and .sse are advertised). Claude Code also loads its own configured MCP servers from user, project and local settings and .mcp.json, alongside the editor's.

/mcp in the chat lists server status and can reconnect, enable or disable a server; reconnecting a server that needs auth starts MCP OAuth via URL elicitation.

Source

Servers passed in session/new/session/load are used: stdio (command, args, env), and http and sse (url, headers), which are advertised in mcpCapabilities. They are added to the servers from the user's and project's .cursor/mcp.json, which still need approval in the CLI first. Dashboard team MCP servers are not loaded in ACP mode.

Source

Partly

Editors can pass stdio and HTTP MCP servers in session/new, session/load, session/resume and session/fork; OpenCode adds them to the session directory for the life of the opencode acp process, alongside the MCP servers from its own config. SSE servers are rejected with an invalid params error.

HTTP headers are passed through; OAuth is not used for editor-supplied servers. Editor-supplied servers are visible to other sessions in the same directory within that process.

1.x advertises and accepts SSE MCP servers as well.

Source

Partly

MCP servers passed in session/new or session/load are accepted but ignored, and the adapter advertises mcpCapabilities http: false, sse: false. pi itself loads its own configured MCP servers from ~/.pi/agent/mcp.json and .pi/mcp.json, which are available in ACP sessions.

Project-level .pi/mcp.json loads only when the project is trusted, which RPC mode cannot prompt for.

Source
What prompts carry and what streams back

Partly

Prompts accept text, images, embedded resources (inlined as <context> blocks) and resource links (as text links); audio is advertised false and dropped. Back come agent message and thought chunks, plan entries and plan-mode markdown (plan_update when the client declares plan support), tool calls with diffs and command output, usage_update, session title updates and, after negotiation, native subagent sessions.

Source

Partly

Prompts can carry text, images (base64 or http URL), embedded text resources (added as <context> blocks) and resource links; audio and binary blob resources are dropped. Streamed back are message and thought chunks, plans (plan from TodoWrite), tool calls with diffs, terminal output, usage_update with token usage and cost, and subagent child sessions for clients that declare subagents.

Source

Partly

Prompts accept text, images and resource links. Audio is not supported, and embeddedContext is advertised as false. Linked file: URIs inside the project root, and embedded text resources, are inlined as extra context. Streamed back: message and thought chunks, tool calls with diffs, plan entries, mode changes, session titles (session_info_update) and subagent updates; there is no usage_update.

Todo lists, subagent status and generated images also arrive through Cursor's cursor/update_todos, cursor/task and cursor/generate_image notifications.

Source

Prompts can carry text, images, embedded resources and resource links (file:// and zed:// links are attached as files); audio blocks are ignored. Back come message and thought chunks, tool calls with kinds, locations and output, permission diffs, usage_update and end-of-turn usage, plus compaction and retry status.

OpenCode does not send plan updates, and tool call updates carry text/image output rather than diff content.

Subagent activity is forwarded on the parent session with tool call ids prefixed <childSessionId>:. If the client advertises elicitation.form, OpenCode asks questions with elicitation/create.

Source

Partly

Prompts can carry text, images and resource links (passed to pi as a [Context] <uri> line); embedded resources are inlined as text only when PI_ACP_ENABLE_EMBEDDED_CONTEXT=true, and audio is not supported. Back come message chunks, thought chunks, tool calls with file locations and edit diffs, usage_update context occupancy, and session titles; there are no plan updates.

Source

The other direction

QuestionCodex CLIchecked at codex-acp 2.2.2, Codex 0.162.1Claude Codechecked at claude-agent-acp 0.90.0Cursor Agentchecked at 2026.10.12OpenCodechecked at 2.0.29pichecked at pi-acp 0.0.34
Drive other ACP agents

Not supported

Neither Codex 0.162.1 nor the adapter can drive other ACP agents: the Codex CLI has no ACP command or ACP dependency, and the adapter only implements the agent side. Codex subagents are its own threads, which the adapter can surface to the editor as ACP subagent sessions.

Source

Not supported

Neither Claude Code nor the adapter can drive other ACP agents. Claude Code's subagents are its own Agent tool, not ACP agents.

Source

Not supported

The Cursor CLI only acts as an ACP agent. It cannot launch or drive other ACP agents, and its subagents are Cursor's own.

Source

Not supported

OpenCode is only an ACP agent; neither 2.x nor 1.x contains ACP client code to launch or drive other ACP agents. Its subagents are OpenCode's own child sessions.

Source

Not supported

Neither pi nor pi-acp can drive other ACP agents.

The third-party pi extension pi-antigravity-acp-provider runs Google Antigravity's ACP server as a pi model provider; it is a single-purpose provider, not general ACP client support.

Source

Notes and sources

Codex CLI
Claude Code
Cursor Agent
OpenCode
pi