@khanhspring/forge-spec 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanhspring/forge-spec",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "Forge spec repo skills for Claude Code — brainstorm, spec, tasks, contract, and more",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,14 +18,40 @@ every unknown either resolved or explicitly accepted as an assumption.
18
18
 
19
19
  <HARD-GATE>
20
20
  Do NOT generate a spec, break down tasks, or write any contracts in this phase.
21
- The ONLY file this skill writes is `features/{slug}/brainstorm.md`, and only AFTER
22
- the user has explicitly approved the Brainstorm Summary at the gate (Step 7).
21
+ The only files this skill writes are `features/{slug}/brainstorm.md` and one row in
22
+ `features/CHANGELOG.md`, and only AFTER the user has explicitly approved the Brainstorm
23
+ Summary at the gate (Step 7).
23
24
  "Simple" features are where unexamined assumptions cause the most wasted work — no feature
24
25
  skips this phase.
25
26
  </HARD-GATE>
26
27
 
27
28
  ---
28
29
 
30
+ ## Step 0 — Check for existing external context
31
+
32
+ Before anything else, check if the user has provided external content to work from.
33
+ Signals: they paste a block of text, mention "we have a Confluence page / Google Doc / proposal /
34
+ PRD / design doc", or say "here's the draft".
35
+
36
+ **If external content is present (pasted inline):**
37
+ Extract everything you can from it — map it to the mandatory question areas in Step 2.
38
+ Note what is covered, what is missing, and what is ambiguous.
39
+ Report back:
40
+ > "I've read your {doc type}. Here's what I extracted:
41
+ > ✅ Covered: {list of areas — problem, actors, happy path, etc.}
42
+ > ❓ Missing or unclear: {list of gaps}
43
+ > ⚠️ Ambiguous: {anything that could be read two ways}
44
+ >
45
+ > I'll ask only about the gaps. Sound good?"
46
+
47
+ **If the user mentions a doc but hasn't pasted it:**
48
+ > "I can't access external URLs directly — could you paste the relevant content here?
49
+ > Even a rough copy-paste is fine; I'll extract what I need."
50
+
51
+ **If no external content** — proceed straight to Step 1.
52
+
53
+ ---
54
+
29
55
  ## Step 1 — Load & Research Context
30
56
 
31
57
  Before asking the user anything, research the existing codebase silently:
@@ -35,14 +61,15 @@ Before asking the user anything, research the existing codebase silently:
35
61
  Note any patterns, naming conventions, or prior decisions relevant to this idea.
36
62
  3. Scan `contracts/*/` — are there existing API contracts this feature will touch or extend?
37
63
  Note existing endpoint shapes, error formats, auth patterns.
38
- 4. Read `CLAUDE.md` — note project principles, conventions, and forbidden patterns
39
- that will constrain design choices.
64
+ 4. Read `CONTEXT.md` — note the actors, domain glossary, principles, conventions, and
65
+ forbidden patterns that will constrain design choices. Use glossary terms verbatim
66
+ in your questions and in the summary — never invent synonyms for existing domain terms.
40
67
 
41
68
  Report your findings before starting questions:
42
69
 
43
70
  > "Before we dive in, here's what I found in the codebase:
44
71
  > - [relevant existing feature or contract, or "No related features found"]
45
- > - [relevant principle from CLAUDE.md, or "No constraints found"]
72
+ > - [relevant principle or constraint from CONTEXT.md, or "No constraints found"]
46
73
  >
47
74
  > I'll use this as context. Here's my understanding of the feature: {1–2 sentence restatement}
48
75
  > Is that right?"
@@ -57,7 +84,8 @@ Then check scope:
57
84
  ## Step 2 — Mandatory questions (one at a time)
58
85
 
59
86
  These MUST all be answered before moving to Step 4. Ask one at a time.
60
- Skip any sub-question already answered by your research in Step 1.
87
+ **Skip any area already covered by Step 0 extraction or Step 1 research.**
88
+ Only ask about genuine gaps — never re-ask what the user already provided.
61
89
 
62
90
  **If a question hits an unknown** — something the user can't answer without researching —
63
91
  use the Research Flag pattern (see Research Handling below).
@@ -183,7 +211,7 @@ apply the Research Handling pattern.
183
211
  ## Step 5 — Propose approaches
184
212
 
185
213
  Propose **2–3 design approaches** with trade-offs. Base them on the researched context
186
- from Step 1 — flag if an approach conflicts with existing patterns or CLAUDE.md principles.
214
+ from Step 1 — flag if an approach conflicts with existing patterns or CONTEXT.md principles.
187
215
 
188
216
  ```
189
217
  I see 2–3 ways to approach this:
@@ -302,8 +330,17 @@ If (b), convert each item to an explicit assumption in the summary.
302
330
 
303
331
  ## Step 8 — Persist the summary (after approval only)
304
332
 
305
- Once the user says **yes**, write the approved summary to `features/{slug}/brainstorm.md`
306
- so it survives across sessions and forge-spec can pick it up later.
333
+ Once the user says **yes**:
334
+
335
+ **8a — Assign sequence number and ask about dependencies**
336
+
337
+ Read `features/CHANGELOG.md`. Count existing rows to get the next `#`.
338
+
339
+ Ask (one message):
340
+ > "Does this feature depend on any other feature being shipped first?
341
+ > _(Enter slugs like `user-registration`, or 'none')_"
342
+
343
+ **8b — Write `features/{slug}/brainstorm.md`**
307
344
 
308
345
  ```markdown
309
346
  # Brainstorm: {Feature Name}
@@ -315,18 +352,26 @@ so it survives across sessions and forge-spec can pick it up later.
315
352
  {the full Brainstorm Summary body from Step 6 — all sections}
316
353
  ```
317
354
 
