acp-cli
Headless CLI client for the Agent Client Protocol (ACP). Talk to coding agents (Claude, Codex, Gemini, etc.) over structured JSON-RPC instead of terminal scraping.
Rust port of ACPX.
Release Highlights (v0.3.1)
--suppress-readsnow works correctly: v0.3.0 silently dropped all tool-completion events due to a protocol handling bug. Fixed by correctly handlingToolCallUpdateand usingToolKind::Readfrom the ACP SDK instead of fragile name matching.- No
prompt_donenoise in queue client: straySession: event(prompt_done): end_turnline no longer appears.
See v0.3.0 below for the full feature set.
Release Highlights (v0.3.0)
--prompt-retries <n>: automatically retry transient failures (spawn errors, connection drops) with exponential backoff and jitter.--suppress-reads: hide file-read body content in text and JSON output; tool name still shown.- New agents:
iflow,qoder,trae. - Agent fixes: claude package renamed to
@agentclientprotocol/claude-agent-acp@^0.24.2, kiro command updated tokiro-cli-chat, pinned npm versions for codex and pi.
Install
Quick Start
# 1. Setup (detect auth, write config)
# 2. Talk to Claude
Usage
# Prompt (persistent session)
# One-shot (no session persistence)
# Read prompt from file
# Pipe from stdin
|
# Different agents
# Named sessions for parallel work
# Output formats
# Timeout
Commands
Flags
| Flag | Default | Description |
|---|---|---|
-s, --session <name> |
Named session | |
--approve-all |
Auto-approve all tool calls | |
--approve-reads |
default | Approve read-only tools, deny writes |
--deny-all |
Deny all tool calls | |
--cwd <dir> |
. |
Working directory |
--format text|json|quiet |
text |
Output format |
--timeout <seconds> |
Max wait time | |
-f, --file <path> |
Read prompt from file (- for stdin) |
|
--no-wait |
Fire-and-forget (queue and return) | |
--agent-override <cmd> |
Raw ACP command override | |
--prompt-retries <n> |
0 |
Retry transient failures with exponential backoff |
--suppress-reads |
Hide file-read body content in output |
Config
Run acp-cli init or create ~/.acp-cli/config.json manually:
Project-level config: .acp-cli.json in git root (same format, overrides global).
Auth Token Resolution
Token for Claude is resolved in order:
ANTHROPIC_AUTH_TOKENenvironment variable~/.acp-cli/config.json→auth_token~/.claude.json→oauthAccount.accessToken- macOS Keychain (
Claude Codeservice)
Note: OAuth tokens (sk-ant-oat01-*) are detected but not injected via env var — the Claude Agent SDK resolves them from Keychain internally using the correct auth flow.
Supported Agents
| Agent | Command | Type |
|---|---|---|
| claude | npx @agentclientprotocol/claude-agent-acp@^0.24.2 |
npm |
| codex | npx @zed-industries/codex-acp@^0.10.0 |
npm |
| gemini | gemini --acp |
native |
| copilot | copilot --acp --stdio |
native |
| cursor | cursor-agent acp |
native |
| goose | goose acp |
native |
| kiro | kiro-cli-chat acp |
native |
| pi | npx pi-acp@^0.0.22 |
npm |
| openclaw | openclaw acp |
native |
| opencode | npx opencode-ai acp |
npm |
| kilocode | npx @kilocode/cli acp |
npm |
| kimi | kimi acp |
native |
| qwen | qwen --acp |
native |
| droid | droid exec --output-format acp |
native |
| iflow | iflow --experimental-acp |
native |
| qoder | qodercli --acp |
native |
| trae | traecli acp serve |
native |
Unknown agent names are treated as raw commands.
Sessions
Sessions auto-resume by matching (agent, git_root, session_name).
The first acp-cli process for a session becomes the queue owner (holds the agent connection). Subsequent processes connect as queue clients via Unix socket.
Architecture
Main thread (Send) ACP thread (!Send, LocalSet)
├── CLI parsing ├── AcpConnection (spawn_local)
├── Output rendering ├── ClientSideConnection I/O
├── Permission resolution └── BridgedAcpClient callbacks
├── Signal handling
└── Queue IPC server Channel bridge (mpsc + oneshot)
Library Usage
acp-cli can be used as a Rust library:
use AcpBridge;
use PathBuf;
let bridge = start.await?;
let result = bridge.prompt.await?;
bridge.shutdown.await?;
License
MIT