Agent Client Protocol

// LSP-for-coding-agents · standardize how editors talk to AI agents · use acpx as the headless client

What ACP is

The Agent Client Protocol is a JSON-RPC standard for communication between code editors and AI coding agents. An agent that speaks ACP works in any ACP-capable editor; an editor that speaks ACP works with any ACP-capable agent. Think LSP, but for "edit my code with an LLM" instead of "tell me what's at this cursor."

Maintained by Sergey Ignatov (lead). Spec lives at agentclientprotocol.com; OpenAPI at /api-reference/openapi.json; libraries in Rust, TypeScript, Python, Java, Kotlin.

Why it exists

Three friction points it eliminates:

The LSP analogy. Before LSP, every editor wrote its own type-checking integration for every language. After LSP, one server per language, one client per editor. ACP applies the same insight to coding agents.

Actors

actorroleexamples
AgentProgram that uses generative AI to autonomously modify code. Receives prompts, emits updates, requests permission for risky ops.Codex, Claude, Gemini, Pi, OpenClaw, Cursor agent
ClientTypically a code editor or orchestrator. Manages the workspace, files, terminals; renders updates to the user.VSCode, Zed, Neovim, JetBrains, acpx

Transports

ACP uses JSON-RPC 2.0 over one of:

┌────────────┐                                     ┌────────────┐
│   Client   │ ── JSON-RPC 2.0 over stdio/ws ──→  │   Agent    │
│ (editor or │ ←── notifications + responses ──   │ (LLM tool) │
│  acpx CLI) │                                     │            │
└────────────┘                                     └────────────┘
       │                                                  │
       └─── manages files/terminals ←─── requests ────────┘

Lifecycle

  1. Initialize. Client calls initialize; agent responds with capabilities.
  2. Authenticate (optional). Client calls authenticate if the agent requires credentials.
  3. Session setup. session/new creates a fresh session; session/load resumes a prior one.
  4. Prompt turn. Client calls session/prompt; agent streams session/update notifications, may request file ops, terminal exec, or permission. Eventually the prompt response arrives with a stop reason.
  5. Cancel (optional). Client sends session/cancel notification at any time during a turn.
  6. Session close (optional but recommended for long-running agents).

Method reference

Agent methods (client → agent)

methodpurpose
initializeHandshake; exchange protocol version + capabilities
authenticateOptional auth flow before sessions
session/newCreate a new conversation session
session/loadResume a previously-created session by id
session/promptSend a user message; receive the turn's stop reason
session/set_modeSwitch operating mode (plan / edit / autonomous, agent-defined)
session/cancelNotification — interrupt the current turn

Client methods (agent → client)

methodpurpose
session/updateNotification — progress: text deltas, tool calls, plan updates
session/request_permissionAsk user to approve a risky operation
fs/read_text_fileRead a file from the workspace
fs/write_text_fileWrite a file (after permission)
terminal/createSpawn a shell session
terminal/outputRead terminal output
terminal/wait_for_exitBlock until the command exits
terminal/killForce-terminate a running command
terminal/releaseRelease the terminal handle

A complete prompt turn

// 1. Client opens session
→ {"jsonrpc":"2.0","id":1,"method":"session/new","params":{"workspace_root":"/Users/me/myproj"}}
← {"jsonrpc":"2.0","id":1,"result":{"session_id":"sess_abc"}}

// 2. Client sends a prompt
→ {"jsonrpc":"2.0","id":2,"method":"session/prompt","params":{
    "session_id":"sess_abc",
    "messages":[{"role":"user","content":[{"type":"text","text":"fix the flaky test"}]}]
  }}

// 3. Agent streams updates back as notifications
← {"jsonrpc":"2.0","method":"session/update","params":{"type":"agent_message_chunk","text":"Looking at "}}
← {"jsonrpc":"2.0","method":"session/update","params":{"type":"tool_call","id":"tc_1","name":"read_file",...}}

// 4. Agent asks the client to read a file
← {"jsonrpc":"2.0","id":"r1","method":"fs/read_text_file","params":{"path":"tests/flaky.test.ts"}}
→ {"jsonrpc":"2.0","id":"r1","result":{"content":"..."}}