355
+ **8c — Append row to `features/CHANGELOG.md`**
356
+
357
+ Add a new row — status `Brainstormed`, modules left blank until forge-spec fills them:
358
+ ```
359
+ | {n} | {slug} | {one-line from Problem section} | Brainstormed | — | {depends or —} |
360
+ ```
361
+
318
362
  Then hand off:
319
- > "Saved to `features/{slug}/brainstorm.md`. Run `/forge-spec {slug}` to write the spec."
363
+ > "Saved to `features/{slug}/brainstorm.md` and added to the changelog as #{n}.
364
+ > Run `/forge-spec {slug}` to write the spec."
320
365
 
321
366
  ---
322
367
 
323
368
  ## Rules
324
369
  - One question per message — never list multiple at once
325
370
  - Prefer multiple-choice when options are predictable
326
- - Never skip Step 2 mandatory areas — even for "simple" features
327
- - Never skip the challenge round (Step 4)
328
- - Never skip the approaches step (Step 5)
371
+ - Cover all Step 2 mandatory areas — but fill from Step 0 extraction first; only ask for genuine gaps
372
+ - Never skip the challenge round (Step 4) — even when a doc covers everything, challenge it
373
+ - Never skip the approaches step (Step 5) — a doc may have a chosen approach but alternatives should still be surfaced
329
374
  - YAGNI: move anything non-core to Out of Scope
330
375
  - The ONLY file written is `features/{slug}/brainstorm.md`, and only after approval (Step 8)
331
376
  - Do NOT skip Step 1 research — always check existing context first
332
- - Do NOT ask questions that could be answered by reading the existing codebase
377
+ - Do NOT ask questions that could be answered by reading the existing codebase or the pasted doc
@@ -93,6 +93,7 @@ Feature progress: {feature-slug}
93
93
  **If all modules are complete:**
94
94
  Update `features/{slug}/tasks.md` header status to `Done`
95
95
  and `features/{slug}/spec.md` header status to `Done`.
96
+ Update `features/CHANGELOG.md`: find the row for `{slug}` and set `Status` → `Done`.
96
97
 
97
98
  > "🎉 All modules done — feature `{slug}` is complete."
98
99
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: "forge-config"
3
- description: "View and interactively update .forge/project.json: add or remove modules, update ports, change stack info, or update the spec repo URL. Asks one question at a time and previews changes before writing."
4
- argument-hint: "Optional hint: 'add module', 'update user-service port', 'remove web-app'"
3
+ description: "View and interactively update .forge/project.json (add/remove modules and submodules, ports, stack, spec repo URL) and CONTEXT.md (actors, glossary, principles, conventions). Asks one question at a time and previews changes before writing."
4
+ argument-hint: "Optional hint: 'add module', 'add submodule to webapps', 'update user-service port', 'edit principles'"
5
5
  compatibility: "Requires spec repo with .forge/project.json"
6
6
  metadata:
7
7
  author: "forge-workflow"
@@ -12,14 +12,16 @@ disable-model-invocation: true
12
12
 
13
13
  # Forge Config
14
14
 
15
- View and update the project configuration at `.forge/project.json`.
15
+ View and update the project configuration at `.forge/project.json`, and the
16
+ project-wide domain context at `CONTEXT.md`.
16
17
 
17
18
  ## Step 1 — Load & display
18
19
 
19
20
  Read `.forge/project.json`.
20
21
  If missing: "No project config found. Run `/forge-init` to set up this repo first."
21
22
 
22
- Display the current config:
23
+ Display the current config. Modules with submodules show one indented `↳` row per
24
+ submodule — the parent row has no port/stack (those belong to each submodule):
23
25
 
24
26
  ```
25
27
  Project: {project-name}
@@ -28,13 +30,19 @@ Contract tool: {contract_tool}
28
30
 
29
31
  Modules ({n}):
30
32
  · user-service backend Spring Boot 3, Java 21 :8081
31
- · web-app frontend React, TypeScript :3000
33
+ · webapps (3 submodules)
34
+ ↳ admin frontend React :3001 apps/admin
35
+ ↳ landing frontend Next.js :3000 apps/landing
36
+ ↳ portal frontend React :3002 apps/portal
32
37
  ```
33
38
 
34
39
  ## Step 2 — Determine the change
35
40
 
36
- From $ARGUMENTS, infer the intent if given (e.g. "add module", "update user-service port").
37
- If empty, ask: "What do you want to change? (add a module / remove a module / update a field / change spec repo URL)"
41
+ From $ARGUMENTS, infer the intent if given (e.g. "add module", "add submodule to webapps",
42
+ "update user-service port", "edit principles").
43
+ If empty, ask: "What do you want to change? (add a module / add a submodule to an existing
44
+ module / remove a module or submodule / update a field / change spec repo URL / edit project
45
+ context — actors, glossary, principles, conventions)"
38
46
 
39
47
  ## Step 3 — Collect details (one question at a time)
40
48
 
@@ -44,22 +52,68 @@ Ask one question per message — never batch.
44
52
  1. "Module name? (kebab-case, must be unique)"
45
53
  2. "Type? (backend / frontend / worker / gateway)"
46
54
  3. "Tech stack? (e.g. 'Spring Boot 3, Java 21')"
