Guides
Configuration
On this page
Config directory (.sandcastle/)
All per-repo sandbox configuration lives in .sandcastle/. Run sandcastle init to create it.
Custom Dockerfile
The .sandcastle/Dockerfile controls the sandbox environment. The default template installs:
- Node.js 22 (base image)
- git, curl, jq (system dependencies)
- GitHub CLI (
gh) - Claude Code CLI
- A non-root
agentuser (required — Claude runs as this user)
When customizing the Dockerfile, ensure you keep:
- A non-root user (the default
agentuser) for Claude to run as git(required for commits and branch operations)gh(required for issue fetching)- Claude Code CLI installed and on PATH
Add your project-specific dependencies (e.g., language runtimes, build tools) to the Dockerfile as needed.
Hooks
Hooks are grouped by where they run — host (on the developer's machine) or sandbox (inside the container):
hooks: {host: {onWorktreeReady: [{ command: "cp .env.example .env" }],onSandboxReady: [{ command: "echo sandbox is up" }],},sandbox: {onSandboxReady: [{ command: "npm install", timeoutMs: 300_000 },{ command: "apt-get install -y ffmpeg", sudo: true },],},}
| Hook | Runs on | When | Working directory |
|---|---|---|---|
host.onWorktreeReady | Host | After copyToWorktree, before sandbox start | Worktree path (host repo root under head) |
host.onSandboxReady | Host | After sandbox is up | Worktree path (host repo root under head) |
sandbox.onSandboxReady | Sandbox | After sandbox is up | Sandbox repo directory |
Ordering: copyToWorktree -> host.onWorktreeReady (sequential) -> sandbox created -> host.onSandboxReady + sandbox.onSandboxReady (parallel).
- Host hooks accept
{ command: string; timeoutMs?: number }— nosudo, nocwd. Usecdor inline env in the command string. - Sandbox hooks accept
{ command: string; sudo?: boolean; timeoutMs?: number }— setsudo: truefor elevated privileges. timeoutMsoverrides the default 60 s per-hook timeout. Useful for long-running setup commands like dependency installs (e.g.timeoutMs: 300_000for 5 minutes).- Within each hook point, sandbox hooks run in parallel; host hooks within
onSandboxReadyalso run in parallel with sandbox hooks.host.onWorktreeReadyhooks run sequentially in declared order. - If any hook exits non-zero, setup fails fast.
- When a
signalis passed torun(), it is threaded to all hooks — aborting the signal cancels any in-flight hook commands.