Skip to main content

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

agentxchain.json (runtime entry)
{
"local-dev": {
"type": "local_cli",
"command": ["claude", "--print", "--dangerously-skip-permissions", "--bare"],
"cwd": ".",
"prompt_transport": "stdin"
}
}
SettingValueWhy
--printRequiredSends output to stdout instead of interactive mode
--dangerously-skip-permissionsRequired for authoritativeGrants unattended file writes — without it the subprocess hangs on approval prompts
prompt_transportstdinClaude 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 --print mode.
  • connector check now warns about both of these: look for authority_intent and transport_intent warnings.

Verify:

agentxchain connector check local-dev # binary + authority intent + transport
agentxchain connector validate local-dev # full synthetic governed turn

OpenAI Codex CLI

agentxchain.json (runtime entry)
{
"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:

agentxchain.json (runtime entry, absolute path)
{
"local-dev": {
"type": "local_cli",
"command": ["/Applications/Codex.app/Contents/Resources/codex", "exec", "--dangerously-bypass-approvals-and-sandbox", "{prompt}"],
"cwd": ".",
"prompt_transport": "argv"
}
}
SettingValueWhy
execRequiredRuns Codex non-interactively for governed execution
--dangerously-bypass-approvals-and-sandboxRequired for authoritativeGrants full unattended authority — --full-auto is NOT sufficient
{prompt}RequiredPlaceholder that AgentXchain replaces with the full dispatch prompt
prompt_transportargvRecommended when you want AgentXchain to replace {prompt} inline

Common mistakes:

  • Using --full-auto instead of --dangerously-bypass-approvals-and-sandbox → Codex still blocks on some operations. connector check will warn: "does NOT grant full unattended authority."
  • Omitting exec or keeping an old --quiet flag → current Codex CLI exits before the turn starts. connector check now warns with command_intent.
  • Forgetting {prompt} in the command array → the prompt is never delivered. connector check warns: "no {prompt} placeholder found."
  • Using prompt_transport: "stdin" is also valid with codex exec if 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

agentxchain.json (runtime entry)
{
"local-dev": {
"type": "local_cli",
"command": ["openclaw", "run", "--non-interactive"],
"cwd": ".",
"prompt_transport": "stdin"
}
}
SettingValueWhy
--non-interactiveRequiredRuns in headless mode without terminal UI
prompt_transportstdinOpenClaw reads the prompt from standard input

Custom / Other CLIs

Any local binary that can:

  1. Accept a prompt (via stdin, argv placeholder, or by reading PROMPT.md from disk)
  2. Write files to the working directory
  3. Exit with status 0 on success

...can be used as a local_cli runtime.

agentxchain.json (runtime entry)
{
"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

TransportMechanismWhen to use
stdinPrompt piped to process standard inputClaude Code, OpenClaw, any tool that reads from stdin
argv{prompt} placeholder replaced in command arrayCodex CLI, any tool accepting prompt as CLI argument
dispatch_bundle_onlyNo prompt delivery; agent reads PROMPT.md from diskSelf-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:

agentxchain.json (global override)
{
"run_loop": {
"startup_watchdog_ms": 240000
}
}
agentxchain.json (per-runtime override)
{
"runtimes": {
"slow-model": {
"type": "local_cli",
"command": ["codex", "exec", "--dangerously-bypass-approvals-and-sandbox", "{prompt}"],
"prompt_transport": "argv",
"startup_watchdog_ms": 300000
}
}
}
ScopeFieldWhen to use
Per-runtimeruntimes.<id>.startup_watchdog_msOne runtime needs more (cold-start model download) or less (fast local binary) than others.
Globalrun_loop.startup_watchdog_msEvery runtime in this project has a consistent startup profile that differs from the 180s default.
Default180000 (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_fired entries 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:

LabelMeaningPayload highlights
spawn_attachedNode confirmed the OS spawned the child process. The watchdog is now armed.pid, at, startup_watchdog_ms
first_outputWatchdog cleared — the child produced its first stdout byte or a staged turn-result.json.at, stream (stdout | staged_result), startup_latency_ms
startup_watchdog_firedWatchdog 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_sigkillThe 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; includes startup_failure_type (no_subprocess_output or runtime_spawn_failed), stdout_bytes, stderr_bytes, and a stderr_excerpt if the child printed anything on stderr before exiting.
  • spawn_error — emitted only when the Node spawn itself errored (binary not found, EACCES, etc.); includes code, 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_cli runtime 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_authorityWhat it means
authoritativeTurn writes directly to the repo. Requires full-authority CLI flags.
proposedTurn authors patches. Does not require dangerous flags.
review_onlyInvalid 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:

  1. spawn_attached present, no first_output, then startup_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
  2. spawn_error with code: "ENOENT". The CLI binary is not on PATH for the dispatch environment. Use an absolute path in runtime.command or add the directory to PATH in your shell rc.
  3. first_output present but no staged turn-result.json. The subprocess is running and producing output but never writes the governed turn artifact. Run agentxchain 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.