@jamie-tam/forge 6.0.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.
Files changed (213) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +389 -0
  3. package/agents/architect.md +92 -0
  4. package/agents/builder.md +122 -0
  5. package/agents/code-reviewer.md +107 -0
  6. package/agents/concept-designer.md +207 -0
  7. package/agents/craft-reviewer.md +132 -0
  8. package/agents/critic.md +130 -0
  9. package/agents/doc-writer.md +85 -0
  10. package/agents/dreamer.md +129 -0
  11. package/agents/e2e-runner.md +89 -0
  12. package/agents/gotcha-hunter.md +127 -0
  13. package/agents/prototype-builder.md +193 -0
  14. package/agents/prototype-codifier.md +204 -0
  15. package/agents/prototype-reviewer.md +163 -0
  16. package/agents/security-reviewer.md +108 -0
  17. package/agents/spec-reviewer.md +94 -0
  18. package/agents/tracer.md +98 -0
  19. package/agents/wireframer.md +109 -0
  20. package/commands/abort.md +25 -0
  21. package/commands/bugfix.md +151 -0
  22. package/commands/evolve.md +118 -0
  23. package/commands/feature.md +236 -0
  24. package/commands/forge.md +100 -0
  25. package/commands/greenfield.md +185 -0
  26. package/commands/hotfix.md +98 -0
  27. package/commands/refactor.md +147 -0
  28. package/commands/resume.md +25 -0
  29. package/commands/setup.md +201 -0
  30. package/commands/status.md +27 -0
  31. package/commands/task-force.md +110 -0
  32. package/commands/validate.md +12 -0
  33. package/dist/__tests__/active-manifest.test.js +272 -0
  34. package/dist/__tests__/copy.test.js +96 -0
  35. package/dist/__tests__/gate-check.test.js +384 -0
  36. package/dist/__tests__/wiki.test.js +472 -0
  37. package/dist/__tests__/work-manifest.test.js +304 -0
  38. package/dist/active-manifest.js +229 -0
  39. package/dist/cli.js +158 -0
  40. package/dist/copy.js +124 -0
  41. package/dist/gate-check.js +326 -0
  42. package/dist/hooks.js +60 -0
  43. package/dist/init.js +140 -0
  44. package/dist/manifest.js +90 -0
  45. package/dist/merge.js +77 -0
  46. package/dist/paths.js +36 -0
  47. package/dist/uninstall.js +216 -0
  48. package/dist/update.js +158 -0
  49. package/dist/verify-manifest.js +65 -0
  50. package/dist/verify.js +98 -0
  51. package/dist/wiki-ui.js +310 -0
  52. package/dist/wiki.js +364 -0
  53. package/dist/work-manifest.js +798 -0
  54. package/hooks/config/gate-requirements.json +79 -0
  55. package/hooks/hooks.json +143 -0
  56. package/hooks/scripts/analyze-telemetry.sh +114 -0
  57. package/hooks/scripts/gate-enforcer.sh +164 -0
  58. package/hooks/scripts/pre-compact.sh +90 -0
  59. package/hooks/scripts/session-start.sh +81 -0
  60. package/hooks/scripts/telemetry.sh +41 -0
  61. package/hooks/scripts/wiki-lint.sh +87 -0
  62. package/hooks/templates/AGENTS.md.template +48 -0
  63. package/hooks/templates/CLAUDE.md.template +45 -0
  64. package/package.json +55 -0
  65. package/protocols/README.md +40 -0
  66. package/protocols/codex.md +151 -0
  67. package/protocols/graphify.md +156 -0
  68. package/references/common/agent-coordination.md +65 -0
  69. package/references/common/coding-standards.md +54 -0
  70. package/references/common/feature-tracking.md +21 -0
  71. package/references/common/io-protocol.md +36 -0
  72. package/references/common/phases.md +57 -0
  73. package/references/common/quality-gates.md +130 -0
  74. package/references/common/skill-authoring.md +154 -0
  75. package/references/common/skill-compliance.md +30 -0
  76. package/references/python/standards.md +44 -0
  77. package/references/react/standards.md +61 -0
  78. package/references/typescript/standards.md +42 -0
  79. package/rules/common/forge-system.md +59 -0
  80. package/rules/common/git-workflow.md +40 -0
  81. package/rules/common/guardrails.md +37 -0
  82. package/rules/common/quality-gates.md +18 -0
  83. package/rules/common/security.md +50 -0
  84. package/rules/common/skill-selection.md +78 -0
  85. package/rules/common/testing.md +58 -0
  86. package/rules/common/verification.md +39 -0
  87. package/skills/build-pr-workflow/SKILL.md +301 -0
  88. package/skills/build-pr-workflow/references/pr-template.md +62 -0
  89. package/skills/build-pr-workflow/references/subagent-merge.md +47 -0
  90. package/skills/build-pr-workflow/references/worktree-setup.md +125 -0
  91. package/skills/build-prototype/SKILL.md +264 -0
  92. package/skills/build-scaffold/SKILL.md +340 -0
  93. package/skills/build-tdd/SKILL.md +89 -0
  94. package/skills/build-wireframe/SKILL.md +110 -0
  95. package/skills/build-wireframe/assets/baseline-template.html +486 -0
  96. package/skills/build-wireframe/references/demo-walkthroughs.md +170 -0
  97. package/skills/build-wireframe/references/gotchas.md +188 -0
  98. package/skills/build-wireframe/references/legend-lines.md +141 -0
  99. package/skills/concept-slides/SKILL.md +192 -0
  100. package/skills/deliver-db-migration/SKILL.md +466 -0
  101. package/skills/deliver-deploy/SKILL.md +407 -0
  102. package/skills/deliver-onboarding/SKILL.md +198 -0
  103. package/skills/deliver-onboarding/references/document-templates.md +393 -0
  104. package/skills/deliver-onboarding/templates/getting-started.md +122 -0
  105. package/skills/discover-codebase-analysis/SKILL.md +448 -0
  106. package/skills/discover-requirements/SKILL.md +418 -0
  107. package/skills/discover-requirements/templates/prd.md +99 -0
  108. package/skills/discover-requirements/templates/technical-spec.md +123 -0
  109. package/skills/discover-requirements/templates/user-stories.md +76 -0
  110. package/skills/harden/SKILL.md +214 -0
  111. package/skills/iterate-prototype/SKILL.md +241 -0
  112. package/skills/plan-architecture/SKILL.md +457 -0
  113. package/skills/plan-architecture/templates/adr-template.md +52 -0
  114. package/skills/plan-architecture/templates/api-contract.md +99 -0
  115. package/skills/plan-architecture/templates/db-schema.md +81 -0
  116. package/skills/plan-architecture/templates/system-design.md +111 -0
  117. package/skills/plan-brainstorm/SKILL.md +433 -0
  118. package/skills/plan-design-system/SKILL.md +279 -0
  119. package/skills/plan-task-decompose/SKILL.md +454 -0
  120. package/skills/quality-code-review/SKILL.md +286 -0
  121. package/skills/quality-security-audit/SKILL.md +292 -0
  122. package/skills/quality-security-audit/references/audit-report-template.md +89 -0
  123. package/skills/quality-security-audit/references/owasp-checks.md +178 -0
  124. package/skills/quality-test-execution/SKILL.md +435 -0
  125. package/skills/quality-test-plan/SKILL.md +297 -0
  126. package/skills/quality-test-plan/references/test-type-guide.md +263 -0
  127. package/skills/quality-test-plan/templates/e2e-test-plan.md +72 -0
  128. package/skills/quality-test-plan/templates/integration-test-plan.md +74 -0
  129. package/skills/quality-test-plan/templates/load-test-plan.md +111 -0
  130. package/skills/quality-test-plan/templates/smoke-test-plan.md +68 -0
  131. package/skills/quality-test-plan/templates/unit-test-plan.md +56 -0
  132. package/skills/quality-uiux/SKILL.md +481 -0
  133. package/skills/support-debug/SKILL.md +464 -0
  134. package/skills/support-dream/SKILL.md +213 -0
  135. package/skills/support-gotcha/SKILL.md +249 -0
  136. package/skills/support-runtime-reachability/SKILL.md +190 -0
  137. package/skills/support-runtime-reachability/scripts/__fixtures__/case-01-passes-app-use/src/app.ts +7 -0
  138. package/skills/support-runtime-reachability/scripts/__fixtures__/case-01-passes-app-use/src/handlers/cases.ts +7 -0
  139. package/skills/support-runtime-reachability/scripts/__fixtures__/case-02-orphan-no-app-use/src/app.ts +8 -0
  140. package/skills/support-runtime-reachability/scripts/__fixtures__/case-02-orphan-no-app-use/src/handlers/cases.ts +7 -0
  141. package/skills/support-runtime-reachability/scripts/__fixtures__/case-03-orphan-import-only/src/App.tsx +5 -0
  142. package/skills/support-runtime-reachability/scripts/__fixtures__/case-03-orphan-import-only/src/components/RingingBanner.tsx +7 -0
  143. package/skills/support-runtime-reachability/scripts/__fixtures__/case-03-orphan-import-only/src/hooks/useTwilio.ts +6 -0
  144. package/skills/support-runtime-reachability/scripts/__fixtures__/case-04-jsx-component-rendered/src/App.tsx +5 -0
  145. package/skills/support-runtime-reachability/scripts/__fixtures__/case-04-jsx-component-rendered/src/components/MyComp.tsx +3 -0
  146. package/skills/support-runtime-reachability/scripts/__fixtures__/case-05-jsx-component-not-rendered/src/App.tsx +3 -0
  147. package/skills/support-runtime-reachability/scripts/__fixtures__/case-05-jsx-component-not-rendered/src/components/Orphan.tsx +3 -0
  148. package/skills/support-runtime-reachability/scripts/__fixtures__/case-06-class-instantiated/src/lib/Service.ts +6 -0
  149. package/skills/support-runtime-reachability/scripts/__fixtures__/case-06-class-instantiated/src/main.ts +4 -0
  150. package/skills/support-runtime-reachability/scripts/__fixtures__/case-07-class-not-instantiated/src/lib/Lonely.ts +5 -0
  151. package/skills/support-runtime-reachability/scripts/__fixtures__/case-07-class-not-instantiated/src/main.ts +2 -0
  152. package/skills/support-runtime-reachability/scripts/__fixtures__/case-08-default-export-imported-and-called/src/handler.ts +3 -0
  153. package/skills/support-runtime-reachability/scripts/__fixtures__/case-08-default-export-imported-and-called/src/main.ts +3 -0
  154. package/skills/support-runtime-reachability/scripts/__fixtures__/case-09-default-export-orphan/src/handler.ts +3 -0
  155. package/skills/support-runtime-reachability/scripts/__fixtures__/case-09-default-export-orphan/src/main.ts +2 -0
  156. package/skills/support-runtime-reachability/scripts/__fixtures__/case-10-aliased-named-export/src/lib.ts +5 -0
  157. package/skills/support-runtime-reachability/scripts/__fixtures__/case-10-aliased-named-export/src/main.ts +3 -0
  158. package/skills/support-runtime-reachability/scripts/__fixtures__/case-11-re-export-chain/src/lib/index.ts +1 -0
  159. package/skills/support-runtime-reachability/scripts/__fixtures__/case-11-re-export-chain/src/lib/internal.ts +3 -0
  160. package/skills/support-runtime-reachability/scripts/__fixtures__/case-11-re-export-chain/src/main.ts +3 -0
  161. package/skills/support-runtime-reachability/scripts/__fixtures__/case-12-test-only-caller/src/util.test.ts +5 -0
  162. package/skills/support-runtime-reachability/scripts/__fixtures__/case-12-test-only-caller/src/util.ts +3 -0
  163. package/skills/support-runtime-reachability/scripts/__fixtures__/case-13-gated-pending-annotation/src/future.ts +4 -0
  164. package/skills/support-runtime-reachability/scripts/__fixtures__/case-14-untraceable-annotation/src/decorated.ts +4 -0
  165. package/skills/support-runtime-reachability/scripts/__fixtures__/case-15-untraceable-empty/src/lazy.ts +4 -0
  166. package/skills/support-runtime-reachability/scripts/__fixtures__/case-16-python-module/src/lib.py +15 -0
  167. package/skills/support-runtime-reachability/scripts/__fixtures__/case-16-python-module/src/main.py +5 -0
  168. package/skills/support-runtime-reachability/scripts/__fixtures__/case-17-router-use/src/parent.ts +5 -0
  169. package/skills/support-runtime-reachability/scripts/__fixtures__/case-17-router-use/src/routes/cases.ts +5 -0
  170. package/skills/support-runtime-reachability/scripts/__fixtures__/case-18-shadowed-name-fp/src/lib/foo.ts +3 -0
  171. package/skills/support-runtime-reachability/scripts/__fixtures__/case-18-shadowed-name-fp/src/other.ts +8 -0
  172. package/skills/support-runtime-reachability/scripts/__fixtures__/case-19-same-name-different-module/src/handlers/cases.ts +4 -0
  173. package/skills/support-runtime-reachability/scripts/__fixtures__/case-19-same-name-different-module/src/handlers/users.ts +4 -0
  174. package/skills/support-runtime-reachability/scripts/__fixtures__/case-19-same-name-different-module/src/main.ts +5 -0
  175. package/skills/support-runtime-reachability/scripts/__fixtures__/case-20-aliased-import-usage/src/handlers/cases.ts +3 -0
  176. package/skills/support-runtime-reachability/scripts/__fixtures__/case-20-aliased-import-usage/src/main.ts +4 -0
  177. package/skills/support-runtime-reachability/scripts/__fixtures__/case-21-mixed-default-and-named/src/lib.ts +5 -0
  178. package/skills/support-runtime-reachability/scripts/__fixtures__/case-21-mixed-default-and-named/src/main.ts +5 -0
  179. package/skills/support-runtime-reachability/scripts/__fixtures__/case-22-dynamic-import-then-caller/src/lib.ts +3 -0
  180. package/skills/support-runtime-reachability/scripts/__fixtures__/case-22-dynamic-import-then-caller/src/main.ts +8 -0
  181. package/skills/support-runtime-reachability/scripts/__fixtures__/case-23-dynamic-import-with-space/src/lib.ts +3 -0
  182. package/skills/support-runtime-reachability/scripts/__fixtures__/case-23-dynamic-import-with-space/src/main.ts +7 -0
  183. package/skills/support-runtime-reachability/scripts/check.mjs +638 -0
  184. package/skills/support-runtime-reachability/scripts/check.test.mjs +244 -0
  185. package/skills/support-skill-validator/SKILL.md +194 -0
  186. package/skills/support-skill-validator/references/false-positives.md +59 -0
  187. package/skills/support-skill-validator/references/validation-checks.md +280 -0
  188. package/skills/support-system-guide/SKILL.md +311 -0
  189. package/skills/support-task-force/SKILL.md +265 -0
  190. package/skills/support-task-force/references/dispatch-pattern.md +178 -0
  191. package/skills/support-task-force/references/synthesis-template.md +126 -0
  192. package/skills/support-wiki-bootstrap/SKILL.md +37 -0
  193. package/skills/support-wiki-lint/SKILL.md +196 -0
  194. package/skills/support-wiki-lint/scripts/lint.mjs +488 -0
  195. package/skills/support-wiki-lint/scripts/lint.test.mjs +196 -0
  196. package/templates/README.md +23 -0
  197. package/templates/aiwiki/CLAUDE.md.template +78 -0
  198. package/templates/aiwiki/schemas/architecture.md +118 -0
  199. package/templates/aiwiki/schemas/convention.md +112 -0
  200. package/templates/aiwiki/schemas/decision.md +144 -0
  201. package/templates/aiwiki/schemas/gotcha.md +118 -0
  202. package/templates/aiwiki/schemas/oracle.md +105 -0
  203. package/templates/aiwiki/schemas/session.md +125 -0
  204. package/templates/manifests/bugfix.yaml +41 -0
  205. package/templates/manifests/feature.yaml +69 -0
  206. package/templates/manifests/greenfield.yaml +61 -0
  207. package/templates/manifests/hotfix.yaml +45 -0
  208. package/templates/manifests/refactor.yaml +44 -0
  209. package/templates/manifests/v5/SCHEMA.md +327 -0
  210. package/templates/manifests/v5/feature.yaml +77 -0
  211. package/templates/manifests/v6/SCHEMA.md +199 -0
  212. package/templates/wiki-html/dream-detail.html +378 -0
  213. package/templates/wiki-html/dreams-list.html +155 -0
