@garygentry/feature-forge 0.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/LICENSE +21 -0
- package/adapters/GENERATION-REPORT.md +128 -0
- package/adapters/claude/agents/forge-researcher.md +137 -0
- package/adapters/claude/agents/forge-spec-writer.md +115 -0
- package/adapters/claude/agents/forge-verifier.md +121 -0
- package/adapters/claude/references/epic-manifest-schema.json +120 -0
- package/adapters/claude/references/forge-config-schema.json +166 -0
- package/adapters/claude/references/pipeline-state-schema.json +110 -0
- package/adapters/claude/references/portable-root.md +56 -0
- package/adapters/claude/references/process-overview.md +123 -0
- package/adapters/claude/references/ralph-loop-contract.md +221 -0
- package/adapters/claude/references/shared-conventions.md +144 -0
- package/adapters/claude/references/skill-frontmatter.schema.json +17 -0
- package/adapters/claude/references/stack-resolution.md +51 -0
- package/adapters/claude/references/stacks/_generic.md +90 -0
- package/adapters/claude/references/stacks/go.md +138 -0
- package/adapters/claude/references/stacks/python.md +163 -0
- package/adapters/claude/references/stacks/rust.md +151 -0
- package/adapters/claude/references/stacks/typescript.md +111 -0
- package/adapters/claude/references/vendor-construct-inventory.md +49 -0
- package/adapters/claude/scripts/forge-root.sh +50 -0
- package/adapters/claude/skills/forge/SKILL.md +165 -0
- package/adapters/claude/skills/forge-0-epic/SKILL.md +303 -0
- package/adapters/claude/skills/forge-0-epic/references/edit-mode.md +222 -0
- package/adapters/claude/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
- package/adapters/claude/skills/forge-1-prd/SKILL.md +121 -0
- package/adapters/claude/skills/forge-1-prd/references/prd-template.md +106 -0
- package/adapters/claude/skills/forge-2-tech/SKILL.md +198 -0
- package/adapters/claude/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
- package/adapters/claude/skills/forge-3-specs/SKILL.md +154 -0
- package/adapters/claude/skills/forge-3-specs/references/spec-archetypes.md +106 -0
- package/adapters/claude/skills/forge-3-specs/references/spec-examples.md +71 -0
- package/adapters/claude/skills/forge-4-backlog/SKILL.md +146 -0
- package/adapters/claude/skills/forge-5-loop/SKILL.md +303 -0
- package/adapters/claude/skills/forge-5-loop/references/result-reporting.md +63 -0
- package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +214 -0
- package/adapters/claude/skills/forge-6-docs/SKILL.md +179 -0
- package/adapters/claude/skills/forge-6-docs/references/doc-conventions.md +126 -0
- package/adapters/claude/skills/forge-fix/SKILL.md +65 -0
- package/adapters/claude/skills/forge-init/SKILL.md +29 -0
- package/adapters/claude/skills/forge-verify/SKILL.md +219 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists.md +379 -0
- package/adapters/codex/agents/forge-researcher.md +133 -0
- package/adapters/codex/agents/forge-spec-writer.md +112 -0
- package/adapters/codex/agents/forge-verifier.md +115 -0
- package/adapters/codex/agents/openai.yaml +10 -0
- package/adapters/codex/references/epic-manifest-schema.json +120 -0
- package/adapters/codex/references/forge-config-schema.json +166 -0
- package/adapters/codex/references/pipeline-state-schema.json +110 -0
- package/adapters/codex/references/portable-root.md +56 -0
- package/adapters/codex/references/process-overview.md +123 -0
- package/adapters/codex/references/ralph-loop-contract.md +221 -0
- package/adapters/codex/references/shared-conventions.md +144 -0
- package/adapters/codex/references/skill-frontmatter.schema.json +17 -0
- package/adapters/codex/references/stack-resolution.md +51 -0
- package/adapters/codex/references/stacks/_generic.md +90 -0
- package/adapters/codex/references/stacks/go.md +138 -0
- package/adapters/codex/references/stacks/python.md +163 -0
- package/adapters/codex/references/stacks/rust.md +151 -0
- package/adapters/codex/references/stacks/typescript.md +111 -0
- package/adapters/codex/references/vendor-construct-inventory.md +49 -0
- package/adapters/codex/scripts/forge-root.sh +50 -0
- package/adapters/codex/skills/forge/forge.md +164 -0
- package/adapters/codex/skills/forge-0-epic/forge-0-epic.md +302 -0
- package/adapters/codex/skills/forge-0-epic/references/edit-mode.md +222 -0
- package/adapters/codex/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
- package/adapters/codex/skills/forge-1-prd/forge-1-prd.md +120 -0
- package/adapters/codex/skills/forge-1-prd/references/prd-template.md +106 -0
- package/adapters/codex/skills/forge-2-tech/forge-2-tech.md +197 -0
- package/adapters/codex/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
- package/adapters/codex/skills/forge-3-specs/forge-3-specs.md +153 -0
- package/adapters/codex/skills/forge-3-specs/references/spec-archetypes.md +106 -0
- package/adapters/codex/skills/forge-3-specs/references/spec-examples.md +71 -0
- package/adapters/codex/skills/forge-4-backlog/forge-4-backlog.md +145 -0
- package/adapters/codex/skills/forge-5-loop/forge-5-loop.md +302 -0
- package/adapters/codex/skills/forge-5-loop/references/result-reporting.md +63 -0
- package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +214 -0
- package/adapters/codex/skills/forge-6-docs/forge-6-docs.md +178 -0
- package/adapters/codex/skills/forge-6-docs/references/doc-conventions.md +126 -0
- package/adapters/codex/skills/forge-fix/forge-fix.md +64 -0
- package/adapters/codex/skills/forge-init/forge-init.md +29 -0
- package/adapters/codex/skills/forge-verify/forge-verify.md +218 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists.md +379 -0
- package/adapters/copilot/agents/forge-researcher.md +133 -0
- package/adapters/copilot/agents/forge-spec-writer.md +112 -0
- package/adapters/copilot/agents/forge-verifier.md +115 -0
- package/adapters/copilot/references/epic-manifest-schema.json +120 -0
- package/adapters/copilot/references/forge-config-schema.json +166 -0
- package/adapters/copilot/references/pipeline-state-schema.json +110 -0
- package/adapters/copilot/references/portable-root.md +56 -0
- package/adapters/copilot/references/process-overview.md +123 -0
- package/adapters/copilot/references/ralph-loop-contract.md +221 -0
- package/adapters/copilot/references/shared-conventions.md +144 -0
- package/adapters/copilot/references/skill-frontmatter.schema.json +17 -0
- package/adapters/copilot/references/stack-resolution.md +51 -0
- package/adapters/copilot/references/stacks/_generic.md +90 -0
- package/adapters/copilot/references/stacks/go.md +138 -0
- package/adapters/copilot/references/stacks/python.md +163 -0
- package/adapters/copilot/references/stacks/rust.md +151 -0
- package/adapters/copilot/references/stacks/typescript.md +111 -0
- package/adapters/copilot/references/vendor-construct-inventory.md +49 -0
- package/adapters/copilot/scripts/forge-root.sh +50 -0
- package/adapters/copilot/skills/forge/forge.md +164 -0
- package/adapters/copilot/skills/forge-0-epic/forge-0-epic.md +302 -0
- package/adapters/copilot/skills/forge-0-epic/references/edit-mode.md +222 -0
- package/adapters/copilot/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
- package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +120 -0
- package/adapters/copilot/skills/forge-1-prd/references/prd-template.md +106 -0
- package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +197 -0
- package/adapters/copilot/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
- package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +153 -0
- package/adapters/copilot/skills/forge-3-specs/references/spec-archetypes.md +106 -0
- package/adapters/copilot/skills/forge-3-specs/references/spec-examples.md +71 -0
- package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +145 -0
- package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +302 -0
- package/adapters/copilot/skills/forge-5-loop/references/result-reporting.md +63 -0
- package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +214 -0
- package/adapters/copilot/skills/forge-6-docs/forge-6-docs.md +178 -0
- package/adapters/copilot/skills/forge-6-docs/references/doc-conventions.md +126 -0
- package/adapters/copilot/skills/forge-fix/forge-fix.md +64 -0
- package/adapters/copilot/skills/forge-init/forge-init.md +29 -0
- package/adapters/copilot/skills/forge-verify/forge-verify.md +218 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists.md +379 -0
- package/adapters/cursor/agents/forge-researcher.mdc +134 -0
- package/adapters/cursor/agents/forge-spec-writer.mdc +113 -0
- package/adapters/cursor/agents/forge-verifier.mdc +116 -0
- package/adapters/cursor/references/epic-manifest-schema.json +120 -0
- package/adapters/cursor/references/forge-config-schema.json +166 -0
- package/adapters/cursor/references/pipeline-state-schema.json +110 -0
- package/adapters/cursor/references/portable-root.md +56 -0
- package/adapters/cursor/references/process-overview.md +123 -0
- package/adapters/cursor/references/ralph-loop-contract.md +221 -0
- package/adapters/cursor/references/shared-conventions.md +144 -0
- package/adapters/cursor/references/skill-frontmatter.schema.json +17 -0
- package/adapters/cursor/references/stack-resolution.md +51 -0
- package/adapters/cursor/references/stacks/_generic.md +90 -0
- package/adapters/cursor/references/stacks/go.md +138 -0
- package/adapters/cursor/references/stacks/python.md +163 -0
- package/adapters/cursor/references/stacks/rust.md +151 -0
- package/adapters/cursor/references/stacks/typescript.md +111 -0
- package/adapters/cursor/references/vendor-construct-inventory.md +49 -0
- package/adapters/cursor/scripts/forge-root.sh +50 -0
- package/adapters/cursor/skills/forge/forge.mdc +165 -0
- package/adapters/cursor/skills/forge-0-epic/forge-0-epic.mdc +303 -0
- package/adapters/cursor/skills/forge-0-epic/references/edit-mode.md +222 -0
- package/adapters/cursor/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
- package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +121 -0
- package/adapters/cursor/skills/forge-1-prd/references/prd-template.md +106 -0
- package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +198 -0
- package/adapters/cursor/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
- package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +154 -0
- package/adapters/cursor/skills/forge-3-specs/references/spec-archetypes.md +106 -0
- package/adapters/cursor/skills/forge-3-specs/references/spec-examples.md +71 -0
- package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +146 -0
- package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +303 -0
- package/adapters/cursor/skills/forge-5-loop/references/result-reporting.md +63 -0
- package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +214 -0
- package/adapters/cursor/skills/forge-6-docs/forge-6-docs.mdc +179 -0
- package/adapters/cursor/skills/forge-6-docs/references/doc-conventions.md +126 -0
- package/adapters/cursor/skills/forge-fix/forge-fix.mdc +65 -0
- package/adapters/cursor/skills/forge-init/forge-init.mdc +30 -0
- package/adapters/cursor/skills/forge-verify/forge-verify.mdc +219 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists.md +379 -0
- package/adapters/gemini/agents/forge-researcher.md +133 -0
- package/adapters/gemini/agents/forge-spec-writer.md +112 -0
- package/adapters/gemini/agents/forge-verifier.md +115 -0
- package/adapters/gemini/gemini-extension.json +54 -0
- package/adapters/gemini/references/epic-manifest-schema.json +120 -0
- package/adapters/gemini/references/forge-config-schema.json +166 -0
- package/adapters/gemini/references/pipeline-state-schema.json +110 -0
- package/adapters/gemini/references/portable-root.md +56 -0
- package/adapters/gemini/references/process-overview.md +123 -0
- package/adapters/gemini/references/ralph-loop-contract.md +221 -0
- package/adapters/gemini/references/shared-conventions.md +144 -0
- package/adapters/gemini/references/skill-frontmatter.schema.json +17 -0
- package/adapters/gemini/references/stack-resolution.md +51 -0
- package/adapters/gemini/references/stacks/_generic.md +90 -0
- package/adapters/gemini/references/stacks/go.md +138 -0
- package/adapters/gemini/references/stacks/python.md +163 -0
- package/adapters/gemini/references/stacks/rust.md +151 -0
- package/adapters/gemini/references/stacks/typescript.md +111 -0
- package/adapters/gemini/references/vendor-construct-inventory.md +49 -0
- package/adapters/gemini/scripts/forge-root.sh +50 -0
- package/adapters/gemini/skills/forge/forge.md +164 -0
- package/adapters/gemini/skills/forge-0-epic/forge-0-epic.md +302 -0
- package/adapters/gemini/skills/forge-0-epic/references/edit-mode.md +222 -0
- package/adapters/gemini/skills/forge-0-epic/references/epic-manifest-subcommands.md +64 -0
- package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +120 -0
- package/adapters/gemini/skills/forge-1-prd/references/prd-template.md +106 -0
- package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +197 -0
- package/adapters/gemini/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
- package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +153 -0
- package/adapters/gemini/skills/forge-3-specs/references/spec-archetypes.md +106 -0
- package/adapters/gemini/skills/forge-3-specs/references/spec-examples.md +71 -0
- package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +145 -0
- package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +302 -0
- package/adapters/gemini/skills/forge-5-loop/references/result-reporting.md +63 -0
- package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +214 -0
- package/adapters/gemini/skills/forge-6-docs/forge-6-docs.md +178 -0
- package/adapters/gemini/skills/forge-6-docs/references/doc-conventions.md +126 -0
- package/adapters/gemini/skills/forge-fix/forge-fix.md +64 -0
- package/adapters/gemini/skills/forge-init/forge-init.md +29 -0
- package/adapters/gemini/skills/forge-verify/forge-verify.md +218 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists.md +379 -0
- package/dist/agent-targets.d.ts +70 -0
- package/dist/agent-targets.js +111 -0
- package/dist/apply.d.ts +49 -0
- package/dist/apply.js +246 -0
- package/dist/cli.d.ts +94 -0
- package/dist/cli.js +508 -0
- package/dist/detect.d.ts +45 -0
- package/dist/detect.js +72 -0
- package/dist/fsutil.d.ts +56 -0
- package/dist/fsutil.js +175 -0
- package/dist/hash.d.ts +50 -0
- package/dist/hash.js +107 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/manifest.d.ts +72 -0
- package/dist/manifest.js +222 -0
- package/dist/plan.d.ts +66 -0
- package/dist/plan.js +166 -0
- package/dist/rauf.d.ts +83 -0
- package/dist/rauf.js +118 -0
- package/dist/report.d.ts +35 -0
- package/dist/report.js +110 -0
- package/dist/source.d.ts +69 -0
- package/dist/source.js +164 -0
- package/dist/types.d.ts +264 -0
- package/dist/types.js +57 -0
- package/package.json +42 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
---
|
|
2
|
+
# GENERATED — DO NOT EDIT. Source: skills/forge-0-epic/SKILL.md. Regenerate: python3 scripts/build-adapters.py
|
|
3
|
+
description: 'Create or edit a forge epic: decompose a large change into discrete member features with dependencies, charters, and structured contracts, producing epic-manifest.json + EPIC.md. Re-run on an existing epic to enter edit mode (add/remove/reorder features, change dependencies). Use when the user runs /feature-forge:forge-0-epic or explicitly asks to start/modify an epic. Do NOT trigger for single-feature PRD work (that is forge-1-prd) or for general project planning outside forge.'
|
|
4
|
+
globs: []
|
|
5
|
+
alwaysApply: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# forge-0-epic — Epic Decomposition & Orchestration
|
|
9
|
+
|
|
10
|
+
Create an epic — a named grouping of related forge features with declared dependencies
|
|
11
|
+
and shared contracts — through a structured decomposition interview, OR edit an existing
|
|
12
|
+
epic. The manifest is the source of truth; EPIC.md mirrors it. All graph/validation work
|
|
13
|
+
is delegated to `scripts/epic-manifest.py`.
|
|
14
|
+
|
|
15
|
+
This skill **composes** JSON and **issues** helper commands. It NEVER eyeballs a dependency
|
|
16
|
+
graph for cycles, NEVER hand-rolls a manifest write where a mutator exists, and NEVER asks a
|
|
17
|
+
question in inline prose — every question goes through `AskUserQuestion`.
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
Read and follow `references/shared-conventions.md` for:
|
|
22
|
+
- the **Feature Name Requirement** (applied here to the *epic* name — see below),
|
|
23
|
+
- the **User Input Protocol** (the AskUserQuestion guardrail — all questions go through the tool),
|
|
24
|
+
- **Configuration Reading**, and
|
|
25
|
+
- the **Git Commit Protocol**.
|
|
26
|
+
|
|
27
|
+
**Epic name handling.** The single positional argument is the **epic** name (not a feature).
|
|
28
|
+
If no name is given, STOP and ask for one — do not guess. Convert multi-word input to a single
|
|
29
|
+
kebab-case token. The name must satisfy `SAFE_NAME_RE` (`^[a-z0-9]+(?:-[a-z0-9]+)*$`); the
|
|
30
|
+
helper rejects unsafe names. Member feature names are elicited later, in the interview.
|
|
31
|
+
|
|
32
|
+
**Force mode.** `--force` is honored as in shared-conventions: skip pipeline-state prerequisite
|
|
33
|
+
checks but still load any on-disk artifacts.
|
|
34
|
+
|
|
35
|
+
**Config values read** (defaults from shared-conventions): `specsDir` (default `./specs`),
|
|
36
|
+
`gitCommitAfterStage` (default true), `commitPrefix` (default `forge`).
|
|
37
|
+
|
|
38
|
+
**Helper invocation.** Every helper call uses the convention from 01 §2.2 — the absolute
|
|
39
|
+
plugin path and the configured specs dir:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
43
|
+
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
44
|
+
python3 "$R/scripts/epic-manifest.py" <subcommand> ... --specs-dir "{specsDir}"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`$R` resolves to the installed plugin root via the portable resolver (`scripts/forge-root.sh`,
|
|
48
|
+
bootstrapped by the prelude above; see `references/portable-root.md`). Pass `--specs-dir "{specsDir}"`
|
|
49
|
+
on every invocation.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Step 0 — Dispatch Detection
|
|
54
|
+
|
|
55
|
+
Resolve the epic subtree path `{specsDir}/{epic}/` and decide which branch to run.
|
|
56
|
+
|
|
57
|
+
1. **Collision check — is this name already a standalone feature?** If `{specsDir}/{epic}/`
|
|
58
|
+
exists and directly contains a `.pipeline-state.json` of its own (i.e. it is itself a
|
|
59
|
+
*feature* directory, not an epic root), STOP. Surface verbatim:
|
|
60
|
+
> `{epic}` is already a standalone feature, not an epic. Choose a different epic name or
|
|
61
|
+
> relocate the feature.
|
|
62
|
+
|
|
63
|
+
2. **Manifest existence probe** — does this epic already have a manifest?
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
test -f "{specsDir}/{epic}/epic-manifest.json" && echo EXISTS || echo NEW
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- **NEW** (no `epic-manifest.json`) → **Creation branch** (Step C1 onward).
|
|
70
|
+
- **EXISTS** → **Edit branch** (§ Edit Mode below).
|
|
71
|
+
|
|
72
|
+
3. **Pre-flight epic-name uniqueness (creation only).** Before composing anything for a NEW
|
|
73
|
+
epic, confirm the epic name itself does not collide with any existing feature or epic:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
77
|
+
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
78
|
+
python3 "$R/scripts/epic-manifest.py" check-name "{epic}" --specs-dir "{specsDir}"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- Exit `0` → the name is free; proceed to C1.
|
|
82
|
+
- Exit `1` (`duplicate-name`) → STOP and surface the helper's finding **verbatim**; ask
|
|
83
|
+
(via `AskUserQuestion`) for a different epic name, then re-run check-name.
|
|
84
|
+
- Exit `2` (unsafe name) → STOP and surface the finding; ask for a corrected name.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Creation Branch
|
|
89
|
+
|
|
90
|
+
### Step 1 — Branch Setup (optional)
|
|
91
|
+
|
|
92
|
+
If `gitCommitAfterStage` is true and the project uses git, use `AskUserQuestion`:
|
|
93
|
+
"Create a `forge/{epic}` branch for this epic? (Recommended — keeps epic work isolated.)"
|
|
94
|
+
If yes, create and checkout the branch before proceeding.
|
|
95
|
+
|
|
96
|
+
### Step C1 — Epic Framing Interview
|
|
97
|
+
|
|
98
|
+
Output context as text (what an epic is, that a decomposition interview will follow). Then
|
|
99
|
+
call `AskUserQuestion` to elicit:
|
|
100
|
+
|
|
101
|
+
1. **Epic goal / problem** — the overarching change being decomposed. Becomes the EPIC.md
|
|
102
|
+
"Overall Goal" narrative and seeds the manifest `description`.
|
|
103
|
+
2. **One-paragraph description** — a confirmed/edited summary. Becomes the manifest `description`.
|
|
104
|
+
|
|
105
|
+
The epic `name` is the validated CLI argument from Step 0 — do NOT prompt for it again.
|
|
106
|
+
|
|
107
|
+
### Step C2 — Feature-List Interview
|
|
108
|
+
|
|
109
|
+
Drive a decomposition dialogue. Output your analysis as text first (how the goal might split,
|
|
110
|
+
right-sizing guidance: each feature should be a single pipeline-sized unit — a unit forge-1-prd
|
|
111
|
+
through forge-5-loop would carry end-to-end — not item-level interleaving). Then use
|
|
112
|
+
`AskUserQuestion` to elicit the candidate feature list. Probe with questions like "Is any of
|
|
113
|
+
these two features really one?" and "Is any one of these really two?" Iterate until the user
|
|
114
|
+
confirms the set.
|
|
115
|
+
|
|
116
|
+
For **each** proposed feature name, before accepting it into the set, enforce global uniqueness
|
|
117
|
+
and name safety via the helper:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
121
|
+
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
122
|
+
python3 "$R/scripts/epic-manifest.py" check-name "{feature}" --specs-dir "{specsDir}"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- Exit `0` → accept the name.
|
|
126
|
+
- Exit `1` (`duplicate-name`) → reject that name; surface the finding verbatim and re-prompt
|
|
127
|
+
(via `AskUserQuestion`) for a different name.
|
|
128
|
+
- Exit `2` (`unsafe-name`) → reject; surface the finding and re-prompt.
|
|
129
|
+
|
|
130
|
+
Never accept a feature name that has not passed `check-name` exit 0.
|
|
131
|
+
|
|
132
|
+
### Step C3 — Per-Feature Charter + Structured Contracts
|
|
133
|
+
|
|
134
|
+
For each confirmed feature, run a focused `AskUserQuestion` batch (one feature at a time,
|
|
135
|
+
2–3 questions per call) eliciting:
|
|
136
|
+
|
|
137
|
+
- **Charter** — a single paragraph: scope statement + contract obligations. This is a
|
|
138
|
+
**charter only, NOT a PRD**. Do NOT conduct a full requirements interview here. If the user
|
|
139
|
+
starts dictating detailed requirements, redirect (as context text, then continue the batch):
|
|
140
|
+
> "That's PRD-level detail — `forge-1-prd` will capture it when this feature is ready. For
|
|
141
|
+
> the charter I just need the one-paragraph scope and what it must expose/consume."
|
|
142
|
+
- **`exposes`** — zero or more structured `Contract` objects this feature provides to
|
|
143
|
+
dependents. Each is `{ "name", "kind", "summary" }` where `kind` ∈
|
|
144
|
+
`function | type | endpoint | module | event`.
|
|
145
|
+
- **`consumes`** — zero or more structured `ConsumedContract` objects this feature relies on.
|
|
146
|
+
Each is `{ "from", "name", "summary" }`, where `from` is a sibling feature name in this epic.
|
|
147
|
+
|
|
148
|
+
Collect these into plain JSON objects per feature. Do NOT free-form the contracts in prose —
|
|
149
|
+
the structured arrays are the source of truth; EPIC.md renders them as prose later (Step C6).
|
|
150
|
+
|
|
151
|
+
### Step C4 — Dependency-Edge Interview
|
|
152
|
+
|
|
153
|
+
For each feature, use `AskUserQuestion`: "Which sibling features must be complete before this
|
|
154
|
+
one can build?" → populates `dependsOn: [names]`.
|
|
155
|
+
|
|
156
|
+
**Seed the suggestion from `consumes`:** a `consumes.from` X strongly implies `dependsOn` X.
|
|
157
|
+
Offer the union of each feature's `consumes.from` set as the default, but let the user confirm —
|
|
158
|
+
`dependsOn` is the authoritative edge set.
|
|
159
|
+
|
|
160
|
+
The `features[]` array order is the user-declared sequence from C2 (order is a presentation
|
|
161
|
+
sequence, **not** a dependency ordering). Preserve the C2 order unless the user asks to reorder.
|
|
162
|
+
|
|
163
|
+
### Step C5 — Compose & Validate the Manifest
|
|
164
|
+
|
|
165
|
+
Compose the full `epic-manifest.json` per the 00 §2 schema, setting:
|
|
166
|
+
|
|
167
|
+
- `schemaVersion`: `1`
|
|
168
|
+
- `epic`: `"{epic}"`
|
|
169
|
+
- `description`: from C1
|
|
170
|
+
- `status`: `"active"`
|
|
171
|
+
- `narrativeDoc`: `"EPIC.md"`
|
|
172
|
+
- `createdAt` and `updatedAt`: the **same** current ISO-8601 UTC timestamp (`createdAt == updatedAt`)
|
|
173
|
+
- `features[]`: in declared order, each with `name`, `charter`, `dependsOn`, `exposes`,
|
|
174
|
+
`consumes`. **No per-feature `status` field** — including one makes the manifest fail
|
|
175
|
+
validation (the `cached-status` finding).
|
|
176
|
+
|
|
177
|
+
Write the composed JSON to `{specsDir}/{epic}/epic-manifest.json` (creating the epic dir first).
|
|
178
|
+
For the *initial* creation write the skill writes the file directly — atomic guarantees are only
|
|
179
|
+
required for in-place mutation, which is the helper mutators' job. Then validate:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
183
|
+
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
184
|
+
python3 "$R/scripts/epic-manifest.py" validate "{epic}" --specs-dir "{specsDir}" --json
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
- Exit `0` → proceed to C6.
|
|
188
|
+
- Exit `1` → the manifest is malformed. Surface **every** `findings[]` entry **verbatim**, do
|
|
189
|
+
NOT proceed, and loop back into the relevant interview step to correct, then re-compose and
|
|
190
|
+
re-validate:
|
|
191
|
+
- `cycle` → re-open the dependency interview (C4).
|
|
192
|
+
- `dangling-ref` → re-open C4 (bad `dependsOn`) or C3 (bad `consumes.from`).
|
|
193
|
+
- `duplicate-name` / `unsafe-name` → re-open the feature-list interview (C2).
|
|
194
|
+
- `cached-status` / schema violation → fix the composed JSON and re-validate.
|
|
195
|
+
- Exit `2` → IO/usage error (missing manifest or unreadable). Surface and STOP.
|
|
196
|
+
|
|
197
|
+
Acyclicity, uniqueness, and dangling-ref checks are thus ALWAYS performed by the helper, never
|
|
198
|
+
by the LLM eyeballing the graph.
|
|
199
|
+
|
|
200
|
+
> **Contracts have no mutator.** There is intentionally no `--exposes-json`/`--consumes-json`
|
|
201
|
+
> flag. At creation, the skill populates each feature's `exposes`/`consumes` directly in the
|
|
202
|
+
> composed manifest entry (above), then re-runs `validate` — exactly as described here. The
|
|
203
|
+
> same pattern applies after an edit-mode `add-feature` (see Edit Mode).
|
|
204
|
+
|
|
205
|
+
### Step C6 — Generate EPIC.md
|
|
206
|
+
|
|
207
|
+
Generate `{specsDir}/{epic}/EPIC.md` from the **validated** manifest. It is the human-readable
|
|
208
|
+
**mirror** of the manifest (the manifest is the source of truth). For the full EPIC.md structure
|
|
209
|
+
skeleton, read `references/edit-mode.md` (EPIC.md Mirror Template section) — the same template the
|
|
210
|
+
edit-mode E5 patch applies.
|
|
211
|
+
|
|
212
|
+
**The mirror rule.** Render each feature's `exposes`/`consumes` arrays as prose, one bullet per
|
|
213
|
+
contract entry, preserving `name`, `kind`/`from`, and `summary`. Do not invent a contract that
|
|
214
|
+
is not in the manifest, and do not omit one that is. The Overall Goal and Decomposition
|
|
215
|
+
Rationale are the only prose without a 1:1 manifest counterpart. The skill does NOT itself diff
|
|
216
|
+
EPIC.md against the manifest — drift detection is `forge-verify` epic mode CHECK-E06.
|
|
217
|
+
|
|
218
|
+
### Step C7 — Create Member Subdirectories + Back-Pointer States
|
|
219
|
+
|
|
220
|
+
After the manifest validates and EPIC.md is written, create one subdirectory per member feature
|
|
221
|
+
so the navigator and resolver can see them before any stage runs. For each `features[].name`:
|
|
222
|
+
|
|
223
|
+
1. Create `{specsDir}/{epic}/{feature}/`.
|
|
224
|
+
2. Write `{specsDir}/{epic}/{feature}/.pipeline-state.json` conforming to
|
|
225
|
+
`references/pipeline-state-schema.json`, carrying:
|
|
226
|
+
- `epic`: `"{epic}"` — the back-pointer.
|
|
227
|
+
- `currentStage`: `"forge-1-prd"` — the next actionable stage for the member.
|
|
228
|
+
- `stages["forge-0-epic"]`: `{ "status": "complete", "version": 1, "completedAt": "<ts>" }`
|
|
229
|
+
— recording that the epic stage seeded this member.
|
|
230
|
+
- No other stages (all other stages absent/pending), exactly as a freshly-initialized
|
|
231
|
+
standalone feature. **No per-feature `status` beyond the stage entry** — the member state
|
|
232
|
+
holds derived stage progress only.
|
|
233
|
+
|
|
234
|
+
For an example member state, read `references/edit-mode.md` (Member State Example section).
|
|
235
|
+
|
|
236
|
+
The member subtree holds the **same** artifact set a standalone feature holds; only
|
|
237
|
+
`.pipeline-state.json` exists at creation. No PRD/specs are authored here. The epic subtree is
|
|
238
|
+
now self-contained: manifest + EPIC.md + one subdirectory per member.
|
|
239
|
+
|
|
240
|
+
### Step C8 — Review, Pipeline State & Commit
|
|
241
|
+
|
|
242
|
+
1. **Review.** Present a summary (epic name, N features, dependency edges, contracts) as text,
|
|
243
|
+
then use `AskUserQuestion`: "Does this epic decomposition look right? Any feature, dependency,
|
|
244
|
+
or contract to change before I commit?" If the user wants changes, loop back to the relevant
|
|
245
|
+
creation step, re-compose, and re-validate.
|
|
246
|
+
|
|
247
|
+
2. **Commit (Git Commit Protocol).** If `gitCommitAfterStage` is true, follow the Git Commit
|
|
248
|
+
Protocol in shared-conventions:
|
|
249
|
+
- Stage the whole epic subtree only: `git add {specsDir}/{epic}/` — never `git add -A`. This
|
|
250
|
+
captures `epic-manifest.json`, `EPIC.md`, and all member `.pipeline-state.json` files
|
|
251
|
+
atomically.
|
|
252
|
+
- Commit with message `"{commitPrefix}({epic}): create epic with {N} features"`.
|
|
253
|
+
- On success, capture the commit hash. On failure (pre-commit hook, conflict), report and do
|
|
254
|
+
not mark complete; never use `--no-verify`/`--force`.
|
|
255
|
+
|
|
256
|
+
3. **Closing message.** After a successful creation, tell the user the next steps:
|
|
257
|
+
|
|
258
|
+
> Epic `{epic}` created with {N} features. Next steps:
|
|
259
|
+
> - `/feature-forge:forge {epic}` to see the epic dashboard
|
|
260
|
+
> - `/feature-forge:forge-verify {epic}` to verify the epic
|
|
261
|
+
> - `/feature-forge:forge-1-prd {first-actionable-feature}` to start the first feature
|
|
262
|
+
|
|
263
|
+
The first-actionable feature is any feature with empty `dependsOn` (or the first entry of
|
|
264
|
+
`render-status`'s `actionable` set).
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Edit Mode
|
|
269
|
+
|
|
270
|
+
Entered from Step 0 when `{specsDir}/{epic}/epic-manifest.json` already exists (the **EXISTS**
|
|
271
|
+
branch). The edit branch mutates the manifest **only** through helper mutators — atomic
|
|
272
|
+
(temp file + `os.replace`) and internally re-validated, so a refused write leaves the manifest
|
|
273
|
+
**byte-identical**; the skill never hand-rolls an in-place write. Every question goes through
|
|
274
|
+
`AskUserQuestion`, and **every mutation is committed individually** so git history is the audit trail.
|
|
275
|
+
|
|
276
|
+
For the full E1–E6 mechanics — the E1 refuse-if-invalid protocol, E2 operation→mutator table, E3
|
|
277
|
+
contracts/remove-feature caveats (incl. the verbatim WARN block), E4 impact-warning rules, E5
|
|
278
|
+
EPIC.md patch rule, and the E6 Observability / Pipeline State & Commit machinery
|
|
279
|
+
(`.epic-state.json` schema, `updatedAt` rules, Git Commit Protocol shared with C8) — read
|
|
280
|
+
`references/edit-mode.md`. For the exact `epic-manifest.py` mutator flag surface and
|
|
281
|
+
per-subcommand exit-code (`0`/`1`/`2`) handling, read `references/epic-manifest-subcommands.md`.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Error Handling
|
|
286
|
+
|
|
287
|
+
The skill **never** repairs a corrupt manifest automatically and **never** proceeds past a gating
|
|
288
|
+
helper exit `≥ 1`. All findings are surfaced **verbatim**. For the full condition → helper-signal →
|
|
289
|
+
skill-behavior disposition table, read `references/epic-manifest-subcommands.md` (Error Handling
|
|
290
|
+
section).
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Gotchas
|
|
295
|
+
|
|
296
|
+
- The argument names an **epic**, not a feature — this is the only stage where that is true.
|
|
297
|
+
Member feature names come from the C2 interview, each gated through `check-name`.
|
|
298
|
+
- Never eyeball the dependency graph for cycles. Compose the manifest, run `validate`, and
|
|
299
|
+
surface findings. The helper owns acyclicity, uniqueness, dangling-ref, and schema checks.
|
|
300
|
+
- A charter is one paragraph, not a PRD. Redirect requirement-level detail to `forge-1-prd`.
|
|
301
|
+
- Contracts have no mutator: edit `exposes`/`consumes` in the composed manifest entry, then
|
|
302
|
+
re-run `validate`.
|
|
303
|
+
- All questions go through `AskUserQuestion`. Never put a question in your text output.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# forge-0-epic — Edit Mode (E1–E6) + Observability / Pipeline State & Commit
|
|
2
|
+
|
|
3
|
+
Lookup detail relocated out of the `forge-0-epic` SKILL.md body. The skill body keeps the
|
|
4
|
+
entry condition (the **EXISTS** branch from Step 0) and the high-level "every mutation is
|
|
5
|
+
committed individually" rule, and points here for the full mechanics. The exact mutator flag
|
|
6
|
+
surface and per-subcommand exit-code handling live in `references/epic-manifest-subcommands.md`.
|
|
7
|
+
|
|
8
|
+
Entered from Step 0 when `{specsDir}/{epic}/epic-manifest.json` already exists (the **EXISTS**
|
|
9
|
+
branch). The edit branch mutates the manifest **only** through helper mutators — the skill never
|
|
10
|
+
hand-rolls an in-place write. Every mutator is atomic (temp file + `os.replace`) and re-validates
|
|
11
|
+
the edited graph internally, so a refused write leaves the manifest **byte-identical**. Every
|
|
12
|
+
question goes through `AskUserQuestion`.
|
|
13
|
+
|
|
14
|
+
## Step E1 — Load + Validate, Refuse if Invalid
|
|
15
|
+
|
|
16
|
+
Before offering any edit, validate the existing manifest:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
20
|
+
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
21
|
+
python3 "$R/scripts/epic-manifest.py" validate "{epic}" --specs-dir "{specsDir}" --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- Exit `0` → the manifest is well-formed; proceed to E2.
|
|
25
|
+
- Exit `1` or `2` → the manifest is corrupt or invalid (hand-edited, `corrupt-json`, `cycle`,
|
|
26
|
+
`dangling-ref`, `duplicate-name`, `cached-status`, `unsafe-name`, …). Surface **every**
|
|
27
|
+
`findings[]` entry **verbatim**, then **refuse ALL mutation** until the user repairs the
|
|
28
|
+
manifest by hand. **Never auto-repair**, never offer an edit operation, and never proceed past
|
|
29
|
+
this gate. Tell the user what is wrong and STOP.
|
|
30
|
+
|
|
31
|
+
## Step E2 — Choose Operation
|
|
32
|
+
|
|
33
|
+
Use `AskUserQuestion` to offer the edit operations, each mapping to one helper mutator:
|
|
34
|
+
|
|
35
|
+
| Operation | Helper subcommand |
|
|
36
|
+
|-----------|-------------------|
|
|
37
|
+
| Add a feature | `add-feature` |
|
|
38
|
+
| Remove a feature | `remove-feature` |
|
|
39
|
+
| Reorder features | `reorder` |
|
|
40
|
+
| Change a dependency edge | `set-dep` |
|
|
41
|
+
| Change epic lifecycle status | `set-status` |
|
|
42
|
+
|
|
43
|
+
For **add-feature**, first run `check-name "{feature}"` (exactly as C2) so no new duplicate is
|
|
44
|
+
introduced — surface a `duplicate-name`/`unsafe-name` finding verbatim and re-prompt — then
|
|
45
|
+
elicit the new feature's **charter** + **`exposes`/`consumes`** + **`dependsOn`** exactly as in
|
|
46
|
+
C3/C4.
|
|
47
|
+
|
|
48
|
+
## Step E3 — Apply via Helper Mutator (re-validated)
|
|
49
|
+
|
|
50
|
+
Issue the chosen mutator. Each writes atomically and re-runs full validation internally, refusing
|
|
51
|
+
the write if it would introduce a cycle, dangling ref, duplicate, or schema violation. For the
|
|
52
|
+
exact `epic-manifest.py` mutator flag surface and per-subcommand exit-code handling, read
|
|
53
|
+
`references/epic-manifest-subcommands.md`.
|
|
54
|
+
|
|
55
|
+
**Contracts have no mutator.** `add-feature` seeds empty `exposes`/`consumes`. To populate the
|
|
56
|
+
new feature's contracts, edit its `exposes`/`consumes` arrays **directly in the composed manifest
|
|
57
|
+
entry** (exactly as creation C5 does), then re-run `validate "{epic}" --json` to confirm — there
|
|
58
|
+
is intentionally no `--exposes-json`/`--consumes-json` flag.
|
|
59
|
+
|
|
60
|
+
**remove-feature leaves the member directory in place (§7.5).** The mutator drops only the
|
|
61
|
+
manifest entry. The skill does **not** delete or relocate `{specsDir}/{epic}/{feature}/`. WARN the
|
|
62
|
+
user verbatim:
|
|
63
|
+
|
|
64
|
+
> Removed `{feature}` from the manifest. Its directory `{specsDir}/{epic}/{feature}/` is left in
|
|
65
|
+
> place; move it to `{specsDir}/{feature}/` by hand if you want it as a standalone feature.
|
|
66
|
+
> Relocation is manual — there is no migration tooling.
|
|
67
|
+
|
|
68
|
+
The orphaned subdir still holds a `.pipeline-state.json` with an `epic` back-pointer the manifest
|
|
69
|
+
no longer lists; per the conflict rule the **manifest wins**, and `forge-verify` epic mode
|
|
70
|
+
CHECK-E07 reports the inconsistency non-fatally. The skill does **not** silently edit the orphaned
|
|
71
|
+
state file.
|
|
72
|
+
|
|
73
|
+
## Step E4 — Impact Warning (in-flight / completed features)
|
|
74
|
+
|
|
75
|
+
Before applying — or immediately after eliciting — a mutation that affects a feature whose derived
|
|
76
|
+
status is **not** `not-started`, warn the user. Read the **live** status (never re-derive
|
|
77
|
+
completion in prose):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
81
|
+
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
82
|
+
python3 "$R/scripts/epic-manifest.py" render-status "{epic}" --specs-dir "{specsDir}" --json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If the operation removes, reorders-around, or re-deps a feature whose derived status is
|
|
86
|
+
`in-progress` or `complete`, use `AskUserQuestion` with an explicit warning naming the affected
|
|
87
|
+
in-flight/completed feature(s) and **require confirmation** before applying. Example: "`token-service`
|
|
88
|
+
is already in-progress (forge-3-specs). Removing `config-store`, which it consumes `JWT_SECRET`
|
|
89
|
+
from, may invalidate its in-flight specs. Proceed?" If `render-status` exits `≥ 1`, surface the
|
|
90
|
+
findings and STOP (do not mutate over an invalid graph).
|
|
91
|
+
|
|
92
|
+
## Step E5 — Patch EPIC.md
|
|
93
|
+
|
|
94
|
+
Patch **only** the affected feature/Contracts section(s) — the section(s) for the added, removed,
|
|
95
|
+
or changed feature and any feature whose `dependsOn`/`consumes` changed — applying the §C6 mirror
|
|
96
|
+
rule (one bullet per `exposes`/`consumes` entry). **Full regeneration happens only on explicit
|
|
97
|
+
user request**: offer it via `AskUserQuestion` but default to the targeted patch. The skill keeps
|
|
98
|
+
EPIC.md in sync but does not itself diff it against the manifest — drift detection is `forge-verify`
|
|
99
|
+
epic mode CHECK-E06.
|
|
100
|
+
|
|
101
|
+
## Step E6 — Pipeline State & Commit
|
|
102
|
+
|
|
103
|
+
Proceed to the **Observability, Pipeline State & Commit** section below. Each edit-mode mutation is
|
|
104
|
+
committed individually so git history is the audit trail.
|
|
105
|
+
|
|
106
|
+
## Observability, Pipeline State & Commit
|
|
107
|
+
|
|
108
|
+
### Manifest `updatedAt`
|
|
109
|
+
|
|
110
|
+
Every helper mutator bumps the manifest's top-level `updatedAt` to the current ISO-8601 UTC
|
|
111
|
+
timestamp as part of the same atomic write. The skill does **not** bump it manually in edit mode.
|
|
112
|
+
For the initial creation write (C5) the skill sets `createdAt == updatedAt`.
|
|
113
|
+
|
|
114
|
+
### Pipeline state
|
|
115
|
+
|
|
116
|
+
- **Epic-level:** the epic subtree has **no `.pipeline-state.json` of its own** (that is what
|
|
117
|
+
distinguishes an epic root from a feature). The epic's lifecycle lives in the manifest `status`
|
|
118
|
+
field. The `forge-0-epic` run is recorded in **member** states, not in an epic-level state file.
|
|
119
|
+
- **Member-level (creation):** each member's `.pipeline-state.json` records
|
|
120
|
+
`stages["forge-0-epic"].status = "complete"` and `currentStage = "forge-1-prd"` (see C7).
|
|
121
|
+
- **Edit mode:** edits mutate the **manifest**, not member pipeline states — except the
|
|
122
|
+
newly-created subdir for `add-feature`, which follows C7 (create the member subdir + back-pointer
|
|
123
|
+
state). The skill does **not** rewrite existing members' `stages` on an edit.
|
|
124
|
+
- **`.epic-state.json` (lazily created, written by skills — NOT the helper):** epic-*scoped* stage
|
|
125
|
+
entries that belong to no single member — currently only `forge-verify-epic` — are persisted in a
|
|
126
|
+
dedicated `{specsDir}/{epic}/.epic-state.json`. It holds **only** epic-scoped stage entries,
|
|
127
|
+
never derived per-feature status (so it does not violate REQ-STATE-02). `forge-0-epic` does
|
|
128
|
+
**not** create this file — no epic-scoped stage runs during creation or edit; it appears only once
|
|
129
|
+
`forge-verify` epic mode runs. When a skill does write it (e.g. forge-verify epic mode), it writes
|
|
130
|
+
**directly** using an atomic temp-file + `os.replace` pattern — the helper exposes no subcommand
|
|
131
|
+
for it. On I/O failure the skill reports and leaves any prior file intact (never a partial write).
|
|
132
|
+
Minimal schema:
|
|
133
|
+
|
|
134
|
+
```jsonc
|
|
135
|
+
{
|
|
136
|
+
"epic": "auth-overhaul", // matches manifest `epic`
|
|
137
|
+
"stages": {
|
|
138
|
+
"forge-verify-epic": {
|
|
139
|
+
"status": "findings-reported", // "findings-reported" | "passed" | "findings-applied"
|
|
140
|
+
"findingsFile": ".verification/VERIFY-epic-2026-06-12.md",
|
|
141
|
+
"findingsCount": 3,
|
|
142
|
+
"verifiedAt": "2026-06-12T00:00:00Z"
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The git-commit step below stages the whole epic subtree, so `.epic-state.json` is captured
|
|
149
|
+
automatically when present.
|
|
150
|
+
|
|
151
|
+
### Git Commit Protocol
|
|
152
|
+
|
|
153
|
+
After creation (C8) **and after each edit-mode mutation (E6)**, if `gitCommitAfterStage` is true,
|
|
154
|
+
follow the Git Commit Protocol in shared-conventions:
|
|
155
|
+
|
|
156
|
+
1. Stage the whole epic subtree only: `git add {specsDir}/{epic}/` — **never** `git add -A`. This
|
|
157
|
+
captures `epic-manifest.json`, `EPIC.md`, member `.pipeline-state.json` files, and any
|
|
158
|
+
`.epic-state.json` together atomically.
|
|
159
|
+
2. Commit with message `"{commitPrefix}({epic}): <action>"`, e.g.
|
|
160
|
+
`"forge({epic}): create epic with 4 features"`, `"forge({epic}): add feature api-gateway"`,
|
|
161
|
+
`"forge({epic}): remove feature legacy-session"`, `"forge({epic}): reorder features"`,
|
|
162
|
+
`"forge({epic}): set dependency on token-service"`, or `"forge({epic}): set status paused"`.
|
|
163
|
+
3. On success, capture the commit hash. On failure (pre-commit hook, conflict), report and do
|
|
164
|
+
**not** mark complete; never use `--no-verify`/`--force`.
|
|
165
|
+
|
|
166
|
+
Because every mutation is committed, the git history of `epic-manifest.json` is the audit trail; no
|
|
167
|
+
separate in-manifest audit log is kept.
|
|
168
|
+
|
|
169
|
+
### Closing message
|
|
170
|
+
|
|
171
|
+
After a successful **creation**, present the next-steps message (already specified in C8). After a
|
|
172
|
+
successful **edit-mode mutation**, confirm the change and re-surface the dashboard pointer:
|
|
173
|
+
|
|
174
|
+
> Epic `{epic}` updated (`<action>`). Run `/feature-forge:forge {epic}` to see the refreshed
|
|
175
|
+
> dashboard, or re-run `/feature-forge:forge-0-epic {epic}` to make another change.
|
|
176
|
+
|
|
177
|
+
## EPIC.md Mirror Template (creation C6 / edit E5)
|
|
178
|
+
|
|
179
|
+
`forge-0-epic` Step C6 generates `{specsDir}/{epic}/EPIC.md` from the **validated** manifest; the
|
|
180
|
+
edit-mode E5 patch applies the **same mirror rule** to the affected sections. The full skeleton:
|
|
181
|
+
|
|
182
|
+
```markdown
|
|
183
|
+
# {epic} — Epic
|
|
184
|
+
|
|
185
|
+
## Overall Goal
|
|
186
|
+
{the epic goal from C1, expanded into narrative prose}
|
|
187
|
+
|
|
188
|
+
## Decomposition Rationale
|
|
189
|
+
{why the change was split this way; right-sizing notes; ordering rationale}
|
|
190
|
+
|
|
191
|
+
## Features
|
|
192
|
+
{for each feature, in manifest order:}
|
|
193
|
+
|
|
194
|
+
### {feature.name}
|
|
195
|
+
{feature.charter, as prose}
|
|
196
|
+
|
|
197
|
+
**Depends on:** {comma-separated dependsOn, or "nothing"}
|
|
198
|
+
|
|
199
|
+
#### Contracts
|
|
200
|
+
**Exposes:**
|
|
201
|
+
- `{exposes[i].name}` ({exposes[i].kind}) — {exposes[i].summary}
|
|
202
|
+
{… or "Nothing exposed." if the exposes array is empty}
|
|
203
|
+
|
|
204
|
+
**Consumes:**
|
|
205
|
+
- `{consumes[i].name}` from `{consumes[i].from}` — {consumes[i].summary}
|
|
206
|
+
{… or "Nothing consumed." if the consumes array is empty}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Member State Example (creation C7)
|
|
210
|
+
|
|
211
|
+
Each member's `.pipeline-state.json` (created in Step C7) conforms to
|
|
212
|
+
`references/pipeline-state-schema.json`. Example member state:
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"epic": "{epic}",
|
|
217
|
+
"currentStage": "forge-1-prd",
|
|
218
|
+
"stages": {
|
|
219
|
+
"forge-0-epic": { "status": "complete", "version": 1, "completedAt": "<iso-8601-utc>" }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# forge-0-epic — `epic-manifest.py` Subcommand Reference
|
|
2
|
+
|
|
3
|
+
Lookup detail relocated out of the `forge-0-epic` SKILL.md body (Step E3 command
|
|
4
|
+
catalog + exit-code disposition, and the Error Handling table). The skill body keeps
|
|
5
|
+
the decision logic and step ordering; this file is the flag-surface catalog and the
|
|
6
|
+
per-subcommand exit-code reference.
|
|
7
|
+
|
|
8
|
+
## Edit-Mode Mutator Flag Surface (Step E3)
|
|
9
|
+
|
|
10
|
+
Issue the chosen mutator. Each writes atomically and re-runs full validation internally, refusing
|
|
11
|
+
the write if it would introduce a cycle, dangling ref, duplicate, or schema violation. The exact
|
|
12
|
+
flag surface (owned by 02 §7):
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
R="$(for d in "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/*/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done)"
|
|
16
|
+
[ -n "$R" ] || { echo "feature-forge: cannot locate plugin root" >&2; exit 1; }
|
|
17
|
+
# Add a feature — seeds EMPTY exposes/consumes; contracts are populated below.
|
|
18
|
+
python3 "$R/scripts/epic-manifest.py" add-feature "{epic}" "{feature}" \
|
|
19
|
+
--charter "…" --specs-dir "{specsDir}" [--depends-on a,b]
|
|
20
|
+
|
|
21
|
+
# Remove a feature (drops its manifest entry; directory is left in place — see E3 note).
|
|
22
|
+
python3 "$R/scripts/epic-manifest.py" remove-feature "{epic}" "{feature}" \
|
|
23
|
+
--specs-dir "{specsDir}"
|
|
24
|
+
|
|
25
|
+
# Reorder the features[] sequence (must be an exact permutation of current member names).
|
|
26
|
+
python3 "$R/scripts/epic-manifest.py" reorder "{epic}" \
|
|
27
|
+
--order "feat-a,feat-c,feat-b" --specs-dir "{specsDir}"
|
|
28
|
+
|
|
29
|
+
# Change a dependency edge (--depends-on "" clears it).
|
|
30
|
+
python3 "$R/scripts/epic-manifest.py" set-dep "{epic}" "{feature}" \
|
|
31
|
+
--depends-on "config-store,token-service" --specs-dir "{specsDir}"
|
|
32
|
+
|
|
33
|
+
# Change epic lifecycle status (active|paused|abandoned|complete).
|
|
34
|
+
python3 "$R/scripts/epic-manifest.py" set-status "{epic}" \
|
|
35
|
+
--status paused --specs-dir "{specsDir}"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Per-Subcommand Exit-Code Disposition (Step E3)
|
|
39
|
+
|
|
40
|
+
- Exit `0` → the mutator wrote the manifest and bumped `updatedAt`. Proceed to E4/E5.
|
|
41
|
+
- Exit `1` → surface the `findings[]` **verbatim** and **abort the edit**. The manifest is
|
|
42
|
+
unchanged (the write was refused atomically — byte-identical). Loop back to E2 or re-elicit.
|
|
43
|
+
- Exit `2` → unsafe name / missing|corrupt manifest / bad `--status` value / write failure.
|
|
44
|
+
Surface and STOP.
|
|
45
|
+
|
|
46
|
+
## Error Handling
|
|
47
|
+
|
|
48
|
+
The skill **never** repairs a corrupt manifest automatically and **never** proceeds past a gating
|
|
49
|
+
helper exit `≥ 1`. All findings are surfaced **verbatim**.
|
|
50
|
+
|
|
51
|
+
| Condition | Helper signal | Skill behavior |
|
|
52
|
+
|-----------|---------------|----------------|
|
|
53
|
+
| Epic name duplicates an existing name | `check-name` exit 1 (`duplicate-name`) | STOP creation; surface finding; ask for a new name via `AskUserQuestion` |
|
|
54
|
+
| Member feature name duplicates | `check-name` exit 1 (`duplicate-name`) | Reject that name in C2 / add-feature; surface verbatim; re-prompt |
|
|
55
|
+
| Unsafe name (`/`, `..`, absolute) | `check-name`/mutator exit 2 (`unsafe-name`) | Reject; surface; re-prompt |
|
|
56
|
+
| Composed manifest has a cycle | `validate` exit 1 (`cycle`) | Surface verbatim; re-open the dependency interview (C4); never finalize |
|
|
57
|
+
| Dangling `dependsOn`/`consumes.from` | `validate` exit 1 (`dangling-ref`) | Surface verbatim; re-open C4 (bad `dependsOn`) or C3 (bad `consumes.from`) |
|
|
58
|
+
| Corrupt/unparseable manifest (edit) | `validate` exit 1 (`corrupt-json`) | Surface ALL findings verbatim; **refuse all mutation** until repaired; never auto-repair |
|
|
59
|
+
| Existing manifest otherwise invalid (edit) | `validate` exit 1/2 | Surface ALL findings verbatim; **refuse all mutation** (E1) |
|
|
60
|
+
| Mutator would introduce cycle/dangling ref/duplicate | mutator exit 1 | Abort the edit; manifest byte-identical (atomic refusal); surface finding |
|
|
61
|
+
| Bad `--status` value | `set-status` exit 2 (argparse) | Surface; re-prompt via `AskUserQuestion` with the valid choices |
|
|
62
|
+
| Edit affects in-flight/completed feature | `render-status` derived status (`in-progress`/`complete`) | Warn naming the affected feature(s); require confirmation before applying (E4) |
|
|
63
|
+
| `render-status` over an invalid graph | `render-status` exit ≥ 1 | Surface findings; STOP (do not mutate over an invalid graph) |
|
|
64
|
+
| Git commit fails | — | Report; leave state `in-progress`; never bypass hooks (`--no-verify`/`--force`) |
|