sandcastle
Librarymattpocock/sandcastle
Library to orchestrate sandboxed AI coding agents in TypeScript.
Overview
Sandcastle is a TypeScript library that runs AI coding agents in isolated sandboxes with built-in support for Docker, Podman, and Vercel. It provides a programmatic API to handle sandboxing, branching, and merging commits, enabling parallel agent execution and review pipelines.
README Preview
\n \n \n \n \n \n\n\n## What Is Sandcastle?\n\nA TypeScript library for orchestrating AI coding agents in isolated sandboxes:\n\n1. You invoke agents with a single `sandcastle.run()`.\n2. Sandcastle handles sandboxing the agent with a configurable branch strategy.\n3. The commits made on the branches get merged back.\n\nSandcastle is provider-agnostic — it ships with built-in providers for Docker, Podman, and Vercel, and you can create your own. Great for parallelizing multiple AFK agents, creating review pipelines, or even just orchestrating your own agents.\n\n## Prerequisites\n\n- [Git](https://git-scm.com/)\n- A sandbox provider — Sandcastle needs an isolated environment to run agents in. Built-in options:\n - [Docker Desktop](https://www.docker.com/) — most common for local development\n - [Podman](https://podman.io/) — rootless alternative to Docker\n - [Vercel](https://vercel.com/) — cloud-based Firecracker microVMs via `@vercel/sandbox`\n - Or [create your own](#custom-sandbox-providers) using `createBindMountSandboxProvider` or `createIsolatedSandboxProvider`\n\n## Quick start\n\n1. Install the package:\n\n```bash\nnpm install --save-dev @ai-hero/sandcastle\n```\n\n2. Run `sandcastle init`. This scaffolds a `.sandcastle` directory with all the files needed.\n\n```bash\nnpx sandcastle init\n```\n\n3. Edit `.sandcastle/.env` and fill in your default values for `ANTHROPIC_API_KEY`. If you want to use your Claude subscription instead of an API key, see [#191](https://github.com/mattpocock/sandcastle/issues/191).\n\n```bash\ncp .sandcastle/.env.example .sandcastle/.env\n```\n\n4. Run the `.sandcastle/main.ts` (or `main.mts`) file with `npx tsx`\n\n```bash\nnpx tsx .sandcastle/main.ts\n```\n\n```typescript\n// 3. Run the agent via the JS API\nimport { run, claudeCode } from "@ai-hero/sandcastle";\nimport { docker } from "@ai-hero/sandcastle/sandboxes/docker";\n\nawait run({\n agent: claudeCode("claude-opus-4-7"),\n sandbox: docker(), // or podmanFAQ (3)
how_toHow to continue an agent conversation across multiple prompts in sandcastle?
Use the resume(prompt) method on the RunResult object returned by run(). Example: const r = await run({ agent: claudeCode('claude-opus-4-6'), sandbox: docker(), prompt: 'draft a plan' }); await r.resume('now execute the plan');. This continues the agent session with full context, removing the need to manually thread sessionId and avoiding sandbox rebuilds. Available in @ai-hero/sandcastle.
TroubleshootingWhy does createSandbox keep an outdated branch when run multiple times for the same branch?
The sandbox reuses a local clone of the branch from the first run, so subsequent runs don’t pull the latest changes. Workaround: add an onSandboxReady hook to execute git pull origin <branch> inside the workspace.
TroubleshootingHow to fix "PromptExpansionTimeoutError" crashing the entire run when a shell expansion times out in @ai-hero/sandcastle?
Apply a retry wrapper to the shell command inside the prompt. For example, replace !\\gh api graphql ...\\` with !\\for i in 1 2 3; do gh api graphql ... && break; sleep 2; done\\`. This handles transient flakes like token cache contention or API stalls. Until the upstream library adds native retry (track issue #617), this manual loop prevents a single timeout from aborting an AFK run. Reduce parallel sandboxed agents if contention persists.