Skip to content

Latest commit

 

History

History
603 lines (448 loc) · 26.9 KB

File metadata and controls

603 lines (448 loc) · 26.9 KB
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

Overview

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)
  • exec runs one prompt in a temporary session

Full command grammar

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 bare acpx <prompt> default to codex.
  • 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, acpx reads prompt text from stdin when piped.
  • --file works for implicit prompt, prompt, and exec commands.
  • acpx with no args in an interactive terminal shows help.

flow run subcommand

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/flows runtime.
  • Persists run artifacts under ~/.acpx/flows/runs/<runId>/.
  • Reuses one implicit main ACP session by default for non-isolated acp nodes.
  • acp nodes 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.
  • acp and action nodes use the global --timeout value as their default step timeout. If --timeout is 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, acpx fails fast before starting the flow and tells you which permission flag to pass.
  • --input-json passes flow input inline as JSON.
  • --input-file reads flow input JSON from disk.
  • --default-agent supplies the default agent profile for acp nodes that do not pin one.
  • The file is always provided by the caller at runtime. acpx does not require any built-in flow registry.
  • The source repo includes example flow files under examples/flows/, including a larger PR-triage example under examples/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.

Global options

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.

Global option examples

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'

Agent commands

Each agent command supports the same shape.

pi

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

openclaw

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"
    }
  }
}

codex

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

claude

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.

Custom positional agents

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 sessions

prompt subcommand (explicit)

Persistent-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 4 and guidance to run sessions 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-wait returns 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 codex

exec subcommand

One-shot prompt (no saved session):

acpx [global_options] <agent> exec [prompt_options] [prompt_text...]
acpx [global_options] exec [prompt_options] [prompt_text...]   # defaults to codex

Behavior:

  • 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 -

cancel command

acpx [global_options] <agent> cancel [-s <name>]
acpx [global_options] cancel [-s <name>]   # defaults to codex

Behavior:

  • Sends cooperative session/cancel through queue-owner IPC when a prompt is running.
  • If no prompt is running, prints nothing to cancel and exits success.

set-mode command

acpx [global_options] <agent> set-mode <mode> [-s <name>]
acpx [global_options] set-mode <mode> [-s <name>]   # defaults to codex

Behavior:

  • 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.

set command

acpx [global_options] <agent> set <key> <value> [-s <name>]
acpx [global_options] set <key> <value> [-s <name>]   # defaults to codex

Behavior:

  • 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 call session/set_model instead. Some agents support session/set_model but not session/set_config_option for model changes; routing through the dedicated method ensures broad compatibility.

sessions subcommand

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 codex

Behavior:

  • sessions and sessions list are equivalent
  • list returns all saved sessions for selected agentCommand (across all cwd values)
  • sessions new creates a fresh cwd-scoped default session
  • sessions 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 includes acpxSessionId and, when the adapter exposes one, agentSessionId
  • sessions ensure returns the nearest matching active session or creates one for cwd
  • sessions ensure --name <name> does the same for named sessions
  • sessions close soft-closes the current cwd default session
  • sessions close <name> soft-closes current cwd named session
  • sessions show [name] displays stored session metadata
  • sessions history [name] displays stored turn history previews (default 20, configurable with --limit)
  • sessions prune --dry-run previews closed sessions that can be deleted
  • sessions prune deletes closed session records for the selected agent; add --include-history to delete event stream files too
  • sessions 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

status command

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, or no-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).

config command

acpx [global_options] config show
acpx [global_options] config init
  • config show prints the resolved config from global + project files.
  • config init writes 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 escape hatch

--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 --agent in one command.
  • The resolved command string becomes the session scope key (agentCommand).
  • Invalid empty command or unterminated quoting in --agent is a usage error.

Session behavior and scoping

Session records are stored in:

~/.acpx/sessions/*.json

Auto-resume

For prompt commands:

  1. Detect the nearest git root by checking for .git while walking up from absoluteCwd.
  2. If a git root is found, walk from absoluteCwd up to that git root (inclusive).
  3. If no git root exists, only check exact absoluteCwd (no parent-directory walk).
  4. At each checked directory, find the first active (non-closed) session matching (agentCommand, dir, optionalName).
  5. If found, use that session record for prompt queueing and resume attempts.
  6. If not found, exit with code 4 and print guidance to create one via sessions 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.

Prompt queueing

When a prompt is already in flight for a session, acpx uses a per-session queue owner process:

  1. owner process keeps the active turn running
  2. other acpx invocations enqueue prompts through local IPC
  3. owner drains queued prompts one-by-one after each completed turn
  4. after the queue drains, owner waits for new work up to TTL (--ttl, default 300s)
  5. submitter either blocks until completion (default) or exits immediately with --no-wait
  6. if interrupted (Ctrl+C) during an active turn, acpx sends session/cancel first, waits briefly for cancelled completion, then force-kills only if needed

Soft-close behavior

  • soft-closed sessions remain on disk with closed: true and closedAt
  • 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

Named sessions

-s, --session <name> adds name into the scope key so multiple parallel conversations can coexist in the same repo and agent command.

CWD scoping

--cwd sets the starting point for directory-walk routing (bounded by git root) and the exact scope directory when creating sessions via sessions new.

Output formats

--format controls output mode:

  • text (default): human-readable stream
  • json: raw ACP NDJSON stream for automation
  • quiet: assistant text only
  • --format json --json-strict: same ACP NDJSON stream, with non-JSON stderr output suppressed

Prompt/exec output behavior

  • text: assistant text, tool status blocks, client-operation logs, plan updates, and [done] <reason>
  • json: one raw ACP JSON-RPC message per line
  • quiet: concatenated assistant text only

When --suppress-reads is enabled:

  • text: read-like tool outputs render as [read output suppressed]
  • json: ACP fs/read_text_file responses 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/stream wrapper fields,
  • no ACP payload key renaming.

Control-command JSON mapping

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/query command output behavior

  • sessions list with text: tab-separated id, name, cwd, lastUsedAt (closed sessions include a [closed] marker next to id)
  • sessions list with json: a single JSON array of session records
  • sessions list with quiet: one session id per line (closed sessions include [closed])
  • sessions show with text: key/value metadata dump
  • sessions show with json: full session record object
  • sessions history with text: tab-separated timestamp role textPreview entries
  • sessions history with json: object containing entries array
  • sessions prune with text: summary plus pruned ids and close/last-used time
  • sessions prune with json: object containing action, dryRun, count, bytesFreed, and pruned
  • sessions prune with quiet: one pruned session id per line
  • status with text: key/value process status lines

Permission modes

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 with PERMISSION_PROMPT_UNAVAILABLE

Exit codes

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)

Environment variables

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

Practical examples

# 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'