--- 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 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. ```bash acpx [global_options] [prompt_text...] acpx [global_options] prompt [prompt_options] [prompt_text...] acpx [global_options] exec [prompt_options] [prompt_text...] acpx [global_options] compare ... '' acpx [global_options] compare ... --file acpx [global_options] flow run [--input-json | --input-file ] [--default-agent ] acpx [global_options] cancel [-s ] acpx [global_options] set-mode [-s ] acpx [global_options] set [-s ] acpx [global_options] status [-s ] acpx [global_options] sessions [list | new [--name ] | ensure [--name ] | close [name] | show [name] | history [name] [--limit ] | export [name] --output | import [--name ] [--cwd ]] acpx [global_options] config [show | init] acpx [global_options] [prompt_options] [prompt_text...] acpx [global_options] prompt [prompt_options] [prompt_text...] acpx [global_options] exec [prompt_options] [prompt_text...] acpx [global_options] cancel [-s ] acpx [global_options] set-mode [-s ] acpx [global_options] set [-s ] acpx [global_options] status [-s ] acpx [global_options] sessions [list | new [--name ] | ensure [--name ] | close [name] | show [name] | history [name] [--limit ] | export [name] --output | import [--name ] [--cwd ]] ``` The global `--mcp-config ` option loads an external JSON file's `mcpServers` array for the invocation, replacing project/global MCP configuration. Relative paths resolve from `--cwd`. For a persistent session, close the existing session before switching its MCP config. `` can be: - built-in friendly name from [the README](https://github.com/openclaw/acpx/blob/main/README.md) - unknown token (treated as raw command) - overridden by `--agent ` escape hatch Additional built-in agent docs live in [the Agents page](agents.md). Prompt options: ```bash -s, --session Use named session instead of cwd default --no-wait Queue prompt and return immediately if session is busy -f, --file Read prompt text from file (`-` means stdin) ``` Notes: - Top-level `prompt`, `exec`, `cancel`, `set-mode`, `set`, `sessions`, and bare `acpx ` default to `codex`. - Top-level `flow run ` 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 ```bash acpx [global_options] flow run [--input-json | --input-file ] [--default-agent ] ``` - Runs a user-authored workflow module step by step through the `acpx/flows` runtime. - Persists run artifacts under `~/.acpx/flows/runs//`. - 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: ```bash 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 ` | Raw ACP agent command (escape hatch) | Do not combine with positional agent token. | | `--cwd ` | 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 ` | 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-fs` | Disable ACP filesystem capabilities | Advertises `clientCapabilities.fs.readTextFile` and `writeTextFile` as `false` during ACP initialize for new agent clients. | | `--no-terminal` | Disable ACP terminal capability | Advertises `clientCapabilities.terminal: false` during ACP initialize for new agent clients. | | `--non-interactive-permissions ` | Non-TTY prompt policy | `deny` (default) or `fail` when approval prompt cannot be shown. | | `--permission-policy ` | Per-tool permission policy | JSON object or file path with `autoApprove`, `autoDeny`, `escalate`, and optional `defaultAction` (`approve`, `deny`, `escalate`). Alias: `--policy`. | | `--timeout ` | Max wait time for agent response | Must be positive. Decimal seconds allowed. | | `--ttl ` | Queue owner idle TTL before shutdown | Default `300`. `0` disables TTL. | | `--model ` | Set agent model | Claude-compatible adapters may consume session creation metadata; other agents must advertise a model config option or legacy `models` metadata. | | `--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. For model configuration, acpx prefers a valid select control with both `category: "model"` and `id: "model"`. Otherwise it uses the first valid model-category control, including custom IDs, then the legacy `id: "model"` fallback. This keeps provider selectors in the same category from taking over the actual model control. ### Global option examples ```bash 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 --policy '{"escalate":["execute"],"defaultAction":"deny"}' --format json codex exec 'run tests' 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-fs codex exec 'use agent-native file operations' 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` ```bash 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 ] | ensure [--name ] | close [name]] ``` Built-in command mapping: `pi -> npx pi-acp` ### `openclaw` ```bash 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 ] | ensure [--name ] | close [name]] ``` Built-in command mapping: `openclaw -> openclaw acp` For repo-local OpenClaw checkouts, override the built-in command in config: ```json { "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` ```bash 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 ] | ensure [--name ] | close [name]] ``` Built-in command mapping: `codex -> npx -y @agentclientprotocol/codex-acp` ### `claude` ```bash 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 ] | ensure [--name ] | close [name]] ``` Built-in command mapping: `claude -> npx -y @agentclientprotocol/claude-agent-acp` Additional built-in agent docs live in [the Agents page](agents.md). ### Custom positional agents Unknown agent names are treated as raw commands: ```bash 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: ```bash acpx [global_options] 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: ```bash acpx [global_options] [prompt_options] [prompt_text...] acpx [global_options] [prompt_text...] # defaults to codex ``` ## `exec` subcommand One-shot prompt (no saved session): ```bash acpx [global_options] exec [prompt_options] [prompt_text...] acpx [global_options] exec [prompt_options] [prompt_text...] # defaults to codex ``` Behavior: - Creates temporary ACP session - Applies `--model`, then each repeatable `--config-option `, before prompting - Sends prompt once - Does not write/use a saved session record - Supports prompt text from args, stdin, `--file `, and `--file -` - Stops without prompting if the adapter rejects a requested config option ```bash acpx --model gpt-5.4 codex exec \ --config-option reasoning_effort=high \ 'review this checkout' ``` ## `compare` subcommand One-shot prompt against multiple agents: ```bash acpx [global_options] compare ... '' acpx [global_options] compare ... --file acpx [global_options] compare ... -- prompt words after the delimiter ``` Behavior: - Runs each agent with the same temporary `exec`-style ACP session. - Uses the same global execution controls as `exec`, including `--cwd`, `--timeout`, permission flags, `--policy`, auth, terminal advertising, retries, model/system options, and `--format`. - `--format text` prints one summary table row per agent. - `--format json` or command-local `--json` prints a `CompareRow[]` summary payload. - `--format quiet` prints `\t` per row. - Agents run serially in the requested workspace. The command does not create saved sessions or separate compare transcript directories. Use `--format json` when you need a machine-readable artifact. `CompareRow.status` is `ok`, `cancelled`, `permission_denied`, or `error`. ## `cancel` command ```bash acpx [global_options] cancel [-s ] acpx [global_options] cancel [-s ] # 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 ```bash acpx [global_options] set-mode [-s ] acpx [global_options] set-mode [-s ] # defaults to codex ``` Behavior: - Calls ACP `session/set_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 ```bash acpx [global_options] set [-s ] acpx [global_options] set [-s ] # 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 `**: Uses the advertised model config option through `session/set_config_option`; adapters that explicitly advertise legacy `models` metadata use `session/set_model`. - Saves accepted values for existing non-mode selections, including reasoning effort adjusted or removed by a model switch; does not pin unselected defaults. - Restores saved model and config selections after reconnect, before the next prompt; already loaded sessions are reused without replay. ## `sessions` subcommand ```bash acpx [global_options] sessions acpx [global_options] sessions list acpx [global_options] sessions list [--cursor ] [--filter-cwd ] [--local] acpx [global_options] sessions new acpx [global_options] sessions new --name acpx [global_options] sessions ensure acpx [global_options] sessions ensure --name acpx [global_options] sessions close acpx [global_options] sessions close acpx [global_options] sessions show acpx [global_options] sessions show acpx [global_options] sessions history acpx [global_options] sessions history [--limit ] acpx [global_options] sessions export [name] --output [--cwd ] acpx [global_options] sessions import [--name ] [--cwd ] acpx [global_options] sessions prune [--dry-run] [--before | --older-than ] [--include-history] acpx [global_options] sessions ... # defaults to codex ``` Behavior: - `sessions` and `sessions list` are equivalent - list uses ACP `session/list` when the agent advertises `sessionCapabilities.list`, returning agent-native `SessionInfo` metadata and `nextCursor` in JSON output - `sessions list --cursor ` fetches an agent-side page from an ACP cursor returned by a prior list response - `sessions list --filter-cwd ` sends the ACP cwd filter; relative values resolve against global `--cwd` - `sessions list --local` reads saved acpx records for selected `agentCommand` instead of contacting the agent - when the agent does not support `session/list`, list falls back to local saved records unless agent-side list filters were requested - `sessions new` creates a fresh cwd-scoped default session - `sessions new --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 ` does the same for named sessions - `sessions close` soft-closes the current cwd default session - `sessions close ` 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 export [name] --output ` writes a portable JSON archive with session state and event history; `--cwd ` selects a different source cwd relative to global `--cwd` - `sessions import ` writes a fresh local record from a portable archive, reopens it as idle, keeps the provider session id, and clears source-machine process metadata - Imported sessions must resume that provider session; if the destination agent cannot load it, prompts fail clearly instead of starting an empty conversation - `sessions import --name ` and `--cwd ` override the imported destination scope; import fails instead of creating a duplicate when an active session already exists for that `(agent, cwd, name)` scope or when another local record already uses the same provider session id - `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 ` and `--older-than ` filter by close time, falling back to last-used time for older records - close errors if the target session does not exist ## `status` command ```bash acpx [global_options] status acpx [global_options] status -s acpx [global_options] status acpx [global_options] status -s ``` Shows local process status for the cwd-scoped session: - `running`, `idle`, `dead`, or `no-session` - session id, agent command, live queue-owner pid when available - 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). Cached session PIDs are not reported unless a live queue-owner lease ties them to the session. ## `config` command ```bash 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: `/.acpxrc.json` (merged on top of global) Supported keys: ```json { "defaultAgent": "codex", "defaultPermissions": "approve-all", "nonInteractivePermissions": "deny", "authPolicy": "skip", "ttl": 300, "timeout": null, "format": "text", "agents": { "my-custom": { "argv": ["./bin/my-acp-server", "acp"] } }, "auth": { "my_auth_method_id": "credential-value" } } ``` CLI flags always override config values. Custom agents should use structured `agents..argv`, which is required on Windows. Legacy `command` plus `args` entries migrate when `command` is an unquoted executable with no whitespace. Raw command strings, including `--agent`, are supported only on Unix. For ACP `authenticate` handshakes, use either config `auth` entries or explicit `ACPX_AUTH_` 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 ` sets a raw adapter command explicitly on Unix. On Windows, define a named agent with `agents..argv` so executable and argument boundaries remain unambiguous. Examples: ```bash 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: ```text ~/.acpx/sessions/*.json ``` On POSIX systems, session records and the session index are written with mode `0600`, and their session directory uses `0700`. Each write reapplies these private permissions, including when replacing an older, more permissive file. The embedded runtime's `createFileSessionStore()` uses the same policy. This is storage hardening; it does not isolate agents running under the same OS user. Operator-managed session-directory symlinks remain supported; permissions apply to their target directory. Windows access remains governed by the directory's ACLs. ### 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 ]` when you explicitly want a fresh scoped session. Use `sessions ensure [--name ]` when you want idempotent "get-or-create" behavior. If a saved session PID is dead, `acpx` respawns the agent, tries `session/resume` when advertised or `session/load` otherwise, and transparently falls back to `session/new` when reconnecting 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 Queue-owner records remain private across heartbeat updates. Shutdown finishes pending record updates before releasing ownership, and recovery checks the observed owner's generation again before terminating it or removing its files. Abandoned incomplete reservations remain recoverable after the stale-owner window. ### 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 ` 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 on stdout; failed prompts emit one structured `[acpx] error:` line on stderr - `--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] ` - `json`: one raw ACP JSON-RPC message per line - `quiet`: concatenated assistant text on stdout; failed prompts emit one structured `[acpx] error:` line on stderr 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: ```json {"jsonrpc":"2.0","id":"req-1","method":"session/prompt","params":{"sessionId":"019c...","prompt":[{"type":"text","text":"hi"}]}} {"jsonrpc":"2.0","method":"session/update","params":{"sessionId":"019c...","update":{"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/export/import/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 export` with `text`: output path summary - `sessions export` with `json`: object containing `action` and `output` - `sessions export` with `quiet`: output path - `sessions import` with `text`: imported record id and cwd summary - `sessions import` with `json`: object containing `action`, `record_id`, and `cwd` - `sessions import` with `quiet`: imported record id - `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 ? (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` Per-tool policy: - `--permission-policy ` or `--policy ` matches ACP permission requests by tool kind, title head, title, or raw input tool/name. - `autoDeny` wins over `autoApprove`, which wins over `escalate`; unmatched requests use `defaultAction` when set, otherwise the selected permission mode. - Non-interactive escalations deny the current request. Text mode prints a `[permission]` notice; JSON mode keeps raw ACP NDJSON and includes escalation details, including tool input when supplied by the agent, on the `session/request_permission` response at `_meta.acpx.permissionEscalation`. ## 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 `ACPX_CLAUDE_INCLUDE_USER_SETTINGS=1` makes built-in `claude` sessions include Claude Code user settings. By default, they load only project and local settings to avoid globally enabled channel or daemon plugins interfering with spawned ACP sessions. `ACPX_PERF_METRICS_FILE` enables optional NDJSON performance capture, including command arguments. On POSIX, capture files use `0600`; existing parent directory permissions are preserved. Symbolic links, hardlinked files, and special files such as FIFOs are skipped. Capture failures leave the command's exit status unchanged. Related runtime behavior: - session storage path is derived from OS home directory (`~/.acpx/sessions`) - child processes inherit the current environment by default - Windows terminal kill and release requests fail if process cleanup cannot finish after escalation. The terminal remains available for a cleanup retry; restore a working `taskkill` command before retrying. - ACP `terminal/create` honors agent `outputByteLimit`; `0` stores nothing and the default when omitted is 64 KiB. Hosts can opt into an additional per-terminal retention ceiling with `ACPX_TERMINAL_MAX_OUTPUT_BYTES` (for example, `16777216` for 16 MiB). Unset, empty, or zero disables only the host ceiling, preserving the agent limit and default. Positive values must be safe integers. The smaller limit applies to combined stdout and stderr, retaining the newest UTF-8 output and reporting `truncated: true` when exceeded. This bounds retained output per terminal, not total process memory. Each ACP client snapshots the setting at construction; restart warm queue owners to change it. ## Practical examples ```bash # 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(.method=="session/update") | .params.update | select(.sessionUpdate=="tool_call" or .sessionUpdate=="tool_call_update") | [(.status // "-"), (.title // "-")] | @tsv' ``` ### Queue request size `ACPX_QUEUE_MAX_REQUEST_BYTES` optionally bounds a queue owner's incoming request lines in UTF-8 bytes, excluding the newline. Unset, empty, or zero keeps the existing unlimited request size. Positive values must be safe integers. Clients with the same setting reject oversized submissions with `QUEUE_REQUEST_TOO_LARGE` before opening a socket. Owners disconnect a raw peer that exceeds the cap, including incomplete lines, while continuing to serve other clients. The existing owner-response limit is unchanged. An owner keeps the setting with which it starts; setting the variable does not reconfigure an already-running owner. Request JSON can be larger than the prompt file because it carries both structured content and display text.