Use acpx as a headless ACP CLI for agent-to-agent communication, including installed-agent inspection, prompt/exec/sessions workflows, session scoping, queueing, permissions, output formats, system-prompt overrides, and multi-agent flows authored with defineFlow/decision/decisionEdge.
60
75%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Fix and improve this skill with Tessl
tessl review fix ./skills/acpx/SKILL.mdUse this skill when you need to run coding agents through acpx, manage persistent ACP sessions, queue prompts, override the Claude system prompt, prune stale sessions, consume structured agent output from scripts, or compose multi-agent workflows declaratively with acpx/flows.
acpx is a headless, scriptable CLI client for the Agent Client Protocol (ACP). It is built for agent-to-agent communication over the command line and avoids PTY scraping.
Core capabilities:
exec)-s/--session)sessions ensure)sessions prune with age filters and history cleanup)--no-wait)cancel) for in-flight turnssession/cancel on interruptset-mode, set <key> <value>)--fileconfig show|initsessions show, sessions history)sessions watch -s <name> --cursor <cursor>; omit the cursor for retained history)statusauthenticate handshake via env/config credentialstext, json, quiet) with optional --suppress-reads_meta preservation across direct, queued, compare, and embedded-runtime results--agent escape hatch--system-prompt / --append-system-prompt--no-fs and --no-terminal--allowed-tools), turn cap (--max-turns), retry on transient failures (--prompt-retries)acpx flow run and the acpx/flows authoring API (defineFlow, decision, decisionEdge, acp, action, compute, checkpoint)npm i -g acpxFor normal session reuse, prefer a global install over npx.
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] compare <agent>... '<prompt_text>'
acpx [global_options] compare <agent>... --file <path>
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>] | watch [-s <name>] [--cursor <cursor>] | 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>] | watch [-s <name>] [--cursor <cursor>] | 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.
Friendly agent names resolve to commands:
pi -> npx pi-acp (ACPX-owned package range; see agents/Pi.md)openclaw -> openclaw acp (see the OpenClaw guide)codex -> npx -y @agentclientprotocol/codex-acp (ACPX-owned package range)claude -> npx -y @agentclientprotocol/claude-agent-acp (ACPX-owned package range; see agents/Claude.md)gemini -> gemini --acpcursor -> cursor-agent acpcopilot -> copilot --acp --stdioantigravity -> agy_acp_server.par (--uid= on Linux; agy_acp_server.exe on Windows). Install the official runtime/helper pair and configure its own sign-in first; see Antigravity. Fixed-choice interaction questions are cancelled, including with --approve-all, host permission callbacks, and existing custom launchers; acpx cannot supply user answers through permission approval.devin -> devin acpdroid -> droid exec --output-format acp (factory-droid and factorydroid also resolve to droid)fast-agent -> uvx fast-agent-mcp acpfx -> fx acp (install and authenticate a provider first; see the fx guide)grok-build -> grok agent stdioiflow -> iflow --experimental-acpjunie -> junie --acp=true (install and authenticate Junie first; see the Junie guide)kilocode -> npx -y @kilocode/cli acpkimi -> kimi acpkiro -> kiro-cli-chat acpmcode -> mcode acp (install/authenticate MCode first; prefer exec for one-shot work, and require advertised ACP reload support for cross-invocation continuity)mux -> mux acp via an ACPX-owned npm rangeopencode -> npx -y opencode-ai acppool -> pool acpqoder -> qodercli --acp
Forwards Qoder-native --allowed-tools and --max-turns startup flags from acpx session options.qwen -> qwen --acptrae -> traecli acp servezeroclaw -> zeroclaw acpRules:
codex for top-level prompt, exec, and sessions.--agent <command> explicitly sets a raw ACP adapter command.--agent in the same command.launchId; one session can produce several adapter processes. Checks retire their owned processes and output pipes before settling.When embedding ACPX, import createAgentRegistry from acpx/agent-registry and use inspect(agentId) to obtain installed launch facts without starting an agent. Treat undefined as uninspectable. Check the returned missing command/package requirements before acquiring a session; recheck when launching because installed files can change. Authentication and native model discovery belong to session acquisition.
Custom registry names such as constructor and __proto__ work with resolution, listing, and inspection. Without an explicit registry entry, unknown names remain raw commands.
Use getStatus({ handle }).models.availableModels when present for native display names, and pass the selected opaque model ID, including any slashes, unchanged to setModel. Model changes validate against the connected session's advertised models, including after reconnect. setConfigOption applies the same validation when key names the advertised model option and returns that operation's native ACP response with the accepted configOptions. Use the response to update model and reasoning controls together. Embedded callers can identify unknown or ambiguous model failures with isRequestedModelUnsupportedError(error) and error.reason === "unadvertised-model". When a Cursor alias matches multiple advertised variants, the error also has ambiguous: true; a selector with no advertised match omits that flag. Claude ACP retains its forwarding exception for selectors absent from its advertised list.
Use prepareFreshSession({ handle }) to persist a fresh-session request across restart, then ensure without resumeSessionId. Ordinary close retains session continuity; explicit remote discard requires the adapter’s optional close capability.
Embedded controls save accepted settings with the current conversation. Turn finalization and one-shot cleanup wait for admitted controls, preserving final output, usage, and selections in the saved session. Ordinary close can return before active prompt cancellation finishes; the later save preserves its close/reset markers.
For persistent sessions, compatible ensureSession calls may reuse an active record, including from permission callbacks during control reconnects. Changing its working directory, adapter invocation, or resume identity while turns or controls remain unfinished rejects with ACP_SESSION_INIT_FAILED; await that work or use a different key. After an active close, await its turn result before reopening. Idle replacement retires the old owner before initializing the successor; other records and distinct one-shot sessions remain independent.
For installed entrypoints and prerequisites, read the matching agent guide. For resolver callbacks, custom command overrides, and lifecycle details, read embedded agent discovery.
Implicit:
acpx codex 'fix flaky tests'Explicit:
acpx codex prompt 'fix flaky tests'
acpx prompt 'fix flaky tests' # defaults to codexBehavior:
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'
acpx --model gpt-5.6-sol codex exec --config-option reasoning_effort=xhigh 'review this repo'Behavior:
--model, then repeatable --config-option <key=value> selections, before promptingacpx compare pi openclaw codex 'summarize this checkout'
acpx --format json compare codex claude --file prompt.mdBehavior:
exec controls: cwd, timeout, permissions, --policy, auth, terminal, retries, model/system options, and output format--format text prints one summary table row per agent--format json or --json prints CompareRow[]--format quiet prints <agent>\t<status> per rowacpx codex cancel
acpx codex set-mode auto
acpx codex set model gpt-5.6-sol
acpx codex set reasoning_effort maxBehavior:
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-mode replaces the old saved mode without replaying it. Other saved settings restore first; the new mode preference is saved only after acceptance.set: calls ACP session/set_config_option.mode keeps config-option transport; explicit set-mode uses the separate session/set_mode control.model and reasoning_effort as separate config options.--model <id>: Claude-compatible adapters may consume session creation metadata; other agents must advertise a model config option or legacy models metadata.set model <id>: validates against the connected session's advertised models, uses session/set_config_option for model config options, and preserves session/set_model for explicitly advertised legacy models. Claude Code still accepts or rejects selectors absent from its advertised list.set-mode/set route through queue-owner IPC when active, otherwise reconnect directly.Use acpx --format json pi sessions watch -s reviewer to observe another client's work. Resume with --cursor using the last event's opaque cursor. Watchers do not cancel turns when stopped; use turn_result for the settled outcome, and treat owner-loss errors as unknown outcomes rather than retry instructions. See Watching sessions.
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 statusBehavior:
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: approve tool permission requests not resolved by a per-tool policy--approve-reads: approve remaining read/search requests and prompt for other tools (default mode)--deny-all: deny tool permission requests not resolved by a per-tool policy--non-interactive-permissions <policy>: choose deny or fail when the permission mode requires a prompt but stdin or stderr is not a TTY--permission-policy <json-or-file> / --policy: per-tool ACP permission rules that take precedence over the permission mode--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>: response deadline (positive number); partial text is not completion. A final response during the bounded drain keeps its actual outcome. Queued prompts wait for cancellation and retirement of unfinished connections before reconnecting to the saved session; cleanup can extend elapsed time beyond the deadline.--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 a model config option or legacy models metadata--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. Both system-prompt flags also apply to persistent and isolated ACP nodes in flow run.--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); cancelling a queued turn stops remaining attempts, while already-received final responses keep their outcome--no-fs: disable ACP filesystem callbacks so compatible agents use their native file operations. This is a protocol callback policy, not an OS sandbox for the agent's own filesystem access.--no-terminal: disable the ACP terminal callback. This is a protocol callback policy, not an OS sandbox for the agent's own process access.--verbose: verbose ACP/debug logs to stderrCursor may advertise bracketed model IDs such as composer-2.5[fast=false]. An exact
advertised ID always wins. Only Cursor accepts a bare model name through a unique
advertised bracketed variant; unknown or ambiguous names are rejected before the
model change. This rule uses the current connected catalog for set model, embedded
setModel, and model selections through setConfigOption, including after reconnect.
An acknowledged model alias is saved as the resolved current model ID; its original spelling remains the preference replayed on reconnect. Non-list config catalogs are treated as acknowledgements, while an explicit empty list withdraws the catalog.
Permission 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.
# Create a named session with a replacement system prompt.
acpx --system-prompt "You are a code reviewer who challenges every implicit assumption." \
claude sessions new --name review
acpx claude -s review 'review the current diff'
# Create a named session with an appended guideline.
acpx --append-system-prompt "Always explain trade-offs before recommending a fix." \
claude sessions new --name impl
acpx claude -s impl 'implement the requested change'Run the creation command once, then select the session with -s for later prompts. Running sessions new again in the same scope closes the prior local record and creates a fresh session.
The override is forwarded via ACP _meta.systemPrompt (or _meta.systemPrompt.append) on session/new, session/load, and session/resume 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.
Embedded SessionAgentOptions.systemPrompt preserves raw nonempty replacement or append text through saving and reconnecting, including whitespace-only text. CLI prompt flags trim surrounding whitespace and reject whitespace-only values.
Built-in acpx claude sessions load Claude project and local settings, but not
user settings. The same isolation and saved session options apply on creation,
load, and resume. This prevents globally enabled channel and daemon plugins from
claiming singleton external resources in an ACP-spawned session.
Set ACPX_CLAUDE_INCLUDE_USER_SETTINGS=1 only when the spawned session needs
the user's global Claude settings and no such plugin conflict exists. Ambient
credentials and other environment variables are still inherited normally.
On Windows, native Claude executable discovery resolves relative PATH entries
from the selected session cwd. An explicit CLAUDE_CODE_EXECUTABLE still takes
precedence.
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-01Without --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 -> { argv: [executable, ...args] }); structured argv is required on Windows, and legacy { command, args } entries migrate automaticallyauth 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.
The devin shortcut runs the installed Devin CLI. Authenticate with Devin before starting sessions:
acpx devin exec 'summarize this repo'acpx --model <id> devin uses the advertised ACP model config option. Raw --agent overrides remain available for launch flags. Devin launches retain their scoped Windsurf-compatible identity; see agents/Devin.md for detection, version overrides, capabilities, and extension handling.
Persistent prompt sessions are scoped by:
agentCommandcwdnamePersistence:
~/.acpx/sessions/*.json.-s/--session selects a named conversation; create it with sessions new --name <name> or sessions ensure --name <name> before prompting.--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./tmp/acpx-<home-hash>/<session-hash>.sock.~/.acpx/queues/<session-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 on stdout; failed prompts emit one structured [acpx] error: line on stderr--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(.method=="session/update") | .params.update
| select(.sessionUpdate=="tool_call" or .sessionUpdate=="tool_call_update")
| [(.status // "-"), (.title // "-")] | @tsv'For ACP tool permission requests, per-tool policy takes precedence over the permission mode. Rules are evaluated in this order: autoDeny, autoApprove, escalate, then defaultAction. The selected mode applies only when the policy does not resolve the request.
--approve-all: approve remaining tool permission requests without prompting--approve-reads (default): approve remaining read/search requests and prompt for other tools--deny-all: deny remaining tool permission requests--non-interactive-permissions <deny|fail>: choose what happens when the mode requires a prompt but stdin or stderr is not a TTY--policy <json-or-file>: match ACP tool permission requests by kind, title, title head, or raw input tool nameAn autoApprove rule can approve a tool request under --deny-all. An escalate rule can prompt under --approve-all when stdin and stderr are TTYs. Without both TTYs, escalation denies or cancels the current request and adds _meta.acpx.permissionEscalation to the ACP response, even when --non-interactive-permissions fail is selected.
Per-tool policies govern session/request_permission. ACP filesystem and terminal operations use the client's permission mode separately; a tool approval does not bypass those operation checks.
If every permission request is denied/cancelled and none approved, acpx exits with permission-denied status.
Interactive tool, file-write, and terminal questions are serialized within each acpx process. Each question needs a separate answer; EOF denies active and waiting questions.
Pending permissions, file operations, and terminal creation retain their admitting prompt's lifetime. Cancelled, completed, timed-out, superseded, or closed prompts cannot gain new mutation/spawn authority from late answers. Individual ACP request cancellation stays local to that request. Already-dispatched OS work is not rolled back.
When a tool kind is absent, read/search approval is inferred only from complete leading action words. Filenames or substrings in other action titles do not grant approval; ambiguous titles still require the normal permission decision.
Codex refusals prefer an offered non-cancelling one-time rejection. If safe refusal uses cancellation, acpx explains the possible turn termination in text output, quiet stderr, JSON response _meta.acpx.permissionNotice, and embedded status events. Permission denial never grants the requested operation. See Codex.
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 claudeRun 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.
Each attempt has one deadline across preparation, execution, and parsing. Callbacks receive context.signal; function actions also receive context.runShell to run commands whose processes and output streams the runner owns. A command's own timeout returns partial output with timedOut: true; enclosing node cancellation rejects after cleanup and prevents later managed commands. Admitted runtime writes finish before routing or final publication. Check the signal around custom asynchronous side effects: arbitrary JavaScript cannot be forcibly stopped, and completed effects are not rolled back. Persistent reconnects must load the same backend session or fail. See docs/flows.md for the command result and cancellation contracts.
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 claude, 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).
For explicit prompt and exec, an agent-level --file is inherited unless the subcommand supplies its own file. Agent-level --no-wait also applies to prompt. Session-list options work on sessions or list, with explicit child values taking precedence. Watch inherits the agent's session selector unless watch --name/-s overrides it; its --cursor stays local to watch and never inherits the list pagination cursor.
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 Claude reviewer that survives session reuse:
acpx --system-prompt "You are a reviewer who refuses to approve untested changes." \
claude sessions new --name reviewer
acpx claude -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'Machine-readable output for orchestration:
acpx --format json --json-strict codex 'review current branch changes' > events.ndjsonRaw 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-historyMulti-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'27efb1b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.