Backend selection — the seven wired backends
Read it when a node runs on the wrong backend or you wire a new one. The full per-backend reference is docs/backends.md; the stale-free wiring list is the generated map-packages.md.
Backend selection
Seven backends are wired:
claw(in-process; automatic or explicit, and the last-resort fallback) — recommended for direct provider calls and Iterion-native declared tools. Use any provider model claw supports, e.g.model: "openai/gpt-5.4-mini"ormodel: "anthropic/claude-opus-5". Amodel:pin alone does not select it; usebackend: "claw"when the direct path is required.claude_code— recommended coding-agent CLI for implementation work and rich tool/shell access (implementers, fixers). A structured output (output:withjsonfields) is materialized strict-safe for this CLI: the CLI's validator only tolerates the type-union schema that codex/OpenAI require for an any-valued field as a warning (and is reported to strip it on other builds), so at this backend ajsonfield reaches the CLI as the semantically equivalent type-less any-schema (strictStructuredOutput, pkg/backend/delegate/claudesdk/strict_output_schema.go) while codex keeps the union.pi— the pi coding agent driven through the generic CLI-agent seam (ADR-065 + ADR-085, pkg/backend/delegate/pi.go):backend: "pi", prompt on stdin (pi's argv parser drops a message starting with-/@),--append-system-promptvia a file,--provider/--modelemitted together,--thinkingfor effort. Drives a long-lived--mode rpcsession by default (ITERION_PI_MODE=printrolls back to one-shot): the only CLI backend where tool events reach the studio timeline, operator chat rides nativesteer, and accounting comes fromget_session_stats. Reach for it to run a model the other backends cannot: ~36 first-class providers, plus a provider-computed USD cost (cost.AnnotateWithUSD) instead of an estimate. Its wire types are a pinned port of pi's own exported client surface in pkg/backend/delegate/pisdk/ (theclaudesdk/precedent). Capability gaps that are easy to miss:__ITERION_SECRET_*__placeholders are not materialised (file secrets work);ultracodedegrades toxhigh. iterion refuses the target repo's.pi/extensions by default (they execute as TypeScript inside the agent process). An embedded TypeScript extension (pi-extension/, bundled into pkg/backend/delegate/piext/asset/) supplies what pi has no native surface for (RPC transport only): iterion's permission gate — resolving through the samepermission.Policyas claude_code/claw —ask_userplus the async pair (ask_user_async/await_answers, ADR-081; answers delivered mid-run via nativesteer), and a hand-rolled MCP client on all three transports (streamable http, legacy sse, stdio), since pi ships none. That client is what makes boardcapabilities:and workflowmcp_server:blocks reach a pi node; tools are discovered viatools/list, never hardcoded. Bridging happens inside pi'ssession_start, which iterion's own RPC handshake waits on, so each server is bounded byITERION_PI_MCP_CONNECT_TIMEOUT_MS(default 10s) and connects in parallel — an unreachable server costs its own tools, never the run.task pi-ext:checkfails if the committed asset is stale. Cost gotcha: pi injects the repo'sAGENTS.md+CLAUDE.mdon every call — measured at 26,933 vs 448 input tokens for a one-word prompt when this repo'sCLAUDE.mdwas 103 KB (ADR-085);ITERION_PI_NO_CONTEXT_FILES=1turns it off.codex— supported Codex CLI backend (pkg/backend/delegate/codex.go), selected explicitly per node/workflow or by adding it toITERION_BACKEND_PREFERENCE. It uses the Codex CLI login, including ChatGPT OAuth, and supports images, reasoning effort, sessions and structured output. Its native tool set cannot currently be narrowed through Iterion'stools:list (AllowedTools/CanUseTooldo not gate the built-in shell), and the pinned SDK cannot run inside Iterion's outer Docker/Kubernetes sandbox; document and test those capability boundaries when extending it.kimi— Moonshot's kimi-code CLI driven through the generic CLI-agent seam (ADR-065, pkg/backend/delegate/kimi.go):backend: "kimi", prompt via-p, stream-json output, model alias passed through verbatim (e.g.model: "kimi-code/kimi-for-coding"); credentials are resolved by the CLI itself from its own env/config. Sessions are best-effort — resume/fork are not wired for CLI-agent backends, so each node runs fresh.grok— xAI Grok Build CLI driven through the same CLI-agent seam (ADR-065, pkg/backend/delegate/grok.go):backend: "grok", prompt via-p,--output-format json,system:via--rules(append — never override the native agentic baseline), model via-m(optionalxai/prefix stripped),reasoning_effortvia--reasoning-effort; headless tool approval forced with--permission-mode bypassPermissions --always-approve. Credentials come from the CLI itself (Grok Build login /~/.grok). Distinct from the metered xAI HTTP API path (backend: claw+model: "xai/…").opencode— the opencode agent CLI through the same CLI-agent seam (ADR-065, pkg/backend/delegate/opencode.go):backend: "opencode", headless via therunsubcommand FIRST (2.x refuses a flag before it;ITERION_OPENCODE_ARGV=1re-emits the 1.x flags-first order), prompt on stdin (its message is a variadic positional, which swallows a prompt starting with-— the same trap pi documents),--format json, model via-m provider/modelpassed through unchanged (its own format is iterion's spec shape),reasoning_effortfolded into it as#variant(accepted names are per-model; iterion passes the level verbatim, and 2.x refuses an unknown one; a reference that already spells one keeps it and the dial is warned, not appended). Credentials come from the CLI itself. Capability gaps that are easy to miss: it cannot enforce iterion's permission gate in ANY mode — noPreToolUsehook — so a gated node is refused by C176 at compile and again at dispatch;interaction: asyncis refused by C267; session resume/fork is wired (--session <id>/--fork=true, afterrun; an unknown id is "Session not found" on 1.x and CREATED on 2.x) butsession: persistis not — opencode keeps its sessions in one SQLite database, with no per-session file to pack; MCP forwarding andtools:narrowing are not wired;command:(C174) andprovider:(C088) are inert. Security: opencode executes the workspace's.opencode/plugin[s]/*.tsinside the agent process, so iterion refuses a workspace carrying one unlessITERION_OPENCODE_TRUST_PROJECT=1, and pinsOPENCODE_DISABLE_CLAUDE_CODE=1so a node's prompt never depends on the operator's~/.claude. Not baked into the stock sandbox image.
