Running
Hooks
On this page
Pass hooks to run(). Here a sandbox hook installs dependencies before the agent starts:
import { run, claudeCode } from "@ai-hero/sandcastle";import { docker } from "@ai-hero/sandcastle/sandboxes/docker";await run({agent: claudeCode("claude-opus-4-8"),sandbox: docker(),promptFile: ".sandcastle/prompt.md",hooks: {host: {onSandboxReady: [{ command: "echo sandbox is up" }],},sandbox: {onSandboxReady: [{ command: "npm install", timeoutMs: 300_000 }],},},});
Hooks are grouped by where they run — host (on the developer's machine) or sandbox (inside the sandbox):
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: trueto run the whole command as root. Ondockerandpodmanthis runs it as the container's root user, so the image needs nosudobinary; ondaytonaandvercelit uses the sandbox's ownsudo.sudo: trueisn't available on the native providers (bwrap,seatbelt), which have no root: the hook fails, naming the provider and pointing todocker(). Install system packages on your host instead. 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.
Related terms
- Core concepts: the host and the sandbox
- Branch strategies: the worktree that host hooks run in
- Sandbox providers: which providers support
sudo: true - Prompts: shell expressions, which run after sandbox hooks
run()reference: thehooksoption