Install the dependencies
A code-execution tool
The smallest useful integration is a tool that runs Python in a sandbox, given to a tool-calling agent. The sandbox is not created inside the tool — it is passed in through LangGraph’s runtime context, so every call in the run reuses the same kernel and the same filesystem:runtime: ToolRuntime[Context] is injected by LangGraph and never appears in the schema the model sees — the model only sees code. You pass context= on every invoke, which is what makes the lifecycle below possible. Any tool-calling chat model works here; for OpenAI reasoning models use the Responses API (use_responses_api=True) and set reasoning={"effort": ...} — OpenAI recommends Responses for function calling with reasoning models.
Sandbox lifecycle across graph steps
A LangGraph run can outlive a single tool call by a lot: nodes run one after another, a checkpointer persists state between them, andinterrupt() can hold the graph for as long as a human takes to answer. The sandbox has its own lifecycle. Three rules keep the two in step.
Keep the Sandbox in context and the sandbox_id in state
Graph state is checkpointed, so everything in it must be serialisable. The Sandbox object is not — it holds a live connection. Put the object in context_schema and its id in state:
runtime.context.sandbox and gets the same sandbox. Files written in one node are there for the next; variables defined in one run_code call are defined in the next.
Rebuild the context when you resume
Context is not checkpointed. After aninterrupt(), or when a resume runs in a different process from the original invoke, nodes see runtime.context as None. The only thing the checkpoint kept is the sandbox_id in state — reconnect from it:
Sandbox.connect() returns a handle to the same sandbox, with its filesystem and running processes intact. If the sandbox was paused in the meantime, connect() resumes it.
Let the sandbox outlive the interrupt
The default sandbox timeout is 300 seconds. A human reviewing a plan may take longer, and a sandbox that hit its timeout is gone. Tell E2B to pause instead of kill, and to wake up when the graph comes back:Sandbox.connect(), run_code(), files.read() — resumes it automatically. See Auto-resume and Persistence.
Tear down explicitly
Kill the sandbox in afinally block so cleanup runs whether the graph finished, was rejected at the interrupt, or raised. If you would rather tie it to the agent’s lifetime, an AgentMiddleware after_agent hook receives the same runtime and can call runtime.context.sandbox.kill().
Plan-and-execute coding agent
The cookbook example puts all of this into one hand-wired graph. It repairs a small Python project whose tests fail:bootstrapuploads the project, installs pytest and records the failing output — in a sandbox created withon_timeout: pause.planasks the model for an ordered list of file changes as structured output.approvestops the graph withinterrupt(); the resume reconnects fromsandbox_id.executeruns one plan step per node visit with a small tool-calling agent (read_file,write_file,run_command), always in the same sandbox — pytest installed inbootstrapis still there.verifyre-runs the suite; the graph re-plans on red, at most three times, and exits non-zero if the tests never pass.
Results and errors
run_code() returns an Execution:
logs.stdout/logs.stderr— lists of output lines;results— rich outputs such as text, charts (png), HTML or JSON;execution.textis the text of the last one;error—None, or an object withname,valueandtracebackwhen the cell raised.
sandbox.commands.run() raises CommandExitException on a non-zero exit — it carries exit_code, stdout and stderr, so a tool can catch it and return all three.
Security considerations
E2B isolates model-generated code from the machine running your graph. The sandbox still processes untrusted input and produces untrusted output:- do not expose API keys or other host secrets to the sandbox unless the task needs them;
- keep sandbox and per-call timeouts as short as the workload allows, and use
on_timeout: pauserather than a very long timeout when a human is in the loop; - kill sandboxes you own, in
finally; - treat files the agent writes as a proposal to review, not a result to trust.
LangGraph vs. Deep Agents vs. Open SWE
All three are LangChain projects and all three run on the LangGraph runtime. They differ in how much graph you write and in what role the sandbox plays:Related guides
Sandbox persistence
Pause and resume sandboxes with memory and filesystem intact
Auto-resume
Pause on timeout and wake up on the next request
Deep Agents
LangChain’s agent harness with E2B as the sandbox backend