- name
- design-system
- description
- Section-by-section GDD authoring for one system — walks through each required section, cross-references dependencies.
- argument-hint
- <system-name> [--review full|lean|solo]
- user-invocable
- true
- allowed-tools
- Read, Glob, Grep, Write, Edit, Agent, AskUserQuestion, TaskCreate, TaskGet, TaskList, TaskUpdate, Bash(bash "*/.claude/skills/design-system/../../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,system_overrides`
Resolved above — use as-is; `--review` overrides `review_mode`. No block →
defaults in `.claude/docs/config-resolution.md`.
When this skill is invoked:
## 1. Parse Arguments & Validate
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).
**`docs.density`** — it controls per-section *depth*, where `workflow`
controls which sections exist. `modes.rigor` sets both together; set
`docs.density` explicitly to vary depth alone: `terse` (the default, via `rigor: minimal`) = bullet points, 2–5 lines per section,
skip rationale and preambles; `balanced` = paragraphs with light rationale
(`rigor: standard`); `thorough` = full prose with rationale, examples, and alternatives
considered. Apply it to every section you author. Mandated structures (the
Formulas variable table, Given-When-Then acceptance criteria) are correctness
requirements at every density — `terse` trims the surrounding prose, never the
required structure itself.
A system name or retrofit path is **required**. If missing:
1. Check if `design/gdd/systems-index.md` exists.
2. If it exists: read it, find the highest-priority system with status "Not Started" or equivalent, and use `AskUserQuestion`:
- Prompt: "The next system in your design order is **[system-name]** ([priority] | [layer]). Start designing it?"
- Options: `[A] Yes — design [system-name]` / `[B] Pick a different system` / `[C] Stop here`
- If [A]: proceed with that system name. If [B]: ask which system to design (plain text). If [C]: exit.
3. If no systems index exists, fail with:
> "Usage: `/design-system <system-name>` — e.g., `/design-system movement`
> Or to fill gaps in an existing GDD: `/design-system retrofit design/gdd/[system-name].md`
> No systems index found. Run `/map-systems` first to map your systems and get the design order."
**Detect retrofit mode:**
If the argument starts with `retrofit` or the argument is a file path to an
existing `.md` file in `design/gdd/`, enter **retrofit mode**:
1. Read the existing GDD file.
2. Identify which of the 8 **possible** sections are present (scan for section
headings): Overview, Player Fantasy, Detailed Design/Rules, Formulas,
Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria.
**Which of them are *required* depends on the effective tier** (§1) — at
`standard` only 5 are, plus Formulas for math categories, and Player Fantasy
and Tuning Knobs are skipped **by design**. Report an absent section as a gap
only when the tier requires it; otherwise list it as available-to-add. Calling
all 8 required here reports two by-design-absent sections as gaps on every
`standard` project.
3. Identify which sections contain only placeholder text (`[To be designed]` or
equivalent — blank, a single line, or obviously incomplete).
4. Present to the user before doing anything:
```
## Retrofit: [System Name]
File: design/gdd/[filename].md
Sections already written (will not be touched):
✓ [section name]
✓ [section name]
Missing or incomplete sections (will be authored):
✗ [section name] — missing
✗ [section name] — placeholder only
```
5. Ask: "Shall I fill the [N] missing sections? I will not modify any existing content."
6. If yes: proceed to **Phase 2 (Gather Context)** as normal, but in **Phase 3**
skip creating the skeleton (file already exists) and in **Phase 4** skip
sections that are already complete. Only run the section cycle for missing/
incomplete sections.
7. **Never overwrite existing section content.** Use Edit tool to replace only
`[To be designed]` placeholders or empty section bodies.
If NOT in retrofit mode, normalize the system name to kebab-case for the
filename (e.g., "combat system" becomes `combat-system`).
**`workflow`** for this system (per `.claude/docs/workflow-modes.md`) — use the
`system_overrides` row for this system if the block lists one, else the project
value.
The resolved tier determines which GDD sections are **required** (applied in §4).
**`## Summary` is required at every tier and is not one of the 8** — §5-pre
authors it unconditionally (*"This runs at every tier"*), but it appeared in none
of the per-tier lists below, and these lists are what other skills and gates
apply. A GDD checked against a tier list alone would pass with no Summary, the
one section `/review-all-gdds` and the tiered-loading readers depend on. Read
every list below as "`## Summary`, plus:".
- `full` — all 8 sections
- `standard` — Overview, Detailed Design, Edge Cases, Dependencies, Acceptance
Criteria (5 required); **Formulas conditional** — required when the system
**defines numeric rules**: rates, curves, thresholds, costs, damage, drop
weights, or any value a balance pass would tune. Optional only when the system
defines no such value. **The `Category` in `systems-index.md` is a hint, not
the test** — `Gameplay`, `Economy` and `Progression` systems almost always
qualify, and a `Core`, `UI` or `Persistence` system that defines a numeric rule
qualifies too. If the Detailed Design states a quantity that is not a constant
of the engine, Formulas is required. **Player Fantasy and Tuning Knobs skipped**
unless `workflow_overrides` force them (`tuning_knobs: true` forces Tuning Knobs)
> **Do not gate this on a category token.** A rule of the form "required when
> the system category is combat / economy / progression / AI" does not work:
> those four tokens are not what `/map-systems` writes — `templates/systems-index.md`
> defines the categories as `Core · Gameplay · Progression · Economy ·
> Persistence · UI · Audio · Narrative · Meta` and lists **combat and AI as
> example systems under `Gameplay`**. A combat system categorised exactly as the
> template instructs matches none of the four, and Formulas would be dropped for
> the system most likely to need it.
- `minimal` — a GDD is not required (the game brief replaces it). If invoked
voluntarily at minimal, author exactly the 5 standard sections (Overview,
Detailed Design, Edge Cases, Dependencies, Acceptance Criteria) — the
conditional Formulas rule does NOT re-apply at minimal — and tell the user
the GDD is optional at this workflow level.
Retrofit mode is unaffected — it fills whatever sections are missing regardless
of tier.
---
## 2. Gather Context (Read Phase)
Read all relevant context **before** asking the user anything. This is the skill's
primary advantage over ad-hoc design — it arrives informed.
### 2a: Required Reads
> **At `minimal`** (design-system is voluntary at this tier): read
> `design/game-brief.md` in place of the game concept, and **skip the systems-index
> read** — neither `game-concept.md` nor `systems-index.md` exists at `minimal`.
> Author from the brief's relevant MVP feature and its core loop.
>
> **This callout keys on the PROJECT tier, not this system's effective tier.**
> The two differ whenever `workflow_overrides.system_overrides` bumps one system
> above a `minimal` project — the configuration `.claude/docs/settings-guidance.md`
> advertises as the reason the override exists ("bump one deep system"). Those two
> files are absent because the *project* is `minimal`; raising *this system* to
> `standard` or `full` does not create them. So on a `minimal` project, take this
> branch **even for an overridden system**, and read the brief.
>
> The effective tier still governs everything downstream — the required section
> set (§1), the skeleton (§3), the section cycle (§4) and §5a. Only the
> required-*reads* branch here follows the project tier.
>
> **Then derive `Category`, `Layer` and `Priority` from the brief, once, here.**
> Six later steps are keyed on the systems index you just skipped — §2e's engine
> domain, Section A's and Section B's recommended options, the Visual/Audio
> REQUIRED table, §6 specialist routing, and §5-pre's Quick reference — and none
> of them has an absent-index branch. An overridden system reaches all six at
> `standard` or `full`, so "skip the index" leaves them with no input at all.
> Derive from the brief instead:
>
> - **`Category`** — one of the nine in `templates/systems-index.md`
> (`Core · Gameplay · Progression · Economy · Persistence · UI · Audio ·
> Narrative · Meta`), chosen from what the brief says the system *does*.
> - **`Layer`** — `Foundation` if other systems depend on it, else `Feature`.
> - **`Priority`** — `MVP` if the brief's build order lists it, else `Post-MVP`.
>
> Carry all three for the rest of the run and treat them as the index's answer.
> **Mark them inferred** in §5-pre's Quick reference (*"Category: Gameplay
> (inferred from the brief — no systems index at this tier)"*) so a later reader
> does not mistake a derivation for an indexed fact. Do **not** write a systems
> index to hold them: `/map-systems` owns that file (§5d).
>
> Read literally without this rule, an overridden system resolves to `full`, falls
> through to the fail-fast reads below, and aborts with *"No game concept found.
> Run `/brainstorm` first"* — killing the escape hatch on step one of the very
> configuration it was built for.
- **Game concept**: Read `design/gdd/game-concept.md` — fail if missing:
> "No game concept found. Run `/brainstorm` first."
- **Systems index**: Read `design/gdd/systems-index.md` — fail if missing:
> "No systems index found. Run `/map-systems` first to map your systems."
- **Target system**: Find the system in the index. If not listed, warn:
> "[system-name] is not in the systems index. Would you like to add it, or
> design it as an off-index system?"
- **Entity registry**: Read `design/registry/entities.yaml` if it exists.
Extract all entries referenced by or relevant to this system (grep
`referenced_by.*[system-name]` and `source.*[system-name]`). Hold these
in context as **known facts** — values that other GDDs have already
established and this GDD must not contradict.
- **Reflexion log**: Read `docs/consistency-failures.md` if it exists.
Extract entries whose Domain matches this system's category. These are
recurring conflict patterns — present them under "Past failure patterns"
in the Phase 2d context summary so the user knows where mistakes have
occurred before in this domain.
### 2b: Dependency Reads
From the systems index, identify:
- **Upstream dependencies**: Systems this one depends on (decisions this system
must respect).
- **Downstream dependents**: Systems that depend on this one (expectations this
system must satisfy).
For each dependency GDD that exists, read **only the four sections that carry the
cross-system contract** — not the whole GDD:
```
Grep pattern="^## ([0-9]+\. )?(Dependencies|Formulas|Edge Cases|Tuning Knobs)" glob="design/gdd/[dep].md" output_mode="content" -A 20
```
- Key interfaces and data flow (from Dependencies)
- Formulas that reference this system's outputs
- Edge cases that assume this system's behavior
- Tuning knobs that feed into this system
Much of this is already in `entities.yaml` (loaded in 2a) — the registry's
`formula_map`/`constant_map` carry the owned values with their `source:`. Use the
registry first; the section grep fills what it does not hold.
### 2c: Optional Reads
- **Game pillars**: Read `design/gdd/game-pillars.md` if it exists
- **Existing GDD**: Read `design/gdd/[system-name].md` if it exists (resume, don't
restart from scratch)
- **Related systems**: do **not** glob-and-read `design/gdd/*.md` hunting for
"thematically related" systems — there is no deterministic proxy for that and it
is the read the registry exists to replace. `entities.yaml` (2a) already holds
the cross-system facts a related GDD would supply. If a specific overlap is
known, treat it as a dependency above and section-grep it; otherwise rely on the
registry.
### 2d: Present Context Summary
Before starting design work, present a brief summary to the user:
> **Designing: [System Name]**
> - Priority: [from index] | Layer: [from index]
> - Depends on: [list, noting which have GDDs vs. undesigned]
> - Depended on by: [list, noting which have GDDs vs. undesigned]
> - Existing decisions to respect: [key constraints from dependency GDDs]
> - Pillar alignment: [which pillar(s) this system primarily serves]
> - **Known cross-system facts (from registry):**
> - [entity_name]: [attribute]=[value], [attribute]=[value] (owned by [source GDD])
> - [item_name]: [attribute]=[value], [attribute]=[value] (owned by [source GDD])
> - [formula_name]: variables=[list], output=[min–max] (owned by [source GDD])
> - [constant_name]: [value] [unit] (owned by [source GDD])
> *(These values are locked — if this GDD needs different values, surface
> the conflict before writing. Do not silently use different numbers.)*
>
> If no registry entries are relevant: omit the "Known cross-system facts" section.
If any upstream dependencies are undesigned, warn:
> "[dependency] doesn't have a GDD yet. We'll need to make assumptions about
> its interface. Consider designing it first, or we can define the expected
> contract and flag it as provisional."
### 2e: Technical Feasibility Pre-Check
Before asking the user to begin designing, load engine context and surface any
constraints or knowledge gaps that will shape the design.
**Step 1 — Determine the engine domain for this system:**
Map the system's category (from systems-index.md) to an engine domain:
Keyed on the `Category` column of `systems-index.md`. All nine categories
`templates/systems-index.md` defines appear here; where a category spans several
engine domains, pick the row matching what the system actually does and say
which you picked.
| `Category` | Engine Domain |
|-----------|--------------|
| `Gameplay` | **Physics** for combat / collision / movement; **Navigation** for AI and pathfinding; **Scripting** for rule-only systems with no engine surface |
| `Core` | **Core** — scene management, state, resource loading; **Input** for controls and keybinding |
| `UI` | UI |
| `Audio` | Audio |
| `Narrative` | Scripting — dialogue, quests, cutscenes |
| `Progression` | Scripting — save-adjacent rule logic, no dedicated domain |
| `Economy` | Scripting — data and rule logic, no dedicated domain |
| `Persistence` | Core — save/load, settings, serialization |
| `Meta` | Core — analytics, tutorials, accessibility plumbing |
> Animation, Rendering and Networking are engine domains with no category of
> their own: a system needing them will be `Gameplay` or `Core`. Name the domain
> you read the reference for, whichever row you came in on.
**Step 2 — Read engine context (if available):**
- Identify the engine and version: read `engine.name` and `engine.version` from `project.yaml`. Resolve each field independently — if its key is absent or empty (including when `project.yaml` has no `engine:` block), fall back to `.claude/docs/technical-preferences.md` (a `[TO BE CONFIGURED]` value means not set)
- If engine is configured, read `docs/engine-reference/[engine]/VERSION.md`
- Read `docs/engine-reference/[engine]/modules/[domain].md` if it exists.
**If it does not exist, say so by name** — *"no engine reference for `[domain]`
under `docs/engine-reference/[engine]/modules/`; feasibility not checked against
the pinned engine"* — and carry that into §5-pre. A silent skip here is
indistinguishable from a feasibility check that ran and found nothing wrong,
which is the failure `.claude/rules/skill-authoring.md` obligation 3 exists to
stop.
> **This is not a rare branch.** The domain table above names `Scripting` and
> `Core` for five of the nine categories (`Narrative`, `Progression`, `Economy`
> → Scripting; `Persistence`, `Meta` → Core), plus a sub-row each under
> `Gameplay` and `Core`. The Godot reference ships `animation, audio, input,
> navigation, networking, physics, rendering, ui` — **there is no
> `scripting.md` and no `core.md`**. So the majority of non-`Gameplay` systems
> hit the absent branch every time, and `if it exists` turned that into
> silence. Either the reference gains those two files or the check reports it;
> until the former, do the latter.
- Read `docs/engine-reference/[engine]/breaking-changes.md` for domain-relevant entries
- Find the domain-matching ADRs without reading every ADR to learn the field you
filter on — grep the Domain field first, then read only the matches:
```
View on GitHub