Coding-agent backends¶
Every member pane runs one of three coding-agent binaries: claude (Claude
Code), codex (OpenAI Codex CLI), or opencode. The backend is recorded
per member in member_placements.coding_agent; selection and inheritance via
--coding-agent, mixed-backend teams, and identity delivery are covered in
Coding agents. This page specifies each
backend's spawn argv, auto-approval posture, model-flag format, and
version/config requirements.
Spawn argv¶
| Backend | Spawn argv |
|---|---|
claude |
claude --permission-mode dontAsk --name <member-name> <prompt> |
codex |
codex --ask-for-approval never --sandbox workspace-write <prompt> |
opencode |
opencode --agent cafleet --prompt <prompt> |
Shared contract:
- All three postures enable the Bash tool with no runtime permission prompts. claude and codex members run cafleet (and any shell command) directly; opencode members run cafleet and the other commands on the preset's deny-by-default allowlist, and route everything else to the Director.
- All three honor the leading-
!shell shortcut thatcafleet member execuses. --model <m>fromcafleet member createis inserted immediately before the prompt. The value passes through verbatim — the binary rejects unknown models, so newly released models need no cafleet release. Omitted, no model tokens are emitted and the binary uses its configured default. (The opencode backend additionally validates the value's format — see below.)--effort <level>fromcafleet member createforwards a reasoning-effort level, emitted immediately after the model tokens (before the prompt). Unlike--model, the accepted level set is validated per backend at create time — an unknown level exits 2 before any registration or multiplexer side effect. Omitted, no effort tokens are emitted and the argv is byte-identical to the no-effort form. opencode does not support the flag — see below.- A missing binary fails the spawn: exit 1 with
Error: binary <name> not found on PATH. - Only
claudesets the pane title (via--name); locatecodexandopencodepanes throughcafleet member list(pane_idis ground truth).
Claude¶
--permission-mode dontAsk is the reference auto-approval posture the other
backends match. Example --model values: haiku, sonnet, opus, fable.
Reasoning-effort levels: low, medium, high, xhigh, max, forwarded
as --effort <level> immediately after the model tokens. An unknown level
fails at create time with exit 2 and
Error: --effort for the claude backend must be one of low, medium, high, xhigh, max (got '<value>').
Codex¶
--sandbox workspace-write confines writes to the workspace under a
kernel-enforced sandbox — codex is the only backend with one.
--ask-for-approval never disables interactive approval prompts (upstream
write-up: https://developers.openai.com/codex/agent-approvals-security).
Example --model values: gpt-5.6-sol (default), gpt-5.6-terra,
gpt-5.6-luna, gpt-5.5.
Reasoning-effort levels: minimal, low, medium, high, xhigh,
forwarded as the single token --config=model_reasoning_effort=<level>
immediately after the model tokens. An unknown level fails at create time
with exit 2 and
Error: --effort for the codex backend must be one of minimal, low, medium, high, xhigh (got '<value>').
Two ~/.codex/config.toml requirements, covered in
Quickstart § Configure: network_access = true
(the multiplexer socket counts as network access) and writable_roots
including the cafleet DB directory. The working directory must also be
trusted before spawning
(Quickstart § Trust the working directory):
The cafleet rules file¶
~/.codex/rules/cafleet.rules grants the auto-approval posture for cafleet
commands. It ships as a static file in the assets release archive
(presets/codex/cafleet.rules) and is installed by cafleet setup:
prefix_rule(pattern = ["cafleet"], decision = "allow")
prefix_rule(
pattern = ["cafleet", "member", "exec"],
decision = "prompt",
justification = "cafleet member exec runs arbitrary commands on a member",
)
Codex applies the strictest decision when more than one rule matches
(forbidden > prompt > allow): cafleet member exec matches both rules,
so its prompt wins and each invocation keeps requiring approval, while every
other subcommand matches only the broad ["cafleet"] allow — for every fleet,
since --fleet-id is a trailing flag past the matched prefix.
The file is owned by cafleet setup: it is overwritten on every install,
so operator customizations belong in a separate rules file under
~/.codex/rules/ — Codex loads every *.rules file in that directory at
startup and applies the strictest decision across all of them. The rules file
is a permission posture, not a spawn dependency: cafleet member create
--coding-agent codex requires only the codex binary on PATH.
Opencode¶
The pane runs the bare opencode TUI (not opencode run), so it stays a
long-lived, observable pane like the other backends. The prompt is passed via
--prompt — bare opencode's positional is a project path, not a message.
--model values must be <provider-id>/<model-id>, split on the first
/ into two non-empty segments (model ids may contain further slashes).
Violations fail at create time with exit 2 and
Error: --model for the opencode backend must be '<provider-id>/<model-id>' (got '<value>').
Example values: anthropic/claude-sonnet-4-6, openai/gpt-5.5.
opencode exposes no reasoning-effort control: --effort with this backend
fails at create time with exit 2 and
Error: opencode does not support reasoning effort., before any side effect.
The cafleet agent preset¶
--agent cafleet binds the member to ~/.opencode/agents/cafleet.md. The
preset ships as a static file in the assets release archive
(presets/opencode/cafleet.md) and is installed — overwriting any existing
copy — by cafleet setup; to refresh after a CAFleet upgrade, re-run it. The
preset is a spawn precondition: the spawn argv references --agent cafleet,
so cafleet member create --coding-agent opencode fails with opencode agent
preset not found at <preset>; run 'cafleet setup' first when the file is
missing.
The preset's bash ruleset is deny-by-default: a "*": "deny" base first,
then an explicit allowlist translated from the operator's Claude Code
permissions.allow set (cafleet *, non-destructive git subcommands,
file-inspection utilities, and Python project tooling). opencode selects the
last matching rule, so this order is the safety floor — every check
resolves to allow or deny, never ask. A permission popup in an opencode pane is
therefore a regression escape, not a runtime decision: capture the pane,
escalate, and extend the allowlist by operator decision — do not answer the
popup ad hoc.
Safety-floor caveats¶
The posture is a deny-by-default allowlist, with no OS-level sandbox:
- MCP-contributed tools bypass the permission evaluator. cafleet ships no MCP stanzas; operators MUST NOT add MCP servers to any opencode config their machine loads.
- Standalone un-enumerated commands fall to the
"*": "deny"base, but bypasses under allowed globs persist: argument-space abuse and shell chaining inside acmd *match (a compound line whose leading tokens match an allowed glob, e.g.git log --stat; curl … | shmatchinggit log *), and interpreter/hook execution via allowed tooling (uv run pytest *executes workspace-writable test code;git commit *runs.git/hooks) — unless opencode's per-sub-command evaluation of compound lines is verified and recorded here. For kernel-enforced isolation, use thecodexbackend.
Validated against opencode 1.15.5 (the minimum supported version).