Closes the PRD-lifecycle gap surfaced by the user: when sandcastle
finishes an epic's last task, the seed PRD should auto-flip from
approved -> shipped. Builds the mechanism, wires it into the work
CLI + state index + reviewer prompt + docs.
scripts/work/prd-ship.mjs (new):
- parseFrontmatter / serializeFrontmatter — minimal YAML-ish parser
sufficient for PRD frontmatter (scalar + list shapes)
- flipPrdStatus — pure function: takes PRD text, returns new text
with status=shipped + shipped=<date> + optional shipping-commits.
Refuses to flip draft, idempotent fail-soft on already-shipped,
rejects unexpected statuses
- deriveShippingCommits — best-effort git log of the linked epic
folder for the --auto-commits flag
- findPrdPath — id -> path lookup under docs/work/prds/
- runCli — wiring for `pnpm work prd-ship <id> [--commits|--auto-commits]`
scripts/work/prd-ship.test.mjs (new, 17 tests):
- Frontmatter parser handles scalars + lists + missing frontmatter
- flipPrdStatus covers all transitions + refusals + body/key preservation
- findPrdPath + serializeFrontmatter coverage
scripts/work/state-builder.mjs:
- Epic entries gain a `prd` field
- New computeNeedsPrdShip surfaces epics done with PRD status not yet
shipped: state.needs_prd_ship[] with action commands
scripts/work/cli.mjs:
- New subcommand `pnpm work prd-ship <id>`
.sandcastle/reviewer.prompt.md:
- "Epic close-out: PRD status flip" section instructing reviewer to
check _state.json.needs_prd_ship and run the suggested action
- JSON output extends with prd_shipped: "<id>" | null
docs/work/README.md:
- "PRD lifecycle" section documenting the 4 statuses + auto-flip
Future PRDs follow the lifecycle automatically: decomposer refuses
draft, human flips to approved, sandcastle ships the epic, reviewer
runs prd-ship on the final task, PRD lands as shipped with its
commit trail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
.sandcastle/
This directory holds prompt templates that the future orchestrator
(pnpm work dispatch in the sandcastle-dispatch-v1 epic) feeds to
sandcastle when dispatching
agents.
Prompt templates
| File | Role | Variables |
|---|---|---|
prd-eliciter.prompt.md |
Interview a human to produce a PRD draft | {{INITIAL_BRIEF}} |
adr-eliciter.prompt.md |
Interview a human to produce an ADR draft | {{INITIAL_PROPOSAL}} |
decomposer.prompt.md |
Turn a PRD into epic + story files | {{PRD_FILE_CONTENT}} |
implementer.prompt.md |
Execute a single task | {{TASK_FILE_CONTENT}} |
reviewer.prompt.md |
Review the implementer's diff | {{TASK_FILE_CONTENT}}, {{DIFF}} |
Convention: every prompt enforces "generators first"
Each prompt template starts with the same non-negotiable rule: the agent
must prefer pnpm turbo gen <kind> over hand-rolled scaffolding. This
applies to feature packages, events, jobs, realtime channels, optional
core packages, and atomic-design components. Hand-rolled code is only
acceptable when the generator's output doesn't cover the case — and even
then, the agent runs the generator first and modifies its output rather
than starting from scratch.
Environment
Configure runtime tokens via .env (gitignored). Copy .env.example
and fill values for the providers you use.
Manual usage
Until the orchestrator ships, these templates are usable manually: copy
the relevant .prompt.md content into a Claude / Codex / other agent
session, fill the {{VARIABLE}} placeholders by hand, and run.