backend-design
You are about to design and scaffold a backend for an existing frontend in the current working directory. Supported frontends (auto-detected by the CLI): Next.js (App or Pages Router), React SPA, Vue, Nuxt, Svelte, SvelteKit, Angular 17+, Astro, SolidJS / SolidStart, Qwik, Remix / React Router v7, Gatsby, HTMX, vanilla HTML/JS. The frontend is the source of truth: every button, form, fetch call, and route in the UI implies a backend obligation. Your job is to extract those obligations, get the user's approval on the shape of the backend, and then build it in the stack they chose.
Skill root: locate this skill's directory once at the start. It's the directory containing this SKILL.md. Refer to it as <SKILL_DIR> below — typical values are ~/.claude/skills/backend-design (default install) or ~/.claude/plugins/.../skills/backend-design (plugin install). Resolve all <SKILL_DIR>/... references against the actual location, not the literal string.
The stack is not fixed — it's selected by the user via npx backend-design start before activating this skill, and recorded in .backend-design/config.json. Supported stacks:
stack.id | Codegen prompt |
|---|---|
node-express-prisma | prompts/codegen-node-express-prisma.md |
node-fastify-prisma | prompts/codegen-node-fastify-prisma.md |
node-hono-drizzle | prompts/codegen-node-hono-drizzle.md |
nextjs-prisma | prompts/codegen-nextjs-prisma.md |
python-fastapi | prompts/codegen-python-fastapi.md |
s2ai-schema | (no prompt — Phase 4 runs scripts/render-s2ai-schema.mjs to emit ./schema.mmd only) |
Workflow
Execute 4 phases in order. Phase 3 is a hard stop — do not start Phase 4 until the user approves the design doc.
All design state lives in .backend-design/state/*.json — one file per category, written by Phase-1 agents and the Phase-2 synthesis agent. These JSON files are the single source of truth. The human-readable backend-design.md is rendered from them by scripts/render-design.mjs; the codegen agent in Phase 4 reads them directly.
A validator at <SKILL_DIR>/validate.mjs checks the state for invariants (FK targets exist, every endpoint has a UI trigger, every entity has a PK, etc.). Run it after each synthesis step and fix errors before continuing. If the validator emits the same error class three runs in a row, stop and surface the unfixable issues to the user — do not loop indefinitely.
Phase 0 — Resumption check
Run before the pre-flight check. Decides whether to start fresh or skip ahead based on what was last completed.
-
Read
.backend-design/checkpoint.jsonwith theReadtool. If missing → fresh run; proceed to Pre-flight. -
Run the decision script:
node <SKILL_DIR>/scripts/checkpoint.mjs decideIt prints one line of JSON:
{"action": "...", "reason": "...", "next_phase": ...}. The script computes the current frontend signature (git HEAD + dirty hash if the repo is git-managed, otherwise a content hash over the source tree) and compares it tocheckpoint.frontend_signature. -
Branch on
action:actionWhat to do freshNo prior state. Proceed to Pre-flight → Phase 1. resume_phase_2Phase 1 inventory is on disk and frontend unchanged. Skip Phase 1; proceed to Phase 2. resume_phase_2_5Phase 2 synthesis on disk. Skip Phases 1+2; run node <SKILL_DIR>/scripts/render-design.mjsto regeneratebackend-design.mdfrom existing state, then proceed to Phase 2.5. Never hand-render — the script is the source of truth.resume_phase_3Design and next-steps docs exist. Skip everything except the Phase 3 review gate — print the summary and wait for approval. resume_phase_4Design approved but scaffold not generated. Skip to Phase 4 directly. gaps_onlyScaffold complete, frontend unchanged. Run node <SKILL_DIR>/scripts/detect-gaps.mjsfollowed bynode <SKILL_DIR>/scripts/render-env-example.mjsto refresh both./backend-design-next-steps.mdand./backend-design.env.example. Report and stop — do not re-scaffold or re-render the design doc.fresh_with_gaps_preservedFrontend changed since the last run. Re-run from Phase 1. Preserve .backend-design/gaps.jsonso closure detection still works on this run. -
Tell the user one line of context (echo the
reasonfield):Resuming at Phase 4 — design approved, scaffold not yet generated.etc. Forgaps_only, say something likeScaffold already generated and frontend unchanged — refreshing ./backend-design-next-steps.md and ./backend-design.env.example only.so it's clear no design or codegen work is being repeated.
After each subsequent phase succeeds, update the checkpoint via Read + Write on .backend-design/checkpoint.json (merge fields; never overwrite the whole file blindly):
| Phase | Fields to add |
|---|---|
| 1 | phase_1_at: <ISO-8601 now>, frontend_signature: <output of node <SKILL_DIR>/scripts/checkpoint.mjs signature> |
| 2 | phase_2_at: <now> |
| 2.5 | phase_2_5_at: <now> |
| 3 (user approves) | design_approved_at: <now> |
| 4 (verification passes) | phase_4_at: <now> |
The signature is captured once at end of Phase 1 — not re-captured on later phases, because we want to detect "did the frontend change between this run and the last one," not "did the frontend change since the most recent phase."
Pre-flight check
Before Phase 1:
-
Read
.backend-design/config.json. If missing, tell the user:Run
npx backend-design startfirst to detect your frontend and pick your stack. Then re-invoke this skill. Stop here. -
Confirm to the user in one line:
Targeting <config.stack.label> with <config.auth.strategy> auth on <config.frontend.framework> → <config.output_dir>. -
Load framework patterns. Read
<SKILL_DIR>/prompts/frontend-patterns.md. Extract the section whose heading matchesconfig.frontend.patterns_key. You will inject this section into each Phase-1 agent's prompt so they search the right files. Keep it handy — call it<<PATTERNS>>in the agent briefs below.If
patterns_keydoes not match any section infrontend-patterns.md, stop and tell the user: "Your detected framework<framework>is unrecognized. Edit.backend-design/config.jsonor useprompts/frontend-patterns.mdpatterns manually." -
Create the state directory:
mkdir -p .backend-design/state
Phase 1 — Frontend inventory
Goal: catalog every screen, every component, every interactive element, and every relationship between them — enough that someone could rebuild the UI from the inventory alone. Be exhaustive, not selective. Partial coverage here corrupts every later phase.
Spawn four general-purpose subagents in parallel (single message, four tool calls). Each writes a single JSON file. general-purpose is the correct agent type here — Explore is read-only and cannot use Write, so it can't produce the output files this phase requires.
| Agent | Model | Output file |
|---|---|---|
| 1. Screens & navigation | sonnet | .backend-design/state/screens.json |
| 2. Component tree & shared state | sonnet | .backend-design/state/components.json |
| 3. Network calls & API contracts | sonnet | .backend-design/state/endpoints.json |
| 4. Forms, buttons, auth surface | sonnet | .backend-design/state/forms.json |
Pass the model parameter to the Agent tool when spawning each agent (e.g. Agent({ subagent_type: "general-purpose", model: "sonnet", prompt: "..." })). All four agents run on Sonnet — Haiku is not reliable enough for the inference required (template-literal URL resolution, validation rule extraction, existing-handler detection).
Each agent writes exactly one JSON file. Do not let them output