Join a video meeting as an AI bot with voice, avatar, and screenshare across four operating modes.
Coding
acpx-faq
Try itRun coding agents (codex, claude, agy/Antigravity) through the acpx ACP CLI - the headless lane outside a herdr pane (no HERDR_ENV). Use before launching or prompting a subagent, and when a command fails, a session is not found, or a prompt is lost.
What it does
Drive coding agents headlessly through acpx (>= 0.15.1). Command syntax: - the binary ships its own reference and is the tiebreaker on syntax. That doc is strong on command shape and silent on failure semantics: it has no exit-code table, no state table, and does not mention at all. This file is…
The skill document
acpx FAQ
Drive coding agents headlessly through acpx (>= 0.15.1).
Command syntax: acpx --skill show acpx - the binary ships its own reference and is the
tiebreaker on syntax. That doc is strong on command shape and silent on failure semantics: it
has no exit-code table, no status state table, and does not mention --mcp-config at all.
This file is the other half.
Read the Invariants, then your agent's section in Per agent - each is a complete launch-to-result recipe. After that: Sessions, Completion, MCP, Limits, Failures.
Invariants
- Global flags precede the agent subcommand.
--cwd,--model,--approve-all,--agent,--format,--timeout,--ttl,--mcp-configare all global. The subcommand accepts only-s,--no-wait,-f(andexecalso takes--config-option). Putting a global flag after the agent exits 2 witherror: unknown option '--cwd'. -snever creates a session. It resolves one, walking from--cwdup to the git root. No match exits 4. Create first withsessions ensure --name.statusis not a turn signal. It reports the queue-owner process, not the turn, and keeps sayingrunningafter the turn has ended. Never gate automation on it.- Permission flags only gate requests the adapter chooses to raise. Neither the codex nor
the claude adapter asks before writing files, so
--deny-alldoes not stop writes. Isolation comes from the--cwdyou hand it, never from a flag. [done] end_turnand exit 0 are not proof of success. A content-filter kill, an MCP load failure, or a truncated turn all end that way. Read the stream, or require the agent to write a result file you can check.
Per agent
Each section is self-contained: flags, launch, and the quirks that bite while it runs.
agy / Antigravity - the --agent escape hatch
acpx has no Antigravity adapter and never will get one. Issue #362 was closed as
externally blocked: Antigravity ships no supported ACP stdio mode. The built-in gemini agent
is the public Gemini CLI, a different product, and it is dead for Code Assist:
[error] RUNTIME: This client is no longer supported for Gemini Code Assist for individuals.
To continue using Gemini, please migrate to the Antigravity suite of products
The only route is Google's own signed ACP server through the raw-command escape hatch:
D=/abs/real/dir # must exist: roots resolve through realpath
acpx --agent ~/.local/lib/antigravity-acp/agy_acp_server.par \
--cwd "$D" --model gemini-3.7-flash-medium --timeout 1800 \
exec 'Carry out $D/brief.md. Write your report to $D/report.md.'
- Effort lives in the model id -
gemini-3.7-flash-{low,medium,high},gemini-3.8-flash-high. This server exposes no separate effort option. - First run only:
[error] RUNTIME: Authentication required. Re-run once withACPX_AUTH_OAUTH_PERSONAL=1and complete the browser sign-in; credentials persist in~/.geminiand every later run needs nothing. - Never pass a positional agent with
--agent- exit 2,Do not combine positional agent with --agent override. - Check the tier before sending anything private. The
oauth-personalpath can reportcurrentTier: {'id': 'free-tier'}, whose terms permit human review of submitted prompts and code for up to 18 months. Run with--verboseand greploadCodeAssist responseto see it. - agy hides MCP failures inside a successful-looking turn. A failed server appears as
inline text -
MCP load failed for pond: ... expect initialized request, but received: ... "server/discover"- in a stream that still ends[done] end_turnwith exit 0. Grep the output forMCP load failed, do not trust the exit code. - The CLI (
agy) and this ACP server keep separate state under the same home: two onboardings, and authenticating one does not authenticate the other.
codex
D=/abs/dir
acpx --cwd "$D" codex sessions ensure --name work # idempotent; -s cannot create
acpx --cwd "$D" codex set model gpt-5.6-sol -s work # -> model set: gpt-5.6-sol
acpx --cwd "$D" codex set reasoning_effort high -s work # -> config set: ... (5 options)
acpx --cwd "$D" --approve-all --timeout 5400 --ttl 0 --format quiet --suppress-reads \
codex -s work 'Carry out ./brief.md. Write your report to ./report.md.' > run.log 2>&1 &
For a one-shot, skip the session entirely - exec --config-option sets model and effort
inline (0.14.0+), applied after --model and before the prompt:
acpx --cwd "$D" --timeout 1800 codex exec --config-option reasoning_effort=low 'Summarize ./DESIGN.md'
- The adapter floats.
@agentclientprotocol/codex-acp@^1.1.5is a caret on a 1.x, so it tracks the latest 1.x on everynpxresolution. A codex-side change can land without you upgrading acpx. - OpenAI's content filter kills benign turns and the turn ends looking clean
(
[done] end_turn, exit 0). Vocabulary like race / sweep / exploit / attack in a filename, comment or prompt triggers it. Read the transcript tail for the flag line before believing completion. Recover by re-prompting the same-s(context survives): rename the artifact neutrally and list the remaining steps explicitly. - Queue a follow-up onto a live session by prompting the same name again - it runs after the current turn rather than interrupting. This is how you course-correct a running executor without relaunching it.
- Headful takeover:
sessions showprints asessionIdthat is the ordinary codex rollout id, socodex resumeopens the same thread in a TUI with model and effort intact. Close first -sessions close- or you getalready has an active writer (code -32600). codex queue --threaddoes not reach an acpx-driven session (see What acpx cannot do).
claude
D=/abs/dir
acpx --cwd "$D" --model claude-opus-5 claude sessions ensure -s work
acpx --cwd "$D" --model claude-opus-5 --approve-all --suppress-reads --timeout 2400 \
claude -s work -f /abs/brief.md >> run.log 2>&1 &
- No effort knob.
set reasoning_effortreturnsInternal error. Only the model id. --modelandset modelvalidate differently, and this surprises people. The adapter advertises["default","opus[1m]","claude-fable-5[1m]","sonnet","haiku"], andset modelrefuses anything outside that list:Invalid value for config option model: claude-opus-5 (ACP -32603, adapter reported "Internal error"). The global--modelat session creation passes the id through to the harness instead, so--model claude-opus-5works fine. A genuinely unknown id still fails loudly:RUNTIME: Internal error: There's an issue with the selected model ().- Fable runs:
--model 'claude-fable-5[1m]'(quote it - the brackets are shell globs). - User-scope skills are excluded on purpose. The adapter loads project and local settings
but not user settings, so a user-level skill or slash command comes back
Unknown command: /polish. Fix withACPX_CLAUDE_INCLUDE_USER_SETTINGS=1- and settings bind at session creation, so an existing session must be recreated, not re-prompted. - Second account: export
CLAUDE_CONFIG_DIRandCLAUDE_SECURESTORAGE_CONFIG_DIRbeforeacpx; the child inherits them. That is the whole mechanism for driving another lane. - The adapter is pinned far behind your CLI.
claude-agent-acp@^0.60.0resolves to exactly 0.60.0, which pins@anthropic-ai/claude-agent-sdk@0.3.215, which bundles claude 2.1.215- regardless of the version on your PATH. Consequences: the bundled binary predates the
cross-session messaging socket, so these sessions are unreachable by peer messaging, and any
newer harness feature is simply absent. Override with
--agentpointed at a newer adapter build if you need one.
- regardless of the version on your PATH. Consequences: the bundled binary predates the
cross-session messaging socket, so these sessions are unreachable by peer messaging, and any
newer harness feature is simply absent. Override with
- A session-creation stall is a known adapter combination bug; acpx's own error text
recommends
--approve-allwithnonInteractivePermissions=deny, upgrading both sides, or falling back toclaude execas a one-shot.
Sessions
A session is keyed on (agent command, absolute cwd, optional name). Because cwd is part
of the key, parallel executors each need their own directory - give every one its own git
worktree and their per-session model and effort settings cannot race.
| verb | behavior |
|---|---|
sessions ensure --name | returns the existing session or creates one - idempotent, safe before every prompt |
sessions new --name | soft-closes any current session and creates a fresh one ((replaced )) |
a bare prompt with -s | never auto-creates; exits 4 with Create one: ... |
sessions show | lastActivity, lastPrompt, historyEntries, sessionId, closed |
sessions history --limit N | the actual turn content |
sessions close | releases the agent; required before codex resume and before sessions export |
sessions list --local | local records including closed ones |
sessions prune | deletes closed records - they persist indefinitely otherwise |
Resolution without -s walks from --cwd up to the git root. A session whose cwd you have
since deleted becomes an unreachable registry row: sessions close cannot target it without
its cwd, so prune it.
Completion
Never poll status. It is a local kill(pid,0)-style check on the queue owner and never
touches the agent. Its states are running, idle, dead, no-session, where dead means
the owner is gone or the last exit was abnormal. A turn that finished seconds ago still reads
running, because the owner survives for its idle TTL (default 300s, --ttl ,
--ttl 0 to keep it forever). A loop waiting for idle will spin past real completion and
time out.
What is actually correct:
- the foreground stream's terminating
[done] end_turn, plus the process exit code; sessions show(lastActivity,historyEntries) andsessions history;- best of all, a result file the brief required the agent to write - poll for the file.
--no-wait returns as soon as the queue owner acknowledges the submission - [queued] in well under a second, even on an idle session. It is not delivery and not completion:
if a turn is already running, the prompt waits for the turn boundary. Background a normal
blocking prompt when you want the transcript; use --no-wait only to enqueue.
Supervising a backgrounded run: count tool lines and check mtime
(rg -c '^\[tool\]' run.log, stat -f '%Sm' run.log) rather than tailing the whole log, and
check liveness with pgrep -fl 'acpx|codex-acp|claude-agent-acp'.
Ctrl+C (and the cancel subcommand) sends ACP session/cancel first and force-kills only
if the agent does not stop in time.
MCP
--mcp-config replaces the project/global mcpServers for that invocation;
relative paths inside resolve from --cwd.
The file shape is not the one every other tool uses. acpx wants a JSON array of named server objects. Handing it the standard object-keyed map throws an uncaught Node exception with a stack trace, not a clean CLI error:
Error: Invalid mcpServers in /path/to/config.json: expected array
at parseMcpServers (.../acpx/dist/cli.js:1393)
// WRONG - the Claude Code / standard shape
{ "mcpServers": { "pond": { "command": "pond", "args": ["mcp"] } } }
// RIGHT - an array, each entry carrying its own name
{ "mcpServers": [ { "name": "pond", "type": "http", "url": "http://127.0.0.1:9797/mcp" } ] }
Two more traps:
- A live queue owner refuses a config change. The owner carries the config path and a
SHA-256 fingerprint; switching MCP config on a persistent session requires
sessions closefirst. - stdio servers can fail against a strict client. Antigravity's MCP client sends
server/discoverbeforeinitialized, which a compliant stdio server rejects (expect initialized request). Serve over HTTP instead when the consumer is agy.
${...} expansion inside an MCP config is evaluated in the launcher's environment,
because the acpx child inherits it - so a variable like a session id resolves to your id,
not the child's. Never let an identity flow in through the environment.
Limits
- Incoming ACP messages are capped at 64 MiB since 0.15.1 (previously unlimited). Raise
with
ACPX_MAX_ACP_MESSAGE_BYTES, or0to disable. A previously-working large-payload script can start failing here. - Terminal output retention is 64 KiB per call;
ACPX_TERMINAL_MAX_OUTPUT_BYTESadjusts it. --timeoutis the wall clock for the whole prompt. Long unattended work wants--timeout 5400 --ttl 0; a wrapping shelltimeoutis a reasonable belt-and-braces.- Output:
--format quietfor many backgrounded executors,textfor one you are watching,json(with--json-strict) when a script parses it.--suppress-readskeeps read-file contents out of the log and is worth setting on every long run. - Pass long briefs with
-for a path in the prompt, not inlined text: it keeps the content out of the shell command, where a driving harness's classifier may block on it.
What acpx cannot do
Structural, not bugs. Do not design around them.
- An ACP session does not wake. An externally injected message lands in the transcript but
starts no turn, because under ACP the turn loop belongs to the ACP client. The only inbound
channel to an acpx session is acpx itself (
-s, optionally--no-wait). codex queue --threaddoes not reach an acpx-driven codex session, though it does wake a plain interactive codex. The ACP wrapper is not in the app-server's context.- acpx-spawned Claude sessions bind no IPC socket (
entrypoint: sdk-cli, no key file), soListAgents/SendMessagecannot see or reach them. - acpx cannot attach to a session it did not start. It owns the process it drives; a human-started headful session is out of reach.
- Permission flags are not a sandbox. See invariant 4:
--deny-alldoes not prevent file writes, because the adapters do not ask.--no-terminalgenuinely removes the terminal capability (an agent that calls it gets a hard error), but for filesystem safety the only real control is which--cwdyou hand it.
Failures
Exit codes, which the shipped doc does not list:
| code | meaning |
|---|---|
| 0 | success (also cancel with nothing to cancel) |
| 1 | agent / protocol / runtime error - the catch-all |
| 2 | usage error: bad or conflicting flags, malformed --agent |
| 3 | --timeout exceeded |
| 4 | no session found by the directory walk |
| 5 | every permission request denied or cancelled, none approved |
| 130 | interrupted (cooperative cancel first) |
⚠ No acpx session found (searched up to ). (exit 4) - invariant 2. Emitted by
set, by -s prompts, by anything that resolves a session. Fix:
sessions ensure --name first. Confirm --cwd is the directory you think it is.
error: unknown option '--cwd' (exit 2) - a global flag placed after the agent
subcommand. Move it before.
Do not combine positional agent with --agent override (exit 2) - drop the positional
claude/codex when --agent supplies the adapter.
Invalid mcpServers in : expected array (uncaught, stack trace) - the MCP config is
the standard object map; convert it to an array. See MCP.
Invalid value for config option model: (ACP -32603, adapter reported "Internal error")
set modelwith an id outside the adapter's advertised list. Use--modelat session creation, or pick an advertised id from--format json ... status.
RUNTIME: Internal error: There's an issue with the selected model () - the harness
itself rejects the id. This is a real typo or an entitlement problem, not the previous case.
Internal error from claude set reasoning_effort - there is no effort knob on the
claude adapter. Expected; ignore.
[error] RUNTIME: Authentication required - the agy ACP server has never been
authenticated. One run with ACPX_AUTH_OAUTH_PERSONAL=1.
RUNTIME: This client is no longer supported for Gemini Code Assist for individuals - you
used the built-in gemini agent. It is the public Gemini CLI, not Antigravity; use --agent
with the .par server.
already has an active writer (code -32600) - codex resume while acpx still owns the
thread. sessions close first.
Missing --skill action. (exit 1) - --skill needs show, list, install, export
or help.
error: unknown option '--one-shot' (exit 2, usage on stderr) - not a verb; exec is
the one-shot form.
Timeouts (exit 3) mean the wall clock ran out, not that the agent is stuck. Check
sessions show for lastActivity before assuming failure, and remember an adapter-side
timeout surfaces as exit 1 instead.
Silent failures worth an explicit check: a content-filter kill and an MCP load failure both
end [done] end_turn with exit 0; a --no-wait prompt that "sent" may still be queued behind
a running turn; status reporting running long after completion; and a session record whose
cwd no longer exists lingering until pruned.
Related skills
Stores durable facts in a categorized, plain-markdown vault on disk, alongside your agent's built-in memory.
Generate and edit Draw.io, Mermaid, and Excalidraw diagrams from natural language using a structured JSON spec.
Trade crypto, manage a multi-chain wallet, and query an AI analyst from one CLI.
Fetch raw ad creative, app, ranking, and revenue data from AdMapix as structured JSON.
Query Twitter/X profiles, tweets, follower events, and KOL data through the 6551 REST API.
More from tenequm
Browse all skillsReference patterns for TanStack Query, Router, and Start in full-stack React apps.
Build HTTP 402 machine-to-machine payments with the MPP protocol across TypeScript, Python, and Rust SDKs.
Opinionated guide to building Agent Skills for any agent, covering layout, frontmatter, descriptions, and Claude Code specifics.
Pinned reference for Lance v11.0.0-beta.6 and the Rust/Python engine, with v10.0.0 as the stable line.
Build and deploy JavaScript, TypeScript, Python, or Rust code on Cloudflare's global edge network using the Wrangler CLI.
Build native macOS apps with Swift 6.3, SwiftUI, SwiftData, concurrency, and on-device AI.