47
- 4. "Local dev port?"
48
- 5. "Git repo URL? (or 'none')"
49
- 6. "One-sentence description? (or 'none')"
50
-
51
- **Removing a module:**
52
- - Check whether any `features/*/tasks.md` has a `### {module}` section.
53
- If so, warn: "`{module}` has tasks in {feature(s)}. Removing it from config won't delete those tasks. Remove anyway? (yes/no)"
54
- - Otherwise confirm: "Remove `{module}` from the project? (yes/no)"
55
+ 4. "Git repo URL? (or 'none')"
56
+ 5. "Does `{name}` contain multiple submodules — e.g. a monorepo with several apps,
57
+ or a Gradle multi-module build? (yes / no)"
58
+ - **If yes** → collect submodules one at a time (see below). Skip step 6 —
59
+ port and stack belong to each submodule, not the parent; drop the stack from step 3
60
+ if it was given for the parent.
61
+ - **If no** continue.
62
+ 6. "Local dev port?" _(skip when the module has submodules)_
63
+ 7. "One-sentence description? (or 'none')"
64
+
65
+ **Adding a submodule** (to an existing module) — ask which module first if not given.
66
+
67
+ - If the parent is currently a **simple module** (no `submodules[]`), warn before converting:
68
+ > "`{module}` is currently a standalone module. Adding a submodule converts it:
69
+ > its `port` and `stack` move to the submodules — the parent keeps only `name`,
70
+ > `repo`, and `description`. If `{module}` already has tasks or contracts under its
71
+ > own name, those stay as-is and won't match a submodule name. Convert? (yes/no)"
72
+ If yes, ask whether the existing port/stack should become the first submodule
73
+ (asking for its `name` and `path`) or be discarded.
74
+ - Then collect each new submodule, one field at a time (same as `/forge-init`):
75
+ 1. "Submodule name? (kebab-case, unique across the whole project — not just within `{module}`)"
76
+ 2. "Type? (backend / frontend / worker)"
77
+ 3. "Stack?"
78
+ 4. "Port?"
79
+ 5. "Path within the `{module}` repo? (e.g. `apps/admin` or `auth-ui`)"
80
+ 6. "One sentence: what does it do? _(Skip with 'none')_"
81
+ - Confirm each: "`{sub}` — {type} — {stack} — :{port} — path: {path}. Another submodule? (yes / no)"
82
+
83
+ > **Submodule rules (same as `/forge-init`):**
84
+ > - No `repo` field on a submodule — it shares the parent module's repo
85
+ > - No `port` or `stack` on a parent that has submodules
86
+ > - Submodule names must be unique across the whole project — contracts live at
87
+ > `contracts/{submodule}/` and tasks.md uses `### {submodule}` headings directly
88
+
89
+ **Removing a module or submodule:**
90
+ - Check whether any `features/*/tasks.md` has a `### {name}` section (module name for
91
+ simple modules, submodule name for submodules).
92
+ If so, warn: "`{name}` has tasks in {feature(s)}. Removing it from config won't delete those tasks. Remove anyway? (yes/no)"
93
+ - Otherwise confirm: "Remove `{name}` from the project? (yes/no)"
94
+ - If removing the **last submodule** of a module, ask: "That's the last submodule of
95
+ `{module}`. Convert it back to a standalone module (needs a port and stack), or remove
96
+ the whole module?"
55
97
 
56
98
  **Updating a field:**
57
99
  - Show the current value, then ask for the new one:
58
100
  "`{module}.{field}` is currently `{old}`. What should it be?"
101
+ - Submodule fields use the path `{module}.submodules[{sub}].{field}` — e.g.
102
+ "`webapps.submodules[admin].port` is currently `3001`. What should it be?"
103
+ - Refuse to set `port` or `stack` on a parent with submodules, or `repo` on a
104
+ submodule — explain the rule instead.
59
105
 
60
106
  **Changing spec repo URL:**
61
107
  - "Current spec_repo is `{old}`. New URL?"
62
108
 
109
+ **Editing project context (`CONTEXT.md`):**
110
+ - Read `CONTEXT.md`. If missing, offer to create it with the template from `/forge-init`
111
+ Phase 6, asking the Phase 2 and Phase 4 questions to fill it.
112
+ - Ask which section: "Which section? (What This Project Is / Business Goal / Actors /
113
+ Domain Glossary / Current State / Principles / Conventions / Out of Scope)"
114
+ - Show the section's current content, then ask what to add, change, or remove.
115
+ - Context edits go to `CONTEXT.md` only — never to CLAUDE.md or project.json.
116
+
63
117
  ## Step 4 — Preview & gate
64
118
 
65
119
  Show the before/after of exactly what will change:
@@ -69,19 +123,36 @@ Change preview:
69
123
  modules[user-service].port: 8081 → 8090
70
124
  ```
71
125
 
72
- > "Apply this change to `.forge/project.json`? Say **yes** to write, or tell me what to adjust."
126
+ Adding a submodule:
127
+ ```
128
+ Change preview:
129
+ modules[webapps].submodules + { name: reports, type: frontend,
130
+ stack: [React], port: 3003, path: apps/reports }
131
+ ```
132
+
133
+ Converting a simple module to one with submodules, show the moved fields too:
134
+ ```
135
+ Change preview:
136
+ modules[webapps].port 3000 → (removed — moves to submodules)
137
+ modules[webapps].stack [React] → (removed — moves to submodules)
138
+ modules[webapps].submodules + { name: admin, ... }
139
+ ```
140
+
141
+ For CONTEXT.md edits, show the section before/after instead.
142
+
143
+ > "Apply this change to `{file}`? Say **yes** to write, or tell me what to adjust."
73
144
 
74
145
  Wait for confirmation. Do not write before the user says yes.
75
146
 
76
147
  ## Step 5 — Write & confirm
77
148
 
78
- Apply the change, preserving all other fields and formatting.
79
- Confirm: "Updated `.forge/project.json` — {summary of what changed}."
149
+ Apply the change, preserving all other fields, sections, and formatting.
150
+ Confirm: "Updated `{file}` — {summary of what changed}."
80
151
 
81
- If a module name changed, warn:
82
- > "Heads up: `{module}` is referenced by the module repo's `.forge/module.json` and by
83
- > `### {module}` headings in tasks.md. Update those to match, or `/forge-implement` and
84
- > `/forge-close` will break."
152
+ If a module or submodule name changed, warn:
153
+ > "Heads up: `{name}` is referenced by the module repo's `.forge/module.json`, by
154
+ > `### {name}` headings in tasks.md, and by the `contracts/{name}/` folder. Update
155
+ > those to match, or `/forge-implement` and `/forge-close` will break."
85
156
 
