---
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/<epic>/<story>/NN-<slug>.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 `<promise>COMPLETE</promise>` 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...<task-branch>` 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 `<promise>COMPLETE</promise>` marker; return the JSON decision.

   Read the returned JSON: `decision`, `scope_violations`, `notes`.

6. **Run the loop.**
   - **`approve`** → merge `<task-branch>` 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 `<promise>` 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.
