@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,201 @@
1
+ ---
2
+ name: setup
3
+ description: "Infer project stack from manifests, fill in the CLAUDE.md and AGENTS.md project profiles, and scaffold the .forge and aiwiki directories. Run after forge init."
4
+ ---
5
+
6
+ # /setup — Configure Project Profile
7
+
8
+ You are configuring the forge project profile. The CLI (`npx @jamie-tam/forge init`) already installed skills, commands, agents, hooks, all language rules, and the CLAUDE.md / AGENTS.md templates. This command infers the project's tech profile, fills the templates, and scaffolds the working directories.
9
+
10
+ Language rules ship complete (typescript, react, python). Agents read the rule files matching the work at hand — no install-time pruning needed.
11
+
12
+ ## Step 1: Detect Optional Tools & Build Graph
13
+
14
+ Detect optional tools first — Graphify's knowledge graph enriches stack inference and reduces tokens for all later steps.
15
+
16
+ **Graphify (knowledge graph):**
17
+
18
+ Run the graphify status check from `protocols/graphify.md`:
19
+
20
+ 1. Check three things:
21
+ - `graphify-out/graph.json` exists?
22
+ - `graphify --version` succeeds (CLI installed)?
23
+ - `~/.claude/skills/graphify/SKILL.md` exists (skill installed for `/graphify` to work)?
24
+ 2. Prompt based on status (see the full guard table in `protocols/graphify.md`):
25
+ - **Nothing installed** → offer install (CLI + skill manual path from protocol)
26
+ - **CLI installed, skill missing** → offer skill install only (so `/graphify` works)
27
+ - **Both installed, no graph** → offer build (`/graphify`)
28
+ - **Graph exists, both installed** → offer update (`/graphify --update`)
29
+ - **Graph exists, CLI missing** → use static files only
30
+ 3. If user accepts build/update → invoke the `/graphify` skill, then continue.
31
+ 4. If graph is available after this step, it will enrich Step 2.
32
+
33
+ **Codex plugin:**
34
+ ```bash
35
+ codex --version 2>/dev/null
36
+ ```
37
+ - If detected: note the version for the report.
38
+ - If not detected: do not mention it.
39
+
40
+ **Gitignore setup:**
41
+ Ensure `.forge/local.yaml` is in `.gitignore`. This file stores per-user preferences (e.g., Codex consent, Graphify consent) and must not be committed.
42
+
43
+ ```bash
44
+ grep -q '.forge/local.yaml' .gitignore 2>/dev/null || echo '.forge/local.yaml' >> .gitignore
45
+ ```
46
+
47
+ <GATE>
48
+ STOP. If Graphify was recommended for installation or a graph build was offered, wait for the user's response before proceeding. Do NOT skip ahead to stack inference — the graph data from this step enriches the next step. Only proceed to Step 2 after the user has responded to all tool recommendations.
49
+ </GATE>
50
+
51
+ ## Step 2: Infer Project Profile & Fill Templates
52
+
53
+ Read the project's manifest files to infer the tech profile. Check whichever exist:
54
+
55
+ | Look for | Tells you |
56
+ |---|---|
57
+ | `package.json` | name, dependencies, frameworks (React/Vue/Next/Astro/Hono/etc.), test runner (vitest/jest/playwright), bundler |
58
+ | `pnpm-workspace.yaml`, `package.json` `workspaces` | monorepo structure — scan each workspace's manifest |
59
+ | `pyproject.toml`, `requirements.txt`, `Pipfile` | Python deps, framework (FastAPI/Django/Flask), test runner (pytest) |
60
+ | `go.mod`, `Cargo.toml`, `pom.xml`, `build.gradle` | Go / Rust / Java / Kotlin |
61
+ | Lock files (`pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, `package-lock.json`, `uv.lock`, `poetry.lock`) | Package manager |
62
+ | `tsconfig.json` | TypeScript |
63
+ | `Dockerfile`, `docker-compose.yml` | Container setup, often database hints |
64
+ | `vite.config.*`, `next.config.*`, `astro.config.*`, etc. | Confirm framework |
65
+ | `tailwind.config.*`, `postcss.config.*` | Styling stack |
66
+
67
+ If a Graphify graph is available, cross-reference its technology nodes and community labels to validate and enrich the inference (especially for monorepos and modern frameworks the manifests don't fully reveal).
68
+
69
+ Synthesize what you find into a profile. Aim for accurate version numbers (read package versions, not just names). Present for confirmation:
70
+
71
+ ```
72
+ Inferred project profile:
73
+ Name: my-app
74
+ Stack: typescript/react 18 + next 14
75
+ Database: postgresql (via @prisma/client)
76
+ Unit tests: vitest
77
+ E2E tests: playwright
78
+ Package manager: pnpm
79
+ Notable libs: zustand, tailwind 4, lucide-react
80
+
81
+ Is this right? (y / correct field=value / describe what's off)
82
+ ```
83
+
84
+ Let the user correct any fields. Honor user corrections — they know their project; you're inferring.
85
+
86
+ <GATE>
87
+ STOP. Do NOT proceed until the user has confirmed or corrected the inferred profile. The values flow into project docs and the wiki — wrong values mislead every later session.
88
+ </GATE>
89
+
90
+ After confirmation, fill both project docs. Show the filled content for review before writing:
91
+
92
+ - **`.claude/CLAUDE.md`** — populate the `project:` YAML block: name, stack, database, test_runner, package_manager.
93
+ - **`AGENTS.md`** (repo root) — populate the Project section: Name, Stack, Test runner, Package manager. Replace the `(run /setup)` placeholders with actual values.
94
+
95
+ <GATE>
96
+ STOP. Present the filled CLAUDE.md and AGENTS.md content to the user for review before writing. Do NOT write files without user confirmation.
97
+ </GATE>
98
+
99
+ ## Step 2a: Configure Gate Enforcement Mode
100
+
101
+ `npx @jamie-tam/forge init` installs PreToolUse hooks that block manifest `gate-passed: true` edits unless telemetry shows the matching skill was invoked via the Skill tool. Useful for production-grade work; high-friction for prototype iteration where most phases are explicitly skipped.
102
+
103
+ **Default suggestion** (computed from Step 2 profile):
104
+ - If signals match **prototype mode** (path under `pocs/`, `package.json` `"private": true` with no CI, no `aiwiki/architecture/`): suggest **disable**
105
+ - If signals match **production mode** (CI configured, tests present, codified architecture exists or imminent): suggest **keep enabled**
106
+
107
+ Ask the user:
108
+
109
+ ```
110
+ Gate enforcement (PreToolUse hooks that block manifest gate-passed edits without skill-invocation telemetry):
111
+
112
+ Suggested for this project: <KEEP ENABLED | DISABLE>
113
+
114
+ • Keep enabled — production-grade discipline; manifests cannot lie about gate state
115
+ • Disable — prototype iteration; faster loop, telemetry still recorded for retrospective audit
116
+
117
+ Choice? [Y]es (keep enabled) / [d]isable / [k]eep enabled regardless of suggestion
118
+ ```
119
+
120
+ **On "disable"**: remove the two gate-enforcer matcher entries from `.claude/settings.local.json` (the entries with `matcher: Edit` or `matcher: Write` whose command invokes `.claude/hooks/scripts/gate-enforcer.sh`). The file is gitignored so this is a local-only change. Keep the PostToolUse telemetry hook — telemetry is still recorded for retrospective audit; only the blocking is removed.
121
+
122
+ **On "keep enabled"**: leave settings.local.json as installed.
123
+
124
+ Tell the user: "Gate enforcement <enabled / disabled>. To toggle later, edit `.claude/settings.local.json` — see `hooks/hooks.json` in the forge repo for the canonical entries."
125
+
126
+ Note in the manifest or session memo what was chosen, so future sessions don't have to re-detect.
127
+
128
+ ## Step 3: Create .forge Directory
129
+
130
+ Create the working directory structure if it doesn't exist:
131
+
132
+ ```
133
+ .forge/
134
+ ├── work/ # Per-work-item artifacts and manifests, one subdir per type
135
+ │ ├── feature/
136
+ │ ├── bugfix/
137
+ │ ├── refactor/
138
+ │ ├── hotfix/
139
+ │ └── greenfield/
140
+ ├── state/ # Runtime state (telemetry, wiki receipts, dream history)
141
+ └── wiki-history/ # Pre-swap snapshots of aiwiki/ before atomic accept (for rollback)
142
+ ```
143
+
144
+ Only create the top-level directories. Individual work-item folders are created on demand by the relevant command.
145
+
146
+ ## Step 4: Create aiwiki Directory
147
+
148
+ The `aiwiki/` is the project's persistent context layer — typed pages (decisions, gotchas, conventions, architecture, sessions), an auto-loaded usage rules file, and the schema definitions LINT validates against. Scaffold from templates installed by `npx @jamie-tam/forge init`:
149
+
150
+ ```
151
+ aiwiki/
152
+ ├── CLAUDE.md # Auto-loaded by Claude Code at session start (wiki usage rules)
153
+ ├── INDEX.md # Sortable index of recent activity (dream-maintained)
154
+ ├── projectbrief.md # One-pager: what this project is (filled by user)
155
+ ├── decisions/ # ADRs
156
+ ├── gotchas/ # Recurring failures + prevention
157
+ ├── conventions/ # Codebase patterns + rationale
158
+ ├── architecture/ # System-shape docs (one file per subsystem)
159
+ ├── sessions/ # Per-session handoff index (hook + dream maintained)
160
+ ├── raw/ # Incoming, unclassified — compile or delete at phase close
161
+ ├── proposed/ # Dream output awaiting user review (input untouched)
162
+ └── schemas/ # Per-page-type schemas used by wiki-lint
163
+ ```
164
+
165
+ REQUIRED SUB-SKILL: Use **support-wiki-bootstrap** to ensure aiwiki/ exists.
166
+
167
+ After bootstrap, update `aiwiki/projectbrief.md` with the project name and stack from Step 2 (replace the placeholder description). Ask the user to fill `projectbrief.md` before continuing — the wiki references it for orientation context.
168
+
169
+ <GATE>
170
+ STOP. The aiwiki/CLAUDE.md is auto-loaded by Claude Code on every session start in this project. Confirm with the user that they accept the wiki usage rules (citation requirements, typed page schemas, no-speculation rule, dream review flow) before completing setup. They can edit aiwiki/CLAUDE.md to customize.
171
+ </GATE>
172
+
173
+ ## Step 5: Report
174
+
175
+ Print a summary:
176
+ ```
177
+ Setup complete!
178
+
179
+ Project profile:
180
+ Name: {name}
181
+ Stack: {stack}
182
+ Test runner: {test_runner}
183
+ Package manager: {package_manager}
184
+
185
+ Configured:
186
+ - CLAUDE.md and AGENTS.md profiles filled
187
+ - .forge/ working directory (work/, state/, wiki-history/)
188
+ - aiwiki/ directory scaffolded (CLAUDE.md, schemas/, projectbrief.md, typed-page subdirs)
189
+
190
+ Optional tools:
191
+ - Codex plugin: {detected version | not detected}
192
+ {If detected: "Second opinions available during quality and planning phases."}
193
+ - Graphify: {detected version | "not installed — pip install graphifyy"}
194
+ {If detected + graph built: "Knowledge graph available ({N} nodes, {N} communities)."}
195
+ {If detected + no graph: "Run /graphify to build a knowledge graph."}
196
+
197
+ Next steps:
198
+ 1. Review .claude/CLAUDE.md and AGENTS.md
199
+ 2. Run /validate to verify system health
200
+ 3. Start with /feature or /greenfield
201
+ ```
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: status
3
+ description: "List in-flight .forge/work items and their current phase."
4
+ ---
5
+
6
+ # /status — Work Item Status
7
+
8
+ List active work items from `.forge/work/` without modifying files.
9
+
10
+ ## Scope
11
+
12
+ Reports in-flight `.forge/work/` items and their current phase. Read-only — does not modify manifests, files, or wiki. Does NOT resume work, route between commands, or judge whether a stalled item should be aborted. Invoke when the user asks "what's in flight?", before `/resume` (to pick a target), or before `/abort` (to confirm which item).
13
+
14
+ ## Steps
15
+
16
+ 1. Find manifests at `.forge/work/*/*/manifest.yaml`.
17
+ 2. Exclude items whose `status` is `completed`, `abandoned`, or `escalated`.
18
+ 3. For each remaining item, infer the current phase from the first phase or gate that is not complete, locked, skipped, or not-applicable. Prefer explicit fields such as `build.current_phase` when present.
19
+ 4. Print a table:
20
+
21
+ ```markdown
22
+ | Type | Name | Status | Current phase | Manifest |
23
+ |---|---|---|---|---|
24
+ | feature | add-payments | in-progress | quality.test-execution | .forge/work/feature/add-payments/manifest.yaml |
25
+ ```
26
+
27
+ If no in-flight items exist, say so clearly.
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: task-force
3
+ description: "Dispatch a parallel task-force per item in a user-provided punch list. Phase-aware sizing (light teams in prototype phases, full crew in production). Routes command-shaped items (features, bugfixes, refactors) to their owning commands. Include !max (or --full-power) in your prompt to force full-crew production teams regardless of detected phase."
4
+ argument-hint: "task1; task2; task3 (or numbered/bulleted list); append !max to force full crew"
5
+ ---
6
+
7
+ # /task-force
8
+
9
+ Run a parallel ad-hoc task-force dispatcher over a punch list of independent tasks.
10
+
11
+ ## When to use
12
+
13
+ - You have 3-20 independent tasks to do in parallel
14
+ - The tasks are heterogeneous (mix of dev, research, docs, debug, quick fixes)
15
+ - None of the tasks individually warrants a full `/feature` or `/bugfix` workflow
16
+ - You want Codex-paired second opinions where it earns its keep
17
+
18
+ ## When NOT to use
19
+
20
+ - A single task — use the appropriate skill or command directly
21
+ - A coherent feature spec — use `/feature`
22
+ - A single bug to fix — use `/bugfix`
23
+ - A refactor — use `/refactor`
24
+ - Everything in the list is command-shaped — invoke those commands instead
25
+
26
+ ## Process
27
+
28
+ REQUIRED SUB-SKILL: Use **support-task-force** to:
29
+ 1. Run Codex consent (one-time per run, per `protocols/codex.md`)
30
+ 2. Detect repo phase (prototype vs production) from active manifest or repo state
31
+ 3. Parse the task list (numbered, bulleted, or semicolon-separated argument)
32
+ 4. Classify each task by type (dev / research / debug / docs / review / security / quick / complex / command-shaped)
33
+ 5. Route command-shaped items to their owning commands (do NOT dispatch task-forces for them)
34
+ 6. Assemble a team per task, sized by task type AND phase mode
35
+ 7. Dispatch all task-forces in parallel (background subagents)
36
+ 8. Aggregate per-task verdicts with Claude+Codex consensus check
37
+ 9. Surface a run-summary with conflicts highlighted
38
+
39
+ ## Arguments
40
+
41
+ Either:
42
+ - Pass the list directly: `/task-force update README; explore caching options; add test for parser`
43
+ - Or pass a numbered/bulleted list in the next prompt after invoking `/task-force` bare
44
+
45
+ ## Output
46
+
47
+ `.forge/task-force/{run-id}/` containing:
48
+ - `codex.yaml` — Codex consent choice
49
+ - `tasks.yaml` — task classifications
50
+ - `task-{n}/{role}.md` — per-agent output
51
+ - `task-{n}/verdict.md` — per-task consensus verdict
52
+ - `run-summary.md` — consolidated report
53
+
54
+ ## Caps
55
+
56
+ - Hard cap: 20 tasks per run
57
+ - Soft cap: 10 tasks (warn, offer to batch)
58
+ - Per-task team: 1-5 agents depending on phase mode and task type
59
+ - Total agents per run: ~5-80 typically
60
+
61
+ ## Examples
62
+
63
+ ### Standard (phase-aware sizing)
64
+
65
+ ```
66
+ /task-force
67
+ 1. Update README with new install steps
68
+ 2. Explore options for adding a /status command
69
+ 3. Add unit test for parser edge cases
70
+ 4. Bump dep "yaml" to ^2.3
71
+ 5. Investigate why CI is flaky on test 17
72
+ ```
73
+
74
+ Expected behavior (production phase detected):
75
+ - Task 1 (docs): `doc-writer` + Codex verify
76
+ - Task 2 (research): 2 explorers + Codex
77
+ - Task 3 (dev): `builder` + dispatch `quality-code-review`
78
+ - Task 4 (quick): one agent + Codex verify
79
+ - Task 5 (debug): dispatch `support-debug` + `gotcha-hunter` + Codex
80
+ - Total: ~12 agents in parallel
81
+
82
+ In prototype phase, the same list dispatches ~5 agents (light templates, no Codex on quick/docs).
83
+
84
+ ### Force full power (`!max` override)
85
+
86
+ ```
87
+ /task-force !max
88
+ 1. Update README with new install steps
89
+ 2. Add helper function for date parsing
90
+ 3. Investigate why CI is flaky on test 17
91
+ ```
92
+
93
+ Expected behavior (production teams enforced even if repo is in prototype phase):
94
+ - All tasks dispatch with full production templates
95
+ - Mandatory Codex pairing throughout
96
+ - No "quick mode" shortcut
97
+ - Total: ~8 agents
98
+
99
+ Use `!max` (short form) or `--full-power` (canonical form) when prototype code is about to graduate to production, or when you want maximum review depth regardless of phase state. Both forms are equivalent.
100
+
101
+ ## Manifest
102
+
103
+ This command does NOT create a `.forge/work/{type}/{name}/` manifest — task-force runs are not phase-gated. State lives in `.forge/task-force/{run-id}/` only.
104
+
105
+ If an active feature/bugfix manifest exists, the task-force run-id is appended to its current phase as `task-force-runs: [...]` for audit.
106
+
107
+ ## See also
108
+
109
+ - `skills/support-task-force/SKILL.md` — full process documentation
110
+ - `/feature`, `/bugfix`, `/refactor` — for command-shaped work that this skill refuses to swallow
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: validate
3
+ description: "Validate that all skills, rules, and commands are consistent. Run after modifying skills or to check system health."
4
+ ---
5
+
6
+ # /validate — System Consistency Check
7
+
8
+ REQUIRED SUB-SKILL: Use **support-skill-validator** in **full scan mode**.
9
+
10
+ Run all five validation checks: directive conflicts, I/O graph integrity, responsibility overlaps, gate completeness, post-evolve drift.
11
+
12
+ Present results to the user. For Critical issues, suggest specific fixes. If fixes are applied, re-run to confirm resolution.
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Smoke test for src/active-manifest.ts.
3
+ *
4
+ * Run via: npm run build && node dist/__tests__/active-manifest.test.js
5
+ *
6
+ * Uses a tmp dir as cwd so the real .forge/state is untouched.
7
+ */
8
+ import { mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { clearActiveManifest, getActiveManifest, getActivePointerPath, setActiveManifest, } from "../active-manifest.js";
12
+ let passed = 0;
13
+ let failed = 0;
14
+ const fails = [];
15
+ function test(name, fn) {
16
+ try {
17
+ fn();
18
+ passed++;
19
+ console.log(` PASS ${name}`);
20
+ }
21
+ catch (e) {
22
+ failed++;
23
+ const msg = e instanceof Error ? e.message : String(e);
24
+ fails.push(`${name}: ${msg}`);
25
+ console.log(` FAIL ${name}\n ${msg}`);
26
+ }
27
+ }
28
+ function withTmpProject(fn) {
29
+ const tmp = mkdtempSync(join(tmpdir(), "forge-active-"));
30
+ // Make it a git repo so getStateDir resolves cleanly
31
+ try {
32
+ require("node:child_process").execSync("git init -q", { cwd: tmp });
33
+ }
34
+ catch {
35
+ /* ignore */
36
+ }
37
+ const manifestPath = join(tmp, "manifest.yaml");
38
+ writeFileSync(manifestPath, "schema_version: \"5\"\n");
39
+ try {
40
+ fn(tmp, manifestPath);
41
+ }
42
+ finally {
43
+ rmSync(tmp, { recursive: true, force: true });
44
+ }
45
+ }
46
+ console.log("\n=== active-manifest.ts smoke tests ===\n");
47
+ test("get when not set returns null", () => {
48
+ withTmpProject((cwd) => {
49
+ const ptr = getActiveManifest(cwd);
50
+ if (ptr !== null)
51
+ throw new Error(`expected null, got ${JSON.stringify(ptr)}`);
52
+ });
53
+ });
54
+ test("set + get roundtrip", () => {
55
+ withTmpProject((cwd, manifestPath) => {
56
+ const setResult = setActiveManifest(manifestPath, { cwd, setBy: "test" });
57
+ if (setResult.manifest_path !== manifestPath) {
58
+ throw new Error(`set returned wrong path: ${setResult.manifest_path}`);
59
+ }
60
+ if (setResult.set_by !== "test") {
61
+ throw new Error(`set_by mismatch: ${setResult.set_by}`);
62
+ }
63
+ const got = getActiveManifest(cwd);
64
+ if (!got)
65
+ throw new Error("expected pointer, got null");
66
+ if (got.manifest_path !== manifestPath) {
67
+ throw new Error(`get returned wrong path: ${got.manifest_path}`);
68
+ }
69
+ if (!got.set_at.match(/^\d{4}-\d{2}-\d{2}T/)) {
70
+ throw new Error(`set_at not ISO-8601: ${got.set_at}`);
71
+ }
72
+ });
73
+ });
74
+ test("set rejects non-existent path", () => {
75
+ withTmpProject((cwd) => {
76
+ let threw = false;
77
+ try {
78
+ setActiveManifest(join(cwd, "does-not-exist.yaml"), { cwd });
79
+ }
80
+ catch {
81
+ threw = true;
82
+ }
83
+ if (!threw)
84
+ throw new Error("expected throw on non-existent path");
85
+ });
86
+ });
87
+ test("set with skipExistsCheck allows missing path (for tests)", () => {
88
+ withTmpProject((cwd) => {
89
+ const r = setActiveManifest(join(cwd, "future.yaml"), { cwd, skipExistsCheck: true });
90
+ if (!r.manifest_path.endsWith("future.yaml")) {
91
+ throw new Error("path not set");
92
+ }
93
+ });
94
+ });
95
+ test("clear when not set returns false (idempotent)", () => {
96
+ withTmpProject((cwd) => {
97
+ const r = clearActiveManifest(cwd);
98
+ if (r !== false)
99
+ throw new Error(`expected false, got ${r}`);
100
+ });
101
+ });
102
+ test("set + clear + get returns null", () => {
103
+ withTmpProject((cwd, manifestPath) => {
104
+ setActiveManifest(manifestPath, { cwd });
105
+ const cleared = clearActiveManifest(cwd);
106
+ if (cleared !== true)
107
+ throw new Error("clear should return true after a set");
108
+ const got = getActiveManifest(cwd);
109
+ if (got !== null)
110
+ throw new Error("expected null after clear");
111
+ });
112
+ });
113
+ test("corrupt JSON throws on get (no silent degradation)", () => {
114
+ withTmpProject((cwd) => {
115
+ const stateDir = join(cwd, ".forge", "state");
116
+ mkdirSync(stateDir, { recursive: true });
117
+ writeFileSync(join(stateDir, "active-manifest.json"), "{ this is not valid json }");
118
+ let threw = false;
119
+ try {
120
+ getActiveManifest(cwd);
121
+ }
122
+ catch (e) {
123
+ threw = true;
124
+ const msg = e instanceof Error ? e.message : String(e);
125
+ if (!msg.includes("corrupt")) {
126
+ throw new Error(`expected 'corrupt' in error message, got: ${msg}`);
127
+ }
128
+ }
129
+ if (!threw)
130
+ throw new Error("expected throw on corrupt JSON");
131
+ });
132
+ });
133
+ test("missing required fields throws on get", () => {
134
+ withTmpProject((cwd) => {
135
+ const stateDir = join(cwd, ".forge", "state");
136
+ mkdirSync(stateDir, { recursive: true });
137
+ writeFileSync(join(stateDir, "active-manifest.json"), JSON.stringify({ manifest_path: "x" }));
138
+ let threw = false;
139
+ try {
140
+ getActiveManifest(cwd);
141
+ }
142
+ catch (e) {
143
+ threw = true;
144
+ const msg = e instanceof Error ? e.message : String(e);
145
+ if (!msg.includes("missing required fields")) {
146
+ throw new Error(`expected 'missing required fields', got: ${msg}`);
147
+ }
148
+ }
149
+ if (!threw)
150
+ throw new Error("expected throw on missing fields");
151
+ });
152
+ });
153
+ test("atomic write: pointer file ends with newline + valid JSON", () => {
154
+ withTmpProject((cwd, manifestPath) => {
155
+ setActiveManifest(manifestPath, { cwd });
156
+ const path = getActivePointerPath(cwd);
157
+ const raw = readFileSync(path, "utf-8");
158
+ if (!raw.endsWith("\n"))
159
+ throw new Error("pointer file should end with newline");
160
+ JSON.parse(raw); // throws if invalid
161
+ });
162
+ });
163
+ test("set rejects directory paths (not a regular file)", () => {
164
+ withTmpProject((cwd) => {
165
+ let threw = false;
166
+ try {
167
+ setActiveManifest(cwd, { cwd });
168
+ }
169
+ catch (e) {
170
+ threw = true;
171
+ const msg = e instanceof Error ? e.message : String(e);
172
+ if (!msg.includes("not a regular file")) {
173
+ throw new Error(`expected 'not a regular file', got: ${msg}`);
174
+ }
175
+ }
176
+ if (!threw)
177
+ throw new Error("expected throw on directory path");
178
+ });
179
+ });
180
+ test("get throws when pointed-to manifest has been deleted", () => {
181
+ withTmpProject((cwd, manifestPath) => {
182
+ setActiveManifest(manifestPath, { cwd });
183
+ rmSync(manifestPath); // simulate deletion / branch switch
184
+ let threw = false;
185
+ try {
186
+ getActiveManifest(cwd);
187
+ }
188
+ catch (e) {
189
+ threw = true;
190
+ const msg = e instanceof Error ? e.message : String(e);
191
+ if (!msg.includes("cannot be read")) {
192
+ throw new Error(`expected 'cannot be read', got: ${msg}`);
193
+ }
194
+ }
195
+ if (!threw)
196
+ throw new Error("expected throw on stale pointer");
197
+ });
198
+ });
199
+ test("get throws when manifest_path is relative in pointer JSON", () => {
200
+ withTmpProject((cwd) => {
201
+ const stateDir = join(cwd, ".forge", "state");
202
+ mkdirSync(stateDir, { recursive: true });
203
+ writeFileSync(join(stateDir, "active-manifest.json"), JSON.stringify({ manifest_path: "relative/path.yaml", set_at: "2026-05-04T00:00:00Z", set_by: "test" }));
204
+ let threw = false;
205
+ try {
206
+ getActiveManifest(cwd);
207
+ }
208
+ catch (e) {
209
+ threw = true;
210
+ const msg = e instanceof Error ? e.message : String(e);
211
+ if (!msg.includes("must be absolute")) {
212
+ throw new Error(`expected 'must be absolute', got: ${msg}`);
213
+ }
214
+ }
215
+ if (!threw)
216
+ throw new Error("expected throw on relative manifest_path");
217
+ });
218
+ });
219
+ test("get throws when manifest_path is wrong type (e.g. number)", () => {
220
+ withTmpProject((cwd) => {
221
+ const stateDir = join(cwd, ".forge", "state");
222
+ mkdirSync(stateDir, { recursive: true });
223
+ writeFileSync(join(stateDir, "active-manifest.json"), JSON.stringify({ manifest_path: 42, set_at: "2026-05-04T00:00:00Z", set_by: "test" }));
224
+ let threw = false;
225
+ try {
226
+ getActiveManifest(cwd);
227
+ }
228
+ catch (e) {
229
+ threw = true;
230
+ const msg = e instanceof Error ? e.message : String(e);
231
+ if (!msg.includes("wrong types") && !msg.includes("missing required fields")) {
232
+ throw new Error(`expected type-validation error, got: ${msg}`);
233
+ }
234
+ }
235
+ if (!threw)
236
+ throw new Error("expected throw on wrong type");
237
+ });
238
+ });
239
+ test("set + clear leaves no orphan tmp files", () => {
240
+ withTmpProject((cwd, manifestPath) => {
241
+ setActiveManifest(manifestPath, { cwd });
242
+ clearActiveManifest(cwd);
243
+ const stateDir = join(cwd, ".forge", "state");
244
+ const entries = readdirSync(stateDir);
245
+ const orphans = entries.filter((e) => e.includes(".tmp"));
246
+ if (orphans.length > 0)
247
+ throw new Error(`found orphan tmp files: ${orphans.join(", ")}`);
248
+ });
249
+ });
250
+ test("set replaces existing pointer (last writer wins)", () => {
251
+ withTmpProject((cwd, manifestPath) => {
252
+ const otherManifest = join(cwd, "other.yaml");
253
+ writeFileSync(otherManifest, "schema_version: \"5\"\n");
254
+ setActiveManifest(manifestPath, { cwd, setBy: "first" });
255
+ setActiveManifest(otherManifest, { cwd, setBy: "second" });
256
+ const got = getActiveManifest(cwd);
257
+ if (!got)
258
+ throw new Error("expected pointer");
259
+ if (got.manifest_path !== otherManifest) {
260
+ throw new Error(`expected second writer to win, got ${got.manifest_path}`);
261
+ }
262
+ if (got.set_by !== "second")
263
+ throw new Error(`set_by should be 'second', got ${got.set_by}`);
264
+ });
265
+ });
266
+ console.log(`\n=== ${passed} passed, ${failed} failed ===`);
267
+ if (failed > 0) {
268
+ console.log("\nFailures:");
269
+ fails.forEach((f) => console.log(" - " + f));
270
+ process.exit(1);
271
+ }
272
+ process.exit(0);