86
157
  ## Schema Reference
87
158
 
@@ -90,6 +161,7 @@ If a module name changed, warn:
90
161
  "project": "my-project", // short slug, no spaces
91
162
  "version": "1.0",
92
163
  "modules": [
164
+ // Module WITHOUT submodules — port and stack on the module itself:
93
165
  {
94
166
  "name": "user-service", // kebab-case, matches module.json in module repos
95
167
  "repo": "git@github.com:org/user-service.git",
@@ -97,6 +169,23 @@ If a module name changed, warn:
97
169
  "stack": ["Spring Boot 3", "Java 21"],
98
170
  "port": 8081,
99
171
  "description": "" // optional, one sentence
172
+ },
173
+ // Module WITH submodules — NO port/stack/type on the parent;
174
+ // each submodule owns type, stack, port, path; NO repo on submodules:
175
+ {
176
+ "name": "webapps",
177
+ "repo": "git@github.com:org/webapps.git",
178
+ "description": "Web app mono-repo",
179
+ "submodules": [
180
+ {
181
+ "name": "admin", // kebab-case, unique across the WHOLE project
182
+ "type": "frontend", // backend | frontend | worker
183
+ "stack": ["React"],
184
+ "port": 3001,
185
+ "path": "apps/admin", // relative path inside the parent repo
186
+ "description": "" // optional, one sentence
187
+ }
188
+ ]
100
189
  }
101
190
  ],
102
191
  "spec_repo": "git@github.com:org/specs.git",
@@ -108,6 +197,10 @@ If a module name changed, warn:
108
197
  ## Rules
109
198
  - One question per message — never batch
110
199
  - Never write before the user confirms the preview in Step 4
111
- - `module.name` must be kebab-case and unique
112
- - `module.name` must match the `module` field in the module repo's `.forge/module.json`
113
- - Never silently remove a module that has tasks referencing it — warn first
200
+ - `module.name` must be kebab-case and unique; submodule names must be unique across
201
+ the whole project (contracts and task headings use the submodule name directly)
202
+ - `module.name` must match the `module` field in the module repo's `.forge/module.json`;
203
+ submodule names must match the `submodules[].name` entries there
204
+ - A module has EITHER `port`+`stack` OR `submodules[]` — never both; submodules never
205
+ have a `repo` field
206
+ - Never silently remove a module or submodule that has tasks referencing it — warn first
@@ -28,7 +28,11 @@ and the user has explicitly confirmed it.
28
28
  - Feature slug from $ARGUMENTS, or ask: "Which feature do you want to generate a contract for?"
29
29
  - Read `features/{slug}/spec.md` — must exist, otherwise stop.
30
30
  - Read `features/{slug}/tasks.md` — must exist, otherwise say "Run `/forge-tasks {slug}` first."
31
- - Read `.forge/project.json` — get module names, ports, stacks.
31
+ - Read `.forge/project.json` — build a flat list of **contract targets**:
32
+ - Module with no submodules → target name = `{module.name}`, contract path = `contracts/{module.name}/`
33
+ - Module with submodules → target name = each `{submodule.name}`, contract path = `contracts/{submodule.name}/`
34
+ - Submodules use their own name as the target — identical to a standalone module — so they can be
35
+ promoted to a separate repo later with no contract path changes.
32
36
 
33
37
  ---
34
38
 
@@ -207,6 +211,8 @@ Update the API Endpoints table in `features/{slug}/spec.md`:
207
211
  Also advance the spec status: change the `**Status:**` line in `features/{slug}/spec.md`
208
212
  from `Draft` to `Ready` (planning complete — ready for implementation).
209
213
 
214
+ Update `features/CHANGELOG.md`: find the row for `{slug}` and set `Status` → `Ready`.
215
+
210
216
  ---
211
217
 
212
218
  ## Step 7 — Completion
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "forge-init"
3
- description: "One-time initialization for a Forge spec repo. Walks through setup conversationally one question at a time, then writes .forge/project.json, CLAUDE.md, and directory scaffolding on confirmation."
3
+ description: "One-time initialization for a Forge spec repo. Walks through setup conversationally one question at a time — project identity, project details, modules, principles — then writes .forge/project.json, CONTEXT.md, CLAUDE.md, and directory scaffolding on confirmation."
4
4
  argument-hint: "Optional: project name to skip the first prompt"
5
5
  compatibility: "Run once in a spec repo before any other forge skills. Safe to re-run — never overwrites existing files."
6
6
  when_to_use: >
