Skip to main content
Sandcastle is a TypeScript library for orchestrating coding agents such as Claude Code and Codex on a git repository. Its built-in E2B provider runs each agent in its own E2B sandbox. Sandcastle copies your repository in, runs the agent there, brings its commits back to a branch on your machine, and kills the sandbox.

Prerequisites

  • Node.js 22.19 or later, and git
  • An E2B API key
  • A key for your agent, for example ANTHROPIC_API_KEY for Claude Code

Install

The E2B provider uses the e2b package as an optional peer dependency, so install both:
Set your E2B API key in the shell where you run Sandcastle, or pass it as the apiKey option:
Don’t put E2B_API_KEY in .sandcastle/.env. Sandcastle forwards every key declared there into the sandbox, where the agent could read it.

Run Claude Code

E2B’s default template has no agent CLI. Use the prebuilt claude template, which ships Claude Code:
run.mts
Run it from the root of your git repository with npx tsx run.mts. The agent’s commits land on your current branch; pass branchStrategy: { type: "branch", branch: "agent/fix" } to put them on a separate branch instead. Only the environment variables you give Sandcastle reach the sandbox: keys declared in .sandcastle/.env, and the env of the agent and sandbox providers. That’s why the example passes ANTHROPIC_API_KEY explicitly.

Run Codex

Use the prebuilt codex template and pass your OpenAI key as CODEX_API_KEY, which codex exec reads. OPENAI_API_KEY alone isn’t enough.
For another agent, use a custom template with its CLI installed, or install it in a Sandcastle onSandboxReady hook.

Run agents in parallel

Each run() creates its own sandbox, so you can start several agents at once with Promise.allSettled, each on its own branch. The cookbook example runs two Claude Code agents on two tasks in parallel, then merges both branches and runs the tests locally.

Configure the sandbox

e2b() accepts the options of the SDK’s Sandbox.create() and passes them through:
The provider sets envs and lifecycle itself, so you can’t override them. env is merged with the rest of Sandcastle’s environment, and maxOutputTailChars limits how much streamed output Sandcastle keeps for the result (64 KiB by default).

Lifecycle

  • run() creates a new sandbox for each call and kills it when the run finishes. createSandbox() keeps one sandbox for several runs until you close it.
  • The repository is copied to $HOME/workspace in the sandbox.
  • The sandbox is always killed, never paused, when timeoutMs runs out. Make the timeout long enough for setup, the agent run, and syncing the commits back. E2B’s Hobby plan caps a sandbox at 1 hour.
  • If you stop Sandcastle with Ctrl+C, it doesn’t kill the sandbox; E2B kills it when timeoutMs runs out.

Limitations

  • interactive() isn’t supported with the E2B provider.
  • sandcastle init doesn’t scaffold E2B; configure e2b() in your script as shown above.

Learn more

Claude Code

The prebuilt claude template

Codex

The prebuilt codex template

Templates

Build a template with your own agent CLI