If your agent calls tools in a chain — fetch a list, loop over it, filter, then summarize — you are paying for a model round-trip on every single call. Ten calls, ten turns, ten times the latency, and a prompt that grows with every result you feed back in. Pydantic AI's Harness ships a capability that collapses that whole loop into one turn: the model writes a single Python script, the script does the fan-out, and you get one answer back. It's a two-line change. Here's what it is and when to reach for it.
The two-line change#
CodeMode is a capability — V2's composable unit that plugs into an agent. You install the extra and attach it:
# uv add "pydantic-ai-harness[code-mode]"
from pydantic_ai import Agent
from pydantic_ai_harness import CodeMode
agent = Agent(
'anthropic:claude-opus-4-7',
capabilities=[CodeMode()],
)
That's it. Your existing tools — the ones you registered with @agent.tool — don't change. What changes is how the model sees them.
What actually happens#
Without CodeMode, every tool you register shows up to the model as a separate callable, and the agent loop is: model emits one tool call → framework runs it → result goes back into the prompt → repeat. Each step is a network round-trip to the model.
With CodeMode, the whole toolset is wrapped behind one tool: run_code. The model no longer emits tool-call JSON one action at a time. It writes a Python script — with loops, conditionals, and await — that calls your tools directly, and the Harness executes that script in a sandbox. A task that used to be ten turns becomes one:
# What the model writes into run_code — one turn, not ten:
urls = await search("agent framework releases 2026") # your tool
pages = [await fetch(u) for u in urls[:10]] # loop, no extra turns
recent = [p for p in pages if "2026-07" in p.date] # filter in-sandbox
return summarize(recent) # your tool
The intermediate results — ten fetched pages — never re-enter the model's context. They live in the sandbox. The model only sees the final return. That's where the token savings come from, and it's the same idea behind MCP code execution vs. direct tool calls and Anthropic's programmatic tool calling — the Harness just makes it a one-line opt-in on an agent you already have.
The trade you're making#
Nothing is free. Three things change the moment you turn it on:
- You're running model-written code. The sandbox is the security boundary. Scope the tools you expose, and don't hand a CodeMode agent secrets or unrestricted network and filesystem access you wouldn't give the model directly. This is the same discipline as any agent that can execute code.
- Debugging moves. You stop reading a clean tool-call trace and start reading the script the model generated. When it goes wrong, it goes wrong in Python, not in JSON.
- Approval granularity drops. If your product needs a human to sign off on each action, CodeMode fights you: the fan-out happens inside one script that a reviewer sees as a single
run_codestep, not ten approvable calls.
When to reach for it#
Turn CodeMode on when the shape of the work is many calls — chains and fan-outs over collections, where the round-trips are your latency and cost. Leave it off when your tools are called once per task, or when per-action approval is a product requirement rather than a nicety.
The larger point is the one the Harness keeps making: agent behavior is becoming something you compose rather than hand-wire. CodeMode is one line in a capabilities=[] list, sitting next to memory, guardrails, and filesystem access — swap it in when the round-trips hurt, swap it out when you need the granularity back.