@@ -40,7 +40,40 @@ _(Skip with 'none' if it's not set up yet — you can add it later with `/forge-
40
40
 
41
41
  ---
42
42
 
43
- ## Phase 2 — Modules
43
+ ## Phase 2 — Project details
44
+
45
+ These answers become `CONTEXT.md` — the project-wide domain context that
46
+ `/forge-brainstorm` and `/forge-spec` read before planning, and that module repos
47
+ see at `specs/CONTEXT.md` during implementation. Getting this right once saves
48
+ re-explaining the project in every feature conversation.
49
+
50
+ Start by offering the shortcut:
51
+ > "If you have a project overview doc (README, pitch doc, Confluence page), paste it
52
+ > and I'll extract these answers — otherwise I'll ask a few short questions."
53
+
54
+ If a doc is pasted, extract what's covered and ask only about genuine gaps.
55
+ Otherwise ask one question at a time:
56
+
57
+ **Q1.** "Who uses this system? List the actors/roles and what each one does.
58
+ _(e.g. 'customer — places orders; admin — manages the catalog; billing-worker — system actor')_"
59
+
60
+ **Q2.** "What are the core domain concepts, in your team's own words?
61
+ _(e.g. 'Order, Quote, Fulfillment — a Quote becomes an Order when accepted')_
62
+ These become the domain glossary — the exact terms specs and contracts will use."
63
+
64
+ **Q3.** "What's the business goal — what does success look like for this project?
65
+ _(1–2 sentences, or 'skip')_"
66
+
67
+ **Q4.** "What's the current state? Greenfield, or are there existing systems this
68
+ replaces or integrates with?
69
+ _(e.g. 'replacing a legacy PHP monolith; auth stays in Keycloak')_"
70
+
71
+ Keep this phase capped at these four areas — deep per-feature questioning is
72
+ `/forge-brainstorm`'s job, not init's.
73
+
74
+ ---
75
+
76
+ ## Phase 3 — Modules
44
77
 
45
78
  Collect modules one at a time. Each module is gathered field by field.
46
79
 
@@ -53,16 +86,39 @@ For each module, ask these in order (one question per message):
53
86
  2. **Type** — "Is `{name}` a backend service, frontend app, or something else?
54
87
  _(backend / frontend / worker / gateway)_"
55
88
  3. **Stack** — "What's the tech stack for `{name}`? (e.g. `Spring Boot 3, Java 21` or `React, TypeScript`)"
56
- 4. **Port** — "What port does `{name}` run on locally?"
57
- 5. **Repo URL** — "What's the git repo URL for `{name}`?
89
+ 4. **Repo URL** — "What's the git repo URL for `{name}`?
58
90
  _(Skip with 'none' if not set up yet)_"
59
- 6. **Description** — "One sentence: what does `{name}` do?
60
- _(Skip with 'none')_"
61
-
62
- After collecting all fields for a module, confirm it back:
91
+ 5. **Submodules** — scan the user's answers so far for signals: words like "monorepo", "multi-module",
92
+ "Gradle modules", a comma-separated list of app names, etc.
93
+ **If signals present**, ask:
94
+ > "It sounds like `{name}` contains multiple submodules ({detected names if any}).
95
+ > Should I configure them separately? (yes / no)"
96
+ **If yes** → collect submodules one at a time (see below). Skip step 6 — port belongs to each submodule, not the parent.
97
+ **If no or no signals** → continue to step 6.
98
+ 6. **Port** _(skip when module has submodules)_ — "What port does `{name}` run on locally?"
99
+ 7. **Description** — "One sentence: what does `{name}` do? _(Skip with 'none')_"
100
+
101
+ **Submodule collection** (repeat for each):
102
+ - "Submodule name? (kebab-case)"
103
+ - "Type? (backend / frontend / worker)"
104
+ - "Stack?"
105
+ - "Port?"
106
+ - "Path within the `{name}` repo? (e.g. `apps/admin` or `auth-ui`)"
107
+ - "One sentence: what does it do? _(Skip with 'none')_"
108
+
109
+ Confirm each: "`{sub}` — {type} — {stack} — :{port} — path: {path}. Another submodule? (yes / no)"
110
+
111
+ > **Rules for submodules:**
112
+ > - No `repo` field — submodules share the parent module's repo
113
+ > - No `port` on the parent module — port belongs to each submodule
114
+ > - `type` and `stack` are per-submodule (may differ from the parent)
115
+
116
+ After collecting all submodules (or just module fields), confirm:
63
117
 
64
118
  > "Got it:
65
- > `{name}` — {type} — {stack} — :{port} — {repo or 'no repo yet'}
119
+ > `{name}` — {type} — {repo or 'no repo yet'}
120
+ > {if no submodules: stack + port}
121
+ > {if submodules: list each as ` ↳ {sub} — {type} — {stack} — :{port} — {path}`}
66
122
  > {description}
67
123
  > Is that right?"
68
124
 
@@ -70,11 +126,11 @@ Then ask:
70
126
  > "Any more modules to add? (yes / no)"
71
127
 
72
128
  If yes, repeat from step 1 of this phase for the next module.
73
- If no, move to Phase 3.
129
+ If no, move to Phase 4.
74
130
 
75
131
  ---
76
132
 
77
- ## Phase 3 — Principles & conventions
133
+ ## Phase 4 — Principles & conventions
78
134
 
79
135
  Ask one at a time. "None" or "not yet" are valid answers — these sections can be filled
80
136
  in later with `/forge-config`.
@@ -93,7 +149,7 @@ Say 'none yet' to skip._"
93
149
 
94
150
  ---
95
151
 
96
- ## Phase 4 — Preview & gate
152
+ ## Phase 5 — Preview & gate
97
153
 
98
154
  Show a full preview of what will be written:
99
155
 
@@ -105,14 +161,21 @@ Ready to initialize. Here's what I'll create:
105
161
  modules: {n} module(s): {comma-separated names}
106
162
  spec_repo: {url or "not set"}
107
163
 
108
- CLAUDE.md
164
+ CONTEXT.md
109
165
  Description: {description}
110
- Modules: {n} listed
166
+ Actors: {n} listed
167
+ Domain glossary: {n} terms
168
+ Business goal: {one line or "skipped"}
169
+ Current state: {one line}
111
170
  Principles: {list or "none yet"}
112
171
  Conventions: {list or "none yet"}
113
172
  Out of scope: {list or "none yet"}
114
173
 
115
- features/.gitkeep
174
+ CLAUDE.md
175
+ Modules: {n} listed
176
+ Forge workflow + structure + pointer to CONTEXT.md
177
+
178
+ features/CHANGELOG.md
116
179
  contracts/.gitkeep
117
180
  .gitignore ← append Forge entries
118
181
  ```
@@ -123,9 +186,11 @@ Wait for confirmation. Do not write anything before the user says yes.
123
186
 
124
187
  ---
125
188
 
126
- ## Phase 5 — Write files
189
+ ## Phase 6 — Write files
127
190
 
128
191
  Write `.forge/project.json`:
192
+
193
+ Module **without** submodules — `port` and `stack` on the module itself:
129
194
  ```json
130
195
  {
131
196
  "project": "{project-name}",
@@ -146,17 +211,98 @@ Write `.forge/project.json`:
146
211
  }
147
212
  ```
148
213
 
149
- Write `CLAUDE.md`:
214
+ Module **with** submodules — no `port` on the module; each submodule owns its `port`, `stack`,
215
+ `type`, and `path`; no `repo` on submodules (they share the parent's repo):
216
+ ```json
217
+ {
218
+ "project": "{project-name}",
219
+ "version": "1.0",
220
+ "modules": [
221
+ {
222
+ "name": "{module-name}",
223
+ "repo": "{repo-url}",
224
+ "description": "{description}",
225
+ "submodules": [
226
+ {
227
+ "name": "{sub-name}",
228
+ "type": "backend|frontend|worker",
229
+ "stack": ["{stack}"],
230
+ "port": {port},
231
+ "path": "{relative-path-in-repo}",
232
+ "description": "{description}"
233
+ }
234
+ ]
235
+ }
236
+ ],
237
+ "spec_repo": "{spec-repo-url}",
238
+ "contract_format": "openapi3",
239
+ "contract_tool": "specmatic"
240
+ }
241
+ ```
242
+
243
+ Write `CONTEXT.md` — the single source of truth for project-wide domain context.
244
+ Fill every section from the Phase 1, 2, and 4 answers; write "None defined yet." only
245
+ where the user explicitly skipped:
246
+ ```markdown
247
+ # {project-name} — Project Context
248
+
249
+ > Domain context for all planning and implementation. `/forge-brainstorm` and
250
+ > `/forge-spec` read this before any feature work; module repos see it at
251
+ > `specs/CONTEXT.md`. Keep it current via `/forge-config`.
252
+
253
+ ## What This Project Is
254
+ {description — 2–4 sentences built from the user's answers, not just the one-liner}
255
+
256
+ ## Business Goal
257
+ {goal — or "Not defined yet."}
258
+
259
+ ## Actors
260
+ | Actor | Who they are | What they do in the system |
261
+ |-------|--------------|----------------------------|
262
+ | {role} | {description} | {responsibilities} |
263
+
264
+ ## Domain Glossary
265
+ | Term | Meaning |
266
+ |------|---------|
267
+ | {term} | {definition in the team's own words} |
268
+
269
+ ## Current State
270
+ {greenfield / existing systems, integrations, migration notes}
271
+
272
+ ## Principles
273
+ {list each as a bullet — or "None defined yet."}
274
+
275
+ ## Conventions
276
+ {list each as a bullet — or "None defined yet."}
277
+
278
+ ## Out of Scope / Forbidden
279
+ {list each as a bullet — or "None defined yet."}
280
+ ```
281
+
282
+ Write `CLAUDE.md` — operational only; domain context lives in `CONTEXT.md`, never
283
+ duplicate it here:
150
284
  ```markdown
151
285
  # {project-name}
152
286
 
153
- {description}
287
+ {description — the 1–2 sentence version}
288
+
289
+ ## Project Context
290
+ Actors, domain glossary, principles, and conventions live in `CONTEXT.md`.
291
+ Read it before any brainstorm, spec, or planning work.
154
292
 
155
293
  ## Modules
156
294
  | Name | Type | Stack | Port |
157
295
  |------|------|-------|------|
158
296
  | {name} | {type} | {stack} | {port} |
159
297
 
298
+ _(For modules with submodules, expand the table with one row per submodule.
299
+ Indent the submodule name with `↳` and omit port/stack from the parent row.)_
300
+
301
+ | Name | Type | Stack | Port | Path |
302
+ |------|------|-------|------|------|
303
+ | {module} | — | — | — | — |
304
+ | ↳ {sub} | {type} | {stack} | {port} | {path} |
305
+
160
306
  ## Forge Workflow
161
307
  1. `/forge-brainstorm` — explore and define a feature
162
308
  2. `/forge-spec` — write the spec
@@ -164,26 +310,28 @@ Write `CLAUDE.md`:
164
310
  4. `/forge-contract` — generate Specmatic OpenAPI contracts
165
311
  5. `/forge-close {slug} {module}` — mark a module's tasks done (after module repo ships)
166
312
 
167
- Utilities: `/forge-status` (feature dashboard) · `/forge-config` (edit modules/ports)
168
-
169
- ## Principles
170
- {list each as a bullet — or "None defined yet."}
171
-
172
- ## Conventions
173
- {list each as a bullet — or "None defined yet."}
174
-
175
- ## Out of Scope / Forbidden
176
- {list each as a bullet — or "None defined yet."}
313
+ Utilities: `/forge-status` (feature dashboard) · `/forge-config` (edit modules/ports/context)
177
314
 
178
315
  ## Structure
316
+ - `CONTEXT.md` — project-wide domain context (actors, glossary, principles)
179
317
  - `features/{slug}/brainstorm.md` — approved brainstorm summary
180
318
  - `features/{slug}/spec.md` — requirements, flows, API list
181
319
  - `features/{slug}/tasks.md` — per-module task breakdown with checkboxes
182
320
  - `contracts/{module}/{slug}.yaml` + `schemas/` + `shared/` — Specmatic OpenAPI 3.0 contracts
183
321
  ```
184
322
 
323
+ Create `features/CHANGELOG.md`:
324
+ ```markdown
325
+ # Feature Changelog
326
+
327
+ Ordered list of all features. Add entries via `/forge-brainstorm`; update via `/forge-spec`,
328
+ `/forge-contract`, and `/forge-close`. Use `Depends on` to declare what must ship first.
329
+
330
+ | # | Slug | Description | Status | Modules | Depends on |
331
+ |---|------|-------------|--------|---------|------------|
332
+ ```
333
+
185
334
  Create:
186
- - `features/.gitkeep`
187
335
  - `contracts/.gitkeep`
188
336
 
189
337
  Append to `.gitignore` if not present:
@@ -199,7 +347,14 @@ Run `git status` and confirm:
199
347
 
200
348
  ## Rules
201
349
  - One question per message — never ask multiple questions at once
202
- - Never write files before the user says yes in Phase 4
350
+ - Never write files before the user says yes in Phase 5
351
+ - Each fact lives in exactly one file: domain context in `CONTEXT.md`, machine config
352
+ in `.forge/project.json`, workflow instructions in `CLAUDE.md` — never duplicate
353
+ content across them
203
354
  - Never overwrite existing files
204
355
  - All written files must be complete — no unfilled placeholders
356
+ - **Extract, don't re-ask**: if the user's answer contains information for upcoming fields
357
+ (e.g. "user-service, Spring Boot 3, port 8080, backend"), extract and fill those fields
358
+ silently — only ask about what is genuinely missing. Never ask a question the user has
359
+ already answered, even indirectly.
205
360
  - If the user provides multiple answers in one message, accept them gracefully and move forward
@@ -44,9 +44,10 @@ Before asking anything, research silently:
44
44
  - How Non-Functional requirements are typically written
45
45
  - Any related feature whose requirements this feature extends or depends on
46
46
 
47
- 2. **CLAUDE.md** — note project principles and conventions.
47
+ 2. **CONTEXT.md** — note the actors, domain glossary, principles, and conventions.
48
48
  Any principle that implies a requirement for this feature?
49
49
  (e.g. "API contract before implementation" → this feature needs a contract requirement)
50
+ Use glossary terms verbatim in requirements — never invent synonyms for existing domain terms.
50
51
 
51
52
  3. **Brainstorm open items** — extract from the brainstorm summary:
52
53
  - Any item listed under **Open Questions** that wasn't resolved
@@ -58,7 +59,7 @@ Report findings:
58
59
  > "Before drafting, here's what I found:
59
60
  > - Related features: {list or 'none'}
60
61
  > - Unresolved from brainstorm: {open questions / assumptions — or 'none, all clear'}
61
- > - CLAUDE.md principles that apply: {list or 'none'}
62
+ > - CONTEXT.md principles that apply: {list or 'none'}
62
63
  > - Naming convention: {e.g. 'REQ-N restarts per feature'}"
63
64
 
64
65
  ---
@@ -270,9 +271,16 @@ Cross-module data: {what is shared with or derived from other modules — or "No
270
271
 
271
272
  ---
272
273
 
273
- ## Step 7 — Gate
274
+ ## Step 7 — Update changelog & gate
274
275
 
275
- After writing, say:
276
+ After writing `spec.md`, update `features/CHANGELOG.md`:
277
+ - Find the row where `Slug` = `{slug}`
278
+ - Update `Status` → `Draft`
279
+ - Update `Modules` → comma-separated list of modules from the spec's **Modules** header
280
+ - If the row doesn't exist (spec written without going through forge-brainstorm), append it:
281
+ `| — | {slug} | {overview first sentence} | Draft | {modules} | — |`
282
+
283
+ Then say:
276
284
  > "Spec written to `features/{slug}/spec.md`. Review it and say **yes** to generate the task breakdown."
277
285
 
278
286
  Do NOT add tasks to spec.md — tasks go in `features/{slug}/tasks.md` via `/forge-tasks`.
@@ -12,44 +12,52 @@ disable-model-invocation: true
12
12
 
13
13
  # Forge Status
14
14
 
15
- Show the current status of all features in this spec repo.
15
+ Show the current status of all features in this spec repo, in changelog order.
16
16
 
17
17
  ## Steps
18
18
 
19
- 1. Scan the `features/` directory. If empty or missing, say "No features yet. Run `/forge-brainstorm` to plan your first feature."
19
+ 1. Read `features/CHANGELOG.md`.
20
+ - If missing or empty (no data rows): "No features yet. Run `/forge-brainstorm` to plan your first feature."
21
+ - Parse each row: `#`, `slug`, `description`, `status`, `modules`, `depends on`.
20
22
 
21
- 2. For each feature folder, determine its state (check in order, top to bottom):
22
- - No `brainstorm.md` and no `spec.md` → 🔵 Brainstorming
23
- - `brainstorm.md` exists, no `spec.md` → 🔵 Brainstormed
24
- - `spec.md` exists, no `tasks.md` → 🟡 Spec written
25
- - `tasks.md` exists, no contract file in `contracts/{any-module}/{slug}.yaml` → 🟠 Tasks ready
26
- - Contract exists, but `tasks.md` has unchecked tasks → 🟣 Implementing
27
- - Contract exists and all tasks in `tasks.md` are checked → ✅ Done
23
+ 2. For each row in changelog order — determine its **live state** by checking the files
24
+ (overrides the stored status for in-progress detail):
28
25
 
29
- 3. For features in Implementing, read `tasks.md` and compute per-module completion
30
- (ticked vs total under each `### {module}` heading) for the detail line.
26
+ | Files present | Live state |
27
+ |---|---|
28
+ | Nothing in `features/{slug}/` | 🔵 Brainstormed |
29
+ | `brainstorm.md` only | 🔵 Brainstormed |
30
+ | `spec.md` exists, no `tasks.md` | 🟡 Draft |
31
+ | `tasks.md` exists, no contract | 🟠 Open |
32
+ | Contract exists, unchecked tasks remain | 🟣 Implementing |
33
+ | All tasks checked (or `Status: Done` in tasks.md) | ✅ Done |
31
34
 
32
- 4. Also check `contracts/` for orphaned contracts (contract file exists but no matching feature folder) and flag them.
35
+ 3. For 🟣 Implementing features, read `tasks.md` and compute per-module completion
36
+ (ticked vs total under each `### {target}` heading).
37
+
38
+ 4. Flag any `Depends on` entries where the dependency is not yet ✅ Done — mark with ⚠️.
33
39
 
34
40
  ## Output Format
35
41
 
36
42
  ```
37
- Feature Status — {project} spec repo
38
- ══════════════════════════════════════════════════════
39
-
40
- ✅ user-auth Done — all modules complete
41
- 🟣 payment-flow Implementing user-service 2/3, web-app 0/2
42
- 🟠 notification-prefs Tasks ready — contract pending
43
- 🟡 search-filters Spec written — tasks pending
44
- 🔵 bulk-export Brainstormed spec pending
45
-
46
- ══════════════════════════════════════════════════════
47
- 5 features · 1 done · 1 implementing · 3 planning
43
+ Feature Status — {project}
44
+ ══════════════════════════════════════════════════════════════════
45
+ # Slug Status Modules Depends on
46
+ ──────────────────────────────────────────────────────────────────
47
+ 1 user-auth ✅ Done user-service
48
+ 2 payment-flow 🟣 Implementing user-service 2/3 #1
49
+ 3 notification-prefs 🟠 Open user-service #1
50
+ 4 search-filters 🟡 Draft user-service
51
+ 5 bulk-export 🔵 Brainstormed — #3 ⚠️ not done yet
52
+ ══════════════════════════════════════════════════════════════════
53
+ 5 features · 1 done · 1 implementing · 3 in planning
48
54
  ```
49
55
 
56
+ The ⚠️ flag means "this feature's dependency is not yet Done — reconsider starting it."
57
+
50
58
  ## What to Show Next
51
- After the table, suggest the next action for each non-done feature:
52
- - Brainstorming/Brainstormed → "Run `/forge-spec {slug}` to write the spec"
53
- - Spec written"Run `/forge-tasks {slug}` to generate the task breakdown"
54
- - Tasks ready"Run `/forge-contract {slug}` to generate the API contract"
55
- - Implementing → "Module repos run `/forge-implement {slug}`, then `/forge-done` → `/forge-close {slug} {module}`"
59
+ After the table, suggest the next action for each non-done feature (in changelog order):
60
+ - 🔵 Brainstormed → `/forge-spec {slug}`
61
+ - 🟡 Draft → `/forge-tasks {slug}`
62
+ - 🟠 Open → `/forge-contract {slug}`
63
+ - 🟣 Implementing → "Module repos: `/forge-implement {slug}` `/forge-done` → `/forge-close {slug} {module}`"
@@ -22,12 +22,20 @@ Generate the task breakdown for a feature and write it to a dedicated file.
22
22
  - If no → generate and write.
23
23
 
24
24
  ## Task breakdown rules
25
- - Group tasks by module using `### {module-name}` headings (use module names from `.forge/project.json`)
26
- - Each task gets a unique ID: `TASK-N` (sequential across all modules)
25
+
26
+ Read `.forge/project.json` and build a flat list of **task targets** the names used as `###` headings:
27
+ - For a module with **no submodules** → the target is `{module.name}`
28
+ - For a module **with submodules** → the targets are each `{submodule.name}` (the parent module name
29
+ is NOT used as a heading; submodules are treated exactly like standalone modules here)
30
+
31
+ This means a submodule can later be promoted to its own repo with zero changes to `tasks.md`.
32
+
33
+ - Group tasks by target using `### {target-name}` headings
34
+ - Each task gets a unique ID: `TASK-N` (sequential across all targets)
27
35
  - Tag each task with type: `[api]` / `[feat]` / `[ui]` / `[test]` / `[infra]`
28
36
  - Write 1–3 acceptance criteria under each task
29
- - Order tasks within each module by dependency (what must be done first)
30
- - For frontend/consumer modules, reference the backend endpoint they integrate against
37
+ - Order tasks within each target by dependency (what must be done first)
38
+ - For frontend/consumer targets, reference the backend endpoint they integrate against
31
39
 
32
40
  ## Output file: `features/{slug}/tasks.md`
33
41
 
@@ -41,7 +49,7 @@ _(Status lifecycle: Open → Done, set by `/forge-close` when all modules finish
41
49
 
42
50
  ---
43
51
 
44
- ### {module-name} ({type})
52
+ ### {target-name} ({type})
45
53
 
46
54
  - [ ] TASK-1 [api] {task title}
47
55
  - {acceptance criterion}
@@ -52,7 +60,7 @@ _(Status lifecycle: Open → Done, set by `/forge-close` when all modules finish
52
60
 
53
61
  ---
54
62
 
55
- ### {module-name} ({type})
63
+ ### {target-name} ({type})
56
64
 
57
65
  - [ ] TASK-3 [ui] {task title}
58
66
  - {acceptance criterion}
@@ -67,10 +75,10 @@ Tasks: {feature-slug}
67
75
  - [ ] TASK-1 [api] POST /users/register
68
76
  - [ ] TASK-2 [feat] Password hashing
69
77
 
70
- ### web-app (frontend)
78
+ ### admin (frontend) ← submodule of webapps, but headed by its own name
71
79
  - [ ] TASK-3 [ui] Registration form component
72
80
  ══════════════════════════════════════════
73
- 3 tasks across 2 modules
81
+ 3 tasks across 3 targets
74
82
  ```
75
83
 
76
84
  ## Gate