--- name: work-dispatch description: Use when a task in the docs/work/ tree should be implemented and reviewed. Triggers — the user asks to dispatch a task, run the next task, run the implement-review loop, or invokes /work-dispatch. --- # work-dispatch Run one work-tree task through the **implement → review loop**, using two separate sub-agents whose roles are defined by the existing Sandcastle prompts. This is the in-session, skill form of `pnpm work dispatch --execute`. It adds a path; it changes nothing about `.sandcastle/` or `pnpm work`. ## Single source of truth — do not copy the prompts Two role definitions, two files, read at dispatch time — **never copied**: - implementer role → **`.sandcastle/implementer.prompt.md`** - reviewer role → **`.sandcastle/reviewer.prompt.md`** `pnpm work dispatch --execute` (Sandcastle) and this skill consume the **same** files. Never paraphrase or inline them. If a prompt and this skill disagree, **the prompt wins**. This skill is only the _wiring_: pick the task, substitute placeholders, dispatch the sub-agents, run the loop. ## Separate sub-agents — non-negotiable The implementer and the reviewer are **distinct sub-agents**, dispatched separately: - The **implementer** writes code. Dispatch a `general-purpose` Agent with `isolation: "worktree"` — it works on an isolated git worktree + branch, so bad output never touches your main tree. - The **reviewer** must be a _different_ agent and must _not_ write. Dispatch an `Explore` Agent (read-only by construction) — it cannot Edit/Write the repo even by accident; it only verifies the diff. Never collapse the two into one agent. An agent that writes code and then grades its own work has not been reviewed. ## Process 1. **Resolve the task.** Default: run `pnpm work next`, then read the first unchecked task file of that story (`docs/work/epics///NN-.task.md`). Or the user names a task id. Read the task file; note its `max-attempts` frontmatter (default 3). 2. **Dispatch the implementer.** Read `.sandcastle/implementer.prompt.md`, substitute `{{TASK_FILE_CONTENT}}` with the task file. Dispatch a `general-purpose` Agent with `isolation: "worktree"`; instructions = the substituted prompt + this environment-adaptation note: > **Environment:** a Claude Code sub-agent in a fresh, isolated git worktree — NOT a Sandcastle Docker sandbox. Run `pnpm install` as your first step (the worktree has no `node_modules`). Commit your slice on a branch. **Report that branch name** in the `notes` field of your output JSON. Ignore the `COMPLETE` marker — there is no iteration loop; just return the structured JSON as your final message. Read the returned JSON: `status`, `commit_sha`, `files_changed`, `notes` (which carries the branch name). 3. **Handle the implementer's status.** `complete` → step 4. `blocked` or `needs-clarification` → surface the `notes` to the user and stop; do not proceed to review. 4. **Compute the diff.** `git diff main...` from the main tree — git worktrees share `.git`, so the implementer's branch is visible. 5. **Dispatch the reviewer.** Read `.sandcastle/reviewer.prompt.md`, substitute `{{TASK_FILE_CONTENT}}` and `{{DIFF}}`. Dispatch an `Explore` Agent (read-only); instructions = the substituted prompt + this environment-adaptation note: > **Environment:** a Claude Code sub-agent reviewing a LOCAL branch — there is no pull request or CI run yet. Where the prompt says to trust Sandcastle's CI step: the implementer has already run and reported the five conformance gates + coverage as its commit precondition — verify AC coverage, out-of-scope discipline, and slice discipline by **reading the diff**, as your checks describe. Run the library-trace check directly (`node scripts/library-decisions/check.mjs`). The Socket and CodeQL steps require a CI run — note them as "deferred to CI", do not block on them. Ignore the `COMPLETE` marker; return the JSON decision. Read the returned JSON: `decision`, `scope_violations`, `notes`. 6. **Run the loop.** - **`approve`** → merge `` into `main`; remove the worktree. Then run `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance` once on `main` as a post-merge safety check. Print the suggested task-checkbox / `_state.json` mutation for the user to apply — **do not write state yourself.** - **`reject`** → re-dispatch the implementer (step 2) with the reviewer's `notes` appended to its instructions. Repeat until `approve`, or until the task's `max-attempts` is reached — then stop and surface the last reviewer notes. ## Why this shape State mutation stays manual (the skill suggests, the human applies) — exactly as Sandcastle's v1 orchestrator does, and consistent with the implementer prompt's "the orchestrator handles state writes." Worktree isolation gives the implementer a clean room without Docker. The read-only reviewer makes "the reviewer does not modify the repo" a property of the tool, not a promise. ## Quick reference | | | | ----------------- | ------------------------------------------------------------------------------------- | | Implementer | `.sandcastle/implementer.prompt.md` · `general-purpose` · `isolation: "worktree"` | | Reviewer | `.sandcastle/reviewer.prompt.md` · `Explore` (read-only) | | Placeholders | implementer: `{{TASK_FILE_CONTENT}}` · reviewer: `{{TASK_FILE_CONTENT}}` + `{{DIFF}}` | | Loop cap | the task's `max-attempts` frontmatter (default 3) | | State writes | suggested to the user, never applied by the skill | | Upstream | `/work-decompose` produces the tasks | | Sandcastle parity | mirrors `pnpm work dispatch --execute` | ## Common mistakes - **Copying a prompt into this skill.** The `.sandcastle/*.prompt.md` files are the source of truth — read them at dispatch time. - **One agent for both roles.** Implementer and reviewer are separate sub-agents; the reviewer is `Explore` (read-only). - **Writing `_state.json` or ticking the checkbox.** The skill prints the suggested mutation; the human applies it. - **Skipping the environment-adaptation note.** Without it the sub-agent follows Sandcastle-only instructions — the `` marker, "trust CI" — that do not apply in-session. - **Reviewing before the implementer says `complete`.** A `blocked` status stops the loop; do not review a partial slice.