Local CLI recipes
This page collects the exact command shapes, transports, and gotchas for every supported local CLI agent runtime. Stop guessing flags — paste the recipe, run connector validate, dispatch your first turn.
Claude Code
{
"local-dev": {
"type": "local_cli",
"command": ["claude", "--print", "--dangerously-skip-permissions", "--bare"],
"cwd": ".",
"prompt_transport": "stdin"
}
}
| Setting | Value | Why |
|---|---|---|
--print | Required | Sends output to stdout instead of interactive mode |
--dangerously-skip-permissions | Required for authoritative | Grants unattended file writes — without it the subprocess hangs on approval prompts |
prompt_transport | stdin | Claude Code reads the prompt from standard input in --print mode |
Common mistakes:
- Omitting
--dangerously-skip-permissions→ subprocess hangs waiting for user approval, turn times out. - Using
prompt_transport: "argv"→ Claude Code does not accept prompts as CLI arguments in--printmode. connector checknow warns about both of these: look forauthority_intentandtransport_intentwarnings.
Verify:
agentxchain connector check local-dev # binary + authority intent + transport
agentxchain connector validate local-dev # full synthetic governed turn
OpenAI Codex CLI
{
"local-dev": {
"type": "local_cli",
"command": ["codex", "exec", "--dangerously-bypass-approvals-and-sandbox", "{prompt}"],
"cwd": ".",
"prompt_transport": "argv"
}
}
If you installed Codex through the macOS app bundle, or doctor says bare codex is not resolvable in the dispatch spawn context, prefer the absolute executable path:
{
"local-dev": {
"type": "local_cli",
"command": ["/Applications/Codex.app/Contents/Resources/codex", "exec", "--dangerously-bypass-approvals-and-sandbox", "{prompt}"],
"cwd": ".",
"prompt_transport": "argv"
}
}
| Setting | Value | Why |
|---|---|---|
exec | Required | Runs Codex non-interactively for governed execution |
--dangerously-bypass-approvals-and-sandbox | Required for authoritative | Grants full unattended authority — --full-auto is NOT sufficient |
{prompt} | Required | Placeholder that AgentXchain replaces with the full dispatch prompt |
prompt_transport | argv | Recommended when you want AgentXchain to replace {prompt} inline |
Common mistakes:
- Using
--full-autoinstead of--dangerously-bypass-approvals-and-sandbox→ Codex still blocks on some operations.connector checkwill warn: "does NOT grant full unattended authority." - Omitting
execor keeping an old--quietflag → current Codex CLI exits before the turn starts.connector checknow warns withcommand_intent. - Forgetting
{prompt}in the command array → the prompt is never delivered.connector checkwarns: "no {prompt} placeholder found." - Using
prompt_transport: "stdin"is also valid withcodex execif you intentionally omit{prompt}and pipe the prompt instead of passing it on argv.
Verify:
agentxchain connector check local-dev
agentxchain connector validate local-dev
OpenClaw
{
"local-dev": {
"type": "local_cli",
"command": ["openclaw", "run", "--non-interactive"],
"cwd": ".",
"prompt_transport": "stdin"
}
}
| Setting | Value | Why |
|---|---|---|
--non-interactive | Required | Runs in headless mode without terminal UI |
prompt_transport | stdin | OpenClaw reads the prompt from standard input |
Custom / Other CLIs
Any local binary that can:
- Accept a prompt (via stdin, argv placeholder, or by reading
PROMPT.mdfrom disk) - Write files to the working directory
- Exit with status 0 on success
...can be used as a local_cli runtime.
{
"local-dev": {
"type": "local_cli",
"command": ["my-agent", "--headless"],
"cwd": ".",
"prompt_transport": "dispatch_bundle_only"
}
}
Use dispatch_bundle_only when the agent reads its own prompt from the dispatch directory rather than from stdin or argv.
Prompt transport reference
| Transport | Mechanism | When to use |
|---|---|---|
stdin | Prompt piped to process standard input | Claude Code, OpenClaw, any tool that reads from stdin |
argv | {prompt} placeholder replaced in command array | Codex CLI, any tool accepting prompt as CLI argument |
dispatch_bundle_only | No prompt delivery; agent reads PROMPT.md from disk | Self-managing agents, custom runners |
Startup watchdog and diagnostics
Every local_cli dispatch is gated by a startup watchdog. The adapter arms the watchdog as soon as the subprocess reports a successful spawn and clears it the instant the process produces its first stdout byte or stages a turn-result.json. Stderr is diagnostic evidence only; stderr by itself does not prove the governed turn started. If the watchdog fires before stdout or a staged result appears, the adapter SIGTERMs the child, escalates to SIGKILL after the grace window if the child ignores SIGTERM, and classifies the turn as startupFailureType: "no_subprocess_output" so run --continuous can recover cleanly instead of wedging.
Default and overrides
The default is 180 seconds (180000 ms) — long enough for realistic dispatch bundles (the tusq.dev beta floor measured 17,737 bytes of prompt + context) to reach Claude Code or Codex CLI and produce their first log line, short enough that a genuinely wedged runtime does not stall lights-out operation for an hour.
Two overrides exist; precedence is per-runtime > global > default:
{
"run_loop": {
"startup_watchdog_ms": 240000
}
}
{
"runtimes": {
"slow-model": {
"type": "local_cli",
"command": ["codex", "exec", "--dangerously-bypass-approvals-and-sandbox", "{prompt}"],
"prompt_transport": "argv",
"startup_watchdog_ms": 300000
}
}
}
| Scope | Field | When to use |
|---|---|---|
| Per-runtime | runtimes.<id>.startup_watchdog_ms | One runtime needs more (cold-start model download) or less (fast local binary) than others. |
| Global | run_loop.startup_watchdog_ms | Every runtime in this project has a consistent startup profile that differs from the 180s default. |
| Default | 180000 (built-in) | You have not observed startup_watchdog_fired and dispatches regularly produce first output within ~60s. |
For observed slow runtimes, set the watchdog above the measured p99 first_output.startup_latency_ms: use max(p99 + 30000, ceil(p99 * 1.5)) as a starting point, then keep tuning per runtime unless every runtime shares the same latency profile.
When to raise
Raise the watchdog when any of the following is true for a specific runtime:
- Cold-start latency is dominated by model download or JIT compile (e.g., Codex against a cold local model, MLX first-load, Ollama pulling a tag).
- The dispatch bundle is unusually large (multi-MB context packs) and the runtime reads the full bundle before printing any startup banner.
- Your operator observed repeated
startup_watchdog_firedentries on a runtime that, when re-run manually, completes successfully with visible output appearing in the 120–180s window.
Raise it on the specific runtime if only one is slow. Raise the global only if every runtime shares the same startup profile.
When to lower
Lower the watchdog when:
- You run an in-house runtime that always prints a startup banner within a few seconds, and you want silent hangs to surface faster in
run --continuous. - You configure a ghost-turn recovery policy (e.g.,
run_loop.continuous.auto_retry_on_ghost) that reissues the turn cheaply — a shorter watchdog trades a slightly higher false-positive rate for faster lights-out recovery.
Do not lower the default below the observed p99 of first_output startup_latency_ms for your slowest runtime; leave at least 30s of headroom or you will false-kill healthy dispatches and produce ghost turns.
Inspecting diagnostics
Every adapter run writes structured diagnostic lines to .agentxchain/dispatch/turns/<turnId>/stdout.log with the prefix [adapter:diag]. The four startup labels you should know:
| Label | Meaning | Payload highlights |
|---|---|---|
spawn_attached | Node confirmed the OS spawned the child process. The watchdog is now armed. | pid, at, startup_watchdog_ms |
first_output | Watchdog cleared — the child produced its first stdout byte or a staged turn-result.json. | at, stream (stdout | staged_result), startup_latency_ms |
startup_watchdog_fired | Watchdog elapsed with no first output and no staged result. The adapter SIGTERMs the child; the turn is retained as a failed start. | startup_watchdog_ms, startup_watchdog_sigkill_grace_ms, pid, spawn_confirmed_at, elapsed_since_spawn_ms |
startup_watchdog_sigkill | The startup watchdog grace window elapsed and the child ignored SIGTERM, so the adapter sent SIGKILL instead of waiting for the longer turn deadline. | startup_watchdog_ms, startup_watchdog_sigkill_grace_ms, pid, elapsed_since_spawn_ms |
Two companion diagnostics help you classify the failure when the watchdog fires:
process_exit— always emitted; includesstartup_failure_type(no_subprocess_outputorruntime_spawn_failed),stdout_bytes,stderr_bytes, and astderr_excerptif the child printed anything on stderr before exiting.spawn_error— emitted only when the Node spawn itself errored (binary not found, EACCES, etc.); includescode,errno,syscall.
To locate the failing turn before opening its dispatch log, use the event stream:
agentxchain events --type turn_start_failed,runtime_spawn_failed,stdout_attach_failed --limit 20 --json
To triage a suspected ghost turn quickly:
# Did the child ever attach?
grep 'adapter:diag.*spawn_attached' .agentxchain/dispatch/turns/<turnId>/stdout.log
# Did it produce first output before the watchdog fired?
grep -E 'adapter:diag (first_output|startup_watchdog_fired)' \
.agentxchain/dispatch/turns/<turnId>/stdout.log
# If the watchdog fired, did it need SIGKILL after SIGTERM?
grep -E 'adapter:diag (startup_watchdog_fired|startup_watchdog_sigkill)' \
.agentxchain/dispatch/turns/<turnId>/stdout.log
A spawn_attached + startup_watchdog_fired pair with no first_output between them is the canonical "runtime started but never spoke" signature — usually a keychain prompt, an auth hang, or a genuinely stuck model. A missing spawn_attached is the signature of a spawn-time failure (bad path, missing binary, sandbox denial) and should show up as spawn_error.
BUG-54 context
Before [email protected] the built-in default was 30,000 ms. Realistic dispatch bundles reliably produced first output in the 60–113s range on working Claude Max setups, so the 30s watchdog false-killed healthy dispatches and generated the ghost-turn stream that dominated early beta reports. The default is now 180s; if you inherited a project pinned to startup_watchdog_ms: 30000 from the old default, unpin it to adopt the new built-in.
Cursor, Windsurf, and other editors
Cursor and Windsurf are editor extensions, not headless CLI tools. They do not have a governed local CLI runtime.
To use AgentXchain with Cursor or Windsurf:
- Install Claude Code or Codex CLI separately
- Configure the
local_cliruntime to point at the CLI tool, not the editor - Use the editor for interactive development; use the CLI runtime for governed automated turns
See the Cursor integration guide and Windsurf integration guide for details.
Authority model recap
The command flags above only control the downstream tool's sandbox/approval behavior. AgentXchain has a separate write_authority setting on each role:
write_authority | What it means |
|---|---|
authoritative | Turn writes directly to the repo. Requires full-authority CLI flags. |
proposed | Turn authors patches. Does not require dangerous flags. |
review_only | Invalid with local_cli — local CLI has repo write access, so review_only is a contradiction. Use api_proxy, mcp, or manual instead. |
See the Authority Model page for the full three-axis explanation.
Troubleshooting
Turn times out or hangs
Check .agentxchain/dispatch/turns/<turnId>/stdout.log first. Three signatures are common:
spawn_attachedpresent, nofirst_output, thenstartup_watchdog_fired. The subprocess is alive but silent — usually waiting for approval input, a keychain prompt, or a cold model load. Add the full-authority flag for your CLI, then see Startup watchdog and diagnostics if the hang persists and you need to raise the watchdog for a genuinely slow runtime:- Claude Code:
--dangerously-skip-permissions - Codex:
--dangerously-bypass-approvals-and-sandbox
- Claude Code:
spawn_errorwithcode: "ENOENT". The CLI binary is not onPATHfor the dispatch environment. Use an absolute path inruntime.commandor add the directory toPATHin your shell rc.first_outputpresent but no stagedturn-result.json. The subprocess is running and producing output but never writes the governed turn artifact. Runagentxchain connector validate <runtime>to confirm the runtime can complete a synthetic turn end-to-end.
connector check shows WARN for authority_intent
Your command array is missing the flag required for the role's write_authority: authoritative setting.
Fix: Follow the Fix: guidance printed by connector check.
connector check shows WARN for transport_intent
The configured prompt_transport does not match what the CLI expects.
Fix: Use the transport listed in the recipe above for your CLI.
Undeclared file changes on acceptance
Your working tree had uncommitted files before the turn was dispatched. The acceptance validator sees them as "new files the agent touched" but they were not in files_changed.
Fix: Commit all changes before dispatching the next authoritative turn. See the clean baseline rule.