diff --git a/.sandcastle/README.md b/.sandcastle/README.md index a4ca239..238a548 100644 --- a/.sandcastle/README.md +++ b/.sandcastle/README.md @@ -30,6 +30,26 @@ than starting from scratch. Configure runtime tokens via `.env` (gitignored). Copy `.env.example` and fill values for the providers you use. +## Build the sandbox image (one-time) + +Sandcastle dispatches into a Docker image tagged `sandcastle:`. +Build it once per clone before `pnpm work dispatch --execute` or +`pnpm work decompose --execute` will work: + +```bash +pnpm exec sandcastle docker build-image +# Tags: sandcastle:template-vertical +``` + +Rebuild after editing this `Dockerfile`: + +```bash +pnpm exec sandcastle docker remove-image +pnpm exec sandcastle docker build-image +``` + +See [`docs/guides/runbook.md` → Using Sandcastle → Prerequisites](../docs/guides/runbook.md#using-sandcastle-for-agent-dispatch) for the full setup. + ## Manual usage Until the orchestrator ships, these templates are usable manually: copy diff --git a/README.md b/README.md index e0c68db..1c60a94 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,43 @@ pnpm work status # docs/work/ epic + story state docker compose up -d # Start PostgreSQL ``` +## Sandcastle setup (one-time) + +Required only if you'll use `pnpm work dispatch --execute` or `pnpm work decompose --execute` (agent dispatch). The dispatch loop runs the implementer / reviewer / decomposer agents inside an isolated Docker sandbox; the image is built once locally. + +```bash +# 1. Ensure Docker is running +docker info >/dev/null + +# 2. Build the sandcastle image (reads .sandcastle/Dockerfile) +pnpm exec sandcastle docker build-image +# Tags as: sandcastle:template-vertical (derived from the root package.json name) + +# 3. Pick ONE auth path: +# (a) Recommended — Claude Pro/Max subscription: +claude login # one-time; ~/.claude/ becomes the auth source +# (b) Fallback — API key: +export ANTHROPIC_API_KEY=sk-ant-... +``` + +After the image exists, dispatch flows work without further setup: + +```bash +pnpm work dispatch # print plan (safe anywhere) +pnpm work dispatch --execute # actually dispatch via sandcastle +pnpm work decompose # print decompose plan +pnpm work decompose --execute # decompose an approved PRD +``` + +To rebuild the image after changing `.sandcastle/Dockerfile`: + +```bash +pnpm exec sandcastle docker remove-image +pnpm exec sandcastle docker build-image +``` + +See [`docs/guides/runbook.md` → Using Sandcastle](./docs/guides/runbook.md#using-sandcastle-for-agent-dispatch) for the full dispatch lifecycle, auth modes, and troubleshooting. + ## Documentation map - **[`docs/guides/runbook.md`](./docs/guides/runbook.md)** — start here diff --git a/docs/guides/runbook.md b/docs/guides/runbook.md index 7b5a58c..ce91d67 100644 --- a/docs/guides/runbook.md +++ b/docs/guides/runbook.md @@ -242,12 +242,28 @@ For the full design see `docs/architecture/agent-first-workflow-and-conformance. ### Prerequisites 1. **Docker running** — sandcastle uses Docker for the sandbox by default. `docker info` should succeed. -2. **Authentication — pick ONE:** +2. **Sandcastle image built (one-time)** — sandcastle dispatches into a tagged Docker image; you build it once per clone: + + ```bash + pnpm exec sandcastle docker build-image + # Tags as: sandcastle:template-vertical (derived from root package.json name) + ``` + + If you see `Image 'sandcastle:template-vertical' not found locally. Build it first with 'sandcastle docker build-image'` on dispatch, this step was skipped. + + To rebuild after editing `.sandcastle/Dockerfile`: + + ```bash + pnpm exec sandcastle docker remove-image + pnpm exec sandcastle docker build-image + ``` + +3. **Authentication — pick ONE:** - **Recommended: Claude Pro / Max subscription.** Run `claude login` once on the host. Sandcastle's sandbox bind-mounts your `~/.claude/` into the container so the Claude Code CLI inside the sandbox uses your subscription session. Zero per-task token spend for subscribers. - **Alternative: API key.** Set `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` in your environment. Falls back automatically when `~/.claude/` is absent. - **Override the creds path** via `SANDCASTLE_CLAUDE_CREDS_DIR` if your Claude Code config lives somewhere non-standard. -3. **GitHub token** (optional) — `GITHUB_TOKEN` if you want the orchestrator to create PRs. -4. **`.sandcastle/` config present** — already in tree: +4. **GitHub token** (optional) — `GITHUB_TOKEN` if you want the orchestrator to create PRs. +5. **`.sandcastle/` config present** — already in tree: - `Dockerfile` — node:22 + pnpm + Claude Code CLI; reads creds from `~/.claude/` inside the container - `prd-eliciter.prompt.md`, `adr-eliciter.prompt.md`, `decomposer.prompt.md`, `implementer.prompt.md`, `reviewer.prompt.md` — the five role prompts diff --git a/scripts/work/dispatch.mjs b/scripts/work/dispatch.mjs index 9bb742d..248a56b 100644 --- a/scripts/work/dispatch.mjs +++ b/scripts/work/dispatch.mjs @@ -234,6 +234,11 @@ async function executeDispatch() { }); } catch (e) { console.error("✗ Implementer dispatch failed:", e.message); + if (/Image '.+' not found locally/.test(e.message ?? "")) { + console.error( + " One-time setup: pnpm exec sandcastle docker build-image", + ); + } console.error( " See docs/guides/runbook.md → 'Using Sandcastle' for setup.", );