Skip to content

Agent CLI driver matrix — verified, not from docs

Every row was read from --help and then confirmed by a live probe that checked what landed on the board. Versions matter; re-run mooting doctor after any CLI upgrade rather than trusting this file.

CLI version headless resume by id prompt via per-run MCP injection read-only mode
Claude Code 2.1.250 -p/--print --session-id/--resume (our UUID) argv --mcp-config + --strict-mcp-config --allowedTools allowlist
Codex 0.149.0 codex exec yes, but see below stdin (-) no — mooting install
Copilot 1.0.81 -p + --allow-all-tools -r/--resume=<id> argv --additional-mcp-config --deny-tool
Antigravity agy 1.1.20 -p/--print --conversation <id> argv no — mooting install --mode plan

Four traps, each of which looks like something else

These cost real time to find. Every one presents as a different problem than it is.

1. Windows .CMD shims cannot carry a multi-line argument

codex and some other CLIs install as npm batch shims. shutil.which resolves codex.CMD, and CreateProcess runs a .CMD through cmd.exe — which cannot pass an argument containing newlines. The prompt breaks at the first line ending and every flag after it disappears.

Council prompts are always multi-line markdown, so this is not an edge case; it is the normal case. And the symptom is not a quoting error:

codex exec "<multi-line prompt>" --approve-for-me
  → header prints  approval: never          (the flag never arrived)
  → MCP tool call requires approval, but approval policy is never

That reads as "the MCP server is misconfigured", and sends you to debug config.toml, -c syntax, and plugins — none of which are involved. Test: the same call with a single-line prompt works. Fix: send the prompt on stdin.

2. codex exec defaults to refusing every MCP call

Its default approval policy is never, which does not mean "don't ask, just run it". It means refuse. The server is loaded, the tool is dispatched, and the call is denied. --approve-for-me is required, and it is mutually exclusive with --sandbox.

3. --json silently defeats --approve-for-me

With both flags the policy reverts to never and every MCP call fails again, same misleading message. Codex prints its session id in the plain-text header anyway.

4. Codex defers MCP tools out of the initial tool list

tool_search_always_defer_mcp_tools is on. Ask codex to "list the tools containing mooting" and it answers NONE while being perfectly able to call them. So "can you see it?" is not a valid health check — only "call it, and did it land?" is. mooting doctor's probe prompt says so explicitly, because an earlier version of it offered "reply NO-MOOTING-TOOLS if you can't see the tool" and codex, truthfully, took that exit every time.

Related noise: a github MCP server that is Not logged in prints rmcp worker quit with fatal: ... AuthRequired on every codex start. It is alarming and irrelevant — other servers load fine alongside it.

Session continuity is optional, and two seats decline it

Claude resumes cleanly by a UUID we choose. The others have reasons not to:

  • Codex — resume and stdin are mutually exclusive. codex exec resume <id> demands a literal positional prompt and will not take -. Since multi-line prompts must go through stdin (trap 1), resume loses.
  • Antigravity--conversation <id> works, but a resumed seat carries its whole history: a probe conversation reached 132k input tokens, and one resumed turn took 800 seconds against 13 for a fresh one.

This costs nothing, because the board is the shared memory. A stateless seat rebuilds context from the record each turn and cannot drift from what was actually said. stateful = False is a supported mode, not a degraded one.

Blast radius

v0 seats deliberate; they do not edit files. Each adapter asks its CLI for the narrowest surface it offers, and they are not equally strong — Claude's --strict-mcp-config plus an allowlist is tightest; Antigravity's plan mode is genuinely read-only; Copilot must be given --allow-all-tools for -p at all, so it is narrowed by denial instead. mooting doctor verifies reachability empirically rather than trusting that a flag did what its name says.

Machine-local quirks belong in the seat, not the driver

mooting agents add <name> <kind> --arg=... appends argv to every wake for that seat. Use it for one machine's problems — a broken plugin to switch off, a flag a newer build needs — so the adapters stay general instead of accumulating one person's environment.