// 5. Agent asks permission to write
← {"jsonrpc":"2.0","id":"p1","method":"session/request_permission",
   "params":{"tool":"write_file","path":"tests/flaky.test.ts","diff":"..."}}
→ {"jsonrpc":"2.0","id":"p1","result":{"granted":true}}

// 6. Agent writes
← {"jsonrpc":"2.0","id":"w1","method":"fs/write_text_file",...}

// 7. Agent finishes the turn
← {"jsonrpc":"2.0","id":2,"result":{"stop_reason":"end_turn"}}

Tool calls & updates

Every action an agent takes during a turn — reading a file, running a command, editing code — surfaces to the client as a session/update notification carrying a content block. Content types include text deltas, tool-call markers, plan updates, diffs, and terminal output. Reusing MCP-compatible content shapes where possible; custom types layered on top for agentic UX (notably diffs).

Permissions

Risky operations — writing files, executing shell commands, deleting things — go through session/request_permission. The client decides how to surface the request to the user (modal dialog, auto-approve list, batch confirmation). The agent waits for the response before proceeding.

Why this matters. Permissions in ACP are first-class messages, not policy hacks. An autonomous orchestrator can implement "auto-approve any read; ask once per session for writes; never permit shell" as plain logic in the client. No prompt-engineering required.

Sessions — new, load, list, resume, fork

A session is a turn-by-turn conversation, persisted by the agent. The protocol defines:

acpx — the headless ACP client

openclaw/acpx is a CLI ACP client. It exists so that LLM orchestrators (autoresearch loops, CI bots, Claude Code itself) can drive coding agents over a structured protocol instead of scraping pseudo-TTYs.

factvalue
languageTypeScript / Node.js
installnpm install -g acpx@latest or npx acpx@latest
version0.6.0 (alpha — interfaces still moving)
licenseMIT
built-in adapterscodex, claude, gemini, cursor, pi, openclaw — auto-downloaded via npx on first use

One-shot prompt

# talk to Codex over ACP, one prompt, no session
acpx codex "fix the flaky test in tests/auth.spec.ts"

# point at a custom ACP-server binary
acpx --agent ./my-acp-server "summarize this repo"

# run a flow file (multi-step orchestration)
acpx flow run ./repair.flow.ts --input-file ./input.json

Persistent sessions

# list / new / show / history / close
acpx codex sessions new
acpx codex sessions list
acpx codex sessions show sess_abc
acpx codex -s backend "implement token pagination"
acpx codex sessions close sess_abc

Control + config

acpx cancel sess_abc                    # interrupt a running turn
acpx set-mode sess_abc plan             # switch operating mode
acpx set sess_abc max_tokens 4096       # session config option
acpx config show
acpx status

Why use acpx instead of raw stdio

SDKs

Official libraries (mint a server or client in your language of choice):

Extensibility

ACP defines a _meta property on most messages that propagates user data through the protocol. Custom capabilities are negotiated during initialize: each side advertises what it supports, and both sides agree on the intersection. Active RFDs add proxy chains (one ACP server fronting several agents), MCP-over-ACP transport, telemetry export, and elicitation (structured user input).

Integrate with this project

Concrete plays for the Organized AI / clip-pipeline setup:

  1. Use acpx as the planner shim. The autoresearch loops in posthog-autoresearch-guide currently fork subprocesses to drive Codex/Claude. Swap that for acpx codex --json, get structured tool calls, log session/update events to PostHog as step.tool_called / step.tool_returned automatically.
  2. Run an ACP server for the clip pipeline. Wrap portrait-foreignfilm-clips as an ACP agent that exposes render, retranscribe, upload as tools. Then any ACP client (acpx, Zed, the dashboard) can drive a render with one prompt.
  3. Standardize the dashboard's "queue a render" button. Today the pipeline-viz dashboard would need bespoke API calls. With ACP, the dashboard speaks one protocol to any agent — local clip-render agent today, remote one tomorrow.
  4. Token Machine routing. Token Machine sits in front of model calls. ACP agents call models. Wire Token Machine as the ACP agent's outbound HTTP transport and you get cost routing for free, with $ai_generation events still flowing through PostHog.

Pitfalls