@khanhspring/forge-spec 1.0.0 → 1.1.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/bin/install.js +3 -4
- package/package.json +2 -9
- package/{forge-brainstorm → skills/forge-brainstorm}/SKILL.md +54 -10
- package/{forge-close → skills/forge-close}/SKILL.md +1 -0
- package/{forge-contract → skills/forge-contract}/SKILL.md +7 -1
- package/{forge-init → skills/forge-init}/SKILL.md +85 -9
- package/{forge-spec → skills/forge-spec}/SKILL.md +9 -2
- package/skills/forge-status/SKILL.md +63 -0
- package/{forge-tasks → skills/forge-tasks}/SKILL.md +16 -8
- package/forge-status/SKILL.md +0 -55
- /package/{forge-config → skills/forge-config}/SKILL.md +0 -0
- /package/{forge-contract → skills/forge-contract}/reference/best-practices.md +0 -0
- /package/{forge-contract → skills/forge-contract}/reference/contract-template.yaml +0 -0
package/bin/install.js
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { cpSync, mkdirSync } from 'fs';
|
|
4
4
|
import { join, dirname } from 'path';
|
|
5
|
-
import { homedir } from 'os';
|
|
6
5
|
import { fileURLToPath } from 'url';
|
|
7
6
|
|
|
8
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
8
|
const ROOT = join(__dirname, '..');
|
|
10
|
-
const SKILLS_DIR = join(
|
|
9
|
+
const SKILLS_DIR = join(process.cwd(), '.claude', 'skills');
|
|
11
10
|
|
|
12
11
|
const SKILLS = [
|
|
13
12
|
'forge-brainstorm',
|
|
@@ -25,9 +24,9 @@ console.log('Installing @forge-workflow/spec skills...\n');
|
|
|
25
24
|
mkdirSync(SKILLS_DIR, { recursive: true });
|
|
26
25
|
|
|
27
26
|
for (const skill of SKILLS) {
|
|
28
|
-
cpSync(join(ROOT, skill), join(SKILLS_DIR, skill), { recursive: true, force: true });
|
|
27
|
+
cpSync(join(ROOT, 'skills', skill), join(SKILLS_DIR, skill), { recursive: true, force: true });
|
|
29
28
|
console.log(` ✓ ${skill}`);
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
console.log(`\nInstalled to ${SKILLS_DIR}`)
|
|
31
|
+
console.log(`\nInstalled to ${SKILLS_DIR} (project-local)`)
|
|
33
32
|
console.log('Restart Claude Code, then run /forge-init in your spec repo.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanhspring/forge-spec",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Forge spec repo skills for Claude Code — brainstorm, spec, tasks, contract, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,14 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
|
11
|
-
"
|
|
12
|
-
"forge-close",
|
|
13
|
-
"forge-config",
|
|
14
|
-
"forge-contract",
|
|
15
|
-
"forge-init",
|
|
16
|
-
"forge-spec",
|
|
17
|
-
"forge-status",
|
|
18
|
-
"forge-tasks"
|
|
11
|
+
"skills"
|
|
19
12
|
],
|
|
20
13
|
"keywords": ["claude-code", "skills", "ai", "workflow", "microservices"],
|
|
21
14
|
"license": "MIT"
|
|
@@ -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
|
|
22
|
-
the user has explicitly approved the Brainstorm
|
|
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:
|
|
@@ -57,7 +83,8 @@ Then check scope:
|
|
|
57
83
|
## Step 2 — Mandatory questions (one at a time)
|
|
58
84
|
|
|
59
85
|
These MUST all be answered before moving to Step 4. Ask one at a time.
|
|
60
|
-
Skip any
|
|
86
|
+
**Skip any area already covered by Step 0 extraction or Step 1 research.**
|
|
87
|
+
Only ask about genuine gaps — never re-ask what the user already provided.
|
|
61
88
|
|
|
62
89
|
**If a question hits an unknown** — something the user can't answer without researching —
|
|
63
90
|
use the Research Flag pattern (see Research Handling below).
|
|
@@ -302,8 +329,17 @@ If (b), convert each item to an explicit assumption in the summary.
|
|
|
302
329
|
|
|
303
330
|
## Step 8 — Persist the summary (after approval only)
|
|
304
331
|
|
|
305
|
-
Once the user says **yes
|
|
306
|
-
|
|
332
|
+
Once the user says **yes**:
|
|
333
|
+
|
|
334
|
+
**8a — Assign sequence number and ask about dependencies**
|
|
335
|
+
|
|
336
|
+
Read `features/CHANGELOG.md`. Count existing rows to get the next `#`.
|
|
337
|
+
|
|
338
|
+
Ask (one message):
|
|
339
|
+
> "Does this feature depend on any other feature being shipped first?
|
|
340
|
+
> _(Enter slugs like `user-registration`, or 'none')_"
|
|
341
|
+
|
|
342
|
+
**8b — Write `features/{slug}/brainstorm.md`**
|
|
307
343
|
|
|
308
344
|
```markdown
|
|
309
345
|
# Brainstorm: {Feature Name}
|
|
@@ -315,18 +351,26 @@ so it survives across sessions and forge-spec can pick it up later.
|
|
|
315
351
|
{the full Brainstorm Summary body from Step 6 — all sections}
|
|
316
352
|
```
|
|
317
353
|
|
|
354
|
+
**8c — Append row to `features/CHANGELOG.md`**
|
|
355
|
+
|
|
356
|
+
Add a new row — status `Brainstormed`, modules left blank until forge-spec fills them:
|
|
357
|
+
```
|
|
358
|
+
| {n} | {slug} | {one-line from Problem section} | Brainstormed | — | {depends or —} |
|
|
359
|
+
```
|
|
360
|
+
|
|
318
361
|
Then hand off:
|
|
319
|
-
> "Saved to `features/{slug}/brainstorm.md
|
|
362
|
+
> "Saved to `features/{slug}/brainstorm.md` and added to the changelog as #{n}.
|
|
363
|
+
> Run `/forge-spec {slug}` to write the spec."
|
|
320
364
|
|
|
321
365
|
---
|
|
322
366
|
|
|
323
367
|
## Rules
|
|
324
368
|
- One question per message — never list multiple at once
|
|
325
369
|
- Prefer multiple-choice when options are predictable
|
|
326
|
-
-
|
|
327
|
-
- Never skip the challenge round (Step 4)
|
|
328
|
-
- Never skip the approaches step (Step 5)
|
|
370
|
+
- Cover all Step 2 mandatory areas — but fill from Step 0 extraction first; only ask for genuine gaps
|
|
371
|
+
- Never skip the challenge round (Step 4) — even when a doc covers everything, challenge it
|
|
372
|
+
- Never skip the approaches step (Step 5) — a doc may have a chosen approach but alternatives should still be surfaced
|
|
329
373
|
- YAGNI: move anything non-core to Out of Scope
|
|
330
374
|
- The ONLY file written is `features/{slug}/brainstorm.md`, and only after approval (Step 8)
|
|
331
375
|
- 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
|
|
376
|
+
- 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
|
|
|
@@ -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` —
|
|
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
|
|
@@ -53,16 +53,39 @@ For each module, ask these in order (one question per message):
|
|
|
53
53
|
2. **Type** — "Is `{name}` a backend service, frontend app, or something else?
|
|
54
54
|
_(backend / frontend / worker / gateway)_"
|
|
55
55
|
3. **Stack** — "What's the tech stack for `{name}`? (e.g. `Spring Boot 3, Java 21` or `React, TypeScript`)"
|
|
56
|
-
4. **
|
|
57
|
-
5. **Repo URL** — "What's the git repo URL for `{name}`?
|
|
56
|
+
4. **Repo URL** — "What's the git repo URL for `{name}`?
|
|
58
57
|
_(Skip with 'none' if not set up yet)_"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
5. **Submodules** — scan the user's answers so far for signals: words like "monorepo", "multi-module",
|
|
59
|
+
"Gradle modules", a comma-separated list of app names, etc.
|
|
60
|
+
**If signals present**, ask:
|
|
61
|
+
> "It sounds like `{name}` contains multiple submodules ({detected names if any}).
|
|
62
|
+
> Should I configure them separately? (yes / no)"
|
|
63
|
+
**If yes** → collect submodules one at a time (see below). Skip step 6 — port belongs to each submodule, not the parent.
|
|
64
|
+
**If no or no signals** → continue to step 6.
|
|
65
|
+
6. **Port** _(skip when module has submodules)_ — "What port does `{name}` run on locally?"
|
|
66
|
+
7. **Description** — "One sentence: what does `{name}` do? _(Skip with 'none')_"
|
|
67
|
+
|
|
68
|
+
**Submodule collection** (repeat for each):
|
|
69
|
+
- "Submodule name? (kebab-case)"
|
|
70
|
+
- "Type? (backend / frontend / worker)"
|
|
71
|
+
- "Stack?"
|
|
72
|
+
- "Port?"
|
|
73
|
+
- "Path within the `{name}` repo? (e.g. `apps/admin` or `auth-ui`)"
|
|
74
|
+
- "One sentence: what does it do? _(Skip with 'none')_"
|
|
75
|
+
|
|
76
|
+
Confirm each: "`{sub}` — {type} — {stack} — :{port} — path: {path}. Another submodule? (yes / no)"
|
|
77
|
+
|
|
78
|
+
> **Rules for submodules:**
|
|
79
|
+
> - No `repo` field — submodules share the parent module's repo
|
|
80
|
+
> - No `port` on the parent module — port belongs to each submodule
|
|
81
|
+
> - `type` and `stack` are per-submodule (may differ from the parent)
|
|
82
|
+
|
|
83
|
+
After collecting all submodules (or just module fields), confirm:
|
|
63
84
|
|
|
64
85
|
> "Got it:
|
|
65
|
-
> `{name}` — {type} — {
|
|
86
|
+
> `{name}` — {type} — {repo or 'no repo yet'}
|
|
87
|
+
> {if no submodules: stack + port}
|
|
88
|
+
> {if submodules: list each as ` ↳ {sub} — {type} — {stack} — :{port} — {path}`}
|
|
66
89
|
> {description}
|
|
67
90
|
> Is that right?"
|
|
68
91
|
|
|
@@ -112,7 +135,7 @@ CLAUDE.md
|
|
|
112
135
|
Conventions: {list or "none yet"}
|
|
113
136
|
Out of scope: {list or "none yet"}
|
|
114
137
|
|
|
115
|
-
features
|
|
138
|
+
features/CHANGELOG.md
|
|
116
139
|
contracts/.gitkeep
|
|
117
140
|
.gitignore ← append Forge entries
|
|
118
141
|
```
|
|
@@ -126,6 +149,8 @@ Wait for confirmation. Do not write anything before the user says yes.
|
|
|
126
149
|
## Phase 5 — Write files
|
|
127
150
|
|
|
128
151
|
Write `.forge/project.json`:
|
|
152
|
+
|
|
153
|
+
Module **without** submodules — `port` and `stack` on the module itself:
|
|
129
154
|
```json
|
|
130
155
|
{
|
|
131
156
|
"project": "{project-name}",
|
|
@@ -146,6 +171,35 @@ Write `.forge/project.json`:
|
|
|
146
171
|
}
|
|
147
172
|
```
|
|
148
173
|
|
|
174
|
+
Module **with** submodules — no `port` on the module; each submodule owns its `port`, `stack`,
|
|
175
|
+
`type`, and `path`; no `repo` on submodules (they share the parent's repo):
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"project": "{project-name}",
|
|
179
|
+
"version": "1.0",
|
|
180
|
+
"modules": [
|
|
181
|
+
{
|
|
182
|
+
"name": "{module-name}",
|
|
183
|
+
"repo": "{repo-url}",
|
|
184
|
+
"description": "{description}",
|
|
185
|
+
"submodules": [
|
|
186
|
+
{
|
|
187
|
+
"name": "{sub-name}",
|
|
188
|
+
"type": "backend|frontend|worker",
|
|
189
|
+
"stack": ["{stack}"],
|
|
190
|
+
"port": {port},
|
|
191
|
+
"path": "{relative-path-in-repo}",
|
|
192
|
+
"description": "{description}"
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"spec_repo": "{spec-repo-url}",
|
|
198
|
+
"contract_format": "openapi3",
|
|
199
|
+
"contract_tool": "specmatic"
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
149
203
|
Write `CLAUDE.md`:
|
|
150
204
|
```markdown
|
|
151
205
|
# {project-name}
|
|
@@ -157,6 +211,14 @@ Write `CLAUDE.md`:
|
|
|
157
211
|
|------|------|-------|------|
|
|
158
212
|
| {name} | {type} | {stack} | {port} |
|
|
159
213
|
|
|
214
|
+
_(For modules with submodules, expand the table with one row per submodule.
|
|
215
|
+
Indent the submodule name with `↳` and omit port/stack from the parent row.)_
|
|
216
|
+
|
|
217
|
+
| Name | Type | Stack | Port | Path |
|
|
218
|
+
|------|------|-------|------|------|
|
|
219
|
+
| {module} | — | — | — | — |
|
|
220
|
+
| ↳ {sub} | {type} | {stack} | {port} | {path} |
|
|
221
|
+
|
|
160
222
|
## Forge Workflow
|
|
161
223
|
1. `/forge-brainstorm` — explore and define a feature
|
|
162
224
|
2. `/forge-spec` — write the spec
|
|
@@ -182,8 +244,18 @@ Utilities: `/forge-status` (feature dashboard) · `/forge-config` (edit modules/
|
|
|
182
244
|
- `contracts/{module}/{slug}.yaml` + `schemas/` + `shared/` — Specmatic OpenAPI 3.0 contracts
|
|
183
245
|
```
|
|
184
246
|
|
|
247
|
+
Create `features/CHANGELOG.md`:
|
|
248
|
+
```markdown
|
|
249
|
+
# Feature Changelog
|
|
250
|
+
|
|
251
|
+
Ordered list of all features. Add entries via `/forge-brainstorm`; update via `/forge-spec`,
|
|
252
|
+
`/forge-contract`, and `/forge-close`. Use `Depends on` to declare what must ship first.
|
|
253
|
+
|
|
254
|
+
| # | Slug | Description | Status | Modules | Depends on |
|
|
255
|
+
|---|------|-------------|--------|---------|------------|
|
|
256
|
+
```
|
|
257
|
+
|
|
185
258
|
Create:
|
|
186
|
-
- `features/.gitkeep`
|
|
187
259
|
- `contracts/.gitkeep`
|
|
188
260
|
|
|
189
261
|
Append to `.gitignore` if not present:
|
|
@@ -202,4 +274,8 @@ Run `git status` and confirm:
|
|
|
202
274
|
- Never write files before the user says yes in Phase 4
|
|
203
275
|
- Never overwrite existing files
|
|
204
276
|
- All written files must be complete — no unfilled placeholders
|
|
277
|
+
- **Extract, don't re-ask**: if the user's answer contains information for upcoming fields
|
|
278
|
+
(e.g. "user-service, Spring Boot 3, port 8080, backend"), extract and fill those fields
|
|
279
|
+
silently — only ask about what is genuinely missing. Never ask a question the user has
|
|
280
|
+
already answered, even indirectly.
|
|
205
281
|
- If the user provides multiple answers in one message, accept them gracefully and move forward
|
|
@@ -270,9 +270,16 @@ Cross-module data: {what is shared with or derived from other modules — or "No
|
|
|
270
270
|
|
|
271
271
|
---
|
|
272
272
|
|
|
273
|
-
## Step 7 —
|
|
273
|
+
## Step 7 — Update changelog & gate
|
|
274
274
|
|
|
275
|
-
After writing
|
|
275
|
+
After writing `spec.md`, update `features/CHANGELOG.md`:
|
|
276
|
+
- Find the row where `Slug` = `{slug}`
|
|
277
|
+
- Update `Status` → `Draft`
|
|
278
|
+
- Update `Modules` → comma-separated list of modules from the spec's **Modules** header
|
|
279
|
+
- If the row doesn't exist (spec written without going through forge-brainstorm), append it:
|
|
280
|
+
`| — | {slug} | {overview first sentence} | Draft | {modules} | — |`
|
|
281
|
+
|
|
282
|
+
Then say:
|
|
276
283
|
> "Spec written to `features/{slug}/spec.md`. Review it and say **yes** to generate the task breakdown."
|
|
277
284
|
|
|
278
285
|
Do NOT add tasks to spec.md — tasks go in `features/{slug}/tasks.md` via `/forge-tasks`.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "forge-status"
|
|
3
|
+
description: "Scans features/ and shows phase status for every feature: 🔵 brainstorming, 🟡 spec written, 🟠 tasks ready, ✅ contract complete. Suggests the next forge command for each in-progress feature."
|
|
4
|
+
argument-hint: ""
|
|
5
|
+
compatibility: "Requires spec repo with .forge/project.json"
|
|
6
|
+
metadata:
|
|
7
|
+
author: "forge-workflow"
|
|
8
|
+
source: "spec-skills/forge-status/SKILL.md"
|
|
9
|
+
user-invocable: true
|
|
10
|
+
disable-model-invocation: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Forge Status
|
|
14
|
+
|
|
15
|
+
Show the current status of all features in this spec repo, in changelog order.
|
|
16
|
+
|
|
17
|
+
## Steps
|
|
18
|
+
|
|
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`.
|
|
22
|
+
|
|
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):
|
|
25
|
+
|
|
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 |
|
|
34
|
+
|
|
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 ⚠️.
|
|
39
|
+
|
|
40
|
+
## Output Format
|
|
41
|
+
|
|
42
|
+
```
|
|
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
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The ⚠️ flag means "this feature's dependency is not yet Done — reconsider starting it."
|
|
57
|
+
|
|
58
|
+
## What to Show Next
|
|
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
|
-
|
|
26
|
-
|
|
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
|
|
30
|
-
- For frontend/consumer
|
|
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
|
-
### {
|
|
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
|
-
### {
|
|
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
|
-
###
|
|
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
|
|
81
|
+
3 tasks across 3 targets
|
|
74
82
|
```
|
|
75
83
|
|
|
76
84
|
## Gate
|
package/forge-status/SKILL.md
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "forge-status"
|
|
3
|
-
description: "Scans features/ and shows phase status for every feature: 🔵 brainstorming, 🟡 spec written, 🟠 tasks ready, ✅ contract complete. Suggests the next forge command for each in-progress feature."
|
|
4
|
-
argument-hint: ""
|
|
5
|
-
compatibility: "Requires spec repo with .forge/project.json"
|
|
6
|
-
metadata:
|
|
7
|
-
author: "forge-workflow"
|
|
8
|
-
source: "spec-skills/forge-status/SKILL.md"
|
|
9
|
-
user-invocable: true
|
|
10
|
-
disable-model-invocation: true
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
# Forge Status
|
|
14
|
-
|
|
15
|
-
Show the current status of all features in this spec repo.
|
|
16
|
-
|
|
17
|
-
## Steps
|
|
18
|
-
|
|
19
|
-
1. Scan the `features/` directory. If empty or missing, say "No features yet. Run `/forge-brainstorm` to plan your first feature."
|
|
20
|
-
|
|
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
|
|
28
|
-
|
|
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.
|
|
31
|
-
|
|
32
|
-
4. Also check `contracts/` for orphaned contracts (contract file exists but no matching feature folder) and flag them.
|
|
33
|
-
|
|
34
|
-
## Output Format
|
|
35
|
-
|
|
36
|
-
```
|
|
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
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## 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}`"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|