- name
- create-stories
- description
- Break one epic into implementable stories embedding TR-ID, ADR guidance, acceptance criteria. Reads the control manifest. After /create-epics.
- argument-hint
- [epic-slug | epic-path] [--review full|lean|solo]
- user-invocable
- true
- allowed-tools
- Read, Glob, Grep, Write, Edit, Agent, AskUserQuestion, Bash(bash "*/.claude/skills/create-stories/../../hooks/yaml-helper.sh" resolve_config *)
- model
- sonnet
!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,automation,workflow,docs.density,story_granularity,qa.level,system_overrides`
Resolved above — use as-is; `--review` overrides `review_mode`. No block →
defaults in `.claude/docs/config-resolution.md`.
# Create Stories
A story is a single implementable behaviour — small enough to complete in one
focused session, self-contained, and fully traceable to a GDD requirement and
an ADR decision. Stories are what developers pick up. Epics are what architects
define.
**Run this skill per epic**, not per layer. Run it for Foundation epics first,
then Core, and so on — matching the dependency order.
**Output:** `production/epics/[epic-slug]/story-NNN-[slug].md` files
**Previous step:** `/create-epics [system]`
**Next step after stories exist:** `/story-readiness [story-path]` then `/dev-story [story-path]` —
at `workflow: minimal`, `/dev-story [story-path]` directly (`/story-readiness` is not on the minimal path)
---
## 1. Parse Argument
See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session.
Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md`
(collaborative asks always · guided major-only · autonomous logs and proceeds;
`automation_always_ask` categories always prompt).
**`workflow`** for this epic's system (per `.claude/docs/workflow-modes.md`) —
use the `system_overrides` row for `<system>` if the block lists one, else the
project value. `<system>` is the epic slug / its GDD system. The tier sets which prerequisites block — see the note in Step 2.
**`story_granularity`** — it sets each
story's AC load: **5–10 ACs covering a whole feature** at `coarse` (the default, via `rigor: minimal`), **2–4 ACs
covering one task** at `balanced` (`rigor: standard`), **1 AC** at `fine` (the story name is
the AC restatement). Group or split ACs into stories to hit the target.
**`docs.density`** — it controls the *depth* of each story's prose (context,
implementation notes, ADR summary), not the AC count (that is
`story_granularity`) and never the AC text itself. `modes.rigor` sets it
alongside `workflow`; set `docs.density` explicitly to vary story prose alone:
`terse` (the default, via `rigor: minimal`) = notes as bullets, no preamble; `balanced` = short context paragraph +
notes (`rigor: standard`); `thorough` = full context, implementation guidance, and ADR
rationale. The embedded TR-ID reference, ADR Version stamp, and acceptance
criteria are structural and are never trimmed by density.
- `/create-stories [epic-slug]` — e.g. `/create-stories combat`
- `/create-stories production/epics/combat/EPIC.md` — full path also accepted
- **A named epic that does not exist** — if `production/epics/[slug]/EPIC.md`
(or the given path) is missing, stop at `standard`/`full`: "No epic at
`production/epics/[slug]/EPIC.md`. Run `/create-epics` to create it, or check
the slug with `ls production/epics/`." Do not decompose from a guess. At
`minimal` there are no `/create-epics` epics to name and that skill is not on
the path — say so, take Step 2's `minimal` branch, and name the slug it uses.
- No argument — at `minimal` there are no epics yet (Option A): skip to Step 2's
`minimal` branch and synthesize the epic from `design/game-brief.md`. At
`standard`/`full`, ask "Which epic would you like to break into stories?" and
Glob `production/epics/*/EPIC.md` to list available epics with their status.
> **If that glob returns nothing at `standard`/`full`, stop — do not build a
> question with no options.** Report:
> "No epics found under `production/epics/`. Run `/create-epics layer: foundation`
> first — an epic is what this skill decomposes."
>
> **The zero-epic path is load-bearing.** Asking which epic *and* globbing to
> list them leaves an `AskUserQuestion` with nothing to offer when the glob is
> empty. Route to `/create-epics` instead — it is named as **Previous step**
> in this skill's own header.
>
> Note what this skill guarded and what it did not. Step 2's ADR validation is
> thorough: three tiers, each with its own stop condition, and an explicit
> message naming the missing file. That is the **deepest** input. The **first**
> input — does an epic exist at all — went unchecked. Guarding the far end of a
> chain while leaving the near end open is the shape to watch for.
>
> At `minimal` this does not apply: there are deliberately no epics, and the
> branch above synthesizes one from the brief.
---
## 2. Load Everything for This Epic
> **`minimal` tier — synthesize the epic from the brief** (Option A). At
> `minimal` there is no `/create-epics` step and usually no `EPIC.md`. Instead:
> 0. **No `design/game-brief.md`?** Stop: "There is no brief to build stories
> from yet — run `/brainstorm` first; it writes the one-page brief."
> **An `EPIC.md` already at `production/epics/<slug>/`** — the named epic, or
> the brief-title slug (`/create-epics` run anyway, or an earlier run of this
> skill) — is the epic: use its scope, still traced to the brief, and never
> rewrite it; Step 6 only appends its Stories table, and the Step 5 ask says
> *update* `EPIC.md`.
> **Stories already in `production/epics/<slug>/`?** This is a return visit —
> `/help` sends a finished build order back here. Never rewrite an existing
> `story-*.md` or the `EPIC.md`: read them, add stories only for brief items
> they do not yet cover (or the new ones the user names), and number on from
> the highest existing `story-NNN`. The one change `EPIC.md` gets is Step 6's:
> a row per new story appended to its Stories table — existing rows and the
> rest of the file stay as they are.
> 1. Read `design/game-brief.md` in full (it is one page).
> 2. Synthesize an implicit epic (first run only — a return visit keeps the
> existing one): draft a lightweight
> `production/epics/<slug>/EPIC.md`, where `<slug>` is the brief's slugified
> working title (`mvp` if untitled) — goal = the brief's one-sentence pitch,
> scope = its MVP feature list, ordering = its **Build order**. Keep it terse;
> this is the container `/dev-story` and `/sprint-status` expect. It is written
> in Step 6, with the stories, after the Step 5 ask names it — never before.
> 3. Generate **one coarse story per MVP feature** (Step 3+), in Build-order
> sequence, each traced to the brief (not a GDD/TR-ID). Leave stories unblocked
> on ADR grounds — none exist at this tier.
> Skip the GDD, control-manifest, TR-registry, and ADR reads below (none exist at
> `minimal`), then continue to Step 3 with the synthesized epic.
For `standard`/`full` (a `/create-epics` epic exists), read in full (these are small):
- `production/epics/[epic-slug]/EPIC.md` — epic overview, governing ADRs, GDD requirements table
- The epic's GDD (`design/gdd/[filename].md`) — at `full` read all 8 sections; at `standard` the 5 required sections (+ conditional Formulas); at `minimal` the GDD may not exist — work from the epic brief + acceptance criteria. Always prioritise Acceptance Criteria, Formulas, and Edge Cases where present.
- `docs/architecture/control-manifest.md` — grep only this epic's layer (`Grep pattern="^## <layer> Layer Rules" path="docs/architecture/control-manifest.md" output_mode="content" -A 40`) plus the header Manifest Version date, not a full read of all layers
- `docs/architecture/tr-registry.yaml` — grep only this system's entries (`Grep pattern="system: <slug>\s*$" path="docs/architecture/tr-registry.yaml" output_mode="content" -B1 -A5`, or `id: TR-<slug>-[0-9]`; the anchors keep `combat` from matching `combat-ai`), not the whole cross-system registry
**Load each governing ADR by section — never with an unbounded full read.** A
substantial ADR exceeds the 25k-token `Read` cap, and a capped read's only
recovery is paging through the remainder — the most expensive possible way to
read a file. Per ADR:
1. **Map the headings** (cheap — line numbers only):
```
Grep pattern="^## |^### Implementation Guidelines" path="docs/architecture/[adr-file].md" output_mode="content" -n
```
2. **Bounded-read exactly the sections this skill consumes**, using the line
numbers from the map to set `Read(offset, limit)` spans that end where the
next section begins:
- `## Summary` and `## Decision` (including its `### Implementation
Guidelines` subsection) — these feed the story's ADR Decision Summary
and Implementation Notes.
- `## Engine Compatibility` — feeds the story's Engine, Risk, and Engine
Notes fields. (Engine Notes is a *story* field derived from this
section — it is not an ADR section name; do not search for one.)
3. **Capture the `## Status` and the `## Last Verified` date** in one call:
```
Grep pattern="^## (Status|Last Verified|Date)" path="docs/architecture/[adr-file].md" output_mode="content" -A 2
```
The Status (Accepted / Proposed / …) is what Step 4 decides `Ready` vs
`Blocked` on — never assume it. For the version, use `Last Verified`,
falling back to `Date`, then to `unversioned` if both are absent. This becomes the story's `ADR Version` stamp — `/dev-story`
uses it to decide whether it can trust this story's distilled summary
instead of re-opening the ADR.
Skip Context, Alternatives Considered, Consequences, Risks, and any
Amendments Log unless a section you loaded explicitly cross-references one of
their entries — then take only the referenced entry with one more bounded
read. If the heading map comes back empty (a nonstandard ADR predating the
template), fall back to one full `Read` — and if that read truncates at the
cap, do **not** page through the remainder; grep for the story-relevant
content directly and flag the ADR for
`/architecture-decision retrofit [file]`.
**ADR existence validation** (tier-gated — resolved in Step 1): After reading the governing ADRs list from the epic, confirm each referenced ADR file exists on disk.
- **`full`** — if **any** referenced ADR file cannot be found, **stop immediately** before decomposing any story.
- **`standard`** — stop only if a **critical (Foundation-layer) ADR** is missing; for a missing non-critical ADR, **warn and continue** (the story embeds the ADR reference and is set `Status: Blocked` until the ADR exists).
- **`minimal`** — no ADR requirement; do **not** stop. Embed any ADR references that do exist; otherwise decompose against the brief + acceptance criteria and leave stories unblocked on ADR grounds.
When stopping (full / standard-critical):
> "Epic references [ADR-NNNN: title] but `docs/architecture/[adr-file].md` was not found.
> Check the filename in the epic's Governing ADRs list, or run `/architecture-decision`
> to create it. Cannot create stories until all referenced ADR files are present."
At `full`, do not proceed to Step 3 until all referenced ADR files are confirmed present.
Report: "Loaded epic [name], GDD [filename], [N] governing ADRs [ADR status], [manifest status]." State the **actual** situation for the resolved tier — e.g. "all confirmed present, control manifest v[date]" at full; "M present, K missing non-critical (embedded + Blocked)" at standard; "no ADRs / manifest required" at minimal. Do not assert "all confirmed present" if any referenced ADR was missing, or name a manifest version when none exists.
---
## 3. Classify Stories by Type
**Story Type Classification** — assign each story a type based on its acceptance criteria:
| Story Type | Assign when criteria reference... |
|---|---|
| **Logic** | Formulas, numerical thresholds, state transitions, AI decisions, calculations |
| **Integration** | Two or more systems interacting, signals crossing boundaries, save/load round-trips |
| **Visual/Feel** | Animation behaviour, VFX, "feels responsive", timing, screen shake, audio sync |
| **UI** | Menus, HUD elements, buttons, screens, dialogue boxes, tooltips |
| **Config/Data** | Balance tuning values, data file changes only — no new code logic |
Mixed stories: assign the type that carries the highest implementation risk.
The type determines what test evidence is required before `/story-done` can close the story.
---
## 4. Decompose the GDD into Stories
For each GDD acceptance criterion:
1. Group related criteria that require the same core implementation
2. Each group = one story
3. Order stories: foundational behaviour first, edge cases last, UI last
**Story sizing rule:** size each story to the resolved `modes.story_granularity`
target (above). The "~2-4 hours / one focused session" heuristic is the
`balanced` target (`rigor: standard`) — at `coarse`, the default, a story spans a whole feature (5–10 ACs,
multi-day), at `fine` a story is a single AC. Split or group criteria to hit the
resolved target, not a fixed session length.
For each story, determine:
- **GDD requirement**: which acceptance criterion(ia) does this satisfy?
- **TR-ID**: look up in `tr-registry.yaml`. Use the stable ID. If no match, use `TR-[system]-???` and warn.
- **Governing ADR**: which ADR governs how to implement this?
- `Status: Accepted` → embed normally
- `Status: Proposed` → set story `Status: Blocked` with note: "BLOCKED: ADR-NNNN is Proposed — accept it with `/architecture-decision accept ADR-NNNN` once decided"
- `Deprecated` or `Superseded by ADR-XXXX` → set story `Status: Blocked` with note: "BLOCKED: ADR-NNNN is [status] — point the story at [successor] (edit its ADR field — `/create-stories` never rewrites an existing story) before implementing"
- **Multiple ADRs apply**: List all governing ADRs in the story's `Governing ADRs:` field. Designate the one most directly controlling the implementation pattern as primary (first in the list). Others are listed as secondary references.
- **No ADR applies at all**: Write `ADR: N/A — [brief reason, e.g. "pure data configuration, no architectural pattern required"]` in the story's ADR field. Do NOT leave the field blank — a blank ADR field means "not checked", not "not applicable".
- **Story Type**: from Step 3 classification
- **Engine risk**: from the ADR's Knowledge Risk field
---
## 4b. QA Lead Story Readiness Gate
**Review mode check** — apply before spawning QL-STORY-READY:
- `solo` → skip. Note: "QL-STORY-READY skipped — Solo mode." Proceed to Step 5 (present stories for review).
- `lean` → skip (not a PHASE-GATE). Note: "QL-STORY-READY skipped — Lean mode." Proceed to Step 5 (present stories for review).
- `full` → spawn as normal.
After decomposing all stories (Step 4 complete) but before presenting them for write approval, spawn `qa-lead` **once** via `Agent` using gate **QL-STORY-READY** (`.claude/docs/director-gates/ql-story-ready.md`). A single call returns **both** the readiness verdict and the test-case specs — do not spawn `qa-lead` a second time to generate specs.
Pass: the full story list inline — no story file exists yet, so the stories themselves stand in for the gate's story paths — with each story's acceptance criteria, story type, and TR-IDs with their requirement text from `tr-registry.yaml`; the epic's GDD acceptance criteria for reference. Require in the return:
1. The QL-STORY-READY verdict per story (ADEQUATE / GAPS / INADEQUATE, or NOT ASSESSED naming a missing input).
2. For every story it marks **ADEQUATE**, its test-case spec block (formats below) — one Given/When/Then per acceptance criterion for Logic and Integration stories, or manual verification steps for Visual/Feel and UI stories.
Present the assessment, then act on each story's verdict — the gate's own words, handled per `.claude/docs/director-gates.md`:
- **ADEQUATE** — keep the returned specs.
- **GAPS** — use `AskUserQuestion`: `Revise flagged criteria` / `Accept and proceed` / `Discuss further`. Do not revise before the user chooses. On *Revise*, draft the revised criteria, show them, and re-request specs for just those stories in one follow-up call. On *Accept*, the criteria stay as written and the story carries no qa-lead specs — its `## QA Test Cases` reads `*Test cases not yet defined — run /qa-plan to generate them.*`
- **INADEQUATE** — blocking: the story is not written as it stands. Revise its criteria with the user (draft, show, confirm), then re-request its specs; if the user will not revise it, drop it from this run and name it as dropped in the Step 5 list.
- **NOT ASSESSED** [missing input] — not an ADEQUATE: name what was missing, then supply it and re-request that story's verdict, or write the story without qa-lead specs (the `/qa-plan` line above in its `## QA Test Cases`) and mark it `QL-STORY-READY: NOT ASSESSED — [input]` in the Step 5 list.
Untestable criteria cannot be implemented correctly, so a story carries qa-lead specs only once it is ADEQUATE.
View on GitHub