`ClaudeCodeOptions.warmup_turn` defaults to `None`, which decides per
agent: on when the agent exposes any MCP, off otherwise. An agent whose
tools are the point shouldn't answer its first message without them, and
an agent with no MCPs shouldn't pay for a warm-up it gains nothing from.
The underlying reason lives in claude-code-api: the CLI connects MCP
servers when a turn starts and doesn't await them, so turn one runs with
built-in tools only.
`ClaudeCodeOptions.transport="stream_json"` runs the agent on `claude -p`
with stream-json on both pipes instead of driving the TUI through a
pseudo-tty. Opt-in: the default stays `pty`, so nothing moves until a
config asks for it.
The reason to ask for it is that the PTY path pays a multi-second
readiness wait before every spawn and can silently lose a prompt to a
swallowed paste; the headless path writes to a pipe and gets a native
`result` record back. `--remote-control` and friends are dropped by the
transport when set, since they'd take claude out of print mode.
`include_partial_messages` then gives clients genuine token-level SSE.
Blocks are emitted from the `StreamEvent`s rather than forwarded raw:
the payload is already Anthropic-shaped but arrives as a dict, so it
would need validating against the SDK union anyway, and rebuilding it
through our own builders drops an unrecognized block or delta type the
same way `_emit_block` already does instead of raising mid-stream on a
claude release that adds one. When streaming, the whole-block records
are kept for TurnCapture but not re-emitted — that would duplicate every
block on the wire.
Verified end-to-end against a live claude: both paths accumulate to the
identical Message (same blocks, same stop_reason, same usage), the
envelope stays 1:1, and block indices stay collision-free across a turn
that spans several API requests.