@@ -0,0 +1,327 @@
1
+ # v5 manifest schema
2
+
3
+ Source of truth for v5 manifest validation rules. The v5 reader and verifier
4
+ in `src/work-manifest.ts` implement against this document. v4 manifests continue
5
+ to parse (single-slice synthesis, see §6).
6
+
7
+ ---
8
+
9
+ ## 1. Top-level fields
10
+
11
+ Required:
12
+
13
+ | Field | Type | Notes |
14
+ |---|---|---|
15
+ | `schema_version` | string | `"5"` for v5 manifests |
16
+ | `name` | string | kebab-case identifier; matches `.forge/work/{type}/{name}/` |
17
+ | `type` | enum | `feature` \| `bugfix` \| `hotfix` \| `refactor` \| `greenfield` |
18
+ | `description` | string | one-line human description |
19
+ | `status` | enum | `in-progress` \| `paused` \| `completed` \| `escalated` \| `abandoned` |
20
+ | `created` | ISO-8601 date | |
21
+ | `command` | string | which slash command produced the manifest |
22
+ | `phases` | object | pre-build (discover, plan) and post-build (quality, deliver, support) gates |
23
+
24
+ Optional:
25
+
26
+ | Field | Type | Notes |
27
+ |---|---|---|
28
+ | `complexity` | enum | `trivial` \| `standard` \| `major` |
29
+ | `escalated_from` | string \| null | upstream manifest path on escalation |
30
+ | `successor_path` | string \| null | downstream manifest path on escalation |
31
+ | `slice_graph` | object | v5 NEW (§3); absent for v4-shaped manifests |
32
+ | `artifacts` | object | free-form artifact registry (e.g. brainstorm-approved.md) |
33
+
34
+ `phases.build` is **intentionally absent** in v5 manifests. v4 manifests
35
+ that contain `phases.build.tasks: []` still parse (see §6).
36
+
37
+ ---
38
+
39
+ ## 2. Phase gates (unchanged from v4)
40
+
41
+ Each gate inside `phases.{discover,plan,quality}.{gate-name}` has shape:
42
+
43
+ ```yaml
44
+ { status: <enum>, gate-passed: <bool> }
45
+ ```
46
+
47
+ `status` ∈ `pending` \| `in-progress` \| `complete` \| `skipped` \| `not-applicable`.
48
+
49
+ `phases.deliver` and `phases.support` use plain booleans (not gate objects)
50
+ for v4 compatibility — these are not enforced by `gate-enforcer.sh`.
51
+
52
+ Gate names are flat strings. `gate-enforcer.sh` looks up requirements by
53
+ exact gate name in `hooks/config/gate-requirements.json`.
54
+
55
+ ---
56
+
57
+ ## 3. Slice graph (v5 NEW)
58
+
59
+ ```yaml
60
+ slice_graph:
61
+ current_slice: <slice-id> # which slice is active
62
+ slices:
63
+ <slice-id>:
64
+ type: skeleton | feature-slice | refactor-slice
65
+ variant: <string> # only for type: skeleton; identifies stack
66
+ depends_on: [<slice-id>...]
67
+ status: pending | in-progress | gated | complete | abandoned
68
+ gates:
69
+ <gate-name>: { status: <enum>, gate-passed: <bool> }
70
+ ```
71
+
72
+ ### 3.1 Slice IDs
73
+
74
+ - Kebab-case strings, unique within the manifest.
75
+ - Must match `^[a-z][a-z0-9-]*$`.
76
+ - `current_slice` MUST refer to an existing slice ID.
77
+
78
+ ### 3.2 DAG invariants (verifier MUST reject)
79
+
80
+ 1. **Unresolved dependency** — every entry in `depends_on` resolves to an existing slice ID in the same manifest.
81
+ 2. **Self-dependency** — slice ID may not appear in its own `depends_on`.
82
+ 3. **Cycle** — the directed graph induced by `depends_on` must be acyclic. Verifier runs Kahn's algorithm; any node remaining after the pass = cycle.
83
+ 4. **Skeleton uniqueness** — at most one slice has `type: skeleton`.
84
+ 5. **Skeleton root** — if a skeleton slice exists, its `depends_on` MUST be empty.
85
+ 6. **Skeleton ancestry** — if a skeleton slice exists, every non-skeleton slice MUST transitively depend on it. Verifier walks reverse-BFS from the skeleton; any unreached non-skeleton slice = error.
86
+ 7. **Variant required for skeleton** — if `type: skeleton`, `variant` MUST be a non-empty string.
87
+ 8. **Variant forbidden for non-skeleton** — if `type` ≠ `skeleton`, `variant` MUST be absent or null.
88
+
89
+ ### 3.3 Sibling ordering
90
+
91
+ When two slices have the same depth in the DAG (siblings), execution order
92
+ is **insertion order in the `slices:` map**. This is deterministic but
93
+ explicit — agents adding new slices MUST insert them at the position they
94
+ should execute. This avoids hidden dependencies on hash-map iteration.
95
+
96
+ **Implementation contract.** The verifier uses `js-yaml` with default
97
+ schema; js-yaml preserves YAML map insertion order on `load()` and `dump()`.
98
+ If the implementer discovers round-trip order loss in any code path
99
+ (library upgrade, alternate serializer, etc.), they MUST add an
100
+ explicit `order: <int>` field per slice as a follow-up before Phase 2.
101
+ Detect by writing a unit test that dumps then re-parses a 5-slice manifest
102
+ and asserts identical key order.
103
+
104
+ ### 3.4 Gate name collisions (verifier MUST reject)
105
+
106
+ A slice gate name MUST NOT collide with any manifest-level gate name in
107
+ `phases.{discover,plan,quality}`. Reason: `gate-enforcer.sh` matches by
108
+ unscoped name. Reusing a name would silently apply the wrong requirement.
109
+
110
+ Reserved manifest-level gate names (v4 + v5): `codebase-analysis`,
111
+ `brainstorm`, `design-system`, `architecture`, `task-decompose`,
112
+ `code-review-final`, `test-plan`, `test-execution`, `uiux-review`.
113
+
114
+ Allowed slice gate names: `skeleton-runs`, `build-tdd`, `wiki-lint`,
115
+ `runtime-reach`, `code-review`. These differ from the manifest-level set
116
+ by design (per Codex round 1, §3).
117
+
118
+ ### 3.5 Slice status lifecycle (convention, not enforced)
119
+
120
+ > **By convention, this section describes a *lifecycle convention* that
121
+ > skills follow voluntarily. The verifier does NOT block transitions.
122
+ > Observed usage has not shown agents bypassing this discipline silently;
123
+ > if it ever does, restore `verifyTransition` from git history
124
+ > (commit `be5ab93`'s parent).**
125
+
126
+ Lifecycle path (recommended; skills are written to follow this):
127
+
128
+ ```
129
+ pending → in-progress → gated → complete
130
+ ↘ abandoned
131
+ gated → in-progress (gate failed; rework)
132
+ ```
133
+
134
+ `complete` and `abandoned` are conventionally terminal. If a downstream
135
+ change invalidates a completed slice's work, the convention is to add a
136
+ NEW slice that supersedes the old (preserving the audit trail) rather
137
+ than mutate the completed slice's status. Skills enforce this in their
138
+ prompts; the verifier does not.
139
+
140
+ A slice should enter `in-progress` only when every slice in its
141
+ `depends_on` is in `complete` status. `abandoned` does not satisfy a
142
+ dependency — descendants of an abandoned slice block. Skills check this
143
+ before advancing.
144
+
145
+ ### 3.6 Fan-out / fan-in completion (planning convention)
146
+
147
+ The slice graph is **terminally settled** when every slice is in
148
+ `complete` or `abandoned` status. Skills running the post-build
149
+ `phases.quality.code-review-final` gate check this convention before
150
+ proceeding.
151
+
152
+ Fan-out: a slice with multiple non-dependent successors creates parallel
153
+ branches. Each branch advances independently when its own gates pass.
154
+
155
+ Fan-in: a slice with multiple `depends_on` entries waits for ALL of them
156
+ to reach `complete` before entering `in-progress`. An `abandoned`
157
+ dependency does NOT satisfy fan-in.
158
+
159
+ `current_slice` is a single global pointer in v5.0; multi-active-slice
160
+ (per-worker pointer for parallel terminal tabs) is deferred to v6.0
161
+ alongside skills-first interruptibility. v5.0 does NOT enforce
162
+ manifest-write serialization at the file level — single-session
163
+ discipline + git review catches this in practice. Restore `flock(2)`
164
+ write serialization if real usage shows concurrent-write corruption.
165
+
166
+ ---
167
+
168
+ ## 4. Slice gate semantics
169
+
170
+ | Gate | Skill | Agent | When |
171
+ |---|---|---|---|
172
+ | `build-tdd` | `build-tdd` | `builder` | Per slice |
173
+ | `wiki-lint` | `support-wiki-lint` | — | Per slice (validates the slice's wiki contributions) |
174
+ | `runtime-reach` | `support-runtime-reachability` | — | Per slice |
175
+ | `code-review` | `quality-code-review` | `craft-reviewer` | Per slice (lighter than `code-review-final`) |
176
+
177
+ Per-slice `code-review` is **distinct** from manifest-level `code-review-final`.
178
+ The slice version checks pattern conformance + stub detection for that
179
+ slice's diff. The final version reviews the cross-slice integration.
180
+
181
+ **Phase-close wiki lint is a hook, not a gate.** The phase-close gate
182
+ hook ALSO invokes `support-wiki-lint`, but against the CUMULATIVE
183
+ `aiwiki/` state at phase close — not against a slice. It does not
184
+ correspond to any manifest gate slot (the per-slice `wiki-lint` already
185
+ gates each slice's contributions). The phase-close invocation is a
186
+ defense-in-depth check that catches drift across the whole wiki between
187
+ when a slice's lint passed and when the phase closes (e.g. another slice
188
+ edited the same file). The hook fails phase-close if lint fails; no
189
+ manifest field tracks it (the failure is its own evidence).
190
+
191
+ ---
192
+
193
+ ## 5. Verifier interface
194
+
195
+ `src/work-manifest.ts` exports two layers — structural (stateless) and
196
+ transitional (stateful):
197
+
198
+ ```ts
199
+ type ManifestParseResult =
200
+ | { ok: true; manifest: Manifest; schema: 'v4' | 'v5' }
201
+ | { ok: false; errors: ManifestError[] };
202
+
203
+ // Structural: validates a single manifest snapshot. Stateless.
204
+ // Implements §1, §3.1-3.4, §3.6, §6.
205
+ function parseManifest(yaml: string): ManifestParseResult;
206
+ function readManifest(path: string): ManifestParseResult;
207
+
208
+ // NOTE: verifyTransition() and the transitional ErrorCode entries
209
+ // (E_BAD_STATUS_TRANSITION, E_DEPENDENCY_NOT_COMPLETE,
210
+ // E_TERMINAL_SLICE_MUTATED) were removed; slice status transitions
211
+ // remain a documented convention, not enforced by the verifier.
212
+
213
+ type ManifestError = {
214
+ code: ErrorCode; // see enum below
215
+ message: string; // human-readable, includes the offending value
216
+ path: string; // YAML path, e.g. "slice_graph.slices.auth-login.depends_on[1]"
217
+ };
218
+
219
+ type ErrorCode =
220
+ | 'E_UNRESOLVED_DEP' | 'E_SELF_DEP' | 'E_CYCLE'
221
+ | 'E_MULTIPLE_SKELETONS' | 'E_SKELETON_NOT_ROOT' | 'E_ORPHAN_SLICE'
222
+ | 'E_VARIANT_REQUIRED' | 'E_VARIANT_FORBIDDEN'
223
+ | 'E_GATE_COLLISION' | 'E_BAD_SLICE_ID' | 'E_BAD_CURRENT_SLICE'
224
+ | 'E_MISSING_REQUIRED_FIELD' | 'E_BAD_ENUM_VALUE'
225
+ | 'E_PHASE_GATE_PREMATURE' // §3.6: phases.quality.code-review-final.gate-passed = true
226
+ // while any slice is not in terminal state (complete/abandoned)
227
+ | 'E_YAML_PARSE' | 'E_FILE_NOT_FOUND';
228
+ ```
229
+
230
+ `parseManifest` returns ALL errors (not first-fail) so users fix the
231
+ manifest in one pass.
232
+
233
+ ### 5.1 Error message format
234
+
235
+ ```
236
+ <E_CODE> <YAML path>
237
+ <human message; one sentence; quotes the offending value>
238
+ Fix: <one-sentence remediation>
239
+ ```
240
+
241
+ Example:
242
+
243
+ ```
244
+ E_CYCLE slice_graph.slices
245
+ Cycle detected: auth-login → profile-page → auth-login.
246
+ Fix: remove one edge from depends_on, or restructure into a single fan-in slice.
247
+ ```
248
+
249
+ ### 5.2 CLI surface
250
+
251
+ The verifier ships as a dedicated sub-command:
252
+
253
+ ```
254
+ $ npx @jamie-tam/forge verify-manifest [path]
255
+ --json Machine-readable output
256
+
257
+ Exit codes:
258
+ 0 No errors
259
+ 1 Verification errors (errors written to stdout in human or JSON format)
260
+ 2 Internal error (file not found, bad YAML syntax, etc.)
261
+ ```
262
+
263
+ ---
264
+
265
+ ## 6. v4 → v5 migration mapping
266
+
267
+ A v4 manifest (no `slice_graph`, has `phases.build.tasks: []`) is
268
+ synthesized into a v5-shaped in-memory structure:
269
+
270
+ ```yaml
271
+ slice_graph:
272
+ current_slice: legacy-build
273
+ slices:
274
+ legacy-build:
275
+ type: feature-slice
276
+ depends_on: []
277
+ status: <derived from phases.build state>
278
+ gates:
279
+ build-tdd: { status: <derived>, gate-passed: <derived> }
280
+ ```
281
+
282
+ Derivation rules (evaluated in order; first match wins):
283
+
284
+ 1. v4 `tasks: []` is empty (no build work yet planned) → `status: pending`, `gate-passed: false`. Treats vacuous "all complete / all pending" as not-yet-started.
285
+ 2. all tasks `complete` (with at least one task) → `status: complete`, `gate-passed: true`.
286
+ 3. any task `in-progress` and none failed → `status: in-progress`, `gate-passed: false`.
287
+ 4. all tasks `pending` (with at least one task) → `status: pending`, `gate-passed: false`.
288
+ 5. otherwise (mixed states without rule 3) → `status: in-progress`, `gate-passed: false`.
289
+
290
+ The v4 `phases.quality.*` gates are kept AS-IS at manifest level (NOT
291
+ duplicated into the synthesized slice). They run at v4-style "post-build"
292
+ time — after `legacy-build` slice completes.
293
+
294
+ The migration is a **read-time synthesis**, not an on-disk rewrite. v4
295
+ manifests on disk stay v4-shaped until `/evolve` runs, which writes a
296
+ true v5 `slice_graph` block.
297
+
298
+ ### 6.1 Migration semantic limitation (acknowledged)
299
+
300
+ The "all v4 tasks complete = `build-tdd` passed" inference is
301
+ **pragmatic, not semantic**. v4 task names were arbitrary (e.g.
302
+ "core-rule", "discover-codebase-analysis", "readme-update") and many
303
+ weren't TDD work. The synthesis treats the migrated slice as a
304
+ black-box "build phase that finished", not as evidence that TDD was
305
+ followed.
306
+
307
+ Consequence: a v4-migrated manifest read by v5 tooling will show
308
+ `build-tdd: passed` even if no TDD occurred. This is acceptable because
309
+ (a) the v4 work has already shipped — re-litigating the gate would
310
+ block all in-flight v4 features, and (b) `/evolve` prompts the user to
311
+ review the synthesis and rewrite the slice graph if they want true
312
+ v5 gate semantics for ongoing work.
313
+
314
+ `/evolve` shows the synthesized slice graph alongside the v4 task list
315
+ and asks: "Accept this synthesis (treat as legacy build), or rewrite as
316
+ v5 slice graph (re-run gates per slice)?". The default is "accept".
317
+
318
+ ---
319
+
320
+ ## 7. Reserved evolutions
321
+
322
+ Out of scope for v5.0; slots reserved in the schema so we don't have
323
+ to break it again:
324
+
325
+ - **Conditional edges** (`depends_on: [{slice: X, when: <cond>}]`) — deferred to v5.2.
326
+ - **Slice retry policy** (`retry: { max, backoff }`) — deferred; rework via `gated → in-progress` is the v5.0 mechanism.
327
+ - **Per-worker `current_slice`** for parallel terminal tabs — deferred to v6.0 with skills-first interruptibility.
@@ -0,0 +1,77 @@
1
+ # v5 manifest template for /feature command.
2
+ # Spec: ../SCHEMA.md (validation rules, DAG invariants, migration mapping).
3
+ # Additive over v4 — v4 manifests still parse and are treated as single-slice
4
+ # by the v5 reader (see src/manifest.ts).
5
+ #
6
+ # Placeholders: {name}, {description}, {date}, {skeleton_variant}
7
+ # Written to: .forge/work/feature/{name}/manifest.yaml
8
+
9
+ schema_version: "5"
10
+ name: {name}
11
+ type: feature
12
+ description: "{description}"
13
+ status: in-progress # in-progress | paused | completed | escalated
14
+ created: "{date}"
15
+ command: feature
16
+ complexity: standard # trivial | standard | major
17
+ escalated_from: null
18
+ successor_path: null
19
+
20
+ # Pre-build phases (unchanged from v4)
21
+ phases:
22
+ discover:
23
+ codebase-analysis: { status: pending, gate-passed: false }
24
+ plan:
25
+ brainstorm: { status: pending, gate-passed: false }
26
+ design-system: { status: pending, gate-passed: false }
27
+ architecture: { status: pending, gate-passed: false }
28
+ task-decompose: { status: pending, gate-passed: false }
29
+ # NOTE: v4's `phases.build.tasks: []` is replaced by `slice_graph` below.
30
+ # `phases.build` is intentionally absent in v5; the v5 reader treats v4
31
+ # manifests (with `phases.build.tasks`) as a single-slice graph.
32
+ quality:
33
+ code-review-final: { status: pending, gate-passed: false }
34
+ test-plan: { status: pending, gate-passed: false }
35
+ test-execution: { status: pending, gate-passed: false }
36
+ uiux-review: { status: pending, gate-passed: false }
37
+ deliver:
38
+ pr-created: false
39
+ deployed: false
40
+ onboarding: false
41
+ support:
42
+ gotchas-recorded: false
43
+
44
+ # v5 NEW — slice graph replaces flat task list.
45
+ # DAG: each slice declares its dependencies. No edges list (per-node
46
+ # depends_on is the source of truth). Verifier (see SCHEMA.md) rejects:
47
+ # unresolved deps, self-deps, cycles, gate-name collisions with manifest-level
48
+ # gates, and non-skeleton slices that don't transitively depend on the
49
+ # skeleton (when a skeleton slice is present).
50
+ #
51
+ # Skeleton is OPTIONAL. /greenfield and /feature use a skeleton slice;
52
+ # /bugfix and /hotfix omit it (small touches don't earn fake structure).
53
+ # At most one slice may have type: skeleton. If present, it is the root.
54
+ slice_graph:
55
+ current_slice: skeleton # which slice the agent is working on now
56
+ slices:
57
+ skeleton:
58
+ type: skeleton # skeleton | feature-slice | refactor-slice
59
+ variant: {skeleton_variant} # backend-server | frontend-spa | cli-tool | library | mobile-app — set during stack selection
60
+ depends_on: []
61
+ status: pending # pending | in-progress | gated | complete | abandoned
62
+ gates:
63
+ skeleton-runs: { status: pending, gate-passed: false }
64
+ wiki-lint: { status: pending, gate-passed: false }
65
+ runtime-reach: { status: pending, gate-passed: false }
66
+
67
+ # Example slice — replace/extend during /feature flow.
68
+ # Slices are added by plan-task-decompose and confirmed by user.
69
+ example-slice:
70
+ type: feature-slice
71
+ depends_on: [skeleton]
72
+ status: pending
73
+ gates:
74
+ build-tdd: { status: pending, gate-passed: false }
75
+ wiki-lint: { status: pending, gate-passed: false }
76
+ runtime-reach: { status: pending, gate-passed: false }
77
+ code-review: { status: pending, gate-passed: false }
@@ -0,0 +1,199 @@
1
+ # v6 manifest schema
2
+
3
+ Source of truth for v6 manifest validation rules. The v6 reader and verifier in `src/work-manifest.ts` implement against this document.
4
+
5
+ v6 layers a `phase_plan:` block on top of v5. Everything else (slice graph, gate state, escalation links) is inherited from v5 unchanged — see `templates/manifests/v5/SCHEMA.md` for the unchanged parts. This document describes the v6 delta and the parsing contract.
6
+
7
+ ---
8
+
9
+ ## 1. Why phase_plan
10
+
11
+ v5 modeled a single canonical workflow: every gate was either `pending`, `complete`, or `skipped` based on what the skill recorded. There was no place to declare *up front* "this whole feature collapses to commit-only delivery, no PR" or "test-plan runs in light mode for this prototype-iteration feature."
12
+
13
+ v6 separates planning from execution:
14
+
15
+ - **`phase_plan:`** — the **plan** for which phases run and at what rigor. Set during preflight (Step 1 of `/feature`, `/bugfix`, etc). Stable through execution.
16
+ - **`phases:`** — the **gate state** as execution proceeds. Mutated by skills; gate-passed booleans recorded after the matching skill runs.
17
+
18
+ The two blocks are complementary, not redundant. A phase with `phase_plan.X: active-light` still has `phases.X.gate-passed: true` once its (lighter) skill invocation completes.
19
+
20
+ ---
21
+
22
+ ## 2. Top-level changes from v5
23
+
24
+ | Field | v5 | v6 |
25
+ |---|---|---|
26
+ | `schema_version` | `"5"` | `"6"` |
27
+ | `phase_plan` | (absent) | **required** at top level |
28
+ | `phases` | required | required (unchanged — still tracks gate state per phase/sub-phase) |
29
+ | `slice_graph` | required by parser | optional (the v5 SCHEMA already documented this as optional; v6 aligns the parser) |
30
+ | `status` enum | `in-progress` \| `paused` \| `completed` \| `escalated` | adds `abandoned` (terminal state recorded by `/abort`; preserves artifacts) |
31
+ | Everything else | — | unchanged |
32
+
33
+ The `slice_graph` change is a parser fix: v5's SCHEMA §1 listed `slice_graph` as optional but the verifier rejected its absence. v6 manifests can ship without a slice graph — it is populated at codify, not at preflight. v4 and v5 manifests continue to require it (v4 synthesizes one; v5 always shipped one in practice).
34
+
35
+ v6 is a purely additive change. Existing v5 fields keep their shape and semantics. `phase_plan` is the only new top-level field, and it is required.
36
+
37
+ The two blocks coexist by design — `phase_plan` captures intent at preflight, `phases` records what skills actually accomplished. A manifest with `phase_plan.X: skipped` keeps the corresponding `phases.X.{gate}.gate-passed: false`; status fields document the discrepancy.
38
+
39
+ ---
40
+
41
+ ## 3. phase_plan structure
42
+
43
+ `phase_plan:` is a map. Keys are workflow milestone identifiers (phase names, gate names, or any string the workflow recognizes). Values are either:
44
+
45
+ - **Scalar form** — one of the allowed plan-status values
46
+ - **Object form** — `{ status: <value>, reason: <string> }` when a reason needs to be attached
47
+
48
+ ```yaml
49
+ phase_plan:
50
+ concept: skipped # scalar form
51
+ wireframe: skipped
52
+ prototype: skipped
53
+ codify: skipped
54
+ production-build: active
55
+ test-plan: # object form
56
+ status: active-light
57
+ reason: "typecheck + browser verify only — no test runner installed"
58
+ uiux-review: active
59
+ code-review-final: active
60
+ deliver: active-commit-only
61
+ onboarding: skipped
62
+ gotchas: as-discovered
63
+ ```
64
+
65
+ ### 3.1 Allowed plan-status values
66
+
67
+ | Value | Meaning | Gate-passed expected? |
68
+ |---|---|---|
69
+ | `active` | Runs at full rigor | yes (skill invocation required) |
70
+ | `active-light` | Runs with reduced rigor (e.g. typecheck-only test phase, no test-runner suite) | yes (skill invocation required) |
71
+ | `active-commit-only` | Runs but truncated to a partial deliverable (e.g. commit on existing branch instead of opening a PR) | yes (skill invocation required) |
72
+ | `skipped` | Does not run; downstream consumers MUST handle absence | no — stays `false` |
73
+ | `as-discovered` | Runs opportunistically when triggered; not scheduled | when triggered |
74
+ | `complete-inline` | Was done inline (often before the manifest existed) without skill invocation | no — stays `false`; status field documents the work |
75
+
76
+ The verifier rejects any other value with `E_BAD_PHASE_PLAN_STATUS`.
77
+
78
+ ### 3.2 Key naming convention
79
+
80
+ Keys are free-form strings — the verifier does NOT validate them against any canonical vocabulary. This is intentional: `/bugfix`, `/hotfix`, `/refactor` workflows have different shapes than `/feature` or `/greenfield`, and each command enumerates its own plannable steps.
81
+
82
+ **This means typos in keys are silent failures.** A misspelled `prototpe` produces no parse error but breaks any downstream routing that reads `phase_plan.prototype` — including the mode-detection signals in `rules/common/skill-selection.md` and command preflight redirects. Treat phase_plan keys as load-bearing identifiers: copy them from the templates exactly, do not invent variants.
83
+
84
+ #### Recommended keys per work type
85
+
86
+ Commands should use these keys (kebab-case, match the templates verbatim):
87
+
88
+ | Work type | Recommended `phase_plan` keys |
89
+ |---|---|
90
+ | `feature` | `discover-codebase`, `concept`, `wireframe`, `plan-design-system`, `prototype`, `iterate`, `codify`, `worktree`, `production-build`, `test-plan`, `uiux-review`, `code-review-final`, `deliver`, `onboarding`, `gotchas` |
91
+ | `greenfield` | `discover-requirements`, `concept`, `wireframe`, `plan-design-system`, `prototype`, `iterate`, `codify`, `scaffold`, `production-build`, `test-plan`, `uiux-review`, `code-review-final`, `deliver`, `onboarding`, `gotchas` |
92
+ | `bugfix` | `debug-root-cause`, `production-build`, `code-review`, `deliver`, `gotchas` |
93
+ | `hotfix` | `debug-root-cause`, `production-build`, `smoke-tests`, `code-review-critical`, `deliver`, `gotchas`, `followup-ticket` |
94
+ | `refactor` | `discover-codebase`, `brainstorm`, `task-decompose`, `production-build`, `test-execution`, `assessment`, `deliver`, `gotchas` |
95
+
96
+ `plan-design-system` is a workflow-specific gate that runs at Step 4.5 of `/feature` and `/greenfield` (post-wireframe-lock, pre-prototype). It is not in `references/common/phases.md` because it is a step within Phase 3-4 rather than its own canonical phase. Backend-only / CLI work skips it (`status: skipped` with a reason); frontend work uses `status: active`.
97
+
98
+ The seven canonical phase names from `references/common/phases.md` (`concept`, `wireframe`, `prototype`, `iterate`, `codify`, `production-build`, `deliver`) MUST match the canonical spelling when used. Other keys are workflow-specific gates or sub-phases.
99
+
100
+ If real usage shows typos causing failures, harden this from convention to per-type enum validation — the parser knows `manifest.type`, so a per-type allowed-keys map is a single Set lookup.
101
+
102
+ ### 3.3 gate-passed discipline
103
+
104
+ A manifest with `phase_plan.X: active` MUST still earn `phases.X.gate-passed: true` through skill invocation — the `gate-enforcer.sh` hook enforces this. Plan-status `active` does NOT pre-authorize gate passage.
105
+
106
+ Conversely, `phase_plan.X: skipped` / `complete-inline` SHOULD keep `phases.X.gate-passed: false`. The plan-status documents intent; the gate field documents whether the rigor was applied. Setting `gate-passed: true` on a skipped phase trains the manifest to lie about gate state.
107
+
108
+ This convention is enforced by skills (they read phase_plan and choose not to set gate-passed on skipped phases). The verifier does NOT cross-validate plan-status against gate-passed — that's a hot path for false positives and the convention is well-understood.
109
+
110
+ ---
111
+
112
+ ## 4. Migration from v5
113
+
114
+ A v5 manifest read by the v6 parser is accepted as-is. The parser returns `schema: 'v5'` and the synthesized in-memory manifest has `phase_plan: undefined`. Tools that need a phase_plan can synthesize a default: every phase in `phases.{block}.{gate}` becomes `phase_plan.{gate}: active`.
115
+
116
+ `/evolve` (when it lands) will offer to rewrite v5 manifests on-disk into v6 shape, prompting for plan-status per phase. v5 manifests parse forever; no forced migration.
117
+
118
+ ---
119
+
120
+ ## 5. Verifier interface delta
121
+
122
+ Added `ErrorCode`:
123
+
124
+ ```ts
125
+ type ErrorCode =
126
+ | ...v5 codes...
127
+ | 'E_BAD_PHASE_PLAN_STATUS' // phase_plan value not in §3.1 enum
128
+ | 'E_BAD_PHASE_PLAN_SHAPE'; // phase_plan not a map; or object-form value missing status
129
+ ```
130
+
131
+ Added `Manifest` field:
132
+
133
+ ```ts
134
+ export type PhasePlanStatus =
135
+ | "active" | "active-light" | "active-commit-only"
136
+ | "skipped" | "as-discovered" | "complete-inline";
137
+
138
+ export interface PhasePlanEntry {
139
+ status: PhasePlanStatus;
140
+ reason?: string;
141
+ }
142
+
143
+ export interface Manifest {
144
+ // ...v5 fields...
145
+ phase_plan?: Record<string, PhasePlanEntry>; // normalized at parse time
146
+ }
147
+ ```
148
+
149
+ At parse time, scalar-form values are normalized to object-form `{ status: <value> }` so downstream code reads a uniform shape.
150
+
151
+ `schema` in the return value gains a third value: `'v4' | 'v5' | 'v6'`.
152
+
153
+ ---
154
+
155
+ ## 6. Artifacts convention
156
+
157
+ The Manifest interface includes an optional top-level `artifacts:` map. v6 standardizes a convention for tracking phase outputs (paths + lock timestamps):
158
+
159
+ ```yaml
160
+ artifacts:
161
+ concept:
162
+ deck_path: decks/{name}/slides.md
163
+ locked_at: "2026-05-12T10:00:00Z"
164
+ wireframe:
165
+ html_path: pocs/{name}-wireframe/index.html
166
+ locked_at: "2026-05-12T11:00:00Z"
167
+ prototype:
168
+ path: pocs/{name}-prototype/
169
+ locked_at: "2026-05-12T12:00:00Z"
170
+ codify:
171
+ locked_at: "2026-05-12T13:00:00Z" # no path — slice_graph is the artifact
172
+ production-build:
173
+ locked_at: "2026-05-12T16:00:00Z" # no path — slice terminal state is the artifact
174
+ ```
175
+
176
+ **Lock signal.** Presence of `artifacts.{phase}.locked_at` is the canonical "phase locked" signal. Skills that gate on a prior phase being locked (e.g. `harden` requires prototype locked, `build-prototype` requires wireframe locked) check this field rather than a separate status enum.
177
+
178
+ **Path fields are phase-specific:**
179
+
180
+ | Phase | Field | Notes |
181
+ |---|---|---|
182
+ | concept | `deck_path` | Path to the slide deck |
183
+ | wireframe | `html_path` | Path to the single-HTML wireframe |
184
+ | prototype | `path` | Path to the prototype directory |
185
+ | codify | (no path) | The slice_graph + aiwiki/architecture/ files ARE the artifacts |
186
+ | production-build | (no path) | Slice terminal state + the production code ARE the artifacts |
187
+ | deliver | `pr_urls` | Array of PR URLs created |
188
+
189
+ The parser does not validate the artifacts shape — this is a documentation convention. Skills follow it; the verifier ignores it.
190
+
191
+ ---
192
+
193
+ ## 7. Reserved evolutions
194
+
195
+ Out of scope for v6.0; slots reserved so we don't break the schema again:
196
+
197
+ - **Plan-status `deferred`** (run later as a follow-up work item) — the current `escalated_from` / `successor_path` fields cover the multi-manifest case; `deferred` is a single-manifest variant we may need.
198
+ - **Phase ordering hints** — currently implicit (insertion order in YAML map). Add an explicit `order:` field if real usage shows fragility.
199
+ - **Strict artifact validation** — per-phase required fields could be enforced if real usage shows skills writing inconsistent shapes.