How this command is triggered — by the user, by Claude, or both
Slash command
/acpx:advanceduse-acpx/references/Files this command reads when invoked
The summary Claude sees in its command listing — used to decide when to auto-load this command
# acpx Advanced Reference ## Built-in agent registry Friendly agent names resolve to commands: - `pi` -> `npx pi-acp` - `openclaw` -> `openclaw acp` - `codex` -> `npx -y @agentclientprotocol/codex-acp` - `claude` -> `npx -y @agentclientprotocol/claude-agent-acp` (ACPX-owned package range) - `gemini` -> `gemini --acp` - `cursor` -> `cursor-agent acp` - `copilot` -> `copilot --acp --stdio` - `droid` -> `droid exec --output-format acp` (`factory-droid` and `factorydroid` also resolve to `droid`) - `fast-agent` -> `uvx fast-agent-mcp acp` - `iflow` -> `iflow --experimental-acp` - `kilocode` ...
Friendly agent names resolve to commands:
pi -> npx pi-acpopenclaw -> openclaw acpcodex -> npx -y @agentclientprotocol/codex-acpclaude -> npx -y @agentclientprotocol/claude-agent-acp (ACPX-owned package range)gemini -> gemini --acpcursor -> cursor-agent acpcopilot -> copilot --acp --stdiodroid -> droid exec --output-format acp (factory-droid and factorydroid also resolve to droid)fast-agent -> uvx fast-agent-mcp acpiflow -> iflow --experimental-acpkilocode -> npx -y @kilocode/cli acpkimi -> kimi acpkiro -> kiro-cli-chat acpopencode -> npx -y opencode-ai acpqoder -> qodercli --acp
Forwards Qoder-native --allowed-tools and --max-turns startup flags from acpx session options.qwen -> qwen --acptrae -> traecli acp serveRules:
codex for top-level prompt, exec, and sessions.--agent <command> explicitly sets a raw ACP adapter command.--agent in the same command.prompt is the default verb.
acpx [global_options] [prompt_text...]
acpx [global_options] prompt [prompt_options] [prompt_text...]
acpx [global_options] exec [prompt_options] [prompt_text...]
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>] | export [name] --output <path> | import <archive> [--name <name>] [--cwd <dir>] | prune [--dry-run] [--before <date> | --older-than <days>] [--include-history]]
acpx [global_options] config [show | init]
acpx [global_options] flow run <file> [--input-json '<json>' | --input-file <path>] [--default-agent <name>]
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>] | export [name] --output <path> | import <archive> [--name <name>] [--cwd <dir>] | prune [--dry-run] [--before <date> | --older-than <days>] [--include-history]]
If prompt text is omitted and stdin is piped, acpx reads prompt text from stdin.
Implicit:
acpx codex 'fix flaky tests'
Explicit:
acpx codex prompt 'fix flaky tests'
acpx prompt 'fix flaky tests' # defaults to codex
Behavior:
NO_SESSION and prompts for sessions newsession/cancel before force-kill fallbackPrompt options:
-s, --session <name>: use a named session within the same cwd--no-wait: enqueue and return immediately when session is already busy-f, --file <path>: read prompt text from file (- means stdin)acpx exec 'summarize this repo'
acpx codex exec 'summarize this repo'
Behavior:
acpx codex cancel
acpx codex set-mode auto
acpx codex set model gpt-5.2[high]
acpx codex set model gpt-5.4
Behavior:
cancel: sends cooperative session/cancel through queue-owner IPC.set-mode: calls ACP session/set_mode.set-mode mode ids are adapter-defined; unsupported values are rejected by the adapter (often Invalid params).set: calls ACP session/set_config_option.--model <id>: 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.set model <id>: calls session/set_model. This is the generic ACP method for mid-session model switching.set-mode/set route through queue-owner IPC when active, otherwise reconnect directly.acpx sessions
acpx sessions list
acpx sessions list --filter-cwd .
acpx sessions list --cursor <cursor>
acpx sessions list --local
acpx sessions new
acpx sessions new --name backend
acpx sessions ensure
acpx sessions ensure --name backend
acpx sessions close
acpx sessions close backend
acpx sessions show
acpx sessions history --limit 20
acpx sessions export backend --output backend-session.json
acpx sessions import backend-session.json --name backend-restored
acpx sessions prune --dry-run --older-than 7
acpx sessions prune --older-than 30 --include-history
acpx status
acpx codex sessions
acpx codex sessions new --name backend
acpx codex sessions ensure --name backend
acpx codex sessions close backend
acpx codex sessions show backend
acpx codex sessions history backend --limit 20
acpx codex sessions export backend --output backend-session.json
acpx codex sessions import backend-session.json --name backend-restored
acpx codex sessions prune --before 2026-04-01 --include-history
acpx codex status
Behavior:
sessions and sessions list are equivalentsessions list uses ACP session/list when the agent advertises it; JSON
includes agent SessionInfo, _meta, and nextCursorsessions list --filter-cwd <dir> applies the ACP cwd filter, and
--cursor <cursor> requests a specific pagesessions list --local reads saved acpx records insteadnew creates a fresh session for the current (agentCommand, cwd, optional name) scopenew --name <name> targets a named session scopenew replaces an existing open session in that scope, the old one is soft-closedensure returns the nearest matching active session for the scope, or creates one when none is open. Idempotent — safe to call before every prompt in scripts.close targets current cwd default sessionclose <name> targets current cwd named sessionshow [name] prints stored metadata for that scoped sessionhistory [name] prints stored turn history previews (default 20, use --limit)export [name] --output <path> writes a portable JSON archive containing session state and event historyimport <archive> creates a fresh local record, reopens the copied session as idle, keeps the provider session id, and clears source-machine process metadataimport --name <name> and --cwd <dir> override the destination scope; import fails if that scope already has an active session or another local record already uses the same provider session idprune deletes closed session records to reclaim disk space
--dry-run previews what would be deleted without touching disk--older-than <days> and --before <date> filter by close time, falling back to last-used time when a record was never explicitly closed--include-history also removes per-session event stream files (otherwise only the JSON record is removed)--agent <command>: raw ACP agent command (escape hatch)--cwd <dir>: working directory for session scope (default: current directory)--approve-all: auto-approve all permission requests--approve-reads: auto-approve reads/searches, prompt for writes (default mode)--deny-all: deny all permission requests--non-interactive-permissions <policy>: when prompting is unavailable, choose deny or fail--permission-policy <json-or-file> / --policy: per-tool ACP permission rules (autoApprove, autoDeny, escalate, defaultAction)--format <fmt>: output format (text, json, quiet)--json-strict: strict JSON mode; requires --format json and suppresses non-JSON stderr output--suppress-reads: suppress raw read-file contents while preserving the selected format--timeout <seconds>: max wait time (positive number)--ttl <seconds>: queue owner idle TTL before shutdown (default 300, 0 disables TTL)--model <id>: request an agent model during session creation; non-Claude agents must advertise ACP models and support session/set_model--system-prompt <text>: replace the agent system prompt. Forwarded to claude-agent-acp via ACP _meta.systemPrompt; persisted in session_options.system_prompt so reuse keeps the override. Other agents ignore the field.--append-system-prompt <text>: append text to the agent system prompt. Forwarded to claude-agent-acp via ACP _meta.systemPrompt.append; same persistence rules as --system-prompt.--allowed-tools <list>: comma-separated tool whitelist (use "" for no tools)--max-turns <count>: cap session turn count--prompt-retries <count>: retry failed prompt turns on transient errors (default 0)--no-terminal: do not advertise the ACP terminal capability — useful for review-only or sandboxed agent invocations--verbose: verbose ACP/debug logs to stderrPermission flags are mutually exclusive.
--system-prompt and --append-system-prompt let you specialize a Claude session without leaving lingering one-off state, while still benefiting from persistent session reuse.
# Replace the system prompt for a named session, persisted across reuse
acpx --system-prompt "You are a code reviewer who challenges every implicit assumption." claude -s review
# Append a guideline on top of the default system prompt
acpx --append-system-prompt "Always explain trade-offs before recommending a fix." claude -s impl
The override is forwarded via ACP _meta.systemPrompt (or _meta.systemPrompt.append) on session/new and stored in session_options.system_prompt. Subsequent prompt/ensure calls in the same scope keep the override unless you explicitly create a new session. Non-Claude adapters ignore the field, so the same flag is safe inside cross-agent scripts.
Closed session records accumulate on disk by default. Use sessions prune to enforce retention:
# Preview what would be deleted (no writes)
acpx codex sessions prune --dry-run --older-than 7
# Remove records closed more than 30 days ago, including their event-stream files
acpx codex sessions prune --older-than 30 --include-history
# Remove everything closed before a date
acpx codex sessions prune --before 2026-04-01
Without --include-history, only the lightweight JSON record is removed; event-stream files are preserved for audit. With it, the per-session event log is also deleted to reclaim disk space.
Config files are merged in this order (later wins):
~/.acpx/config.json<cwd>/.acpxrc.jsonSupported keys:
defaultAgentdefaultPermissions (approve-all, approve-reads, deny-all)nonInteractivePermissions (deny, fail)ttl (seconds)timeout (seconds or null)format (text, json, quiet)agents map (name -> { command, args? })auth map (authMethodId -> credential)Use acpx config show to inspect the resolved config and acpx config init to create the global template.
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.
Persistent prompt sessions are scoped by:
agentCommandcwdnamePersistence:
~/.acpx/sessions/*.json.-s/--session creates parallel named conversations in the same repo.--cwd changes scope and therefore session lookup.closed: true and closedAt until pruned.Resume behavior:
acpx creates a fresh session and updates the saved record.loadSession even if previously closed.--no-waitQueueing is per persistent session.
acpx process for a running prompt becomes the queue owner.~/.acpx/queues/<hash>.sock.~/.acpx/queues/<hash>.lock.--ttl).Submission behavior:
--no-wait: enqueue and return after queue acknowledgement.Ctrl+C during an active turn sends ACP session/cancel, waits briefly, then force-kills only if cancellation does not finish in time.cancel sends the same cooperative cancellation without requiring terminal signals.Use --format <fmt>:
text (default): human-readable stream with updates/tool status and done linejson: NDJSON event stream (good for automation)quiet: final assistant text only--suppress-reads: replace raw read-file contents with [read output suppressed] in text and json output--json-strict: pair with --format json to suppress non-JSON stderr noise (logs, banners) for downstream consumersExample automation:
acpx --format json codex exec 'review changed files' \
| jq -r 'select(.type=="tool_call") | [.status, .title] | @tsv'
--approve-all: no interactive permission prompts--approve-reads (default): approve reads/searches, prompt for writes--deny-all: deny all permission requests--non-interactive-permissions <deny|fail>: chosen behavior when no TTY is available to prompt--policy <json-or-file>: match ACP permission requests by tool kind/title; non-interactive escalations add ACP response metadataIf every permission request is denied/cancelled and none approved, acpx exits with permission-denied status.
Flows let you declare a multi-agent workflow as a graph of typed nodes connected by edges, executed by the acpx runtime. The runtime owns persistence, retries, timeouts, and routing — the flow file declares the shape, not the engine.
acpx flow run ./my-flow.flow.ts --input-file ./flow-input.json
acpx flow run ./my-flow.flow.ts --input-json '{"task":"FIX: add a regression test"}'
acpx --approve-all flow run examples/flows/pr-triage/pr-triage.flow.ts \
--input-json '{"repo":"openclaw/acpx","prNumber":150}'
acpx flow run ./my-flow.flow.ts --default-agent claude
Run artifacts persist under ~/.acpx/flows/runs/<runId>/. Default per-step timeout is 15 minutes when --timeout is unset; flows that declare permission requirements fail fast before starting.
The authoring surface lives in acpx/flows. The minimal example:
import { acp, decision, decisionEdge, defineFlow, checkpoint, extractJsonObject } from "acpx/flows";
const choices = ["bug", "feat", "doc"] as const;
export default defineFlow({
name: "pr-triage",
startAt: "classify",
nodes: {
classify: decision({
choices,
question: ({ input }) =>
`Classify the PR description below. Reply with one of: ${choices.join(", ")}.\n\n${input.description}`,
}),
bug_lane: acp({
prompt: ({ outputs }) =>
`The PR is a bug. Write a regression test that reproduces it.\n\nDecision context: ${JSON.stringify(outputs.classify)}`,
parse: (text) => extractJsonObject(text),
}),
feat_lane: acp({
prompt: () => "List acceptance criteria for the feature, one bullet per criterion.",
}),
doc_lane: checkpoint({
summary: "doc change — needs human review",
run: ({ outputs }) => ({ route: "doc", note: outputs.classify }),
}),
},
edges: [
decisionEdge({
from: "classify",
choices,
cases: {
bug: "bug_lane",
feat: "feat_lane",
doc: "doc_lane",
},
}),
],
});
| Type | Purpose |
|---|---|
acp({ prompt, parse?, agent?, cwd? }) | Model-driven step. The prompt builder receives { input, outputs }. Optional parse coerces the raw text (e.g., extractJsonObject). |
decision({ choices, question }) | Constrained-choice LLM step. choices is a readonly tuple; the runtime validates the model's reply against it and TypeScript infers the union from choices. |
action(...) | Runtime-supervised deterministic operation: shell, GitHub API, test execution, comment posting. |
compute(...) | Pure local data transform: normalization, routing key derivation, signal reduction. |
checkpoint({ summary, run }) | Pause point for human or external trigger. run returns the outcome to record while paused. |
// Linear edge
{ from: "node", to: "next" }
// JSONPath switch — non-decision routing
{
from: "node",
switch: {
on: "$.route",
cases: { "value-a": "branch_a", "value-b": "branch_b" },
},
}
// Decision edge — exhaustive at compile time
decisionEdge({
from: "classify",
choices, // same readonly tuple as decision()
cases: { // every choice must map to a node id
bug: "bug_lane",
feat: "feat_lane",
doc: "doc_lane",
},
})
If a decisionEdge omits a case from choices, the TypeScript compiler refuses to compile — so a flow can't ship with a forgotten branch when new choices are added.
codex, write code with opencode, summarize with gemini — same flow file, no glue.~/.acpx/flows/runs/.See examples/flows/ in the repo for working samples (branch.flow.ts, pr-triage/, two-turn.flow.ts, shell.flow.ts, workdir.flow.ts).
Persistent repo assistant:
acpx codex 'inspect failing tests and propose a fix plan'
acpx codex 'apply the smallest safe fix and run tests'
Parallel named streams:
acpx codex -s backend 'fix API pagination bug'
acpx codex -s docs 'draft changelog entry for release'
Specialized codex reviewer that survives session reuse:
acpx --system-prompt "You are a reviewer who refuses to approve untested changes." codex -s reviewer
acpx codex -s reviewer 'review the diff in src/auth/'
Idempotent session bootstrap (safe to call before every prompt in scripts):
acpx codex sessions ensure -s ci
acpx codex -s ci 'run the smoke suite and report failures'
Queue follow-up without waiting:
acpx codex 'run full test suite and investigate failures'
acpx codex --no-wait 'after tests, summarize root causes and next steps'
One-shot script step:
acpx --format quiet exec 'summarize repo purpose in 3 lines'
Compare one prompt across agents:
acpx --format json compare codex gemini qwen 'propose a fix for the flaky test' \
> compare.json
Session-scoped MCP config without writing a project file:
acpx --mcp-config ./tools.json codex exec 'use the configured MCP servers to inspect the schema'
Machine-readable output for orchestration:
acpx --format json --json-strict codex 'review current branch changes' > events.ndjson
Raw custom adapter command:
acpx --agent './bin/custom-acp-server --profile ci' 'run validation checks'
Periodic cleanup:
acpx codex sessions prune --dry-run --older-than 14
acpx codex sessions prune --older-than 30 --include-history
Multi-agent triage flow:
acpx --approve-all flow run ./pr-triage.flow.ts --input-json '{"prNumber": 842}'
Repo-scoped review with permissive mode:
acpx --cwd ~/repos/shop --approve-all codex -s pr-842 \
'review PR #842 for regressions and propose minimal patch'
npx claudepluginhub daisycatts/dotclaude --plugin acpx