| title | acpx CLI Reference |
|---|---|
| description | Definitive command and behavior reference for the acpx CLI, including grammar, options, session rules, output modes, permissions, and exit codes. |
| author | Bob <bob@dutifulbob.com> |
| date | 2026-02-18 |
acpx is a headless ACP client for scriptable agent workflows.
Default behavior is conversational:
- prompt commands use a persisted session
- session lookup is scoped by agent command and working directory (plus optional session name)
execruns one prompt in a temporary session
Global options apply to all commands.
acpx [global_options] [prompt_text...]
acpx [global_options] prompt [prompt_options] [prompt_text...]
acpx [global_options] exec [prompt_options] [prompt_text...]
acpx [global_options] flow run <file> [--input-json <json> | --input-file <path>] [--default-agent <name>]
acpx [global_options] cancel [-s <name>]
acpx [global_options] set-mode <mode> [-s <name>]
acpx [global_options] set <key> <value> [-s <name>]
acpx [global_options] status [-s <name>]
acpx [global_options] sessions [list | new [--name <name>] | ensure [--name <name>] | close [name] | show [name] | history [name] [--limit <count>]]
acpx [global_options] config [show | init]
acpx [global_options] <agent> [prompt_options] [prompt_text...]
acpx [global_options] <agent> prompt [prompt_options] [prompt_text...]
acpx [global_options] <agent> exec [prompt_options] [prompt_text...]
acpx [global_options] <agent> cancel [-s <name>]
acpx [global_options] <agent> set-mode <mode> [-s <name>]
acpx [global_options] <agent> set <key> <value> [-s <name>]
acpx [global_options] <agent> status [-s <name>]
acpx [global_options] <agent> sessions [list | new [--name <name>] | ensure [--name <name>] | close [name] | show [name] | history [name] [--limit <count>]]<agent> can be:
- built-in friendly name from ../README.md
- unknown token (treated as raw command)
- overridden by
--agent <command>escape hatch
Additional built-in agent docs live in ../agents/README.md.
Prompt options:
-s, --session <name> Use named session instead of cwd default
--no-wait Queue prompt and return immediately if session is busy
-f, --file <path> Read prompt text from file (`-` means stdin)Notes:
- Top-level
prompt,exec,cancel,set-mode,set,sessions, and bareacpx <prompt>default tocodex. - Top-level
flow run <file>executes a user-authored workflow module and persists run state under~/.acpx/flows/runs/. - If a prompt argument is omitted,
acpxreads prompt text from stdin when piped. --fileworks for implicit prompt,prompt, andexeccommands.acpxwith no args in an interactive terminal shows help.
acpx [global_options] flow run <file> [--input-json <json> | --input-file <path>] [--default-agent <name>]- Runs a user-authored workflow module step by step through the
acpx/flowsruntime. - Persists run artifacts under
~/.acpx/flows/runs/<runId>/. - Reuses one implicit main ACP session by default for non-isolated
acpnodes. acpnodes may override their working directory per step, which lets flows prepare an isolated workspace with an action node and then keep the agent session inside that cwd.acpandactionnodes use the global--timeoutvalue as their default step timeout. If--timeoutis omitted, flows default to 15 minutes per active step.- Flows may declare permission requirements. If a flow requires an explicit grant such as
approve-all,acpxfails fast before starting the flow and tells you which permission flag to pass. --input-jsonpasses flow input inline as JSON.--input-filereads flow input JSON from disk.--default-agentsupplies the default agent profile foracpnodes that do not pin one.- The file is always provided by the caller at runtime.
acpxdoes not require any built-in flow registry. - The source repo includes example flow files under
examples/flows/, including a larger PR-triage example underexamples/flows/pr-triage/.
Example invocations:
acpx flow run ./my-flow.ts --input-file ./flow-input.json
acpx flow run examples/flows/branch.flow.ts \
--input-json '{"task":"FIX: add a regression test for the reconnect bug"}'
acpx --approve-all flow run examples/flows/pr-triage/pr-triage.flow.ts \
--input-json '{"repo":"openclaw/acpx","prNumber":150}'The PR-triage example is only an example workflow. It can post GitHub comments or close a PR if you run it against a live repository.
All global options:
| Option | Description | Details |
|---|---|---|
--agent <command> |
Raw ACP agent command (escape hatch) | Do not combine with positional agent token. |
--cwd <dir> |
Working directory | Defaults to current directory. Stored as absolute path for scoping. |
--approve-all |
Auto-approve all permissions | Permission mode approve-all. |
--approve-reads |
Auto-approve reads/searches, prompt for others | Default permission mode. |
--deny-all |
Deny all permissions | Permission mode deny-all. |
--format <fmt> |
Output format | text (default), json, quiet. |
--suppress-reads |
Suppress read file contents | Replaces raw read payloads with [read output suppressed]. |
--json-strict |
Strict JSON mode | Requires --format json; suppresses non-JSON stderr output. |
--no-terminal |
Disable ACP terminal capability | Advertises clientCapabilities.terminal: false during ACP initialize for new agent clients. |
--non-interactive-permissions <policy> |
Non-TTY prompt policy | deny (default) or fail when approval prompt cannot be shown. |
--timeout <seconds> |
Max wait time for agent response | Must be positive. Decimal seconds allowed. |
--ttl <seconds> |
Queue owner idle TTL before shutdown | Default 300. 0 disables TTL. |
--model <id> |
Set agent model | Claude-compatible adapters may consume session creation metadata; other agents must advertise ACP models and support session/set_model, otherwise acpx fails clearly instead of silently falling back. |
--verbose |
Enable verbose logs | Prints ACP/debug details to stderr. |
Permission flags are mutually exclusive. Using more than one of --approve-all, --approve-reads, --deny-all is a usage error.
acpx --approve-all codex 'apply this patch and run tests'
acpx --approve-reads codex 'inspect the repo and propose a plan'
acpx --deny-all codex 'summarize this code without running tools'
acpx --non-interactive-permissions fail codex 'fail fast when prompt cannot be shown'
acpx --cwd ~/repos/api codex 'review auth middleware'
acpx --format json codex exec 'summarize open TODO items'
acpx --format json --json-strict codex exec 'machine-safe JSON output'
acpx --no-terminal codex exec 'summarize without terminal capability'
acpx --timeout 120 codex 'investigate flaky test failures'
acpx --ttl 30 codex 'keep queue owner warm for quick follow-up'
acpx --verbose codex 'debug adapter startup issues'Each agent command supports the same shape.
acpx [global_options] pi [prompt_options] [prompt_text...]
acpx [global_options] pi prompt [prompt_options] [prompt_text...]
acpx [global_options] pi exec [prompt_text...]
acpx [global_options] pi sessions [list | new [--name <name>] | ensure [--name <name>] | close [name]]Built-in command mapping: pi -> npx pi-acp
acpx [global_options] openclaw [prompt_options] [prompt_text...]
acpx [global_options] openclaw prompt [prompt_options] [prompt_text...]
acpx [global_options] openclaw exec [prompt_text...]
acpx [global_options] openclaw sessions [list | new [--name <name>] | ensure [--name <name>] | close [name]]Built-in command mapping: openclaw -> openclaw acp
For repo-local OpenClaw checkouts, override the built-in command in config:
{
"agents": {
"openclaw": {
"command": "env OPENCLAW_HIDE_BANNER=1 OPENCLAW_SUPPRESS_NOTES=1 node scripts/run-node.mjs acp --url ws://127.0.0.1:18789 --token-file ~/.openclaw/gateway.token --session agent:main:main"
}
}
}acpx [global_options] codex [prompt_options] [prompt_text...]
acpx [global_options] codex prompt [prompt_options] [prompt_text...]
acpx [global_options] codex exec [prompt_text...]
acpx [global_options] codex sessions [list | new [--name <name>] | ensure [--name <name>] | close [name]]Built-in command mapping: codex -> npx @zed-industries/codex-acp
acpx [global_options] claude [prompt_options] [prompt_text...]
acpx [global_options] claude prompt [prompt_options] [prompt_text...]
acpx [global_options] claude exec [prompt_text...]
acpx [global_options] claude sessions [list | new [--name <name>] | ensure [--name <name>] | close [name]]Built-in command mapping: claude -> npx -y @agentclientprotocol/claude-agent-acp
Additional built-in agent docs live in ../agents/README.md.
Unknown agent names are treated as raw commands:
acpx [global_options] my-agent [prompt_options] [prompt_text...]
acpx [global_options] my-agent exec [prompt_text...]
acpx [global_options] my-agent sessionsPersistent-session prompt command:
acpx [global_options] <agent> prompt [prompt_options] [prompt_text...]
acpx [global_options] prompt [prompt_options] [prompt_text...]Behavior:
- Finds existing session for scope key
(agentCommand, cwd, name?) - Does not auto-create sessions; missing scope exits with code
4and guidance to runsessions new - Sends prompt on resumed/new session
- If another prompt is already running for that session, submits to the running queue owner instead of starting a second ACP subprocess
- By default waits for queued prompt completion;
--no-waitreturns after queue acknowledgement - Updates session metadata after completion
The agent command itself also has an implicit prompt form:
acpx [global_options] <agent> [prompt_options] [prompt_text...]
acpx [global_options] [prompt_text...] # defaults to codexOne-shot prompt (no saved session):
acpx [global_options] <agent> exec [prompt_options] [prompt_text...]
acpx [global_options] exec [prompt_options] [prompt_text...] # defaults to codexBehavior:
- Creates temporary ACP session
- Sends prompt once
- Does not write/use a saved session record
- Supports prompt text from args, stdin,
--file <path>, and--file -
acpx [global_options] <agent> cancel [-s <name>]
acpx [global_options] cancel [-s <name>] # defaults to codexBehavior:
- Sends cooperative
session/cancelthrough queue-owner IPC when a prompt is running. - If no prompt is running, prints
nothing to canceland exits success.
acpx [global_options] <agent> set-mode <mode> [-s <name>]
acpx [global_options] set-mode <mode> [-s <name>] # defaults to codexBehavior:
- Calls ACP
session/set_mode. <mode>values are adapter-defined (not globally standardized across all ACP adapters).- Unsupported mode ids are rejected by the adapter (often as
Invalid params). - Routes through queue-owner IPC when an owner is active.
- Falls back to a direct client reconnect when no owner is running.
acpx [global_options] <agent> set <key> <value> [-s <name>]
acpx [global_options] set <key> <value> [-s <name>] # defaults to codexBehavior:
- Calls ACP
session/set_config_option. - Routes through queue-owner IPC when an owner is active.
- Falls back to a direct client reconnect when no owner is running.
set model <id>: Intercepted to callsession/set_modelinstead. Some agents supportsession/set_modelbut notsession/set_config_optionfor model changes; routing through the dedicated method ensures broad compatibility.
acpx [global_options] <agent> sessions
acpx [global_options] <agent> sessions list
acpx [global_options] <agent> sessions new
acpx [global_options] <agent> sessions new --name <name>
acpx [global_options] <agent> sessions ensure
acpx [global_options] <agent> sessions ensure --name <name>
acpx [global_options] <agent> sessions close
acpx [global_options] <agent> sessions close <name>
acpx [global_options] <agent> sessions show
acpx [global_options] <agent> sessions show <name>
acpx [global_options] <agent> sessions history
acpx [global_options] <agent> sessions history <name> [--limit <count>]
acpx [global_options] <agent> sessions prune [--dry-run] [--before <date> | --older-than <days>] [--include-history]
acpx [global_options] sessions ... # defaults to codexBehavior:
sessionsandsessions listare equivalent- list returns all saved sessions for selected
agentCommand(across all cwd values) sessions newcreates a fresh cwd-scoped default sessionsessions new --name <name>creates a fresh named session for cwd- creating a fresh session soft-closes the previous open session in that scope (if present)
- text and quiet output print the local
acpxRecordId; JSON output also includesacpxSessionIdand, when the adapter exposes one,agentSessionId sessions ensurereturns the nearest matching active session or creates one for cwdsessions ensure --name <name>does the same for named sessionssessions closesoft-closes the current cwd default sessionsessions close <name>soft-closes current cwd named sessionsessions show [name]displays stored session metadatasessions history [name]displays stored turn history previews (default 20, configurable with--limit)sessions prune --dry-runpreviews closed sessions that can be deletedsessions prunedeletes closed session records for the selected agent; add--include-historyto delete event stream files toosessions prune --before <date>and--older-than <days>filter by close time, falling back to last-used time for older records- close errors if the target session does not exist
acpx [global_options] <agent> status
acpx [global_options] <agent> status -s <name>
acpx [global_options] status
acpx [global_options] status -s <name>Shows local process status for the cwd-scoped session:
running,idle,dead, orno-session- session id, agent command, pid
- uptime when running
- last prompt timestamp
- last known exit code/signal when dead
idle means the persistent session is saved and resumable, but no queue owner is
currently running. The next prompt starts a queue owner and reconnects the
session.
Status checks are local and PID-based (kill(pid, 0) semantics).
acpx [global_options] config show
acpx [global_options] config initconfig showprints the resolved config from global + project files.config initwrites a default global config template if missing.
Config files:
- global:
~/.acpx/config.json - project:
<cwd>/.acpxrc.json(merged on top of global)
Supported keys:
{
"defaultAgent": "codex",
"defaultPermissions": "approve-all",
"nonInteractivePermissions": "deny",
"authPolicy": "skip",
"ttl": 300,
"timeout": null,
"format": "text",
"agents": {
"my-custom": { "command": "./bin/my-acp-server", "args": ["acp"] }
},
"auth": {
"my_auth_method_id": "credential-value"
}
}CLI flags always override config values.
For ACP authenticate handshakes, use either config auth entries or explicit
ACPX_AUTH_<METHOD_ID> environment variables such as ACPX_AUTH_OPENAI_API_KEY.
Ambient provider env vars such as OPENAI_API_KEY are still passed through to
child agents, but they do not trigger ACP auth-method selection on their own.
--agent <command> sets a raw adapter command explicitly.
Examples:
acpx --agent ./my-custom-acp-server 'do something'
acpx --agent 'node ./scripts/acp-dev-server.mjs --mode ci' exec 'summarize changes'Rules:
- Do not combine positional agent and
--agentin one command. - The resolved command string becomes the session scope key (
agentCommand). - Invalid empty command or unterminated quoting in
--agentis a usage error.
Session records are stored in:
~/.acpx/sessions/*.json
For prompt commands:
- Detect the nearest git root by checking for
.gitwhile walking up fromabsoluteCwd. - If a git root is found, walk from
absoluteCwdup to that git root (inclusive). - If no git root exists, only check exact
absoluteCwd(no parent-directory walk). - At each checked directory, find the first active (non-closed) session matching
(agentCommand, dir, optionalName). - If found, use that session record for prompt queueing and resume attempts.
- If not found, exit with code
4and print guidance to create one viasessions new.
Use sessions new [--name <name>] when you explicitly want a fresh scoped session.
Use sessions ensure [--name <name>] when you want idempotent "get-or-create" behavior.
If a saved session PID is dead, acpx respawns the agent, tries session/load, and transparently falls back to session/new when loading fails.
When a prompt is already in flight for a session, acpx uses a per-session queue owner process:
- owner process keeps the active turn running
- other
acpxinvocations enqueue prompts through local IPC - owner drains queued prompts one-by-one after each completed turn
- after the queue drains, owner waits for new work up to TTL (
--ttl, default 300s) - submitter either blocks until completion (default) or exits immediately with
--no-wait - if interrupted (
Ctrl+C) during an active turn,acpxsendssession/cancelfirst, waits briefly for cancelled completion, then force-kills only if needed
- soft-closed sessions remain on disk with
closed: trueandclosedAt - auto-resume ignores closed sessions during scope lookup
- closed sessions still keep full record data and can be resumed explicitly via record id/session load flows
- session records also keep lightweight turn history previews used by
sessions history
-s, --session <name> adds name into the scope key so multiple parallel conversations can coexist in the same repo and agent command.
--cwd sets the starting point for directory-walk routing (bounded by git root) and the exact scope directory when creating sessions via sessions new.
--format controls output mode:
text(default): human-readable streamjson: raw ACP NDJSON stream for automationquiet: assistant text only--format json --json-strict: same ACP NDJSON stream, with non-JSON stderr output suppressed
text: assistant text, tool status blocks, client-operation logs, plan updates, and[done] <reason>json: one raw ACP JSON-RPC message per linequiet: concatenated assistant text only
When --suppress-reads is enabled:
text: read-like tool outputs render as[read output suppressed]json: ACPfs/read_text_fileresponses and read-like tool-call outputs replace raw file contents with[read output suppressed]quiet: unchanged, because quiet mode only prints assistant text
ACP message examples:
{"jsonrpc":"2.0","id":"req-1","method":"session/prompt","params":{"sessionId":"019c...","prompt":"hi"}}
{"jsonrpc":"2.0","method":"session/update","params":{"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":"Hello"}}}
{"jsonrpc":"2.0","id":"req-1","result":{"stopReason":"end_turn"}}Hard rule for the ACP stream:
- no acpx-specific event envelope,
- no synthetic
type/streamwrapper fields, - no ACP payload key renaming.
When --format json is used:
- commands that talk to an ACP adapter emit raw ACP JSON-RPC messages.
- local query commands (
sessions list/show/history/prune) emit local JSON documents (not ACP stream traffic).
sessions listwithtext: tab-separatedid,name,cwd,lastUsedAt(closed sessions include a[closed]marker next to id)sessions listwithjson: a single JSON array of session recordssessions listwithquiet: one session id per line (closed sessions include[closed])sessions showwithtext: key/value metadata dumpsessions showwithjson: full session record objectsessions historywithtext: tab-separatedtimestamp role textPreviewentriessessions historywithjson: object containingentriesarraysessions prunewithtext: summary plus pruned ids and close/last-used timesessions prunewithjson: object containingaction,dryRun,count,bytesFreed, andprunedsessions prunewithquiet: one pruned session id per linestatuswithtext: key/value process status lines
Choose exactly one mode:
--approve-all: auto-approve all permission requests--approve-reads: auto-approve read/search requests, prompt for other kinds (default)--deny-all: auto-deny/reject requests when possible
Prompting behavior in --approve-reads:
- interactive TTY: asks
Allow <tool>? (y/N)for non-read/search requests - non-interactive (no TTY): non-read/search requests are not approved
Non-interactive prompt policy:
--non-interactive-permissions deny: deny non-read/search prompts when no TTY (default)--non-interactive-permissions fail: fail withPERMISSION_PROMPT_UNAVAILABLE
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Agent/protocol/runtime error |
2 |
CLI usage error |
3 |
Timeout |
4 |
No session found (prompt requires an explicit sessions new) |
5 |
Permission denied (permission requested, none approved, and at least one denied/cancelled) |
130 |
Interrupted (SIGINT/SIGTERM) |
No acpx-specific environment variables are currently defined.
Related runtime behavior:
- session storage path is derived from OS home directory (
~/.acpx/sessions) - child processes inherit the current environment by default
# Review a PR in a dedicated named session
acpx --cwd ~/repos/shop codex sessions new --name pr-842
acpx --cwd ~/repos/shop codex -s pr-842 \
'Review PR #842, list risks, and propose a minimal patch'
# Continue that same PR review later
acpx --cwd ~/repos/shop codex -s pr-842 \
'Now draft commit message and rollout checklist'
# Parallel workstreams in one repo
acpx codex sessions new --name backend
acpx codex sessions new --name docs
acpx codex -s backend 'fix checkout timeout'
acpx codex -s docs 'document payment retry behavior'
# One-shot ask with no saved context
acpx claude exec 'summarize src/session.ts in 5 bullets'
# Manage sessions
acpx codex sessions
acpx codex sessions new --name docs
acpx codex sessions show docs
acpx codex sessions history docs --limit 10
acpx codex sessions close docs
acpx codex status
# Prompt from file/stdin
echo 'triage failing tests' | acpx codex
acpx codex --file prompt.md
acpx codex --file - 'also check lint warnings'
# Config inspection
acpx config show
acpx config init
# JSON automation pipeline
acpx --format json codex exec 'review latest diff for security issues' \
| jq -r 'select(.type=="tool_call") | [.status, .title] | @tsv'