Run Pydantic AI coding agents in E2B sandboxes Pydantic AI now offers E2B as a native sandbox provider, letting coding agents run every shell command and file operation inside an isolated E2B microVM instead of on the developer's machine, according to the E2B cookbook walkthrough. Adding E2BSandbox() to an agent's capabilities keeps the host environment out of the sandbox, and the sandbox can pause when a run ends and resume with its filesystem and memory intact; by default a sandbox lives for one hour unless sandbox_timeout is set, after which E2B pauses rather than kills it, internet access is on unless allow_internet_access=False, and Pydantic AI never kills a sandbox when a run ends. The post demonstrates a two-run diagnose-then-fix agent that pauses the sandbox between runs and the same task inside a Temporal workflow where the worker process is killed halfway through. A coding agent that can run python -m unittest and edit files is useful. A coding agent that runs them on your laptop, as you, with your SSH keys in ~/.ssh and your production .env two directories up, is a liability you have agreed to without reading the terms and conditions. The agent decided what to run, and nobody reviewed the command before it ran. An agent that waited for review would not be an agent. E2B https://e2b.dev is now a native sandbox provider in Pydantic AI https://pydantic.dev/docs/ai/ . Add E2BSandbox to an agent's capabilities and every shell command and file operation the agent makes runs inside an isolated E2B microVM instead of on your machine. Nothing from your environment reaches the sandbox. The sandbox can pause when a run ends and resume when the next one starts, with its filesystem and memory intact. And because the workspace is identified by a credential-free reference, a durable workflow can carry it across a worker crash. This post walks through two examples from the E2B cookbook https://github.com/e2b-dev/e2b-cookbook : a two-run diagnose-then-fix agent that pauses the sandbox between runs, and the same task inside a Temporal workflow where the worker process gets killed halfway through. Install the harness with the E2B and Temporal extras, the provider extras the snippets below use the quick start calls Anthropic, the cookbook examples call OpenAI , and the Logfire https://pydantic.dev/logfire extra so the runs are traced. Then set E2B API KEY and the provider key: uv add "pydantic-ai-harness e2b,anthropic,temporal " "pydantic-ai-slim openai,logfire " Then give the agent the sandbox alongside the tools that will use it: python import logfire from pydantic ai import Agent from pydantic ai harness.coder import Coder from pydantic ai harness.e2b sandbox import E2BSandbox logfire.configure logfire.instrument pydantic ai agent = Agent 'anthropic:claude-opus-5-5', capabilities= E2BSandbox , Coder result = agent.run sync 'Clone https://github.com/pydantic/pydantic-ai and summarize how capabilities work.' E2BSandbox supplies execution only. Coder , or the narrower Shell and FileSystem capabilities, supply the tools, and those tools now run in the sandbox. There is no custom E2B adapter and no template to build. E2B's default template ships with Python and git, which is enough for this post; a project with its own dependencies installs them in a custom template https://pydantic.dev/docs/ai/harness/e2b-sandbox/ or with a pip install run inside the sandbox before the agent starts, since the default template has pip but not uv. A few defaults worth knowing before the first run. A sandbox lives for an hour unless you pass sandbox timeout , and when that runs out E2B pauses it rather than killing it. Internet access is on unless you turn it off with allow internet access=False . And Pydantic AI never kills a sandbox when a run ends: the application that created it owns its lifetime, and a sandbox you forget is a sandbox you are paying for. The E2B sandbox guide https://pydantic.dev/docs/ai/harness/e2b-sandbox/ covers cleanup, including an on run error hook for runs that fail before there is a result to read a reference from. The first cookbook example https://github.com/e2b-dev/e2b-cookbook/tree/main/examples/pydantic-ai-python gives the agent a small Python CLI that summarizes JSONL API request logs. Its tests fail: the CLI counts server errors wrong and computes p95 latency wrong. The agent gets two runs. The first reads the code and the failing tests and writes diagnosis.md without touching the source. The application then pauses the sandbox, builds a fresh backend attached to it, and a second run fixes the bug using the saved diagnosis and the first run's conversation history. The agent definition is ordinary Pydantic AI. The only E2B-specific part is the capability: python import logfire from pydantic ai import Agent from pydantic ai harness.e2b sandbox import E2BSandbox from pydantic ai harness.filesystem import FileSystem from pydantic ai harness.shell import Shell logfire.configure logfire.instrument pydantic ai WORKDIR = '/home/user/log-cli' agent = Agent 'openai:gpt-4.1-mini', name='log cli fixer', instructions='Work only in this sandbox project. Use the supplied tools; verify claims by running tests.', capabilities= E2BSandbox working dir=WORKDIR, sandbox timeout=600, allow internet access=False, , Shell tools= 'run command' , default timeout=20, max output chars=6000 , FileSystem tools= 'read file', 'write file', 'edit file' , , The cookbook narrows the tool surface on purpose. Shell exposes only run command , FileSystem exposes three file tools, and internet access is off because the fixture needs no downloads. A sandbox is a boundary, and a narrow tool list makes the boundary cheaper to reason about. The application seeds the fixture before the agent starts, by constructing the backend itself and working in it through Workspace : python from pydantic ai.workspaces import Workspace from pydantic ai harness.e2b sandbox import E2BSandbox, E2BSandboxBackend backend = E2BSandboxBackend working dir=WORKDIR, sandbox timeout=600, allow internet access=False workspace = Workspace backend for name in 'log stats.py', 'test log stats.py', 'requests.jsonl' : await workspace.write bytes name, FIXTURE / name .read bytes first = await agent.run DIAGNOSE, workspace=backend, usage limits=limits ref = first.workspace.ref Building the backend does no I/O. The first write bytes creates the sandbox, and from then on backend.ref identifies it. The run result carries the same reference in first.workspace.ref . Now the pause. The application asks the backend for the typed e2b.AsyncSandbox , pauses it, and then constructs a new backend that knows only the reference: sandbox = await backend.get sandbox assert await sandbox.pause attached = E2BSandbox working dir=WORKDIR, sandbox timeout=600 .backend ref second = await agent.run FIX, workspace=ref, message history=first.all messages , usage limits=limits , assert second.workspace.ref == ref The attached backend's first file read resumes the paused sandbox. E2B keeps a paused sandbox indefinitely https://e2b.dev/docs/sandbox/persistence , filesystem and memory both, so diagnosis.md is where the first run left it. The second run gets workspace=ref to select the sandbox and message history to carry the conversation. Either the ref or a history that names it will select the sandbox, but only the history carries what the agent already knows, and the cookbook passes both. The example then does something I want more agent demos to do: it checks the agent's work instead of trusting the agent's summary. It restores the test file from the trusted host fixture, because a shell command can bypass a file tool's restrictions, confirms the input logs were not edited, and runs the tests itself. Four tests pass, the CLI prints the right counts, and the application kills the sandbox in a finally block and confirms it is gone from the account. Created sandbox: