mindforge-cc 1.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 (324) hide show
  1. package/.agent/CLAUDE.md +462 -0
  2. package/.agent/forge/help.md +7 -0
  3. package/.agent/forge/init-project.md +32 -0
  4. package/.agent/forge/plan-phase.md +30 -0
  5. package/.agent/mindforge/approve.md +18 -0
  6. package/.agent/mindforge/audit.md +30 -0
  7. package/.agent/mindforge/benchmark.md +33 -0
  8. package/.agent/mindforge/complete-milestone.md +18 -0
  9. package/.agent/mindforge/debug.md +126 -0
  10. package/.agent/mindforge/discuss-phase.md +138 -0
  11. package/.agent/mindforge/execute-phase.md +165 -0
  12. package/.agent/mindforge/health.md +21 -0
  13. package/.agent/mindforge/help.md +23 -0
  14. package/.agent/mindforge/init-org.md +131 -0
  15. package/.agent/mindforge/init-project.md +155 -0
  16. package/.agent/mindforge/install-skill.md +15 -0
  17. package/.agent/mindforge/map-codebase.md +298 -0
  18. package/.agent/mindforge/metrics.md +22 -0
  19. package/.agent/mindforge/migrate.md +40 -0
  20. package/.agent/mindforge/milestone.md +12 -0
  21. package/.agent/mindforge/next.md +105 -0
  22. package/.agent/mindforge/plan-phase.md +125 -0
  23. package/.agent/mindforge/plugins.md +40 -0
  24. package/.agent/mindforge/pr-review.md +41 -0
  25. package/.agent/mindforge/profile-team.md +23 -0
  26. package/.agent/mindforge/publish-skill.md +19 -0
  27. package/.agent/mindforge/quick.md +135 -0
  28. package/.agent/mindforge/release.md +10 -0
  29. package/.agent/mindforge/retrospective.md +26 -0
  30. package/.agent/mindforge/review.md +157 -0
  31. package/.agent/mindforge/security-scan.md +233 -0
  32. package/.agent/mindforge/ship.md +100 -0
  33. package/.agent/mindforge/skills.md +141 -0
  34. package/.agent/mindforge/status.md +104 -0
  35. package/.agent/mindforge/sync-confluence.md +11 -0
  36. package/.agent/mindforge/sync-jira.md +12 -0
  37. package/.agent/mindforge/tokens.md +8 -0
  38. package/.agent/mindforge/update.md +42 -0
  39. package/.agent/mindforge/verify-phase.md +62 -0
  40. package/.agent/mindforge/workspace.md +29 -0
  41. package/.claude/CLAUDE.md +462 -0
  42. package/.claude/commands/forge/help.md +7 -0
  43. package/.claude/commands/forge/init-project.md +32 -0
  44. package/.claude/commands/forge/plan-phase.md +30 -0
  45. package/.claude/commands/mindforge/approve.md +18 -0
  46. package/.claude/commands/mindforge/audit.md +30 -0
  47. package/.claude/commands/mindforge/benchmark.md +33 -0
  48. package/.claude/commands/mindforge/complete-milestone.md +18 -0
  49. package/.claude/commands/mindforge/debug.md +126 -0
  50. package/.claude/commands/mindforge/discuss-phase.md +138 -0
  51. package/.claude/commands/mindforge/execute-phase.md +165 -0
  52. package/.claude/commands/mindforge/health.md +21 -0
  53. package/.claude/commands/mindforge/help.md +23 -0
  54. package/.claude/commands/mindforge/init-org.md +131 -0
  55. package/.claude/commands/mindforge/init-project.md +155 -0
  56. package/.claude/commands/mindforge/install-skill.md +15 -0
  57. package/.claude/commands/mindforge/map-codebase.md +298 -0
  58. package/.claude/commands/mindforge/metrics.md +22 -0
  59. package/.claude/commands/mindforge/migrate.md +40 -0
  60. package/.claude/commands/mindforge/milestone.md +12 -0
  61. package/.claude/commands/mindforge/next.md +105 -0
  62. package/.claude/commands/mindforge/plan-phase.md +125 -0
  63. package/.claude/commands/mindforge/plugins.md +40 -0
  64. package/.claude/commands/mindforge/pr-review.md +41 -0
  65. package/.claude/commands/mindforge/profile-team.md +23 -0
  66. package/.claude/commands/mindforge/publish-skill.md +19 -0
  67. package/.claude/commands/mindforge/quick.md +135 -0
  68. package/.claude/commands/mindforge/release.md +10 -0
  69. package/.claude/commands/mindforge/retrospective.md +26 -0
  70. package/.claude/commands/mindforge/review.md +157 -0
  71. package/.claude/commands/mindforge/security-scan.md +233 -0
  72. package/.claude/commands/mindforge/ship.md +100 -0
  73. package/.claude/commands/mindforge/skills.md +141 -0
  74. package/.claude/commands/mindforge/status.md +104 -0
  75. package/.claude/commands/mindforge/sync-confluence.md +11 -0
  76. package/.claude/commands/mindforge/sync-jira.md +12 -0
  77. package/.claude/commands/mindforge/tokens.md +8 -0
  78. package/.claude/commands/mindforge/update.md +42 -0
  79. package/.claude/commands/mindforge/verify-phase.md +62 -0
  80. package/.claude/commands/mindforge/workspace.md +29 -0
  81. package/.forge/org/CONVENTIONS.md +0 -0
  82. package/.forge/org/ORG.md +0 -0
  83. package/.forge/org/SECURITY.md +0 -0
  84. package/.forge/org/TOOLS.md +0 -0
  85. package/.forge/personas/analyst.md +0 -0
  86. package/.forge/personas/architect.md +0 -0
  87. package/.forge/personas/debug-specialist.md +0 -0
  88. package/.forge/personas/developer.md +26 -0
  89. package/.forge/personas/qa-engineer.md +0 -0
  90. package/.forge/personas/release-manager.md +0 -0
  91. package/.forge/personas/security-reviewer.md +33 -0
  92. package/.forge/personas/tech-writer.md +0 -0
  93. package/.forge/skills/api-design/SKILL.md +0 -0
  94. package/.forge/skills/code-quality/SKILL.md +0 -0
  95. package/.forge/skills/documentation/SKILL.md +0 -0
  96. package/.forge/skills/security-review/SKILL.md +23 -0
  97. package/.forge/skills/testing-standards/SKILL.md +27 -0
  98. package/.github/workflows/mindforge-ci.yml +224 -0
  99. package/.gitlab-ci-mindforge.yml +18 -0
  100. package/.mindforge/MINDFORGE-SCHEMA.json +165 -0
  101. package/.mindforge/audit/AUDIT-SCHEMA.md +451 -0
  102. package/.mindforge/ci/ci-config-schema.md +21 -0
  103. package/.mindforge/ci/ci-mode.md +179 -0
  104. package/.mindforge/ci/github-actions-adapter.md +224 -0
  105. package/.mindforge/ci/gitlab-ci-adapter.md +31 -0
  106. package/.mindforge/ci/jenkins-adapter.md +44 -0
  107. package/.mindforge/distribution/registry-client.md +166 -0
  108. package/.mindforge/distribution/registry-schema.md +96 -0
  109. package/.mindforge/distribution/skill-publisher.md +44 -0
  110. package/.mindforge/distribution/skill-validator.md +74 -0
  111. package/.mindforge/engine/compaction-protocol.md +182 -0
  112. package/.mindforge/engine/context-injector.md +128 -0
  113. package/.mindforge/engine/dependency-parser.md +113 -0
  114. package/.mindforge/engine/skills/conflict-resolver.md +69 -0
  115. package/.mindforge/engine/skills/loader.md +184 -0
  116. package/.mindforge/engine/skills/registry.md +98 -0
  117. package/.mindforge/engine/skills/versioning.md +75 -0
  118. package/.mindforge/engine/verification-pipeline.md +111 -0
  119. package/.mindforge/engine/wave-executor.md +235 -0
  120. package/.mindforge/governance/GOVERNANCE-CONFIG.md +17 -0
  121. package/.mindforge/governance/approval-workflow.md +37 -0
  122. package/.mindforge/governance/change-classifier.md +63 -0
  123. package/.mindforge/governance/compliance-gates.md +31 -0
  124. package/.mindforge/integrations/confluence.md +27 -0
  125. package/.mindforge/integrations/connection-manager.md +163 -0
  126. package/.mindforge/integrations/github.md +25 -0
  127. package/.mindforge/integrations/gitlab.md +13 -0
  128. package/.mindforge/integrations/jira.md +102 -0
  129. package/.mindforge/integrations/slack.md +41 -0
  130. package/.mindforge/intelligence/antipattern-detector.md +75 -0
  131. package/.mindforge/intelligence/difficulty-scorer.md +55 -0
  132. package/.mindforge/intelligence/health-engine.md +208 -0
  133. package/.mindforge/intelligence/skill-gap-analyser.md +40 -0
  134. package/.mindforge/intelligence/smart-compaction.md +71 -0
  135. package/.mindforge/metrics/METRICS-SCHEMA.md +42 -0
  136. package/.mindforge/metrics/quality-tracker.md +32 -0
  137. package/.mindforge/monorepo/cross-package-planner.md +114 -0
  138. package/.mindforge/monorepo/dependency-graph-builder.md +32 -0
  139. package/.mindforge/monorepo/workspace-detector.md +129 -0
  140. package/.mindforge/org/CONVENTIONS.md +62 -0
  141. package/.mindforge/org/ORG.md +51 -0
  142. package/.mindforge/org/SECURITY.md +50 -0
  143. package/.mindforge/org/TOOLS.md +53 -0
  144. package/.mindforge/org/integrations/INTEGRATIONS-CONFIG.md +58 -0
  145. package/.mindforge/org/skills/MANIFEST.md +38 -0
  146. package/.mindforge/personas/analyst.md +52 -0
  147. package/.mindforge/personas/architect.md +75 -0
  148. package/.mindforge/personas/debug-specialist.md +52 -0
  149. package/.mindforge/personas/developer.md +85 -0
  150. package/.mindforge/personas/overrides/README.md +85 -0
  151. package/.mindforge/personas/qa-engineer.md +61 -0
  152. package/.mindforge/personas/release-manager.md +76 -0
  153. package/.mindforge/personas/security-reviewer.md +91 -0
  154. package/.mindforge/personas/tech-writer.md +51 -0
  155. package/.mindforge/plugins/PLUGINS-MANIFEST.md +23 -0
  156. package/.mindforge/plugins/plugin-loader.md +93 -0
  157. package/.mindforge/plugins/plugin-registry.md +44 -0
  158. package/.mindforge/plugins/plugin-schema.md +68 -0
  159. package/.mindforge/pr-review/ai-reviewer.md +266 -0
  160. package/.mindforge/pr-review/finding-formatter.md +46 -0
  161. package/.mindforge/pr-review/review-prompt-templates.md +44 -0
  162. package/.mindforge/production/compatibility-layer.md +39 -0
  163. package/.mindforge/production/migration-engine.md +52 -0
  164. package/.mindforge/production/production-checklist.md +165 -0
  165. package/.mindforge/production/token-optimiser.md +68 -0
  166. package/.mindforge/skills/accessibility/SKILL.md +106 -0
  167. package/.mindforge/skills/api-design/SKILL.md +98 -0
  168. package/.mindforge/skills/code-quality/SKILL.md +88 -0
  169. package/.mindforge/skills/data-privacy/SKILL.md +126 -0
  170. package/.mindforge/skills/database-patterns/SKILL.md +192 -0
  171. package/.mindforge/skills/documentation/SKILL.md +91 -0
  172. package/.mindforge/skills/incident-response/SKILL.md +180 -0
  173. package/.mindforge/skills/performance/SKILL.md +120 -0
  174. package/.mindforge/skills/security-review/SKILL.md +83 -0
  175. package/.mindforge/skills/testing-standards/SKILL.md +97 -0
  176. package/.mindforge/team/TEAM-PROFILE.md +42 -0
  177. package/.mindforge/team/multi-handoff.md +23 -0
  178. package/.mindforge/team/profiles/README.md +13 -0
  179. package/.mindforge/team/session-merger.md +18 -0
  180. package/.planning/ARCHITECTURE.md +0 -0
  181. package/.planning/AUDIT.jsonl +0 -0
  182. package/.planning/HANDOFF.json +28 -0
  183. package/.planning/PROJECT.md +33 -0
  184. package/.planning/RELEASE-CHECKLIST.md +68 -0
  185. package/.planning/REQUIREMENTS.md +0 -0
  186. package/.planning/ROADMAP.md +0 -0
  187. package/.planning/STATE.md +31 -0
  188. package/.planning/approvals/.gitkeep +1 -0
  189. package/.planning/archive/.gitkeep +1 -0
  190. package/.planning/audit-archive/.gitkeep +1 -0
  191. package/.planning/decisions/.gitkeep +0 -0
  192. package/.planning/decisions/ADR-001-handoff-tracking.md +41 -0
  193. package/.planning/decisions/ADR-002-markdown-commands.md +46 -0
  194. package/.planning/decisions/ADR-003-skills-trigger-model.md +37 -0
  195. package/.planning/decisions/ADR-004-wave-parallelism-model.md +45 -0
  196. package/.planning/decisions/ADR-005-append-only-audit-log.md +51 -0
  197. package/.planning/decisions/ADR-006-tiered-skills-system.md +22 -0
  198. package/.planning/decisions/ADR-007-trigger-keyword-model.md +22 -0
  199. package/.planning/decisions/ADR-008-just-in-time-skill-loading.md +29 -0
  200. package/.planning/decisions/ADR-009-enterprise-integration-retry-policy.md +8 -0
  201. package/.planning/decisions/ADR-010-governance-tier-escalation.md +8 -0
  202. package/.planning/decisions/ADR-011-multi-developer-handoff-contract.md +8 -0
  203. package/.planning/decisions/ADR-012-intelligence-feedback-loops.md +19 -0
  204. package/.planning/decisions/ADR-013-mindforge-md-constitution.md +16 -0
  205. package/.planning/decisions/ADR-014-metrics-as-signals-not-evaluation.md +15 -0
  206. package/.planning/decisions/ADR-015-npm-based-skill-registry.md +26 -0
  207. package/.planning/decisions/ADR-016-ci-exit-code-0-on-timeout.md +27 -0
  208. package/.planning/decisions/ADR-017-sdk-localhost-only.md +28 -0
  209. package/.planning/decisions/ADR-018-installer-self-install-detection.md +15 -0
  210. package/.planning/decisions/ADR-019-self-update-scope-preservation.md +14 -0
  211. package/.planning/decisions/ADR-020-v1.0.0-stable-interface-contract.md +23 -0
  212. package/.planning/jira-sync.json +9 -0
  213. package/.planning/milestones/.gitkeep +1 -0
  214. package/.planning/phases/day1/REVIEW-DAY1.md +50 -0
  215. package/.planning/phases/day1/SECURITY-REVIEW-DAY1.md +15 -0
  216. package/.planning/phases/day2/REVIEW-DAY2.md +521 -0
  217. package/.planning/phases/day3/REVIEW-DAY3.md +234 -0
  218. package/.planning/slack-threads.json +6 -0
  219. package/CHANGELOG.md +175 -0
  220. package/LICENSE +21 -0
  221. package/MINDFORGE.md +76 -0
  222. package/README.md +182 -0
  223. package/RELEASENOTES.md +41 -0
  224. package/SECURITY.md +4 -0
  225. package/bin/install.js +120 -0
  226. package/bin/installer-core.js +292 -0
  227. package/bin/migrations/0.1.0-to-0.5.0.js +37 -0
  228. package/bin/migrations/0.5.0-to-0.6.0.js +17 -0
  229. package/bin/migrations/0.6.0-to-1.0.0.js +100 -0
  230. package/bin/migrations/migrate.js +151 -0
  231. package/bin/migrations/schema-versions.js +64 -0
  232. package/bin/updater/changelog-fetcher.js +62 -0
  233. package/bin/updater/self-update.js +169 -0
  234. package/bin/updater/version-comparator.js +68 -0
  235. package/bin/validate-config.js +92 -0
  236. package/bin/wizard/config-generator.js +112 -0
  237. package/bin/wizard/environment-detector.js +76 -0
  238. package/bin/wizard/setup-wizard.js +237 -0
  239. package/docs/Context/Master-Context.md +701 -0
  240. package/docs/architecture/README.md +35 -0
  241. package/docs/architecture/decision-records-index.md +26 -0
  242. package/docs/ci-cd-integration.md +30 -0
  243. package/docs/ci-quickstart.md +78 -0
  244. package/docs/commands-reference.md +11 -0
  245. package/docs/contributing/CONTRIBUTING.md +38 -0
  246. package/docs/contributing/plugin-authoring.md +50 -0
  247. package/docs/contributing/skill-authoring.md +41 -0
  248. package/docs/enterprise-setup.md +25 -0
  249. package/docs/faq.md +38 -0
  250. package/docs/getting-started.md +36 -0
  251. package/docs/governance-guide.md +23 -0
  252. package/docs/mindforge-md-reference.md +53 -0
  253. package/docs/monorepo-guide.md +26 -0
  254. package/docs/persona-customisation.md +56 -0
  255. package/docs/quick-verify.md +33 -0
  256. package/docs/reference/audit-events.md +53 -0
  257. package/docs/reference/commands.md +82 -0
  258. package/docs/reference/config-reference.md +64 -0
  259. package/docs/reference/sdk-api.md +48 -0
  260. package/docs/reference/skills-api.md +57 -0
  261. package/docs/release-checklist-guide.md +37 -0
  262. package/docs/requirements.md +29 -0
  263. package/docs/sdk-reference.md +27 -0
  264. package/docs/security/SECURITY.md +42 -0
  265. package/docs/security/penetration-test-results.md +31 -0
  266. package/docs/security/threat-model.md +142 -0
  267. package/docs/skills-authoring-guide.md +119 -0
  268. package/docs/skills-publishing-guide.md +21 -0
  269. package/docs/team-setup-guide.md +21 -0
  270. package/docs/troubleshooting.md +119 -0
  271. package/docs/tutorial.md +195 -0
  272. package/docs/upgrade.md +44 -0
  273. package/docs/user-guide.md +131 -0
  274. package/docs/usp-features.md +214 -0
  275. package/eslint.config.mjs +31 -0
  276. package/examples/starter-project/.planning/AUDIT.jsonl +1 -0
  277. package/examples/starter-project/.planning/HANDOFF.json +23 -0
  278. package/examples/starter-project/.planning/PROJECT.md +27 -0
  279. package/examples/starter-project/.planning/STATE.md +10 -0
  280. package/examples/starter-project/MINDFORGE.md +40 -0
  281. package/examples/starter-project/README.md +14 -0
  282. package/implementation-roadmap/day-1-imp/DAY1-HARDEN.md +823 -0
  283. package/implementation-roadmap/day-1-imp/DAY1-IMPLEMENT.md +2459 -0
  284. package/implementation-roadmap/day-1-imp/DAY1-REVIEW.md +288 -0
  285. package/implementation-roadmap/day-2-imp/DAY2-HARDEN.md +954 -0
  286. package/implementation-roadmap/day-2-imp/DAY2-IMPLEMENT.md +2347 -0
  287. package/implementation-roadmap/day-2-imp/DAY2-REVIEW.md +422 -0
  288. package/implementation-roadmap/day-3-imp/DAY3-HARDEN.md +870 -0
  289. package/implementation-roadmap/day-3-imp/DAY3-IMPLEMENT.md +2798 -0
  290. package/implementation-roadmap/day-3-imp/DAY3-REVIEW.md +484 -0
  291. package/implementation-roadmap/day-4-imp/DAY4-HARDEN.md +1087 -0
  292. package/implementation-roadmap/day-4-imp/DAY4-IMPLEMENT.md +2874 -0
  293. package/implementation-roadmap/day-4-imp/DAY4-REVIEW.md +386 -0
  294. package/implementation-roadmap/day-5-imp/DAY5-HARDEN.md +1078 -0
  295. package/implementation-roadmap/day-5-imp/DAY5-IMPLEMENT.md +3151 -0
  296. package/implementation-roadmap/day-5-imp/DAY5-REVIEW.md +345 -0
  297. package/implementation-roadmap/day-6-imp/DAY6-COMPLETE.md +3919 -0
  298. package/implementation-roadmap/day-7-imp-prod/DAY7-PRODUCTION-FINAL.md +4513 -0
  299. package/package.json +31 -0
  300. package/sdk/README.md +69 -0
  301. package/sdk/eslint.config.mjs +34 -0
  302. package/sdk/package-lock.json +1507 -0
  303. package/sdk/package.json +30 -0
  304. package/sdk/src/client.ts +133 -0
  305. package/sdk/src/commands.ts +63 -0
  306. package/sdk/src/events.ts +166 -0
  307. package/sdk/src/index.ts +22 -0
  308. package/sdk/src/types.ts +87 -0
  309. package/sdk/tsconfig.json +13 -0
  310. package/tests/audit.test.js +206 -0
  311. package/tests/ci-mode.test.js +162 -0
  312. package/tests/compaction.test.js +161 -0
  313. package/tests/distribution.test.js +205 -0
  314. package/tests/e2e.test.js +618 -0
  315. package/tests/governance.test.js +130 -0
  316. package/tests/install.test.js +209 -0
  317. package/tests/integrations.test.js +128 -0
  318. package/tests/intelligence.test.js +117 -0
  319. package/tests/metrics.test.js +96 -0
  320. package/tests/migration.test.js +309 -0
  321. package/tests/production.test.js +416 -0
  322. package/tests/sdk.test.js +200 -0
  323. package/tests/skills-platform.test.js +403 -0
  324. package/tests/wave-engine.test.js +338 -0
@@ -0,0 +1,3919 @@
1
+ # MindForge — Day 6: Distribution, CI, SDK & Scale
2
+ # Branch: `feat/mindforge-distribution-platform`
3
+ # Prerequisite: `feat/mindforge-intelligence-layer` merged to `main`
4
+ # Version target: v0.6.0
5
+
6
+ ---
7
+
8
+ ## BRANCH SETUP
9
+
10
+ ```bash
11
+ git checkout main
12
+ git pull origin main
13
+ git checkout -b feat/mindforge-distribution-platform
14
+ ```
15
+
16
+ Verify all prior days are present and all 9 test suites pass:
17
+
18
+ ```bash
19
+ cat package.json | grep '"version"' # Must be "0.5.0"
20
+ node tests/install.test.js && \
21
+ node tests/wave-engine.test.js && \
22
+ node tests/audit.test.js && \
23
+ node tests/compaction.test.js && \
24
+ node tests/skills-platform.test.js && \
25
+ node tests/integrations.test.js && \
26
+ node tests/governance.test.js && \
27
+ node tests/intelligence.test.js && \
28
+ node tests/metrics.test.js
29
+ ```
30
+
31
+ ---
32
+
33
+ ## DAY 6 SCOPE
34
+
35
+ Day 6 builds the **Distribution, CI/CD, and Scale Layer** — making MindForge
36
+ a platform that organisations can publish to, integrate into pipelines, embed
37
+ in tools, and run at organisation-wide scale.
38
+
39
+ | Component | Description |
40
+ |---|---|
41
+ | Public Skills Registry | `npx mindforge-skills install/publish/search` — npm-based skill distribution |
42
+ | Monorepo & Multi-repo Support | Workspace-aware execution across packages/apps |
43
+ | MindForge CI Mode | Non-interactive execution in GitHub Actions / GitLab CI / Jenkins |
44
+ | AI-Generated PR Reviews | Claude API-powered code review with structured findings |
45
+ | `/mindforge:init-org` | Organisation-wide MindForge setup and standardisation |
46
+ | MindForge SDK | Programmatic TypeScript API for embedding in tools |
47
+ | MINDFORGE.md Schema Validation | JSON Schema validator for config file correctness |
48
+ | Real-time Progress Streaming | SSE-based progress events for tooling integration |
49
+ | Skill Quality Benchmarking | Automated skill effectiveness measurement |
50
+ | Day 6 test suites | `tests/distribution.test.js`, `tests/ci-mode.test.js`, `tests/sdk.test.js` |
51
+
52
+ ---
53
+
54
+ # ═══════════════════════════════════════════════════════════════
55
+ # PART 1: IMPLEMENTATION PROMPT
56
+ # ═══════════════════════════════════════════════════════════════
57
+
58
+ ---
59
+
60
+ ## TASK 1 — Scaffold Day 6 directory additions
61
+
62
+ ```bash
63
+ # Distribution engine
64
+ mkdir -p .mindforge/distribution
65
+ touch .mindforge/distribution/registry-client.md
66
+ touch .mindforge/distribution/skill-publisher.md
67
+ touch .mindforge/distribution/skill-validator.md
68
+ touch .mindforge/distribution/registry-schema.md
69
+
70
+ # CI/CD engine
71
+ mkdir -p .mindforge/ci
72
+ touch .mindforge/ci/ci-mode.md
73
+ touch .mindforge/ci/github-actions-adapter.md
74
+ touch .mindforge/ci/gitlab-ci-adapter.md
75
+ touch .mindforge/ci/jenkins-adapter.md
76
+ touch .mindforge/ci/ci-config-schema.md
77
+
78
+ # Monorepo support
79
+ mkdir -p .mindforge/monorepo
80
+ touch .mindforge/monorepo/workspace-detector.md
81
+ touch .mindforge/monorepo/cross-package-planner.md
82
+ touch .mindforge/monorepo/dependency-graph-builder.md
83
+
84
+ # SDK
85
+ mkdir -p sdk/src
86
+ touch sdk/src/index.ts
87
+ touch sdk/src/types.ts
88
+ touch sdk/src/client.ts
89
+ touch sdk/src/commands.ts
90
+ touch sdk/src/events.ts
91
+ touch sdk/package.json
92
+ touch sdk/tsconfig.json
93
+ touch sdk/README.md
94
+
95
+ # AI PR Review engine
96
+ mkdir -p .mindforge/pr-review
97
+ touch .mindforge/pr-review/ai-reviewer.md
98
+ touch .mindforge/pr-review/review-prompt-templates.md
99
+ touch .mindforge/pr-review/finding-formatter.md
100
+
101
+ # MINDFORGE.md schema
102
+ touch .mindforge/MINDFORGE-SCHEMA.json
103
+ touch bin/validate-config.js
104
+
105
+ # New commands
106
+ touch .claude/commands/mindforge/init-org.md
107
+ touch .claude/commands/mindforge/publish-skill.md
108
+ touch .claude/commands/mindforge/install-skill.md
109
+ touch .claude/commands/mindforge/pr-review.md
110
+ touch .claude/commands/mindforge/workspace.md
111
+ touch .claude/commands/mindforge/benchmark.md
112
+
113
+ # Mirror to Antigravity
114
+ for cmd in init-org publish-skill install-skill pr-review workspace benchmark; do
115
+ cp .claude/commands/mindforge/${cmd}.md .agent/mindforge/${cmd}.md
116
+ done
117
+
118
+ # CI config templates
119
+ mkdir -p .github/workflows
120
+ touch .github/workflows/mindforge-ci.yml
121
+ touch .gitlab-ci-mindforge.yml
122
+
123
+ # Tests
124
+ touch tests/distribution.test.js
125
+ touch tests/ci-mode.test.js
126
+ touch tests/sdk.test.js
127
+
128
+ # Docs
129
+ touch docs/ci-cd-integration.md
130
+ touch docs/sdk-reference.md
131
+ touch docs/skills-publishing-guide.md
132
+ touch docs/monorepo-guide.md
133
+ ```
134
+
135
+ **Commit:**
136
+ ```bash
137
+ git add .
138
+ git commit -m "chore(day6): scaffold Day 6 distribution platform directory structure"
139
+ ```
140
+
141
+ ---
142
+
143
+ ## TASK 2 — Write the Public Skills Registry
144
+
145
+ ### `.mindforge/distribution/registry-schema.md`
146
+
147
+ ```markdown
148
+ # MindForge Skills Registry — Schema & Protocol
149
+
150
+ ## Registry concept
151
+ The public MindForge Skills Registry is an npm-based distribution system.
152
+ Skills are published as npm packages with the `mindforge-skill-` prefix.
153
+ The registry leverages the existing npm ecosystem for versioning, discovery,
154
+ and distribution.
155
+
156
+ ## Package naming convention
157
+ ```
158
+ mindforge-skill-[category]-[name]
159
+ ```
160
+
161
+ Examples:
162
+ - `mindforge-skill-security-owasp` — OWASP security review skill
163
+ - `mindforge-skill-db-postgres-patterns` — PostgreSQL-specific patterns
164
+ - `mindforge-skill-frontend-react-a11y` — React accessibility patterns
165
+ - `mindforge-skill-testing-playwright` — Playwright E2E testing patterns
166
+ - `mindforge-skill-api-graphql` — GraphQL API design patterns
167
+
168
+ ## Package structure
169
+
170
+ ```
171
+ mindforge-skill-[category]-[name]/
172
+ ├── SKILL.md ← The skill file (required)
173
+ ├── package.json ← npm metadata
174
+ ├── README.md ← Human documentation
175
+ ├── CHANGELOG.md ← Version history
176
+ ├── examples/ ← Optional usage examples
177
+ │ └── example-task.md
178
+ ├── scripts/ ← Optional helper scripts
179
+ │ └── helper.sh
180
+ └── tests/
181
+ └── skill.test.js ← Skill validation tests
182
+ ```
183
+
184
+ ## `package.json` for a skill package
185
+
186
+ ```json
187
+ {
188
+ "name": "mindforge-skill-security-owasp",
189
+ "version": "1.2.0",
190
+ "description": "OWASP Top 10 security review skill for MindForge",
191
+ "keywords": [
192
+ "mindforge",
193
+ "mindforge-skill",
194
+ "security",
195
+ "owasp",
196
+ "agentic-framework"
197
+ ],
198
+ "mindforge": {
199
+ "type": "skill",
200
+ "skill-name": "security-owasp",
201
+ "category": "security",
202
+ "min-mindforge-version": "0.5.0",
203
+ "triggers": ["OWASP", "security review", "injection", "auth", "XSS"],
204
+ "tier-recommendation": 1
205
+ },
206
+ "files": ["SKILL.md", "README.md", "examples/", "scripts/"],
207
+ "license": "MIT",
208
+ "homepage": "https://mindforge.dev/skills/security-owasp",
209
+ "repository": { "type": "git", "url": "https://github.com/mindforge-dev/skill-security-owasp" }
210
+ }
211
+ ```
212
+
213
+ ## Registry discovery
214
+
215
+ The MindForge registry is the standard npm registry with keyword filtering:
216
+ ```bash
217
+ # Search for skills
218
+ npm search mindforge-skill [query]
219
+
220
+ # Example searches:
221
+ npm search mindforge-skill security # Find security skills
222
+ npm search mindforge-skill react # Find React-specific skills
223
+ npm search mindforge-skill testing # Find testing skills
224
+ ```
225
+
226
+ ## Registry quality standards
227
+
228
+ A skill package published to the MindForge registry must pass:
229
+ 1. Schema validation: `npx mindforge-cc validate-skill ./SKILL.md`
230
+ 2. Required metadata: package.json `mindforge` field fully populated
231
+ 3. No malicious content: npm security audit passes
232
+ 4. Version policy: follows semver with documented breaking changes
233
+ 5. License: MIT, Apache-2.0, or BSD (GPL derivatives not accepted)
234
+
235
+ ## Local registry (private skills)
236
+
237
+ Organisations with private skills can use:
238
+ - Private npm registry (Verdaccio, Artifactory, GitHub Packages)
239
+ - Configure in `.mindforge/org/integrations/INTEGRATIONS-CONFIG.md`:
240
+ ```
241
+ MINDFORGE_SKILL_REGISTRY=https://npm.your-org.internal/
242
+ ```
243
+ - Skills from private registry install with the same `npx mindforge-skills install` command
244
+ ```
245
+
246
+ ---
247
+
248
+ ### `.mindforge/distribution/registry-client.md`
249
+
250
+ ```markdown
251
+ # MindForge Skills Registry — Client Protocol
252
+
253
+ ## Purpose
254
+ Define how MindForge discovers, downloads, validates, and installs skills
255
+ from the public or private npm-based registry.
256
+
257
+ ## Installation flow
258
+
259
+ ### Step 1 — Resolve package name
260
+ ```bash
261
+ # From skill name to package name:
262
+ SKILL_NAME="security-owasp"
263
+ PACKAGE_NAME="mindforge-skill-${SKILL_NAME}"
264
+
265
+ # Or if user provides full package name:
266
+ PACKAGE_NAME="mindforge-skill-security-owasp"
267
+ ```
268
+
269
+ ### Step 2 — Check if already installed
270
+ ```bash
271
+ # Check local MANIFEST.md
272
+ grep "| ${SKILL_NAME} |" .mindforge/org/skills/MANIFEST.md && echo "Already installed"
273
+
274
+ # Check if SKILL.md exists
275
+ [ -f ".mindforge/skills/${SKILL_NAME}/SKILL.md" ] && echo "Skill file exists"
276
+ ```
277
+
278
+ ### Step 3 — Fetch from registry
279
+ ```bash
280
+ # Download to temp directory
281
+ TEMP_DIR=$(mktemp -d)
282
+ npm pack "${PACKAGE_NAME}@latest" --pack-destination "${TEMP_DIR}" --quiet
283
+
284
+ # Extract the tarball
285
+ cd "${TEMP_DIR}"
286
+ TARBALL=$(ls *.tgz | head -1)
287
+ tar -xzf "${TARBALL}" --strip-components=1 -C "${TEMP_DIR}"
288
+ ```
289
+
290
+ ### Step 4 — Validate the downloaded skill
291
+ Run the full skill validator (see `skill-validator.md`) against the downloaded SKILL.md.
292
+ If validation fails: abort installation. Never install a skill that fails validation.
293
+
294
+ ### Step 5 — Injection guard check
295
+ Run the injection guard from Day 3 (`loader.md`) against the skill content.
296
+ If injection patterns detected: abort, write AUDIT entry, alert user.
297
+
298
+ ### Step 6 — Install to correct tier location
299
+ ```bash
300
+ # Determine target tier from user input or package.json tier-recommendation
301
+ TIER="${USER_SPECIFIED_TIER:-2}"
302
+
303
+ if [ "${TIER}" = "1" ]; then
304
+ TARGET_DIR=".mindforge/skills/${SKILL_NAME}"
305
+ elif [ "${TIER}" = "2" ]; then
306
+ TARGET_DIR=".mindforge/org/skills/${SKILL_NAME}"
307
+ else
308
+ TARGET_DIR=".mindforge/project-skills/${SKILL_NAME}"
309
+ fi
310
+
311
+ mkdir -p "${TARGET_DIR}"
312
+ cp "${TEMP_DIR}/SKILL.md" "${TARGET_DIR}/SKILL.md"
313
+ [ -d "${TEMP_DIR}/examples" ] && cp -r "${TEMP_DIR}/examples" "${TARGET_DIR}/"
314
+ [ -d "${TEMP_DIR}/scripts" ] && cp -r "${TEMP_DIR}/scripts" "${TARGET_DIR}/"
315
+ ```
316
+
317
+ ### Step 7 — Register in MANIFEST.md
318
+ ```bash
319
+ # Add entry to the correct tier section of MANIFEST.md
320
+ SKILL_VERSION=$(node -e "console.log(require('${TEMP_DIR}/package.json').version)")
321
+
322
+ # Insert into MANIFEST.md under the appropriate tier section
323
+ # Format: | name | version | stable | min-mf-version | path |
324
+ ```
325
+
326
+ ### Step 8 — Clean up and report
327
+ ```bash
328
+ rm -rf "${TEMP_DIR}"
329
+ ```
330
+
331
+ Report to user:
332
+ ```
333
+ ✅ Skill installed: ${SKILL_NAME} v${SKILL_VERSION} (Tier ${TIER})
334
+ Triggers: [list from SKILL.md frontmatter]
335
+ Path: ${TARGET_DIR}/SKILL.md
336
+
337
+ Run /mindforge:skills validate to confirm installation.
338
+ ```
339
+
340
+ ### Step 9 — Write AUDIT entry
341
+ ```json
342
+ {
343
+ "event": "skill_installed",
344
+ "skill_name": "security-owasp",
345
+ "skill_version": "1.2.0",
346
+ "package_name": "mindforge-skill-security-owasp",
347
+ "tier": 2,
348
+ "source": "npm-registry | private-registry",
349
+ "validation_passed": true
350
+ }
351
+ ```
352
+
353
+ ## Update protocol
354
+
355
+ ### Check for updates
356
+ ```bash
357
+ # Compare installed version against registry latest
358
+ INSTALLED=$(grep "| ${SKILL_NAME} |" MANIFEST.md | awk -F'|' '{print $3}' | tr -d ' ')
359
+ LATEST=$(npm info "${PACKAGE_NAME}" version 2>/dev/null)
360
+
361
+ if [ "${INSTALLED}" != "${LATEST}" ]; then
362
+ echo "Update available: ${SKILL_NAME} v${INSTALLED} → v${LATEST}"
363
+ fi
364
+ ```
365
+
366
+ ### Update a skill
367
+ ```bash
368
+ # Run install flow for latest version
369
+ # If MAJOR version bump: show breaking changes, require confirmation
370
+ # If MINOR/PATCH: update silently
371
+ ```
372
+
373
+ ## Uninstall protocol
374
+ ```bash
375
+ # Remove skill files
376
+ rm -rf "${TARGET_DIR}"
377
+
378
+ # Remove from MANIFEST.md
379
+ sed -i "/| ${SKILL_NAME} |/d" .mindforge/org/skills/MANIFEST.md
380
+
381
+ # Write AUDIT entry
382
+ # Commit: "chore(skills): uninstall ${SKILL_NAME}"
383
+ ```
384
+ ```
385
+
386
+ ---
387
+
388
+ ### `.mindforge/distribution/skill-validator.md`
389
+
390
+ ```markdown
391
+ # MindForge Skills Registry — Skill Validator
392
+
393
+ ## Purpose
394
+ Validate a SKILL.md file before installation or publication.
395
+ Run as part of both `install-skill` and `publish-skill` commands.
396
+
397
+ ## Validation levels
398
+
399
+ ### Level 1 — Schema validation (always runs)
400
+ ```bash
401
+ npx mindforge-cc validate-skill ./SKILL.md
402
+ ```
403
+
404
+ Checks:
405
+ - [ ] File starts with `---` (YAML frontmatter delimiter)
406
+ - [ ] Frontmatter closes with `---`
407
+ - [ ] `name:` field present and matches kebab-case pattern `[a-z][a-z0-9-]+`
408
+ - [ ] `version:` field present and valid semver `\d+\.\d+\.\d+`
409
+ - [ ] `status:` is one of: `stable`, `beta`, `alpha`, `deprecated`
410
+ - [ ] `triggers:` field present and has >= 5 keywords
411
+ - [ ] No trigger keyword is fewer than 3 characters (too generic)
412
+ - [ ] `min_mindforge_version:` present and valid semver
413
+
414
+ ### Level 2 — Content validation (runs after schema passes)
415
+ - [ ] File size between 1KB and 200KB (not too small, not too large)
416
+ - [ ] Contains `## Mandatory actions` or `## When this skill is active` section
417
+ - [ ] Contains at least one checklist item (`- [ ]`) for self-verification
418
+ - [ ] Does not contain any injection patterns (from `loader.md` guard)
419
+ - [ ] Code examples have language specifiers in code fences (not bare ```)
420
+ - [ ] No placeholder text: `[placeholder]`, `TODO`, `[your-name]`
421
+
422
+ ### Level 3 — Quality validation (optional — runs for publication)
423
+ - [ ] At least 3 code examples
424
+ - [ ] CHANGELOG in frontmatter has at least current version entry
425
+ - [ ] `breaking_changes:` field present (even if empty list)
426
+ - [ ] Examples directory has at least one example file
427
+ - [ ] README.md exists in the package
428
+
429
+ ## Validator output
430
+
431
+ ```
432
+ MindForge Skill Validator — SKILL.md
433
+ ──────────────────────────────────────────────────────────────
434
+
435
+ Schema validation:
436
+ ✅ Frontmatter valid
437
+ ✅ name: security-owasp (valid)
438
+ ✅ version: 1.2.0 (valid semver)
439
+ ✅ status: stable
440
+ ✅ triggers: 31 keywords (min: 5)
441
+ ✅ min_mindforge_version: 0.5.0
442
+
443
+ Content validation:
444
+ ✅ File size: 8.4KB (1KB-200KB range)
445
+ ✅ Mandatory actions section present
446
+ ✅ Self-check checklist present (7 items)
447
+ ✅ No injection patterns detected
448
+ ✅ Code examples have language specifiers
449
+ ✅ No placeholder text found
450
+
451
+ Quality validation:
452
+ ✅ 5 code examples found
453
+ ✅ CHANGELOG has version 1.2.0 entry
454
+ ✅ Breaking changes documented
455
+ ⚠️ Examples directory has 1 file (recommend: 3+)
456
+
457
+ ──────────────────────────────────────────────────────────────
458
+ Result: VALID with 1 warning
459
+ Ready for: installation ✅ | publication ✅ (warning noted)
460
+ ```
461
+
462
+ ## `bin/validate-config.js` — MINDFORGE.md validator
463
+
464
+ ```javascript
465
+ #!/usr/bin/env node
466
+ /**
467
+ * MindForge configuration validator
468
+ * Validates MINDFORGE.md against the JSON schema
469
+ * Usage: node bin/validate-config.js [path-to-MINDFORGE.md]
470
+ */
471
+
472
+ 'use strict';
473
+
474
+ const fs = require('fs');
475
+ const path = require('path');
476
+
477
+ const CONFIG_PATH = process.argv[2] || 'MINDFORGE.md';
478
+ const SCHEMA_PATH = '.mindforge/MINDFORGE-SCHEMA.json';
479
+
480
+ if (!fs.existsSync(CONFIG_PATH)) {
481
+ console.log('ℹ️ MINDFORGE.md not found — using all defaults. Create one to customise.');
482
+ process.exit(0);
483
+ }
484
+
485
+ if (!fs.existsSync(SCHEMA_PATH)) {
486
+ console.log('ℹ️ MINDFORGE-SCHEMA.json not found — skipping schema validation.');
487
+ process.exit(0);
488
+ }
489
+
490
+ const content = fs.readFileSync(CONFIG_PATH, 'utf8');
491
+ const schema = JSON.parse(fs.readFileSync(SCHEMA_PATH, 'utf8'));
492
+
493
+ const errors = [];
494
+ const warnings = [];
495
+
496
+ // Parse key=value pairs from MINDFORGE.md
497
+ const settings = {};
498
+ const lines = content.split('\n');
499
+ lines.forEach(line => {
500
+ const match = line.match(/^([A-Z_]+)=(.+)$/);
501
+ if (match) {
502
+ const [, key, value] = match;
503
+ settings[key] = value.trim();
504
+ }
505
+ });
506
+
507
+ // Validate against schema
508
+ for (const [key, def] of Object.entries(schema.properties || {})) {
509
+ const value = settings[key];
510
+
511
+ if (def.required && !value) {
512
+ errors.push(`${key} is required but not set`);
513
+ continue;
514
+ }
515
+
516
+ if (!value) continue;
517
+
518
+ if (def.type === 'number') {
519
+ const num = parseFloat(value);
520
+ if (isNaN(num)) errors.push(`${key}: expected number, got "${value}"`);
521
+ if (def.minimum !== undefined && num < def.minimum)
522
+ errors.push(`${key}: ${num} is below minimum ${def.minimum}`);
523
+ if (def.maximum !== undefined && num > def.maximum)
524
+ errors.push(`${key}: ${num} exceeds maximum ${def.maximum}`);
525
+ }
526
+
527
+ if (def.type === 'enum' && !def.values.includes(value)) {
528
+ errors.push(`${key}: "${value}" is not valid. Options: ${def.values.join(', ')}`);
529
+ }
530
+
531
+ if (def.type === 'boolean' && !['true','false'].includes(value)) {
532
+ errors.push(`${key}: expected true or false, got "${value}"`);
533
+ }
534
+
535
+ if (def.nonOverridable) {
536
+ warnings.push(`${key}: this is a non-overridable governance primitive (value will be ignored)`);
537
+ }
538
+ }
539
+
540
+ // Report
541
+ const total = errors.length + warnings.length;
542
+ if (total === 0) {
543
+ console.log(`✅ MINDFORGE.md valid — ${Object.keys(settings).length} settings configured`);
544
+ process.exit(0);
545
+ }
546
+
547
+ if (errors.length) {
548
+ console.error(`❌ MINDFORGE.md has ${errors.length} error(s):`);
549
+ errors.forEach(e => console.error(` • ${e}`));
550
+ }
551
+ if (warnings.length) {
552
+ console.warn(`⚠️ MINDFORGE.md has ${warnings.length} warning(s):`);
553
+ warnings.forEach(w => console.warn(` • ${w}`));
554
+ }
555
+
556
+ process.exit(errors.length ? 1 : 0);
557
+ ```
558
+ ```
559
+
560
+ **Commit:**
561
+ ```bash
562
+ git add .mindforge/distribution/ bin/validate-config.js
563
+ git commit -m "feat(distribution): implement skills registry schema, client protocol, and validator"
564
+ ```
565
+
566
+ ---
567
+
568
+ ## TASK 3 — Write MindForge CI Mode
569
+
570
+ ### `.mindforge/ci/ci-mode.md`
571
+
572
+ ```markdown
573
+ # MindForge CI Mode
574
+
575
+ ## Purpose
576
+ Enable MindForge to run in non-interactive CI/CD environments.
577
+ CI mode is fully automated — no user prompts, no interactive approvals,
578
+ no waiting for human input. All decisions are pre-configured.
579
+
580
+ ## Activating CI mode
581
+
582
+ CI mode activates automatically when:
583
+ 1. `CI=true` environment variable is set (standard in GitHub Actions, GitLab CI, Jenkins)
584
+ 2. `MINDFORGE_CI=true` is explicitly set
585
+ 3. `process.stdin.isTTY === false` (piped or non-interactive shell)
586
+
587
+ In CI mode:
588
+ - All interactive prompts are skipped — pre-configured answers are used
589
+ - Approval workflows use the CI approval policy (see below)
590
+ - Progress output is structured JSON (parseable by CI log processors)
591
+ - Exit codes communicate status (0 = success, 1 = failure, 2 = warning)
592
+ - Slack/GitHub notifications are sent as configured (integrations still work)
593
+
594
+ ## CI mode configuration
595
+
596
+ Add to `MINDFORGE.md` for CI-specific settings:
597
+
598
+ ```
599
+ ## CI/CD configuration
600
+
601
+ # Which phases to execute in CI (comma-separated phase numbers, or "all")
602
+ CI_EXECUTE_PHASES=all
603
+
604
+ # Auto-approve Tier 2 changes in CI (default: false — safer)
605
+ CI_AUTO_APPROVE_TIER2=false
606
+
607
+ # Block CI on MEDIUM security findings (default: false)
608
+ CI_BLOCK_ON_MEDIUM_SECURITY=false
609
+
610
+ # Run full security scan in CI (default: true)
611
+ CI_SECURITY_SCAN=true
612
+
613
+ # Skip human UAT in CI — only run automated verification (default: true)
614
+ CI_SKIP_UAT=true
615
+
616
+ # Fail CI if test coverage drops below this threshold
617
+ CI_MIN_COVERAGE_PCT=80
618
+
619
+ # Timeout for entire CI run in minutes (default: 60)
620
+ CI_TIMEOUT_MINUTES=60
621
+
622
+ # Output format for CI logs: json | text | github-annotations
623
+ CI_OUTPUT_FORMAT=github-annotations
624
+ ```
625
+
626
+ ## CI approval policy
627
+
628
+ Tier 1: always auto-approved (same as interactive mode)
629
+ Tier 2: auto-approved IF `CI_AUTO_APPROVE_TIER2=true` in MINDFORGE.md
630
+ rejected (build fails) IF `CI_AUTO_APPROVE_TIER2=false`
631
+ Tier 3: ALWAYS fails the build in CI — Tier 3 changes require human review.
632
+
633
+ The CI build should never be the first time a Tier 3 change is seen.
634
+ Engineers should get Tier 3 changes approved BEFORE pushing to CI.
635
+
636
+ ## CI output format
637
+
638
+ ### JSON format (`CI_OUTPUT_FORMAT=json`)
639
+ ```json
640
+ {
641
+ "mindforge_version": "0.6.0",
642
+ "phase": 3,
643
+ "status": "running | success | failure | warning",
644
+ "timestamp": "ISO-8601",
645
+ "tasks_completed": 5,
646
+ "tasks_total": 8,
647
+ "current_task": "Plan 3-06: Implement auth middleware",
648
+ "gates": {
649
+ "secrets_clean": true,
650
+ "tests_passing": true,
651
+ "security_findings_critical": 0,
652
+ "security_findings_high": 0,
653
+ "coverage_pct": 84
654
+ },
655
+ "events": [
656
+ { "time": "ISO-8601", "type": "task_completed", "plan": "3-01", "commit": "abc1234" },
657
+ { "time": "ISO-8601", "type": "security_finding", "severity": "MEDIUM", "finding": "..." }
658
+ ]
659
+ }
660
+ ```
661
+
662
+ ### GitHub Annotations format (`CI_OUTPUT_FORMAT=github-annotations`)
663
+ ```
664
+ ::group::MindForge Phase 3 Execution
665
+ ::notice::Task 3-01 completed: Create auth middleware [abc1234]
666
+ ::notice::Task 3-02 completed: Add JWT validation [def5678]
667
+ ::warning file=src/auth/session.ts,line=47::Medium security finding: Verbose error message exposes stack trace
668
+ ::notice::Phase 3 complete: 8/8 tasks, all tests passing
669
+ ::endgroup::
670
+ ```
671
+
672
+ ### Error output
673
+ ```
674
+ ::error::MindForge CI failed: Task 3-06 verify step failed
675
+ ::error file=src/api/users.ts,line=89::TypeScript error: Type 'string' is not assignable to 'number'
676
+ ::error::Quality gate failed: test coverage 68% (minimum: 80%)
677
+ ```
678
+
679
+ ## CI environment requirements
680
+
681
+ ```bash
682
+ # Required environment variables for full CI functionality:
683
+ ANTHROPIC_API_KEY= # Claude API access (required for AI features)
684
+ GITHUB_TOKEN= # For PR creation and status checks
685
+ JIRA_API_TOKEN= # Optional — for Jira sync
686
+ SLACK_BOT_TOKEN= # Optional — for notifications
687
+ ```
688
+
689
+ ## CI timeout and resource management
690
+
691
+ ```
692
+ Default execution limits per CI run:
693
+ Maximum tasks per session: 25
694
+ Maximum parallel subagents: 5 (respect CI runner memory limits)
695
+ Task timeout: 10 minutes per task
696
+ Phase timeout: 45 minutes
697
+ Full CI timeout: 60 minutes
698
+
699
+ On timeout:
700
+ 1. Write current state to HANDOFF.json
701
+ 2. Exit with code 2 (warning — not failure)
702
+ 3. The next CI run resumes from HANDOFF.json
703
+ 4. Report: "CI timeout reached. Run will resume from: [next_task]"
704
+ ```
705
+ ```
706
+
707
+ ---
708
+
709
+ ### `.mindforge/ci/github-actions-adapter.md`
710
+
711
+ ```markdown
712
+ # MindForge — GitHub Actions Integration
713
+
714
+ ## Purpose
715
+ Define the GitHub Actions workflow that integrates MindForge into CI/CD pipelines.
716
+
717
+ ## Workflow file: `.github/workflows/mindforge-ci.yml`
718
+
719
+ ```yaml
720
+ name: MindForge CI
721
+
722
+ on:
723
+ push:
724
+ branches: [ main, 'feat/**' ]
725
+ pull_request:
726
+ branches: [ main ]
727
+
728
+ env:
729
+ CI: true
730
+ MINDFORGE_CI: true
731
+ NODE_VERSION: '20'
732
+
733
+ jobs:
734
+ mindforge-health:
735
+ name: MindForge Health Check
736
+ runs-on: ubuntu-latest
737
+ steps:
738
+ - uses: actions/checkout@v4
739
+ with:
740
+ fetch-depth: 0 # Full history for git-based checks
741
+
742
+ - uses: actions/setup-node@v4
743
+ with:
744
+ node-version: ${{ env.NODE_VERSION }}
745
+ cache: 'npm'
746
+
747
+ - name: Install MindForge
748
+ run: npx mindforge-cc@latest --claude --local
749
+
750
+ - name: Validate MINDFORGE.md
751
+ run: node bin/validate-config.js
752
+
753
+ - name: Run MindForge health check
754
+ run: |
755
+ # Health check in CI mode — outputs structured JSON
756
+ echo "::group::MindForge Health Report"
757
+ node -e "
758
+ // CI health check simulation
759
+ // In full implementation: calls mindforge health engine
760
+ const fs = require('fs');
761
+ const files = ['.planning/AUDIT.jsonl', '.planning/STATE.md', '.planning/HANDOFF.json'];
762
+ let allPresent = true;
763
+ files.forEach(f => {
764
+ if (!fs.existsSync(f)) {
765
+ console.log('::warning::Missing state file: ' + f);
766
+ allPresent = false;
767
+ }
768
+ });
769
+ console.log(allPresent ? '::notice::All state files present' : '::warning::Some state files missing');
770
+ "
771
+ echo "::endgroup::"
772
+
773
+ mindforge-security:
774
+ name: Security Scan
775
+ runs-on: ubuntu-latest
776
+ needs: mindforge-health
777
+ steps:
778
+ - uses: actions/checkout@v4
779
+
780
+ - uses: actions/setup-node@v4
781
+ with:
782
+ node-version: ${{ env.NODE_VERSION }}
783
+ cache: 'npm'
784
+
785
+ - name: Install dependencies
786
+ run: npm ci
787
+
788
+ - name: MindForge secret detection
789
+ run: |
790
+ echo "::group::Secret Detection"
791
+ # Secret patterns — exits non-zero if found
792
+ if grep -rE "(sk-[a-zA-Z0-9]{20,}|ghp_[a-zA-Z0-9]+|xoxb-[a-zA-Z0-9-]+)" \
793
+ --include="*.ts" --include="*.js" --include="*.json" \
794
+ --exclude-dir=node_modules --exclude-dir=.git \
795
+ . 2>/dev/null; then
796
+ echo "::error::Credentials detected in source files. Remove before merging."
797
+ exit 1
798
+ fi
799
+ echo "::notice::No credentials detected ✅"
800
+ echo "::endgroup::"
801
+
802
+ - name: Dependency audit
803
+ run: |
804
+ echo "::group::Dependency Audit"
805
+ npm audit --audit-level=high 2>&1 || {
806
+ echo "::error::High/critical vulnerabilities found. Run: npm audit fix"
807
+ exit 1
808
+ }
809
+ echo "::endgroup::"
810
+
811
+ mindforge-quality:
812
+ name: Code Quality Gates
813
+ runs-on: ubuntu-latest
814
+ needs: mindforge-health
815
+ env:
816
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
817
+ steps:
818
+ - uses: actions/checkout@v4
819
+
820
+ - uses: actions/setup-node@v4
821
+ with:
822
+ node-version: ${{ env.NODE_VERSION }}
823
+ cache: 'npm'
824
+
825
+ - name: Install dependencies
826
+ run: npm ci
827
+
828
+ - name: Type check
829
+ run: npx tsc --noEmit 2>&1 | while read line; do
830
+ echo "::error::$line"
831
+ done
832
+
833
+ - name: Lint
834
+ run: npx eslint . --ext .ts,.tsx --max-warnings 0
835
+
836
+ - name: Test suite with coverage
837
+ run: npm test -- --coverage
838
+ env:
839
+ COVERAGE_THRESHOLD: 80
840
+
841
+ - name: Check coverage threshold
842
+ run: |
843
+ COVERAGE=$(cat coverage/coverage-summary.json 2>/dev/null | \
844
+ node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); \
845
+ console.log(Math.floor(d.total.lines.pct))" 2>/dev/null || echo "0")
846
+ MIN=${CI_MIN_COVERAGE_PCT:-80}
847
+ if [ "${COVERAGE}" -lt "${MIN}" ]; then
848
+ echo "::error::Coverage ${COVERAGE}% is below minimum ${MIN}%"
849
+ exit 1
850
+ fi
851
+ echo "::notice::Coverage: ${COVERAGE}% ✅"
852
+
853
+ mindforge-ai-review:
854
+ name: AI Code Review
855
+ runs-on: ubuntu-latest
856
+ needs: [mindforge-security, mindforge-quality]
857
+ if: github.event_name == 'pull_request'
858
+ env:
859
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
860
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
861
+ steps:
862
+ - uses: actions/checkout@v4
863
+ with:
864
+ fetch-depth: 0
865
+
866
+ - uses: actions/setup-node@v4
867
+ with:
868
+ node-version: ${{ env.NODE_VERSION }}
869
+ cache: 'npm'
870
+
871
+ - name: Install MindForge
872
+ run: npx mindforge-cc@latest --claude --local
873
+
874
+ - name: Run AI PR Review
875
+ run: |
876
+ # Get the diff for this PR
877
+ git diff ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }} > /tmp/pr.diff
878
+
879
+ # Run MindForge AI review (outputs GitHub annotations)
880
+ node -e "
881
+ // Placeholder for AI review execution
882
+ // In full implementation: calls Claude API via the pr-review engine
883
+ console.log('::notice::AI PR review completed — see review comment on PR');
884
+ "
885
+
886
+ - name: Post review as PR comment
887
+ uses: actions/github-script@v7
888
+ with:
889
+ script: |
890
+ const fs = require('fs');
891
+ const review = fs.existsSync('/tmp/mindforge-review.md') ?
892
+ fs.readFileSync('/tmp/mindforge-review.md', 'utf8') :
893
+ '✅ MindForge AI review: no significant issues found.';
894
+
895
+ await github.rest.pulls.createReview({
896
+ owner: context.repo.owner,
897
+ repo: context.repo.repo,
898
+ pull_number: context.issue.number,
899
+ body: review,
900
+ event: 'COMMENT'
901
+ });
902
+ ```
903
+ ```
904
+
905
+ **Commit:**
906
+ ```bash
907
+ git add .mindforge/ci/ .github/workflows/mindforge-ci.yml
908
+ git commit -m "feat(ci): implement CI mode engine and GitHub Actions workflow"
909
+ ```
910
+
911
+ ---
912
+
913
+ ## TASK 4 — Write the AI PR Review Engine
914
+
915
+ ### `.mindforge/pr-review/ai-reviewer.md`
916
+
917
+ ```markdown
918
+ # MindForge — AI PR Review Engine
919
+
920
+ ## Purpose
921
+ Use the Claude API directly to perform intelligent, contextual code reviews
922
+ on pull request diffs. Goes beyond static analysis to provide reasoning-based
923
+ feedback that understands architectural context.
924
+
925
+ ## Review philosophy
926
+ The AI reviewer has three goals:
927
+ 1. Catch what static analysis misses (logic errors, design flaws, missing edge cases)
928
+ 2. Confirm that the PR delivers what it claims (requirements traceability)
929
+ 3. Maintain code quality standards consistently across all reviewers
930
+
931
+ The AI reviewer does NOT replace human reviewers — it prepares them.
932
+ It surfaces issues, explains context, and asks questions.
933
+ Human reviewers make final decisions.
934
+
935
+ ## Claude API integration
936
+
937
+ ```javascript
938
+ // pr-review/ai-review-runner.js
939
+
940
+ const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
941
+ if (!ANTHROPIC_API_KEY) {
942
+ console.error('ANTHROPIC_API_KEY not set — AI review unavailable');
943
+ process.exit(0); // Graceful skip, not failure
944
+ }
945
+
946
+ async function runAIReview(diff, context) {
947
+ const response = await fetch('https://api.anthropic.com/v1/messages', {
948
+ method: 'POST',
949
+ headers: {
950
+ 'Content-Type': 'application/json',
951
+ 'x-api-key': ANTHROPIC_API_KEY,
952
+ 'anthropic-version': '2023-06-01',
953
+ },
954
+ body: JSON.stringify({
955
+ model: 'claude-sonnet-4-6',
956
+ max_tokens: 4096,
957
+ system: buildSystemPrompt(context),
958
+ messages: [
959
+ { role: 'user', content: buildReviewPrompt(diff, context) }
960
+ ],
961
+ }),
962
+ });
963
+
964
+ if (!response.ok) {
965
+ const err = await response.text();
966
+ throw new Error(`Claude API error ${response.status}: ${err}`);
967
+ }
968
+
969
+ const data = await response.json();
970
+ return data.content[0].text;
971
+ }
972
+ ```
973
+
974
+ ## System prompt construction
975
+
976
+ ```javascript
977
+ function buildSystemPrompt(context) {
978
+ return `You are a senior code reviewer performing a pull request review for the project: ${context.projectName}.
979
+
980
+ ## Your review context
981
+ Tech stack: ${context.techStack}
982
+ Architecture pattern: ${context.architecturePattern}
983
+ Coding conventions: ${context.conventions}
984
+ Security requirements: ${context.securityRequirements}
985
+
986
+ ## Your review approach
987
+ 1. Read the diff carefully — understand the INTENT of each change, not just the change itself
988
+ 2. Check if the implementation matches the stated PR purpose
989
+ 3. Look for: logic errors, missing error handling, security issues, performance concerns
990
+ 4. Evaluate: code clarity, convention adherence, test coverage
991
+ 5. Flag: anything that seems to contradict the architecture or conventions
992
+
993
+ ## Output format
994
+ Produce a structured review in this exact format:
995
+
996
+ ### Summary
997
+ [2-3 sentences: what this PR does and overall quality assessment]
998
+
999
+ ### Findings
1000
+ For each finding, use exactly:
1001
+ **[CRITICAL|HIGH|MEDIUM|LOW]** \`file:line\` — [Issue description]
1002
+ > [Specific recommendation]
1003
+
1004
+ ### Positive observations
1005
+ [What was done well — be genuine, not perfunctory]
1006
+
1007
+ ### Questions for the author
1008
+ [Numbered questions about unclear decisions or assumptions]
1009
+
1010
+ ### Verdict
1011
+ [APPROVE | REQUEST_CHANGES | COMMENT] — [one sentence rationale]
1012
+
1013
+ Be direct. Be specific. Cite line numbers. Do not be vague.
1014
+ Do not flag issues that are stylistic preferences when conventions permit them.
1015
+ Do not repeat findings from the automated checks (secret detection, type errors) — focus on logic and design.`;
1016
+ }
1017
+ ```
1018
+
1019
+ ## Review prompt construction
1020
+
1021
+ ```javascript
1022
+ function buildReviewPrompt(diff, context) {
1023
+ return `Please review this pull request diff.
1024
+
1025
+ ## PR Information
1026
+ Title: ${context.prTitle}
1027
+ Author: ${context.prAuthor}
1028
+ Branch: ${context.branch} → ${context.base}
1029
+ Files changed: ${context.filesChanged}
1030
+
1031
+ ## Requirements being addressed
1032
+ ${context.requirements || 'No specific requirements listed'}
1033
+
1034
+ ## Architectural context
1035
+ ${context.architectureContext || 'See ARCHITECTURE.md for system design'}
1036
+
1037
+ ## The diff
1038
+ \`\`\`diff
1039
+ ${diff.slice(0, 12000)} ${diff.length > 12000 ? '\n[diff truncated — ' + diff.length + ' chars total]' : ''}
1040
+ \`\`\`
1041
+
1042
+ Focus your review on correctness, security, and architectural alignment.
1043
+ Do not comment on formatting issues handled by the linter.`;
1044
+ }
1045
+ ```
1046
+
1047
+ ## Context loading
1048
+
1049
+ Before calling the API, load review context:
1050
+ ```javascript
1051
+ function loadReviewContext() {
1052
+ const projectMd = readFile('.planning/PROJECT.md');
1053
+ const archMd = readFile('.planning/ARCHITECTURE.md');
1054
+ const convMd = readFile('.mindforge/org/CONVENTIONS.md');
1055
+ const secMd = readFile('.mindforge/org/SECURITY.md');
1056
+
1057
+ return {
1058
+ projectName: extractField(projectMd, 'NAME') || 'Unknown',
1059
+ techStack: extractTechStack(projectMd),
1060
+ architecturePattern: extractField(archMd, '## Architectural pattern') || 'Unknown',
1061
+ conventions: convMd.slice(0, 2000), // First 2000 chars
1062
+ securityRequirements: secMd.slice(0, 1500), // First 1500 chars
1063
+ };
1064
+ }
1065
+ ```
1066
+
1067
+ ## Rate limiting and cost management
1068
+
1069
+ ```javascript
1070
+ // Review request limits to control API costs
1071
+ const REVIEW_LIMITS = {
1072
+ maxDiffSize: 15000, // Characters — larger diffs get summarised
1073
+ maxFilesReviewed: 20, // Review the 20 most-changed files
1074
+ cacheTtlMinutes: 60, // Cache reviews for the same commit SHA
1075
+ maxDailyReviews: 50, // Stop AI reviews after 50 per day (configurable)
1076
+ };
1077
+
1078
+ // Before calling API: check daily limit
1079
+ function checkDailyLimit() {
1080
+ const today = new Date().toISOString().slice(0, 10);
1081
+ const logFile = '.mindforge/metrics/ai-review-usage.jsonl';
1082
+ const todayCount = (readFileLines(logFile) || [])
1083
+ .filter(line => line.includes(today))
1084
+ .length;
1085
+ return todayCount < REVIEW_LIMITS.maxDailyReviews;
1086
+ }
1087
+ ```
1088
+
1089
+ ## Output formatting for GitHub
1090
+
1091
+ ```javascript
1092
+ function formatForGitHub(aiReview, summary) {
1093
+ return `## 🤖 MindForge AI Code Review
1094
+
1095
+ ${aiReview}
1096
+
1097
+ ---
1098
+ *Generated by MindForge AI Review Engine v${VERSION}*
1099
+ *Model: claude-sonnet-4-6 | Context: PROJECT.md + ARCHITECTURE.md + CONVENTIONS.md*
1100
+ *This review supplements but does not replace human code review.*`;
1101
+ }
1102
+ ```
1103
+ ```
1104
+
1105
+ ---
1106
+
1107
+ ### `.mindforge/pr-review/review-prompt-templates.md`
1108
+
1109
+ ```markdown
1110
+ # MindForge — PR Review Prompt Templates
1111
+
1112
+ ## Specialised review templates by change type
1113
+
1114
+ ### Security-focused review (for Tier 3 changes)
1115
+ Used when: PR includes auth, payment, PII, or security changes.
1116
+ Additional system prompt addition:
1117
+ ```
1118
+ SECURITY REVIEW MODE ACTIVE.
1119
+ Apply the OWASP Top 10 checklist systematically to this diff.
1120
+ Flag every instance of:
1121
+ - A01: Access control bypasses
1122
+ - A02: Cryptographic weaknesses (weak algorithms, insecure storage)
1123
+ - A03: Injection vectors (SQL, NoSQL, OS, LDAP)
1124
+ - A07: Authentication failures (session management, credential handling)
1125
+ Any CRITICAL security finding must be listed first, before other findings.
1126
+ ```
1127
+
1128
+ ### Database migration review
1129
+ Used when: PR includes database schema changes.
1130
+ Additional prompt addition:
1131
+ ```
1132
+ DATABASE MIGRATION REVIEW MODE.
1133
+ For this migration, verify:
1134
+ 1. Migration is reversible — is there a DOWN migration?
1135
+ 2. Migration is non-blocking — does it avoid full table locks?
1136
+ 3. New columns with NOT NULL have either a DEFAULT or a two-phase migration
1137
+ 4. No data-loss operations without explicit confirmation in PR description
1138
+ 5. New indexes are added CONCURRENTLY (PostgreSQL) to avoid table locks
1139
+ 6. Foreign key constraints are added with VALIDATE separately from creation
1140
+ ```
1141
+
1142
+ ### API breaking change review
1143
+ Used when: PR changes existing API endpoints or response schemas.
1144
+ Additional prompt addition:
1145
+ ```
1146
+ API BREAKING CHANGE REVIEW MODE.
1147
+ Verify:
1148
+ 1. Is this change documented as breaking in the PR description?
1149
+ 2. Is the API version incremented appropriately?
1150
+ 3. Are existing clients given a deprecation period?
1151
+ 4. Is a migration guide included for API consumers?
1152
+ 5. Do integration tests cover both old and new API contracts?
1153
+ ```
1154
+ ```
1155
+
1156
+ **Commit:**
1157
+ ```bash
1158
+ git add .mindforge/pr-review/
1159
+ git commit -m "feat(pr-review): implement AI PR review engine with Claude API integration"
1160
+ ```
1161
+
1162
+ ---
1163
+
1164
+ ## TASK 5 — Write the Monorepo Support Engine
1165
+
1166
+ ### `.mindforge/monorepo/workspace-detector.md`
1167
+
1168
+ ```markdown
1169
+ # MindForge — Monorepo Workspace Detector
1170
+
1171
+ ## Purpose
1172
+ Detect and understand monorepo structures (npm workspaces, pnpm workspaces,
1173
+ Nx, Turborepo, Lerna) so MindForge can plan and execute phases across
1174
+ multiple packages correctly.
1175
+
1176
+ ## Supported monorepo types
1177
+
1178
+ | Type | Detection file | Package locations |
1179
+ |---|---|---|
1180
+ | npm workspaces | `package.json` with `"workspaces":` | Defined in workspaces array |
1181
+ | pnpm workspaces | `pnpm-workspace.yaml` | Defined in packages array |
1182
+ | Nx | `nx.json` | `apps/` and `libs/` |
1183
+ | Turborepo | `turbo.json` | `apps/` and `packages/` |
1184
+ | Lerna | `lerna.json` | Defined in packages array |
1185
+ | Yarn workspaces | `package.json` with `"workspaces":` | Same as npm |
1186
+
1187
+ ## Detection protocol
1188
+
1189
+ ```bash
1190
+ detect_workspace_type() {
1191
+ local ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
1192
+
1193
+ # Check in priority order
1194
+ if [ -f "${ROOT}/nx.json" ]; then
1195
+ echo "nx"
1196
+ elif [ -f "${ROOT}/turbo.json" ]; then
1197
+ echo "turborepo"
1198
+ elif [ -f "${ROOT}/lerna.json" ]; then
1199
+ echo "lerna"
1200
+ elif [ -f "${ROOT}/pnpm-workspace.yaml" ]; then
1201
+ echo "pnpm"
1202
+ elif node -e "
1203
+ const p = require('./package.json');
1204
+ process.exit(p.workspaces ? 0 : 1)
1205
+ " 2>/dev/null; then
1206
+ echo "npm-workspaces"
1207
+ else
1208
+ echo "none"
1209
+ fi
1210
+ }
1211
+
1212
+ list_packages() {
1213
+ local TYPE="$1"
1214
+ case "${TYPE}" in
1215
+ nx)
1216
+ find apps/ libs/ -name "package.json" -not -path "*/node_modules/*" \
1217
+ -exec dirname {} \; 2>/dev/null | sort
1218
+ ;;
1219
+ turborepo)
1220
+ find apps/ packages/ -name "package.json" -not -path "*/node_modules/*" \
1221
+ -exec dirname {} \; 2>/dev/null | sort
1222
+ ;;
1223
+ pnpm)
1224
+ cat pnpm-workspace.yaml | grep "^ -" | sed "s/ - '//;s/'$//"
1225
+ ;;
1226
+ npm-workspaces|lerna)
1227
+ node -e "
1228
+ const p = require('./package.json');
1229
+ const ws = p.workspaces || require('./lerna.json').packages || [];
1230
+ ws.forEach(w => console.log(w.replace(/\/\*$/, '')));
1231
+ " 2>/dev/null
1232
+ ;;
1233
+ esac
1234
+ }
1235
+ ```
1236
+
1237
+ ## Package metadata extraction
1238
+
1239
+ For each detected package, extract:
1240
+ ```javascript
1241
+ {
1242
+ "name": "package name from package.json",
1243
+ "path": "relative path from monorepo root",
1244
+ "type": "app | lib | shared | api | web | cli",
1245
+ "dependencies": ["list of internal package dependencies"],
1246
+ "scripts": {
1247
+ "build": "build command",
1248
+ "test": "test command",
1249
+ "lint": "lint command"
1250
+ },
1251
+ "mindforge": {
1252
+ "phase-scope": "global | package-specific",
1253
+ "test-command": "override test command if needed",
1254
+ "affected-by": ["list of packages that affect this one"]
1255
+ }
1256
+ }
1257
+ ```
1258
+
1259
+ ## Workspace manifest
1260
+
1261
+ Write to `.planning/WORKSPACE-MANIFEST.json`:
1262
+
1263
+ ```json
1264
+ {
1265
+ "schema_version": "1.0.0",
1266
+ "workspace_type": "turborepo",
1267
+ "root": "/path/to/project",
1268
+ "packages": [
1269
+ {
1270
+ "name": "@myapp/api",
1271
+ "path": "apps/api",
1272
+ "type": "api",
1273
+ "dependencies": ["@myapp/shared"],
1274
+ "test_command": "npm test",
1275
+ "build_command": "npm run build"
1276
+ },
1277
+ {
1278
+ "name": "@myapp/web",
1279
+ "path": "apps/web",
1280
+ "type": "web",
1281
+ "dependencies": ["@myapp/shared", "@myapp/ui"],
1282
+ "test_command": "npm test",
1283
+ "build_command": "npm run build"
1284
+ },
1285
+ {
1286
+ "name": "@myapp/shared",
1287
+ "path": "packages/shared",
1288
+ "type": "lib",
1289
+ "dependencies": [],
1290
+ "test_command": "npm test",
1291
+ "build_command": "npm run build"
1292
+ }
1293
+ ],
1294
+ "dependency_order": ["@myapp/shared", "@myapp/api", "@myapp/web"],
1295
+ "affected_packages": {}
1296
+ }
1297
+ ```
1298
+ ```
1299
+
1300
+ ---
1301
+
1302
+ ### `.mindforge/monorepo/cross-package-planner.md`
1303
+
1304
+ ```markdown
1305
+ # MindForge — Cross-Package Planner
1306
+
1307
+ ## Purpose
1308
+ When a phase spans multiple packages in a monorepo, coordinate execution
1309
+ so that shared dependencies are built and tested before packages that
1310
+ depend on them.
1311
+
1312
+ ## Execution order algorithm
1313
+
1314
+ ```
1315
+ Given: a set of packages involved in the current phase
1316
+ and their inter-package dependencies
1317
+
1318
+ Algorithm: topological sort of package dependency graph
1319
+
1320
+ Input: WORKSPACE-MANIFEST.json dependency_order
1321
+ Output: ordered list of packages to process
1322
+
1323
+ Example:
1324
+ Phase touches: @myapp/api, @myapp/shared, @myapp/web
1325
+ Dependencies: api→shared, web→shared, web→api
1326
+ Topological order: shared → api → web
1327
+
1328
+ Execution:
1329
+ Wave 1: process @myapp/shared (no dependencies on other changed packages)
1330
+ Wave 2: process @myapp/api (depends on Wave 1: shared)
1331
+ Wave 3: process @myapp/web (depends on Wave 2: api + Wave 1: shared)
1332
+ ```
1333
+
1334
+ ## Per-package PLAN file routing
1335
+
1336
+ When PLAN files are created for a monorepo phase, each plan specifies its target package:
1337
+
1338
+ ```xml
1339
+ <task type="auto">
1340
+ <n>Add auth middleware to API</n>
1341
+ <package>@myapp/api</package>
1342
+ <working-dir>apps/api</working-dir>
1343
+ <files>
1344
+ apps/api/src/middleware/auth.ts
1345
+ apps/api/src/middleware/auth.test.ts
1346
+ </files>
1347
+ <action>...</action>
1348
+ <verify>cd apps/api && npm test -- --testPathPattern=auth.middleware</verify>
1349
+ <done>Auth middleware tests passing in apps/api</done>
1350
+ </task>
1351
+ ```
1352
+
1353
+ ## Cross-package test execution
1354
+
1355
+ After all packages in the phase are processed:
1356
+ ```bash
1357
+ # Run tests across all affected packages
1358
+ AFFECTED_PACKAGES=$(cat .planning/WORKSPACE-MANIFEST.json | \
1359
+ node -e "const m=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); \
1360
+ console.log(m.packages.map(p=>p.path).join(' '))")
1361
+
1362
+ for PKG_PATH in ${AFFECTED_PACKAGES}; do
1363
+ echo "Testing ${PKG_PATH}..."
1364
+ cd "${PKG_PATH}" && npm test && cd -
1365
+ done
1366
+
1367
+ # Run integration tests from root (if configured)
1368
+ [ -f "package.json" ] && npm run test:integration 2>/dev/null || true
1369
+ ```
1370
+
1371
+ ## Affected package detection
1372
+
1373
+ When a PLAN modifies a shared library: automatically include all packages
1374
+ that depend on that library in the affected scope:
1375
+
1376
+ ```bash
1377
+ # Detect affected packages from changed files
1378
+ CHANGED_PACKAGES=$(git diff --name-only | \
1379
+ awk -F/ '{print $1"/"$2}' | sort -u | \
1380
+ while read pkg; do
1381
+ node -e "
1382
+ const m = require('.planning/WORKSPACE-MANIFEST.json');
1383
+ const changed = '${pkg}';
1384
+ m.packages.forEach(p => {
1385
+ if (p.path === changed || p.dependencies.some(d => d.includes(changed))) {
1386
+ console.log(p.name);
1387
+ }
1388
+ });
1389
+ " 2>/dev/null
1390
+ done | sort -u)
1391
+ ```
1392
+ ```
1393
+
1394
+ **Commit:**
1395
+ ```bash
1396
+ git add .mindforge/monorepo/
1397
+ git commit -m "feat(monorepo): implement workspace detector and cross-package planner"
1398
+ ```
1399
+
1400
+ ---
1401
+
1402
+ ## TASK 6 — Write the MindForge SDK
1403
+
1404
+ ### `sdk/package.json`
1405
+
1406
+ ```json
1407
+ {
1408
+ "name": "@mindforge/sdk",
1409
+ "version": "0.6.0",
1410
+ "description": "MindForge SDK — Programmatic API for embedding MindForge in tools",
1411
+ "main": "dist/index.js",
1412
+ "types": "dist/index.d.ts",
1413
+ "scripts": {
1414
+ "build": "tsc",
1415
+ "test": "node tests/sdk.test.js",
1416
+ "lint": "eslint src/ --ext .ts"
1417
+ },
1418
+ "keywords": ["mindforge", "agentic-framework", "claude", "sdk"],
1419
+ "license": "MIT",
1420
+ "peerDependencies": {
1421
+ "typescript": ">=5.0.0"
1422
+ },
1423
+ "devDependencies": {
1424
+ "typescript": "^5.4.0"
1425
+ }
1426
+ }
1427
+ ```
1428
+
1429
+ ### `sdk/src/types.ts`
1430
+
1431
+ ```typescript
1432
+ /**
1433
+ * MindForge SDK — Type Definitions
1434
+ */
1435
+
1436
+ export interface MindForgeConfig {
1437
+ /** Path to the project root (default: cwd) */
1438
+ projectRoot?: string;
1439
+ /** Claude API key (default: ANTHROPIC_API_KEY env var) */
1440
+ apiKey?: string;
1441
+ /** CI mode — disables interactive features */
1442
+ ciMode?: boolean;
1443
+ /** Output format for events */
1444
+ outputFormat?: 'json' | 'text' | 'github-annotations';
1445
+ /** Timeout per task in milliseconds (default: 600000 — 10 minutes) */
1446
+ taskTimeoutMs?: number;
1447
+ }
1448
+
1449
+ export interface PhaseResult {
1450
+ phase: number;
1451
+ status: 'success' | 'failure' | 'warning' | 'skipped';
1452
+ tasksCompleted: number;
1453
+ tasksTotal: number;
1454
+ commits: string[];
1455
+ securityFindings: SecurityFinding[];
1456
+ qualityGateResults: GateResult[];
1457
+ durationMs: number;
1458
+ errorMessage?: string;
1459
+ }
1460
+
1461
+ export interface TaskResult {
1462
+ planId: string;
1463
+ taskName: string;
1464
+ status: 'completed' | 'failed' | 'skipped';
1465
+ commitSha?: string;
1466
+ verifyOutput?: string;
1467
+ durationMs: number;
1468
+ errorMessage?: string;
1469
+ }
1470
+
1471
+ export interface SecurityFinding {
1472
+ severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
1473
+ owaspCategory: string;
1474
+ file: string;
1475
+ line: number;
1476
+ description: string;
1477
+ remediation: string;
1478
+ remediated: boolean;
1479
+ }
1480
+
1481
+ export interface GateResult {
1482
+ gate: string;
1483
+ status: 'passed' | 'failed' | 'warning' | 'skipped';
1484
+ detail?: string;
1485
+ }
1486
+
1487
+ export interface HealthReport {
1488
+ overallStatus: 'healthy' | 'warning' | 'error';
1489
+ errors: HealthIssue[];
1490
+ warnings: HealthIssue[];
1491
+ informational: HealthIssue[];
1492
+ timestamp: string;
1493
+ }
1494
+
1495
+ export interface HealthIssue {
1496
+ category: string;
1497
+ message: string;
1498
+ autoRepairable: boolean;
1499
+ fixCommand?: string;
1500
+ }
1501
+
1502
+ export type MindForgeEvent =
1503
+ | { type: 'task_started'; phase: number; plan: string; taskName: string }
1504
+ | { type: 'task_completed'; phase: number; plan: string; commitSha: string }
1505
+ | { type: 'task_failed'; phase: number; plan: string; error: string }
1506
+ | { type: 'wave_started'; phase: number; wave: number; taskCount: number }
1507
+ | { type: 'wave_completed'; phase: number; wave: number }
1508
+ | { type: 'phase_completed'; phase: number; result: PhaseResult }
1509
+ | { type: 'security_finding'; finding: SecurityFinding }
1510
+ | { type: 'gate_result'; gate: GateResult }
1511
+ | { type: 'log'; level: 'info' | 'warn' | 'error'; message: string };
1512
+ ```
1513
+
1514
+ ### `sdk/src/client.ts`
1515
+
1516
+ ```typescript
1517
+ /**
1518
+ * MindForge SDK — Main Client
1519
+ */
1520
+
1521
+ import { EventEmitter } from 'events';
1522
+ import * as fs from 'fs';
1523
+ import * as path from 'path';
1524
+ import type {
1525
+ MindForgeConfig, PhaseResult, TaskResult, HealthReport, MindForgeEvent
1526
+ } from './types';
1527
+
1528
+ export class MindForgeClient extends EventEmitter {
1529
+ private config: Required<MindForgeConfig>;
1530
+ private projectRoot: string;
1531
+
1532
+ constructor(config: MindForgeConfig = {}) {
1533
+ super();
1534
+ this.projectRoot = config.projectRoot ?? process.cwd();
1535
+ this.config = {
1536
+ projectRoot: this.projectRoot,
1537
+ apiKey: config.apiKey ?? process.env.ANTHROPIC_API_KEY ?? '',
1538
+ ciMode: config.ciMode ?? (process.env.CI === 'true'),
1539
+ outputFormat: config.outputFormat ?? 'json',
1540
+ taskTimeoutMs: config.taskTimeoutMs ?? 600_000,
1541
+ };
1542
+ }
1543
+
1544
+ // ── Event emission helper ──────────────────────────────────────────────────
1545
+ private emit<T extends MindForgeEvent>(event: T): boolean {
1546
+ return super.emit(event.type, event);
1547
+ }
1548
+
1549
+ // ── Project state ──────────────────────────────────────────────────────────
1550
+ isInitialised(): boolean {
1551
+ return fs.existsSync(path.join(this.projectRoot, '.planning', 'PROJECT.md'));
1552
+ }
1553
+
1554
+ readState(): Record<string, unknown> | null {
1555
+ const statePath = path.join(this.projectRoot, '.planning', 'STATE.md');
1556
+ if (!fs.existsSync(statePath)) return null;
1557
+ return { raw: fs.readFileSync(statePath, 'utf8') };
1558
+ }
1559
+
1560
+ readHandoff(): Record<string, unknown> | null {
1561
+ const handoffPath = path.join(this.projectRoot, '.planning', 'HANDOFF.json');
1562
+ if (!fs.existsSync(handoffPath)) return null;
1563
+ try {
1564
+ return JSON.parse(fs.readFileSync(handoffPath, 'utf8'));
1565
+ } catch {
1566
+ return null;
1567
+ }
1568
+ }
1569
+
1570
+ // ── Health check ───────────────────────────────────────────────────────────
1571
+ async health(): Promise<HealthReport> {
1572
+ const errors: Array<{ category: string; message: string; autoRepairable: boolean }> = [];
1573
+ const warnings: Array<{ category: string; message: string; autoRepairable: boolean }> = [];
1574
+ const info: Array<{ category: string; message: string; autoRepairable: boolean }> = [];
1575
+
1576
+ const requiredFiles = [
1577
+ '.planning/STATE.md',
1578
+ '.planning/HANDOFF.json',
1579
+ '.planning/AUDIT.jsonl',
1580
+ '.mindforge/org/CONVENTIONS.md',
1581
+ ];
1582
+
1583
+ for (const file of requiredFiles) {
1584
+ const fullPath = path.join(this.projectRoot, file);
1585
+ if (!fs.existsSync(fullPath)) {
1586
+ warnings.push({ category: 'installation', message: `Missing: ${file}`, autoRepairable: false });
1587
+ }
1588
+ }
1589
+
1590
+ // Check HANDOFF.json validity
1591
+ const handoff = this.readHandoff();
1592
+ if (handoff && !handoff.schema_version) {
1593
+ errors.push({ category: 'state', message: 'HANDOFF.json missing schema_version field', autoRepairable: false });
1594
+ }
1595
+
1596
+ // Check AUDIT.jsonl
1597
+ const auditPath = path.join(this.projectRoot, '.planning', 'AUDIT.jsonl');
1598
+ if (fs.existsSync(auditPath)) {
1599
+ const lineCount = fs.readFileSync(auditPath, 'utf8').split('\n').filter(Boolean).length;
1600
+ if (lineCount > 9000) {
1601
+ warnings.push({ category: 'audit', message: `AUDIT.jsonl has ${lineCount} lines — archive soon`, autoRepairable: true });
1602
+ }
1603
+ info.push({ category: 'audit', message: `AUDIT.jsonl: ${lineCount} entries`, autoRepairable: false });
1604
+ }
1605
+
1606
+ return {
1607
+ overallStatus: errors.length > 0 ? 'error' : warnings.length > 0 ? 'warning' : 'healthy',
1608
+ errors,
1609
+ warnings,
1610
+ informational: info,
1611
+ timestamp: new Date().toISOString(),
1612
+ };
1613
+ }
1614
+
1615
+ // ── Audit log reading ──────────────────────────────────────────────────────
1616
+ readAuditLog(filter?: { event?: string; phase?: number; since?: Date }): unknown[] {
1617
+ const auditPath = path.join(this.projectRoot, '.planning', 'AUDIT.jsonl');
1618
+ if (!fs.existsSync(auditPath)) return [];
1619
+
1620
+ return fs.readFileSync(auditPath, 'utf8')
1621
+ .split('\n')
1622
+ .filter(Boolean)
1623
+ .map(line => { try { return JSON.parse(line); } catch { return null; } })
1624
+ .filter(Boolean)
1625
+ .filter(entry => {
1626
+ if (filter?.event && entry.event !== filter.event) return false;
1627
+ if (filter?.phase !== undefined && entry.phase !== filter.phase) return false;
1628
+ if (filter?.since && new Date(entry.timestamp) < filter.since) return false;
1629
+ return true;
1630
+ });
1631
+ }
1632
+
1633
+ // ── Metrics reading ────────────────────────────────────────────────────────
1634
+ readSessionMetrics(limit = 10): unknown[] {
1635
+ const metricsPath = path.join(this.projectRoot, '.mindforge', 'metrics', 'session-quality.jsonl');
1636
+ if (!fs.existsSync(metricsPath)) return [];
1637
+
1638
+ return fs.readFileSync(metricsPath, 'utf8')
1639
+ .split('\n')
1640
+ .filter(Boolean)
1641
+ .slice(-limit)
1642
+ .map(line => { try { return JSON.parse(line); } catch { return null; } })
1643
+ .filter(Boolean);
1644
+ }
1645
+
1646
+ // ── Config validation ──────────────────────────────────────────────────────
1647
+ validateConfig(): { valid: boolean; errors: string[]; warnings: string[] } {
1648
+ const configPath = path.join(this.projectRoot, 'MINDFORGE.md');
1649
+ if (!fs.existsSync(configPath)) {
1650
+ return { valid: true, errors: [], warnings: ['MINDFORGE.md not found — using defaults'] };
1651
+ }
1652
+ // Full validation via bin/validate-config.js
1653
+ return { valid: true, errors: [], warnings: [] };
1654
+ }
1655
+ }
1656
+ ```
1657
+
1658
+ ### `sdk/src/commands.ts`
1659
+
1660
+ ```typescript
1661
+ /**
1662
+ * MindForge SDK — Command Builders
1663
+ * Builds the command strings that can be sent to Claude Code / Antigravity
1664
+ * via their programmatic APIs.
1665
+ */
1666
+
1667
+ export interface CommandOptions {
1668
+ flags?: string[];
1669
+ args?: string[];
1670
+ }
1671
+
1672
+ export const commands = {
1673
+ /**
1674
+ * Build a /mindforge:health command string
1675
+ */
1676
+ health(opts: CommandOptions = {}): string {
1677
+ const flags = opts.flags?.join(' ') ?? '';
1678
+ return `/mindforge:health ${flags}`.trim();
1679
+ },
1680
+
1681
+ /**
1682
+ * Build a /mindforge:plan-phase command string
1683
+ */
1684
+ planPhase(phase: number, opts: CommandOptions = {}): string {
1685
+ const flags = opts.flags?.join(' ') ?? '';
1686
+ return `/mindforge:plan-phase ${phase} ${flags}`.trim();
1687
+ },
1688
+
1689
+ /**
1690
+ * Build a /mindforge:execute-phase command string
1691
+ */
1692
+ executePhase(phase: number, opts: CommandOptions = {}): string {
1693
+ const flags = opts.flags?.join(' ') ?? '';
1694
+ return `/mindforge:execute-phase ${phase} ${flags}`.trim();
1695
+ },
1696
+
1697
+ /**
1698
+ * Build a /mindforge:security-scan command string
1699
+ */
1700
+ securityScan(path?: string, opts: CommandOptions = {}): string {
1701
+ const flags = opts.flags?.join(' ') ?? '';
1702
+ return `/mindforge:security-scan ${path ?? ''} ${flags}`.trim();
1703
+ },
1704
+
1705
+ /**
1706
+ * Build a /mindforge:audit command string with filters
1707
+ */
1708
+ audit(filter: { phase?: number; event?: string; since?: string } = {}): string {
1709
+ const parts = ['/mindforge:audit'];
1710
+ if (filter.phase) parts.push(`--phase ${filter.phase}`);
1711
+ if (filter.event) parts.push(`--event ${filter.event}`);
1712
+ if (filter.since) parts.push(`--since ${filter.since}`);
1713
+ return parts.join(' ');
1714
+ },
1715
+
1716
+ /**
1717
+ * Build a /mindforge:pr-review command string
1718
+ */
1719
+ prReview(opts: CommandOptions = {}): string {
1720
+ const flags = opts.flags?.join(' ') ?? '';
1721
+ return `/mindforge:pr-review ${flags}`.trim();
1722
+ },
1723
+ };
1724
+ ```
1725
+
1726
+ ### `sdk/src/events.ts`
1727
+
1728
+ ```typescript
1729
+ /**
1730
+ * MindForge SDK — Server-Sent Events (SSE) stream for real-time progress
1731
+ * Enables external tools to subscribe to MindForge execution progress.
1732
+ */
1733
+
1734
+ import * as http from 'http';
1735
+ import * as fs from 'fs';
1736
+ import * as path from 'path';
1737
+
1738
+ interface SSEClient {
1739
+ id: string;
1740
+ response: http.ServerResponse;
1741
+ }
1742
+
1743
+ export class MindForgeEventStream {
1744
+ private clients: SSEClient[] = [];
1745
+ private server: http.Server | null = null;
1746
+ private auditWatcher: fs.FSWatcher | null = null;
1747
+ private lastAuditLine = 0;
1748
+
1749
+ /**
1750
+ * Start the SSE server on the given port
1751
+ */
1752
+ start(port = 7337): Promise<void> {
1753
+ return new Promise((resolve, reject) => {
1754
+ this.server = http.createServer((req, res) => {
1755
+ if (req.url !== '/events') {
1756
+ res.writeHead(404);
1757
+ res.end();
1758
+ return;
1759
+ }
1760
+
1761
+ // CORS for local tool integrations
1762
+ res.writeHead(200, {
1763
+ 'Content-Type': 'text/event-stream',
1764
+ 'Cache-Control': 'no-cache',
1765
+ 'Connection': 'keep-alive',
1766
+ 'Access-Control-Allow-Origin': 'http://localhost:*',
1767
+ });
1768
+
1769
+ const clientId = Date.now().toString();
1770
+ this.clients.push({ id: clientId, response: res });
1771
+
1772
+ // Send initial connection event
1773
+ this.sendEvent(res, 'connected', { clientId, timestamp: new Date().toISOString() });
1774
+
1775
+ // Clean up on disconnect
1776
+ req.on('close', () => {
1777
+ this.clients = this.clients.filter(c => c.id !== clientId);
1778
+ });
1779
+ });
1780
+
1781
+ this.server.listen(port, () => {
1782
+ console.log(`MindForge event stream listening on http://localhost:${port}/events`);
1783
+ resolve();
1784
+ });
1785
+
1786
+ this.server.on('error', reject);
1787
+ });
1788
+ }
1789
+
1790
+ /**
1791
+ * Watch AUDIT.jsonl for new entries and broadcast as SSE events
1792
+ */
1793
+ watchAuditLog(projectRoot: string): void {
1794
+ const auditPath = path.join(projectRoot, '.planning', 'AUDIT.jsonl');
1795
+
1796
+ if (!fs.existsSync(auditPath)) {
1797
+ // Create the file if it doesn't exist yet
1798
+ fs.writeFileSync(auditPath, '');
1799
+ }
1800
+
1801
+ // Set initial line count
1802
+ const content = fs.readFileSync(auditPath, 'utf8');
1803
+ this.lastAuditLine = content.split('\n').filter(Boolean).length;
1804
+
1805
+ this.auditWatcher = fs.watch(auditPath, () => {
1806
+ const lines = fs.readFileSync(auditPath, 'utf8')
1807
+ .split('\n')
1808
+ .filter(Boolean);
1809
+
1810
+ // Broadcast new lines
1811
+ for (let i = this.lastAuditLine; i < lines.length; i++) {
1812
+ try {
1813
+ const entry = JSON.parse(lines[i]);
1814
+ this.broadcast('audit_entry', entry);
1815
+ } catch {
1816
+ // Ignore parse errors for incomplete lines
1817
+ }
1818
+ }
1819
+
1820
+ this.lastAuditLine = lines.length;
1821
+ });
1822
+ }
1823
+
1824
+ /**
1825
+ * Broadcast an event to all connected clients
1826
+ */
1827
+ broadcast(eventType: string, data: unknown): void {
1828
+ this.clients.forEach(client => {
1829
+ this.sendEvent(client.response, eventType, data);
1830
+ });
1831
+ }
1832
+
1833
+ private sendEvent(res: http.ServerResponse, type: string, data: unknown): void {
1834
+ try {
1835
+ res.write(`event: ${type}\n`);
1836
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
1837
+ } catch {
1838
+ // Client disconnected
1839
+ }
1840
+ }
1841
+
1842
+ /**
1843
+ * Stop the event stream server
1844
+ */
1845
+ stop(): void {
1846
+ this.auditWatcher?.close();
1847
+ this.server?.close();
1848
+ this.clients.forEach(c => c.response.end());
1849
+ this.clients = [];
1850
+ }
1851
+ }
1852
+ ```
1853
+
1854
+ ### `sdk/src/index.ts`
1855
+
1856
+ ```typescript
1857
+ /**
1858
+ * MindForge SDK — Public API
1859
+ * @module @mindforge/sdk
1860
+ */
1861
+
1862
+ export { MindForgeClient } from './client';
1863
+ export { MindForgeEventStream } from './events';
1864
+ export { commands } from './commands';
1865
+ export type {
1866
+ MindForgeConfig,
1867
+ PhaseResult,
1868
+ TaskResult,
1869
+ SecurityFinding,
1870
+ GateResult,
1871
+ HealthReport,
1872
+ HealthIssue,
1873
+ MindForgeEvent,
1874
+ CommandOptions,
1875
+ } from './types';
1876
+
1877
+ export const VERSION = '0.6.0';
1878
+ ```
1879
+
1880
+ ### `sdk/README.md`
1881
+
1882
+ ```markdown
1883
+ # @mindforge/sdk
1884
+
1885
+ TypeScript SDK for embedding MindForge in tools, dashboards, and CI pipelines.
1886
+
1887
+ ## Installation
1888
+
1889
+ ```bash
1890
+ npm install @mindforge/sdk
1891
+ ```
1892
+
1893
+ ## Quick start
1894
+
1895
+ ```typescript
1896
+ import { MindForgeClient } from '@mindforge/sdk';
1897
+
1898
+ const client = new MindForgeClient({
1899
+ projectRoot: '/path/to/project',
1900
+ apiKey: process.env.ANTHROPIC_API_KEY,
1901
+ });
1902
+
1903
+ // Health check
1904
+ const health = await client.health();
1905
+ console.log(health.overallStatus); // 'healthy' | 'warning' | 'error'
1906
+
1907
+ // Read audit log
1908
+ const findings = client.readAuditLog({ event: 'security_finding' });
1909
+ console.log(findings);
1910
+
1911
+ // Read metrics
1912
+ const metrics = client.readSessionMetrics(5);
1913
+ console.log(metrics);
1914
+ ```
1915
+
1916
+ ## Real-time event streaming
1917
+
1918
+ ```typescript
1919
+ import { MindForgeEventStream } from '@mindforge/sdk';
1920
+
1921
+ const stream = new MindForgeEventStream();
1922
+ await stream.start(7337);
1923
+ stream.watchAuditLog('/path/to/project');
1924
+
1925
+ // Subscribe from browser or tool:
1926
+ const es = new EventSource('http://localhost:7337/events');
1927
+ es.addEventListener('audit_entry', (e) => {
1928
+ const entry = JSON.parse(e.data);
1929
+ if (entry.event === 'task_completed') {
1930
+ console.log('Task done:', entry.task_name);
1931
+ }
1932
+ });
1933
+ ```
1934
+
1935
+ ## Config validation
1936
+
1937
+ ```typescript
1938
+ const { valid, errors } = client.validateConfig();
1939
+ if (!valid) console.error(errors);
1940
+ ```
1941
+
1942
+ ## TypeScript support
1943
+
1944
+ Full type definitions included. No `@types/` package needed.
1945
+ ```
1946
+
1947
+ **Commit:**
1948
+ ```bash
1949
+ git add sdk/
1950
+ git commit -m "feat(sdk): implement MindForge TypeScript SDK with client, events, and command builders"
1951
+ ```
1952
+
1953
+ ---
1954
+
1955
+ ## TASK 7 — Write `/mindforge:init-org` command
1956
+
1957
+ ### `.claude/commands/mindforge/init-org.md`
1958
+
1959
+ ```markdown
1960
+ # MindForge — Init Org Command
1961
+ # Usage: /mindforge:init-org [--org-name "Name"] [--update]
1962
+
1963
+ ## Purpose
1964
+ Set up MindForge at the organisation level — create standardised org-level
1965
+ context files that are shared across ALL projects in the organisation.
1966
+
1967
+ Intended to be run ONCE by a platform engineer or engineering lead.
1968
+ Output is committed to a shared `mindforge-org-config` repository
1969
+ and distributed to projects as a git submodule or npm package.
1970
+
1971
+ ## Step 1 — Gather org information
1972
+
1973
+ Ask (one question at a time):
1974
+ 1. "What is your organisation name?"
1975
+ 2. "Describe what your organisation builds in 1-2 sentences."
1976
+ 3. "What is your primary tech stack? (describe in plain English)"
1977
+ 4. "What is your default deployment target? (AWS / GCP / Azure / self-hosted / hybrid)"
1978
+ 5. "What regulatory frameworks apply to your organisation?"
1979
+ Options: GDPR / HIPAA / SOC 2 / PCI-DSS / ISO 27001 / None / Multiple
1980
+ 6. "What is your source control platform?" (GitHub / GitLab / Bitbucket / Azure DevOps)
1981
+ 7. "What is your issue tracker?" (Jira / GitHub Issues / Linear / Azure DevOps / None)
1982
+ 8. "Who are your Tier 3 compliance approvers? (email addresses, comma-separated)"
1983
+
1984
+ ## Step 2 — Generate org-level context files
1985
+
1986
+ Create (or update with `--update`) these files:
1987
+
1988
+ ### `.mindforge/org/ORG.md`
1989
+ Populated from answers with:
1990
+ - Organisation identity and mission
1991
+ - Default tech stack with version recommendations
1992
+ - Architecture defaults
1993
+ - Team conventions
1994
+ - Compliance requirements
1995
+
1996
+ ### `.mindforge/org/CONVENTIONS.md`
1997
+ Generate sensible defaults based on the tech stack detected.
1998
+ For TypeScript/Node.js stacks: strict TypeScript, ESLint, Conventional Commits
1999
+ For Python stacks: ruff, mypy, black formatting
2000
+ For Go: standard Go toolchain conventions
2001
+ Mark each section clearly: [DEFAULT] or [CUSTOMISE THIS]
2002
+
2003
+ ### `.mindforge/org/SECURITY.md`
2004
+ Generate based on declared compliance frameworks:
2005
+ - GDPR → include GDPR-specific policies
2006
+ - HIPAA → include PHI handling requirements
2007
+ - PCI-DSS → include card data handling policies
2008
+ - SOC 2 → include access control requirements
2009
+ Mark critical sections: [REVIEW WITH SECURITY TEAM]
2010
+
2011
+ ### `.mindforge/org/TOOLS.md`
2012
+ Generate approved library list based on tech stack.
2013
+ Include common forbidden libraries (moment.js, request, etc.)
2014
+ Mark: [ADD YOUR APPROVED LIBRARIES]
2015
+
2016
+ ### `.mindforge/org/integrations/INTEGRATIONS-CONFIG.md`
2017
+ Pre-populate based on declared platforms:
2018
+ - GitHub → fill GitHub config section
2019
+ - Jira → fill Jira config section
2020
+ Mark credential fields clearly: [SET VIA ENVIRONMENT VARIABLE]
2021
+
2022
+ ### `.mindforge/governance/GOVERNANCE-CONFIG.md`
2023
+ Pre-populate based on declared approvers and compliance frameworks.
2024
+ Higher compliance burden → lower Tier 2/3 thresholds.
2025
+ Stricter approval SLAs for HIPAA/PCI-DSS organisations.
2026
+
2027
+ ## Step 3 — Generate skills recommendation
2028
+
2029
+ Based on the tech stack and compliance requirements, recommend skills to install:
2030
+
2031
+ ```
2032
+ Recommended skills for your tech stack:
2033
+
2034
+ Core skills (already included — v0.6.0):
2035
+ ✅ security-review, code-quality, api-design, testing-standards, documentation,
2036
+ performance, accessibility, data-privacy, incident-response, database-patterns
2037
+
2038
+ Additional skills recommended for your stack:
2039
+ [tech-stack-specific recommendations from registry]
2040
+
2041
+ For your compliance requirements:
2042
+ [compliance-specific skill recommendations]
2043
+
2044
+ Install all recommendations?
2045
+ yes → npx mindforge-skills install [list]
2046
+ no → I'll show you the install commands for each
2047
+ ```
2048
+
2049
+ ## Step 4 — Create distribution package
2050
+
2051
+ Offer to create an org-skills npm package for distributing org-level config:
2052
+
2053
+ ```
2054
+ Create `@your-org/mindforge-config` npm package?
2055
+ This package will distribute your org-level MindForge configuration
2056
+ to all projects in your organisation via: npx @your-org/mindforge-config
2057
+
2058
+ Files included:
2059
+ .mindforge/org/ORG.md
2060
+ .mindforge/org/CONVENTIONS.md
2061
+ .mindforge/org/SECURITY.md
2062
+ .mindforge/org/TOOLS.md
2063
+ .mindforge/org/skills/MANIFEST.md
2064
+ .mindforge/org/integrations/INTEGRATIONS-CONFIG.md (without credentials)
2065
+ .mindforge/governance/GOVERNANCE-CONFIG.md (without credentials)
2066
+ ```
2067
+
2068
+ ## Step 5 — Write AUDIT entry and report
2069
+
2070
+ ```json
2071
+ { "event": "org_initialised", "org_name": "[name]", "compliance_frameworks": [...], "skills_recommended": [...] }
2072
+ ```
2073
+
2074
+ Report:
2075
+ ```
2076
+ ✅ MindForge organisation configuration complete.
2077
+
2078
+ Files created:
2079
+ .mindforge/org/ORG.md
2080
+ .mindforge/org/CONVENTIONS.md
2081
+ .mindforge/org/SECURITY.md
2082
+ .mindforge/org/TOOLS.md
2083
+ .mindforge/governance/GOVERNANCE-CONFIG.md
2084
+
2085
+ Next steps:
2086
+ 1. Review each file — look for [CUSTOMISE THIS] markers
2087
+ 2. Fill in SECURITY.md with your security team
2088
+ 3. Commit to your org's mindforge-config repository
2089
+ 4. Share with all projects: npx @your-org/mindforge-config (if you created the package)
2090
+ ```
2091
+ ```
2092
+
2093
+ **Commit:**
2094
+ ```bash
2095
+ cp .claude/commands/mindforge/init-org.md .agent/mindforge/init-org.md
2096
+ git add .claude/commands/mindforge/init-org.md .agent/mindforge/init-org.md
2097
+ git commit -m "feat(commands): add /mindforge:init-org organisation-wide setup command"
2098
+ ```
2099
+
2100
+ ---
2101
+
2102
+ ## TASK 8 — Write remaining Day 6 commands
2103
+
2104
+ ### `.claude/commands/mindforge/install-skill.md`
2105
+
2106
+ ```markdown
2107
+ # MindForge — Install Skill Command
2108
+ # Usage: /mindforge:install-skill [skill-name|package-name] [--tier 1|2|3] [--registry URL]
2109
+
2110
+ Follow the full installation protocol from `.mindforge/distribution/registry-client.md`.
2111
+
2112
+ Steps:
2113
+ 1. Resolve package name from skill name
2114
+ 2. Check if already installed (skip if same version, offer upgrade if newer)
2115
+ 3. Fetch from registry (npm or private if --registry specified)
2116
+ 4. Validate the skill (Level 1 + Level 2 from skill-validator.md)
2117
+ 5. Run injection guard check
2118
+ 6. Install to tier directory (default: Tier 2 org skill)
2119
+ 7. Register in MANIFEST.md
2120
+ 8. Write AUDIT entry
2121
+ 9. Confirm: "Run /mindforge:skills validate to verify installation"
2122
+ ```
2123
+
2124
+ ### `.claude/commands/mindforge/publish-skill.md`
2125
+
2126
+ ```markdown
2127
+ # MindForge — Publish Skill Command
2128
+ # Usage: /mindforge:publish-skill [skill-dir] [--registry URL] [--dry-run]
2129
+
2130
+ Publish a skill to the npm registry (or private registry).
2131
+
2132
+ Pre-publication checklist:
2133
+ 1. Run full skill validation (Level 1 + 2 + 3 from skill-validator.md)
2134
+ Fail if Level 1 or 2 fails. Warn if Level 3 fails.
2135
+ 2. Verify package.json has `mindforge` field with all required sub-fields
2136
+ 3. Verify CHANGELOG.md has an entry for the current version
2137
+ 4. Check if version already published: `npm info [package-name]@[version]`
2138
+ If already published: error "Version already exists. Bump the version."
2139
+ 5. Run `npm pack --dry-run` to preview what will be published
2140
+ 6. Confirm with user: "These files will be published: [list]. Proceed? (yes/no)"
2141
+ 7. If --dry-run: stop here, show preview only
2142
+ 8. Publish: `npm publish --access public`
2143
+ 9. Verify: `npm info [package-name]@[version]` — confirm publication succeeded
2144
+ 10. Write AUDIT: `{ "event": "skill_published", "package": "...", "version": "..." }`
2145
+ 11. Report: "✅ [package-name]@[version] published to npm registry"
2146
+ ```
2147
+
2148
+ ### `.claude/commands/mindforge/pr-review.md`
2149
+
2150
+ ```markdown
2151
+ # MindForge — PR Review Command
2152
+ # Usage: /mindforge:pr-review [--diff path] [--sha base..head] [--output github|json|markdown]
2153
+
2154
+ Run the AI PR review engine on a pull request diff.
2155
+
2156
+ Steps:
2157
+ 1. Determine diff source:
2158
+ - `--diff path`: read diff from file
2159
+ - `--sha base..head`: run `git diff base..head`
2160
+ - Default: `git diff HEAD~1` (last commit) or `git diff --staged` (staged changes)
2161
+
2162
+ 2. Load review context (per ai-reviewer.md):
2163
+ - PROJECT.md, ARCHITECTURE.md, CONVENTIONS.md, SECURITY.md
2164
+ - Current phase's CONTEXT.md (if in an active phase)
2165
+ - Any active ADRs relevant to changed files
2166
+
2167
+ 3. Detect change type and select review template:
2168
+ - Auth/security changes → Security-focused review template
2169
+ - Database migrations → Database migration review template
2170
+ - API changes → API breaking change review template
2171
+ - Default → Standard review template
2172
+
2173
+ 4. Check API availability:
2174
+ - ANTHROPIC_API_KEY set? If not: warn and skip AI review
2175
+ - Check daily review limit (from ai-reviewer.md)
2176
+ - Check cache: has this SHA been reviewed in the last 60 minutes?
2177
+
2178
+ 5. Call Claude API (per ai-reviewer.md buildSystemPrompt + buildReviewPrompt)
2179
+ - Handle errors gracefully — API unavailable is NOT a build failure
2180
+ - Timeout: 60 seconds
2181
+
2182
+ 6. Format output per --output flag:
2183
+ - github: GitHub-flavoured markdown for PR comment
2184
+ - json: structured JSON with findings array
2185
+ - markdown: standard markdown
2186
+
2187
+ 7. Write to output:
2188
+ - If in CI: write to /tmp/mindforge-review.md (read by GitHub Actions step)
2189
+ - If interactive: display to user
2190
+
2191
+ 8. Write AUDIT entry
2192
+ ```
2193
+
2194
+ ### `.claude/commands/mindforge/workspace.md`
2195
+
2196
+ ```markdown
2197
+ # MindForge — Workspace Command
2198
+ # Usage: /mindforge:workspace [detect|list|plan phase N|test]
2199
+
2200
+ Monorepo workspace management.
2201
+
2202
+ ## detect
2203
+ Run workspace detector from `.mindforge/monorepo/workspace-detector.md`.
2204
+ Write WORKSPACE-MANIFEST.json.
2205
+ Report: workspace type, packages found, dependency order.
2206
+
2207
+ ## list
2208
+ Read WORKSPACE-MANIFEST.json and display package list:
2209
+ ```
2210
+ Workspace: Turborepo (4 packages)
2211
+ packages/shared → @myapp/shared (lib, 0 dependents)
2212
+ apps/api → @myapp/api (api, depends on: shared)
2213
+ apps/web → @myapp/web (web, depends on: shared, api)
2214
+ apps/mobile → @myapp/mobile (mobile, depends on: shared)
2215
+ Execution order: shared → api → (web, mobile in parallel)
2216
+ ```
2217
+
2218
+ ## plan phase N
2219
+ Create a phase plan that spans multiple packages.
2220
+ Uses cross-package-planner.md to determine package execution order.
2221
+ Each PLAN file includes a `<package>` and `<working-dir>` field.
2222
+
2223
+ ## test
2224
+ Run tests across all packages in dependency order.
2225
+ Report per-package test results and aggregate coverage.
2226
+ ```
2227
+
2228
+ ### `.claude/commands/mindforge/benchmark.md`
2229
+
2230
+ ```markdown
2231
+ # MindForge — Benchmark Command
2232
+ # Usage: /mindforge:benchmark [--skill skill-name] [--compare skill-a skill-b]
2233
+
2234
+ Measure skill effectiveness over time.
2235
+
2236
+ ## Single skill benchmark
2237
+ For a named skill, analyse AUDIT.jsonl and skill-usage.jsonl:
2238
+ - How many times was the skill loaded this month?
2239
+ - What is the verify pass rate for tasks where this skill was loaded?
2240
+ - Are there anti-patterns less common after this skill is loaded?
2241
+ - What is the average session quality score when this skill is active?
2242
+
2243
+ Report:
2244
+ ```
2245
+ Skill Benchmark: security-review v1.0.0
2246
+ ────────────────────────────────────────
2247
+ Usage (last 30 days): 47 task loads
2248
+ Trigger distribution: text match 68%, file-path 22%, file-name 10%
2249
+ Verify pass rate: 91% (vs. 84% baseline without this skill)
2250
+ Security findings: 8 HIGH caught (0 CRITICAL missed in tasks using this skill)
2251
+ Session quality lift: +6.2 points average when loaded
2252
+
2253
+ Assessment: HIGH VALUE — clear quality improvement signal
2254
+ ```
2255
+
2256
+ ## Skill comparison
2257
+ Compare two skills head-to-head:
2258
+ - Load frequency
2259
+ - Verify pass rate improvement
2260
+ - Anti-pattern detection rate
2261
+ - Context budget cost (token estimate)
2262
+
2263
+ Helps decide: should you keep both skills, or deprecate the lower-performer?
2264
+ ```
2265
+
2266
+ **Commit:**
2267
+ ```bash
2268
+ for cmd in install-skill publish-skill pr-review workspace benchmark; do
2269
+ cp .claude/commands/mindforge/${cmd}.md .agent/mindforge/${cmd}.md
2270
+ done
2271
+ git add .claude/commands/mindforge/ .agent/mindforge/
2272
+ git commit -m "feat(commands): add install-skill, publish-skill, pr-review, workspace, benchmark commands"
2273
+ ```
2274
+
2275
+ ---
2276
+
2277
+ ## TASK 9 — Write the MINDFORGE.md JSON Schema
2278
+
2279
+ ### `.mindforge/MINDFORGE-SCHEMA.json`
2280
+
2281
+ ```json
2282
+ {
2283
+ "$schema": "http://json-schema.org/draft-07/schema#",
2284
+ "title": "MindForge Project Configuration Schema",
2285
+ "description": "JSON Schema for MINDFORGE.md key-value settings",
2286
+ "type": "object",
2287
+ "properties": {
2288
+ "MINDFORGE_VERSION_REQUIRED": {
2289
+ "type": "string",
2290
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
2291
+ "description": "Minimum MindForge version required for this config"
2292
+ },
2293
+ "PLANNER_MODEL": {
2294
+ "type": "enum",
2295
+ "values": ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5", "inherit"],
2296
+ "description": "Claude model to use for the planning agent"
2297
+ },
2298
+ "EXECUTOR_MODEL": {
2299
+ "type": "enum",
2300
+ "values": ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5", "inherit"],
2301
+ "description": "Claude model to use for execution agents"
2302
+ },
2303
+ "REVIEWER_MODEL": {
2304
+ "type": "enum",
2305
+ "values": ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5", "inherit"],
2306
+ "description": "Claude model to use for the code reviewer"
2307
+ },
2308
+ "SECURITY_MODEL": {
2309
+ "type": "enum",
2310
+ "values": ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5", "inherit"],
2311
+ "description": "Claude model to use for security review (recommend Opus for thoroughness)"
2312
+ },
2313
+ "TIER1_AUTO_APPROVE": {
2314
+ "type": "boolean",
2315
+ "description": "Auto-approve Tier 1 changes without user confirmation"
2316
+ },
2317
+ "WAVE_CONFIRMATION_REQUIRED": {
2318
+ "type": "boolean",
2319
+ "description": "Require user confirmation before each execution wave"
2320
+ },
2321
+ "AUTO_DISCUSS_PHASE": {
2322
+ "type": "boolean",
2323
+ "description": "Automatically run discuss-phase before every plan-phase"
2324
+ },
2325
+ "VERIFY_PASS_RATE_WARNING_THRESHOLD": {
2326
+ "type": "number",
2327
+ "minimum": 0,
2328
+ "maximum": 1,
2329
+ "description": "Warn when first-attempt verify pass rate drops below this"
2330
+ },
2331
+ "COMPACTION_THRESHOLD_PCT": {
2332
+ "type": "number",
2333
+ "minimum": 50,
2334
+ "maximum": 90,
2335
+ "description": "Context window percentage that triggers compaction"
2336
+ },
2337
+ "MAX_TASKS_PER_PHASE": {
2338
+ "type": "number",
2339
+ "minimum": 1,
2340
+ "maximum": 50,
2341
+ "description": "Suggest phase split when task count exceeds this"
2342
+ },
2343
+ "MIN_TEST_COVERAGE_PCT": {
2344
+ "type": "number",
2345
+ "minimum": 0,
2346
+ "maximum": 100,
2347
+ "description": "Minimum test coverage percentage required"
2348
+ },
2349
+ "MAX_FUNCTION_LINES": {
2350
+ "type": "number",
2351
+ "minimum": 10,
2352
+ "maximum": 200,
2353
+ "description": "Maximum allowed function length in lines"
2354
+ },
2355
+ "MAX_CYCLOMATIC_COMPLEXITY": {
2356
+ "type": "number",
2357
+ "minimum": 3,
2358
+ "maximum": 30,
2359
+ "description": "Maximum allowed cyclomatic complexity per function"
2360
+ },
2361
+ "BLOCK_ON_MEDIUM_SECURITY_FINDINGS": {
2362
+ "type": "boolean",
2363
+ "description": "Block PR creation on MEDIUM security findings (default: only HIGH+)"
2364
+ },
2365
+ "ALWAYS_LOAD_SKILLS": {
2366
+ "type": "string",
2367
+ "description": "Comma-separated list of skills to always load regardless of triggers"
2368
+ },
2369
+ "DISABLED_SKILLS": {
2370
+ "type": "string",
2371
+ "description": "Comma-separated list of skills to never load"
2372
+ },
2373
+ "MAX_FULL_SKILL_INJECTIONS": {
2374
+ "type": "number",
2375
+ "minimum": 1,
2376
+ "maximum": 10,
2377
+ "description": "Maximum number of skills to inject in full (rest are summarised)"
2378
+ },
2379
+ "COMMIT_FORMAT": {
2380
+ "type": "enum",
2381
+ "values": ["conventional-commits", "custom", "none"],
2382
+ "description": "Commit message format convention"
2383
+ },
2384
+ "BRANCHING_STRATEGY": {
2385
+ "type": "enum",
2386
+ "values": ["none", "phase", "milestone"],
2387
+ "description": "Git branching strategy for MindForge phases"
2388
+ },
2389
+ "NOTIFY_ON": {
2390
+ "type": "string",
2391
+ "description": "Comma-separated events that trigger Slack notifications"
2392
+ },
2393
+ "DISCUSS_PHASE_REQUIRED_ABOVE_DIFFICULTY": {
2394
+ "type": "number",
2395
+ "minimum": 1,
2396
+ "maximum": 5,
2397
+ "description": "Require discuss-phase when difficulty score exceeds this value"
2398
+ },
2399
+ "CI_AUTO_APPROVE_TIER2": {
2400
+ "type": "boolean",
2401
+ "nonOverridable": false,
2402
+ "description": "Auto-approve Tier 2 changes in CI mode"
2403
+ },
2404
+ "CI_SECURITY_SCAN": {
2405
+ "type": "boolean",
2406
+ "description": "Run security scan in CI mode"
2407
+ },
2408
+ "CI_MIN_COVERAGE_PCT": {
2409
+ "type": "number",
2410
+ "minimum": 0,
2411
+ "maximum": 100,
2412
+ "description": "Minimum test coverage in CI (may differ from interactive threshold)"
2413
+ },
2414
+ "CI_OUTPUT_FORMAT": {
2415
+ "type": "enum",
2416
+ "values": ["json", "text", "github-annotations"],
2417
+ "description": "Output format for CI execution logs"
2418
+ },
2419
+ "SECURITY_AUTOTRIGGER": {
2420
+ "type": "boolean",
2421
+ "nonOverridable": true,
2422
+ "description": "NON-OVERRIDABLE: security auto-trigger for auth/payment/PII changes"
2423
+ },
2424
+ "SECRET_DETECTION": {
2425
+ "type": "boolean",
2426
+ "nonOverridable": true,
2427
+ "description": "NON-OVERRIDABLE: secret detection compliance gate"
2428
+ },
2429
+ "PLAN_FIRST": {
2430
+ "type": "boolean",
2431
+ "nonOverridable": true,
2432
+ "description": "NON-OVERRIDABLE: plan-first rule (no implementation without a PLAN)"
2433
+ },
2434
+ "AUDIT_WRITING": {
2435
+ "type": "boolean",
2436
+ "nonOverridable": true,
2437
+ "description": "NON-OVERRIDABLE: AUDIT.jsonl writing for every significant action"
2438
+ }
2439
+ }
2440
+ }
2441
+ ```
2442
+
2443
+ **Commit:**
2444
+ ```bash
2445
+ git add .mindforge/MINDFORGE-SCHEMA.json bin/validate-config.js
2446
+ git commit -m "feat(config): add MINDFORGE.md JSON schema with non-overridable fields"
2447
+ ```
2448
+
2449
+ ---
2450
+
2451
+ ## TASK 10 — Update CLAUDE.md for Day 6
2452
+
2453
+ Add to `.claude/CLAUDE.md` and `.agent/CLAUDE.md`:
2454
+
2455
+ ```markdown
2456
+ ---
2457
+
2458
+ ## DISTRIBUTION & CI LAYER (Day 6)
2459
+
2460
+ ### CI mode awareness
2461
+ If `CI=true` or `MINDFORGE_CI=true` environment variables are set:
2462
+ - All interactive prompts are skipped
2463
+ - Output structured JSON or GitHub annotations (per CI_OUTPUT_FORMAT in MINDFORGE.md)
2464
+ - Tier 3 changes automatically fail (never auto-approve Tier 3 in CI)
2465
+ - UAT is skipped (CI_SKIP_UAT=true default) — only automated verification runs
2466
+ - Log every gate result to stdout in the configured format
2467
+
2468
+ ### Skill installation from registry
2469
+ When the user requests `/mindforge:install-skill [name]`:
2470
+ Follow the full protocol from `.mindforge/distribution/registry-client.md`.
2471
+ Always validate before installing. Always run injection guard.
2472
+ Never install a skill that fails Level 1 or Level 2 validation.
2473
+
2474
+ ### Monorepo awareness
2475
+ If `WORKSPACE-MANIFEST.json` exists in `.planning/`:
2476
+ - The project uses a monorepo structure
2477
+ - Phase execution must follow the cross-package dependency order
2478
+ - Each PLAN file must declare its `<package>` and `<working-dir>`
2479
+ - Run tests per-package, then aggregate
2480
+
2481
+ ### AI PR Review
2482
+ When the user requests `/mindforge:pr-review`:
2483
+ - Check for ANTHROPIC_API_KEY — if missing, skip gracefully (not a failure)
2484
+ - Load review context from PROJECT.md, ARCHITECTURE.md, CONVENTIONS.md
2485
+ - Select the appropriate review template based on change type
2486
+ - Never use the AI review as a substitute for human review
2487
+ - Always include the disclaimer in output
2488
+
2489
+ ### Config validation
2490
+ At session start, if MINDFORGE.md exists:
2491
+ Run `node bin/validate-config.js` silently.
2492
+ If errors: warn the user before proceeding.
2493
+ If warnings about non-overridable settings: ignore the override silently (per ADR-013).
2494
+
2495
+ ### New commands available (Day 6)
2496
+ - `/mindforge:init-org` — organisation-wide setup
2497
+ - `/mindforge:install-skill` — install skill from registry
2498
+ - `/mindforge:publish-skill` — publish skill to registry
2499
+ - `/mindforge:pr-review` — AI code review
2500
+ - `/mindforge:workspace` — monorepo workspace management
2501
+ - `/mindforge:benchmark` — skill effectiveness benchmarking
2502
+
2503
+ ---
2504
+ ```
2505
+
2506
+ **Commit:**
2507
+ ```bash
2508
+ git add .claude/CLAUDE.md .agent/CLAUDE.md
2509
+ git commit -m "feat(core): update CLAUDE.md with Day 6 distribution and CI awareness"
2510
+ ```
2511
+
2512
+ ---
2513
+
2514
+ ## TASK 11 — Write Day 6 test suites
2515
+
2516
+ ### `tests/distribution.test.js`
2517
+
2518
+ ```javascript
2519
+ /**
2520
+ * MindForge Day 6 — Distribution Tests
2521
+ * Run: node tests/distribution.test.js
2522
+ */
2523
+ 'use strict';
2524
+ const fs = require('fs'), path = require('path'), assert = require('assert');
2525
+ let passed = 0, failed = 0;
2526
+
2527
+ function test(name, fn) {
2528
+ try { fn(); console.log(` ✅ ${name}`); passed++; }
2529
+ catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
2530
+ }
2531
+ const read = p => fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : '';
2532
+
2533
+ // ── Skill package name validation ─────────────────────────────────────────────
2534
+ function isValidSkillPackageName(name) {
2535
+ return /^mindforge-skill-[a-z][a-z0-9-]+$/.test(name);
2536
+ }
2537
+
2538
+ // ── Skill frontmatter parser (reused from earlier tests) ──────────────────────
2539
+ function parseSkillFrontmatter(content) {
2540
+ if (!content.startsWith('---')) throw new Error('Missing frontmatter');
2541
+ const end = content.indexOf('---', 3);
2542
+ if (end === -1) throw new Error('Unclosed frontmatter');
2543
+ const fm = content.slice(3, end).trim();
2544
+ const result = {};
2545
+ fm.split('\n').forEach(line => {
2546
+ const colon = line.indexOf(':');
2547
+ if (colon === -1) return;
2548
+ result[line.slice(0, colon).trim()] = line.slice(colon + 1).trim();
2549
+ });
2550
+ return result;
2551
+ }
2552
+
2553
+ // ── MINDFORGE-SCHEMA.json validation ─────────────────────────────────────────
2554
+ function parseMindforgeMd(content) {
2555
+ const settings = {};
2556
+ content.split('\n').forEach(line => {
2557
+ const m = line.match(/^([A-Z_]+)=(.+)$/);
2558
+ if (m) settings[m[1]] = m[2].trim();
2559
+ });
2560
+ return settings;
2561
+ }
2562
+
2563
+ console.log('\nMindForge Day 6 — Distribution Tests\n');
2564
+
2565
+ console.log('Distribution engine files:');
2566
+ [
2567
+ 'registry-client.md', 'skill-publisher.md', 'skill-validator.md', 'registry-schema.md'
2568
+ ].forEach(f => test(`${f} exists`, () => {
2569
+ assert.ok(fs.existsSync(`.mindforge/distribution/${f}`), `Missing: ${f}`);
2570
+ }));
2571
+
2572
+ console.log('\nSkill package naming:');
2573
+ test('valid package name accepted', () => {
2574
+ assert.ok(isValidSkillPackageName('mindforge-skill-security-owasp'));
2575
+ assert.ok(isValidSkillPackageName('mindforge-skill-db-postgres'));
2576
+ assert.ok(isValidSkillPackageName('mindforge-skill-frontend-react-a11y'));
2577
+ });
2578
+
2579
+ test('invalid package names rejected', () => {
2580
+ assert.ok(!isValidSkillPackageName('security-review')); // missing prefix
2581
+ assert.ok(!isValidSkillPackageName('mindforge-skill-')); // empty name
2582
+ assert.ok(!isValidSkillPackageName('mindforge-skill-MY-SKILL')); // uppercase
2583
+ });
2584
+
2585
+ console.log('\nRegistry schema:');
2586
+ test('registry-schema.md defines npm-based distribution', () => {
2587
+ const c = read('.mindforge/distribution/registry-schema.md');
2588
+ assert.ok(c.includes('npm'), 'Should describe npm-based registry');
2589
+ assert.ok(c.includes('mindforge-skill-'), 'Should define naming convention');
2590
+ });
2591
+
2592
+ test('skill validator defines 3 validation levels', () => {
2593
+ const c = read('.mindforge/distribution/skill-validator.md');
2594
+ assert.ok(c.includes('Level 1'), 'Missing Level 1');
2595
+ assert.ok(c.includes('Level 2'), 'Missing Level 2');
2596
+ assert.ok(c.includes('Level 3'), 'Missing Level 3');
2597
+ });
2598
+
2599
+ test('registry client has injection guard step', () => {
2600
+ const c = read('.mindforge/distribution/registry-client.md');
2601
+ assert.ok(c.includes('injection guard') || c.includes('injection'), 'Should run injection guard before install');
2602
+ });
2603
+
2604
+ console.log('\nMINDFORGE.md schema:');
2605
+ test('MINDFORGE-SCHEMA.json exists', () => {
2606
+ assert.ok(fs.existsSync('.mindforge/MINDFORGE-SCHEMA.json'));
2607
+ });
2608
+
2609
+ test('schema is valid JSON', () => {
2610
+ const content = fs.readFileSync('.mindforge/MINDFORGE-SCHEMA.json', 'utf8');
2611
+ assert.doesNotThrow(() => JSON.parse(content));
2612
+ });
2613
+
2614
+ test('schema marks non-overridable fields', () => {
2615
+ const schema = JSON.parse(fs.readFileSync('.mindforge/MINDFORGE-SCHEMA.json', 'utf8'));
2616
+ const nonOverridable = Object.entries(schema.properties || {})
2617
+ .filter(([, def]) => def.nonOverridable === true)
2618
+ .map(([key]) => key);
2619
+ assert.ok(nonOverridable.includes('SECURITY_AUTOTRIGGER'), 'SECURITY_AUTOTRIGGER should be non-overridable');
2620
+ assert.ok(nonOverridable.includes('SECRET_DETECTION'), 'SECRET_DETECTION should be non-overridable');
2621
+ assert.ok(nonOverridable.includes('PLAN_FIRST'), 'PLAN_FIRST should be non-overridable');
2622
+ assert.ok(nonOverridable.includes('AUDIT_WRITING'), 'AUDIT_WRITING should be non-overridable');
2623
+ });
2624
+
2625
+ test('validate-config.js exists and is executable-looking', () => {
2626
+ assert.ok(fs.existsSync('bin/validate-config.js'));
2627
+ const content = read('bin/validate-config.js');
2628
+ assert.ok(content.includes('#!/usr/bin/env node'), 'Missing shebang');
2629
+ assert.ok(content.includes('MINDFORGE-SCHEMA.json'), 'Should reference schema file');
2630
+ });
2631
+
2632
+ console.log('\nSDK:');
2633
+ test('sdk directory structure exists', () => {
2634
+ assert.ok(fs.existsSync('sdk/src/index.ts'));
2635
+ assert.ok(fs.existsSync('sdk/src/client.ts'));
2636
+ assert.ok(fs.existsSync('sdk/src/types.ts'));
2637
+ assert.ok(fs.existsSync('sdk/src/events.ts'));
2638
+ assert.ok(fs.existsSync('sdk/src/commands.ts'));
2639
+ assert.ok(fs.existsSync('sdk/package.json'));
2640
+ });
2641
+
2642
+ test('sdk package.json has correct name', () => {
2643
+ const pkg = JSON.parse(fs.readFileSync('sdk/package.json', 'utf8'));
2644
+ assert.strictEqual(pkg.name, '@mindforge/sdk');
2645
+ });
2646
+
2647
+ test('sdk index.ts exports MindForgeClient', () => {
2648
+ const content = read('sdk/src/index.ts');
2649
+ assert.ok(content.includes('MindForgeClient'), 'Should export MindForgeClient');
2650
+ assert.ok(content.includes('MindForgeEventStream'), 'Should export MindForgeEventStream');
2651
+ });
2652
+
2653
+ test('sdk types.ts defines PhaseResult', () => {
2654
+ const content = read('sdk/src/types.ts');
2655
+ assert.ok(content.includes('PhaseResult'), 'Should define PhaseResult');
2656
+ assert.ok(content.includes('SecurityFinding'), 'Should define SecurityFinding');
2657
+ assert.ok(content.includes('MindForgeEvent'), 'Should define MindForgeEvent');
2658
+ });
2659
+
2660
+ console.log('\nAll 31 commands present:');
2661
+ const ALL_COMMANDS = [
2662
+ 'help','init-project','plan-phase','execute-phase','verify-phase','ship',
2663
+ 'next','quick','status','debug',
2664
+ 'skills','review','security-scan','map-codebase','discuss-phase',
2665
+ 'audit','milestone','complete-milestone','approve','sync-jira','sync-confluence',
2666
+ 'health','retrospective','profile-team','metrics',
2667
+ 'init-org','install-skill','publish-skill','pr-review','workspace','benchmark'
2668
+ ];
2669
+ test(`all ${ALL_COMMANDS.length} commands in .claude/commands/mindforge/`, () => {
2670
+ ALL_COMMANDS.forEach(cmd => {
2671
+ assert.ok(fs.existsSync(`.claude/commands/mindforge/${cmd}.md`), `Missing: ${cmd}.md`);
2672
+ });
2673
+ });
2674
+ test(`all ${ALL_COMMANDS.length} commands mirrored to .agent/mindforge/`, () => {
2675
+ ALL_COMMANDS.forEach(cmd => {
2676
+ assert.ok(fs.existsSync(`.agent/mindforge/${cmd}.md`), `Missing .agent: ${cmd}.md`);
2677
+ });
2678
+ });
2679
+
2680
+ console.log(`\n${'─'.repeat(50)}`);
2681
+ console.log(`Results: ${passed} passed, ${failed} failed`);
2682
+ if (failed > 0) { console.error(`\n❌ ${failed} test(s) failed.\n`); process.exit(1); }
2683
+ else { console.log(`\n✅ All distribution tests passed.\n`); }
2684
+ ```
2685
+
2686
+ ### `tests/ci-mode.test.js`
2687
+
2688
+ ```javascript
2689
+ /**
2690
+ * MindForge Day 6 — CI Mode Tests
2691
+ * Run: node tests/ci-mode.test.js
2692
+ */
2693
+ 'use strict';
2694
+ const fs = require('fs'), assert = require('assert');
2695
+ let passed = 0, failed = 0;
2696
+ function test(name, fn) {
2697
+ try { fn(); console.log(` ✅ ${name}`); passed++; }
2698
+ catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
2699
+ }
2700
+ const read = p => fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : '';
2701
+
2702
+ // ── CI mode detection simulation ──────────────────────────────────────────────
2703
+ function isCiMode() {
2704
+ return process.env.CI === 'true' ||
2705
+ process.env.MINDFORGE_CI === 'true' ||
2706
+ process.stdin.isTTY === false;
2707
+ }
2708
+
2709
+ // ── GitHub annotations format ─────────────────────────────────────────────────
2710
+ function formatGitHubAnnotation(level, message, file, line) {
2711
+ const loc = file ? ` file=${file}${line ? `,line=${line}` : ''}` : '';
2712
+ return `::${level}${loc}::${message}`;
2713
+ }
2714
+
2715
+ // ── Tier3 CI block simulation ─────────────────────────────────────────────────
2716
+ function checkCiTierPolicy(tier, ciAutoApproveTier2 = false) {
2717
+ if (tier === 1) return 'auto-approved';
2718
+ if (tier === 2) return ciAutoApproveTier2 ? 'auto-approved' : 'blocked';
2719
+ if (tier === 3) return 'blocked'; // Always blocked in CI
2720
+ return 'unknown';
2721
+ }
2722
+
2723
+ console.log('\nMindForge Day 6 — CI Mode Tests\n');
2724
+
2725
+ console.log('CI engine files:');
2726
+ ['ci-mode.md','github-actions-adapter.md','gitlab-ci-adapter.md'].forEach(f => {
2727
+ test(`${f} exists`, () => {
2728
+ assert.ok(fs.existsSync(`.mindforge/ci/${f}`), `Missing: .mindforge/ci/${f}`);
2729
+ });
2730
+ });
2731
+
2732
+ console.log('\nCI mode detection:');
2733
+ test('isCiMode returns false in normal test environment', () => {
2734
+ const origCI = process.env.CI;
2735
+ delete process.env.CI;
2736
+ delete process.env.MINDFORGE_CI;
2737
+ // In test environment, stdin.isTTY may be false — we test the env var logic only
2738
+ const ciFromEnv = process.env.CI === 'true' || process.env.MINDFORGE_CI === 'true';
2739
+ assert.strictEqual(ciFromEnv, false, 'Should not be CI mode from env vars');
2740
+ if (origCI) process.env.CI = origCI;
2741
+ });
2742
+
2743
+ test('CI=true activates CI mode', () => {
2744
+ process.env.MINDFORGE_CI = 'true';
2745
+ assert.strictEqual(process.env.MINDFORGE_CI, 'true');
2746
+ delete process.env.MINDFORGE_CI;
2747
+ });
2748
+
2749
+ console.log('\nCI tier policy:');
2750
+ test('Tier 1 is always auto-approved in CI', () => {
2751
+ assert.strictEqual(checkCiTierPolicy(1), 'auto-approved');
2752
+ });
2753
+
2754
+ test('Tier 2 blocked by default in CI (safety-first)', () => {
2755
+ assert.strictEqual(checkCiTierPolicy(2, false), 'blocked');
2756
+ });
2757
+
2758
+ test('Tier 2 can be auto-approved in CI when configured', () => {
2759
+ assert.strictEqual(checkCiTierPolicy(2, true), 'auto-approved');
2760
+ });
2761
+
2762
+ test('Tier 3 is ALWAYS blocked in CI regardless of config', () => {
2763
+ assert.strictEqual(checkCiTierPolicy(3, true), 'blocked'); // even with true
2764
+ assert.strictEqual(checkCiTierPolicy(3, false), 'blocked');
2765
+ });
2766
+
2767
+ console.log('\nGitHub annotations format:');
2768
+ test('notice annotation format is correct', () => {
2769
+ const ann = formatGitHubAnnotation('notice', 'Task 3-01 completed', null, null);
2770
+ assert.strictEqual(ann, '::notice::Task 3-01 completed');
2771
+ });
2772
+
2773
+ test('error annotation with file and line is correct', () => {
2774
+ const ann = formatGitHubAnnotation('error', 'TypeScript error', 'src/auth.ts', 47);
2775
+ assert.strictEqual(ann, '::error file=src/auth.ts,line=47::TypeScript error');
2776
+ });
2777
+
2778
+ test('warning annotation with file only (no line)', () => {
2779
+ const ann = formatGitHubAnnotation('warning', 'Security finding', 'src/utils.ts', null);
2780
+ assert.strictEqual(ann, '::warning file=src/utils.ts::Security finding');
2781
+ });
2782
+
2783
+ console.log('\nGitHub Actions workflow:');
2784
+ test('github-actions-adapter.md defines mindforge-ci.yml structure', () => {
2785
+ const c = read('.mindforge/ci/github-actions-adapter.md');
2786
+ assert.ok(c.includes('mindforge-ci.yml') || c.includes('on:'), 'Should define GitHub Actions workflow');
2787
+ assert.ok(c.includes('mindforge-health'), 'Should include health check job');
2788
+ assert.ok(c.includes('mindforge-security'), 'Should include security scan job');
2789
+ });
2790
+
2791
+ test('ci-mode.md defines Tier 3 block policy', () => {
2792
+ const c = read('.mindforge/ci/ci-mode.md');
2793
+ assert.ok(
2794
+ (c.includes('Tier 3') && c.includes('block')) || c.includes('ALWAYS fails'),
2795
+ 'CI mode should block Tier 3 changes'
2796
+ );
2797
+ });
2798
+
2799
+ test('ci-mode.md has timeout configuration', () => {
2800
+ const c = read('.mindforge/ci/ci-mode.md');
2801
+ assert.ok(c.includes('timeout') || c.includes('TIMEOUT'), 'CI mode should have timeout config');
2802
+ });
2803
+
2804
+ console.log('\nMonorepo support:');
2805
+ ['workspace-detector.md','cross-package-planner.md','dependency-graph-builder.md'].forEach(f => {
2806
+ test(`${f} exists`, () => {
2807
+ assert.ok(fs.existsSync(`.mindforge/monorepo/${f}`), `Missing: .mindforge/monorepo/${f}`);
2808
+ });
2809
+ });
2810
+
2811
+ test('workspace-detector supports major monorepo types', () => {
2812
+ const c = read('.mindforge/monorepo/workspace-detector.md');
2813
+ ['nx', 'turborepo', 'lerna', 'pnpm'].forEach(type => {
2814
+ assert.ok(c.includes(type), `Should support ${type} monorepo type`);
2815
+ });
2816
+ });
2817
+
2818
+ test('cross-package-planner has topological sort', () => {
2819
+ const c = read('.mindforge/monorepo/cross-package-planner.md');
2820
+ assert.ok(
2821
+ c.includes('topological') || c.includes('dependency order') || c.includes('Execution order'),
2822
+ 'Should use topological sort for package order'
2823
+ );
2824
+ });
2825
+
2826
+ console.log(`\n${'─'.repeat(50)}`);
2827
+ console.log(`Results: ${passed} passed, ${failed} failed`);
2828
+ if (failed > 0) { console.error(`\n❌ ${failed} test(s) failed.\n`); process.exit(1); }
2829
+ else { console.log(`\n✅ All CI mode tests passed.\n`); }
2830
+ ```
2831
+
2832
+ ### `tests/sdk.test.js`
2833
+
2834
+ ```javascript
2835
+ /**
2836
+ * MindForge Day 6 — SDK Tests
2837
+ * Run: node tests/sdk.test.js
2838
+ */
2839
+ 'use strict';
2840
+ const fs = require('fs'), path = require('path'), assert = require('assert');
2841
+ let passed = 0, failed = 0;
2842
+ function test(name, fn) {
2843
+ try { fn(); console.log(` ✅ ${name}`); passed++; }
2844
+ catch(e) { console.error(` ❌ ${name}\n ${e.message}`); failed++; }
2845
+ }
2846
+ const read = p => fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : '';
2847
+
2848
+ // ── Lightweight SDK client simulation (without TypeScript compilation) ─────────
2849
+ class MockMindForgeClient {
2850
+ constructor(config = {}) {
2851
+ this.projectRoot = config.projectRoot || process.cwd();
2852
+ }
2853
+ isInitialised() {
2854
+ return fs.existsSync(path.join(this.projectRoot, '.planning', 'PROJECT.md'));
2855
+ }
2856
+ readHandoff() {
2857
+ const p = path.join(this.projectRoot, '.planning', 'HANDOFF.json');
2858
+ if (!fs.existsSync(p)) return null;
2859
+ try { return JSON.parse(fs.readFileSync(p, 'utf8')); }
2860
+ catch { return null; }
2861
+ }
2862
+ readAuditLog(filter = {}) {
2863
+ const p = path.join(this.projectRoot, '.planning', 'AUDIT.jsonl');
2864
+ if (!fs.existsSync(p)) return [];
2865
+ return fs.readFileSync(p, 'utf8')
2866
+ .split('\n').filter(Boolean)
2867
+ .map(l => { try { return JSON.parse(l); } catch { return null; } })
2868
+ .filter(Boolean)
2869
+ .filter(e => !filter.event || e.event === filter.event);
2870
+ }
2871
+ async health() {
2872
+ const warnings = [], errors = [], info = [];
2873
+ const handoff = this.readHandoff();
2874
+ if (handoff && !handoff.schema_version) {
2875
+ errors.push({ category: 'state', message: 'HANDOFF.json missing schema_version' });
2876
+ }
2877
+ return {
2878
+ overallStatus: errors.length > 0 ? 'error' : warnings.length > 0 ? 'warning' : 'healthy',
2879
+ errors, warnings, informational: info,
2880
+ timestamp: new Date().toISOString(),
2881
+ };
2882
+ }
2883
+ }
2884
+
2885
+ // ── Command builder simulation ────────────────────────────────────────────────
2886
+ const commands = {
2887
+ health: (opts = {}) => `/mindforge:health ${(opts.flags||[]).join(' ')}`.trim(),
2888
+ planPhase: (n, opts = {}) => `/mindforge:plan-phase ${n} ${(opts.flags||[]).join(' ')}`.trim(),
2889
+ executePhase: (n, opts = {}) => `/mindforge:execute-phase ${n} ${(opts.flags||[]).join(' ')}`.trim(),
2890
+ audit: (f = {}) => {
2891
+ const parts = ['/mindforge:audit'];
2892
+ if (f.phase) parts.push(`--phase ${f.phase}`);
2893
+ if (f.event) parts.push(`--event ${f.event}`);
2894
+ return parts.join(' ');
2895
+ },
2896
+ };
2897
+
2898
+ console.log('\nMindForge Day 6 — SDK Tests\n');
2899
+
2900
+ console.log('SDK source files:');
2901
+ ['index.ts','client.ts','types.ts','events.ts','commands.ts'].forEach(f => {
2902
+ test(`sdk/src/${f} exists`, () => {
2903
+ assert.ok(fs.existsSync(`sdk/src/${f}`), `Missing: sdk/src/${f}`);
2904
+ });
2905
+ });
2906
+
2907
+ console.log('\nSDK type exports:');
2908
+ test('index.ts exports VERSION', () => {
2909
+ const c = read('sdk/src/index.ts');
2910
+ assert.ok(c.includes("VERSION"), 'Should export VERSION');
2911
+ });
2912
+
2913
+ test('types.ts defines MindForgeConfig', () => {
2914
+ const c = read('sdk/src/types.ts');
2915
+ assert.ok(c.includes('MindForgeConfig'), 'Should define MindForgeConfig');
2916
+ });
2917
+
2918
+ test('types.ts defines all result types', () => {
2919
+ const c = read('sdk/src/types.ts');
2920
+ ['PhaseResult','TaskResult','SecurityFinding','GateResult','HealthReport'].forEach(t => {
2921
+ assert.ok(c.includes(t), `Should define ${t}`);
2922
+ });
2923
+ });
2924
+
2925
+ test('events.ts defines MindForgeEventStream', () => {
2926
+ const c = read('sdk/src/events.ts');
2927
+ assert.ok(c.includes('MindForgeEventStream'), 'Should define MindForgeEventStream');
2928
+ assert.ok(c.includes('watchAuditLog'), 'Should have watchAuditLog method');
2929
+ });
2930
+
2931
+ console.log('\nSDK client behaviour:');
2932
+
2933
+ test('client.isInitialised() returns false when PROJECT.md missing', () => {
2934
+ const client = new MockMindForgeClient({ projectRoot: '/tmp/nonexistent-project' });
2935
+ assert.strictEqual(client.isInitialised(), false);
2936
+ });
2937
+
2938
+ test('client.isInitialised() returns true when PROJECT.md exists', () => {
2939
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
2940
+ // May be true or false depending on whether we're in a MindForge project
2941
+ assert.ok(typeof client.isInitialised() === 'boolean');
2942
+ });
2943
+
2944
+ test('client.readHandoff() returns null when HANDOFF.json missing', () => {
2945
+ const client = new MockMindForgeClient({ projectRoot: '/tmp/nonexistent-project' });
2946
+ assert.strictEqual(client.readHandoff(), null);
2947
+ });
2948
+
2949
+ test('client.readHandoff() parses valid HANDOFF.json', () => {
2950
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
2951
+ const handoff = client.readHandoff();
2952
+ if (handoff) {
2953
+ assert.ok(typeof handoff === 'object', 'HANDOFF.json should parse to object');
2954
+ assert.ok(handoff.schema_version, 'HANDOFF.json should have schema_version');
2955
+ }
2956
+ // null is acceptable if not in a MindForge project
2957
+ });
2958
+
2959
+ test('client.readAuditLog() returns array', () => {
2960
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
2961
+ const log = client.readAuditLog();
2962
+ assert.ok(Array.isArray(log), 'readAuditLog should return array');
2963
+ });
2964
+
2965
+ test('client.readAuditLog() filters by event type', () => {
2966
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
2967
+ const secFindings = client.readAuditLog({ event: 'security_finding' });
2968
+ assert.ok(Array.isArray(secFindings));
2969
+ secFindings.forEach(e => {
2970
+ assert.strictEqual(e.event, 'security_finding', 'All entries should match filter');
2971
+ });
2972
+ });
2973
+
2974
+ test('client.health() returns HealthReport shape', async () => {
2975
+ const client = new MockMindForgeClient({ projectRoot: process.cwd() });
2976
+ const report = await client.health();
2977
+ assert.ok(['healthy','warning','error'].includes(report.overallStatus));
2978
+ assert.ok(Array.isArray(report.errors));
2979
+ assert.ok(Array.isArray(report.warnings));
2980
+ assert.ok(report.timestamp);
2981
+ });
2982
+
2983
+ console.log('\nCommand builders:');
2984
+ test('commands.health() builds correct string', () => {
2985
+ assert.strictEqual(commands.health(), '/mindforge:health');
2986
+ assert.strictEqual(commands.health({ flags: ['--repair'] }), '/mindforge:health --repair');
2987
+ });
2988
+
2989
+ test('commands.planPhase() builds correct string', () => {
2990
+ assert.strictEqual(commands.planPhase(3), '/mindforge:plan-phase 3');
2991
+ });
2992
+
2993
+ test('commands.audit() builds filter string', () => {
2994
+ const cmd = commands.audit({ phase: 3, event: 'security_finding' });
2995
+ assert.ok(cmd.includes('--phase 3'));
2996
+ assert.ok(cmd.includes('--event security_finding'));
2997
+ });
2998
+
2999
+ test('commands.executePhase() includes phase number', () => {
3000
+ const cmd = commands.executePhase(2);
3001
+ assert.ok(cmd.includes('2'));
3002
+ assert.ok(cmd.startsWith('/mindforge:execute-phase'));
3003
+ });
3004
+
3005
+ console.log(`\n${'─'.repeat(50)}`);
3006
+ console.log(`Results: ${passed} passed, ${failed} failed`);
3007
+ if (failed > 0) { console.error(`\n❌ ${failed} test(s) failed.\n`); process.exit(1); }
3008
+ else { console.log(`\n✅ All SDK tests passed.\n`); }
3009
+ ```
3010
+
3011
+ **Commit:**
3012
+ ```bash
3013
+ git add tests/
3014
+ git commit -m "test(day6): add distribution, CI mode, and SDK test suites"
3015
+ ```
3016
+
3017
+ ---
3018
+
3019
+ ## TASK 12 — Run full test battery, bump version, and push
3020
+
3021
+ ```bash
3022
+ # Run all 10 test suites
3023
+ for suite in install wave-engine audit compaction skills-platform \
3024
+ integrations governance intelligence metrics \
3025
+ distribution ci-mode sdk; do
3026
+ node tests/${suite}.test.js | tail -1
3027
+ done
3028
+
3029
+ # Bump to v0.6.0
3030
+ node -e "
3031
+ const fs = require('fs');
3032
+ const p = JSON.parse(fs.readFileSync('package.json','utf8'));
3033
+ p.version = '0.6.0';
3034
+ fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n');
3035
+ console.log('Bumped to v0.6.0');
3036
+ "
3037
+
3038
+ git add package.json
3039
+ git commit -m "chore(release): bump to v0.6.0 — Day 6 distribution platform"
3040
+ git push origin feat/mindforge-distribution-platform
3041
+ ```
3042
+
3043
+ ---
3044
+
3045
+ # ═══════════════════════════════════════════════════════════════
3046
+ # PART 2: REVIEW PROMPT
3047
+ # ═══════════════════════════════════════════════════════════════
3048
+
3049
+ ---
3050
+
3051
+ ## DAY 6 REVIEW — Run after DAY6-IMPLEMENT is complete
3052
+
3053
+ Activate **`architect.md` + `security-reviewer.md`** simultaneously.
3054
+
3055
+ Day 6 risk profile:
3056
+ - **Supply chain security** — skills from external registry could contain malicious content
3057
+ - **CI/CD gate bypass** — CI mode must not weaken governance for speed
3058
+ - **API cost exposure** — AI PR reviews can be expensive at scale
3059
+ - **SDK data exposure** — SDK reads sensitive files (HANDOFF, AUDIT) programmatically
3060
+
3061
+ ---
3062
+
3063
+ ## REVIEW PASS 1 — Skills Registry: Supply Chain Security
3064
+
3065
+ Read `registry-client.md` and `skill-validator.md`.
3066
+
3067
+ - [ ] **Step 5 (injection guard)** runs AFTER download but BEFORE install.
3068
+ What if the skill downloads successfully but the temp directory is world-readable
3069
+ and another process reads it during the window between download and guard check?
3070
+ This is a TOCTOU (time-of-check, time-of-use) race condition.
3071
+ Mitigation: use `mktemp -d` with mode 700 (user-only access).
3072
+ Add: "`TEMP_DIR=$(mktemp -d)` then immediately `chmod 700 ${TEMP_DIR}`"
3073
+
3074
+ - [ ] The skill validator checks for "no placeholder text" — but what is the detection pattern?
3075
+ Add explicit patterns: `\[placeholder\]`, `\[your-name\]`, `TODO`, `FIXME`, `\[fill this in\]`
3076
+
3077
+ - [ ] Level 3 validation is listed as "optional — runs for publication."
3078
+ But the client protocol doesn't explicitly mention running Level 3 at install time.
3079
+ Should it? For a private registry (known, trusted source): Level 2 is sufficient.
3080
+ For the public registry (unknown authors): Level 3 should also run at install.
3081
+ Add: "For public registry installs: run Level 3 validation. Warn on failures but don't block."
3082
+
3083
+ - [ ] The `npm audit` step is not in the installation flow.
3084
+ A skill package could have vulnerable JavaScript dependencies in `scripts/`.
3085
+ Add: "Step 4.5: if the skill package has a `package.json` in `scripts/`:
3086
+ run `npm audit --prefix ${TEMP_DIR} --audit-level=high`.
3087
+ If HIGH or CRITICAL vulnerabilities: warn user but allow install.
3088
+ Document in AUDIT: `"skill_dependency_vulnerability": true`"
3089
+
3090
+ ---
3091
+
3092
+ ## REVIEW PASS 2 — CI Mode: Governance Integrity
3093
+
3094
+ Read `ci-mode.md` and `github-actions-adapter.md`.
3095
+
3096
+ - [ ] **The Tier 3 block in CI** is correct. But what message does the CI output?
3097
+ If the CI build fails without a clear message about WHY Tier 3 changes block CI,
3098
+ engineers will be confused. Add explicit CI failure message:
3099
+ ```
3100
+ ::error::MindForge CI: Tier 3 change detected (auth/payment/PII modification).
3101
+ Tier 3 changes require human compliance review before CI can pass.
3102
+ Get approval using: /mindforge:approve [approval-id]
3103
+ Then push again — a Tier 3 change with an approved approval request will pass CI.
3104
+ ```
3105
+
3106
+ - [ ] **CI timeout handling** says "exit with code 2 (warning)." But GitHub Actions
3107
+ treats any non-zero exit code as failure (code 1 or 2 — both fail the job).
3108
+ The "warning" intent doesn't work with standard CI conventions.
3109
+ Fix: use exit code 0 for timeout with a clear warning message AND a "timeout" artifact.
3110
+ The next CI run reads the HANDOFF.json to resume.
3111
+ But: mark the job as "warning" using GitHub's `$GITHUB_STEP_SUMMARY` approach,
3112
+ not via exit codes.
3113
+
3114
+ - [ ] **ANTHROPIC_API_KEY in CI** — the workflow file has `ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}`.
3115
+ What happens when this secret is not configured?
3116
+ The AI review step should gracefully skip (not fail) if the key is absent.
3117
+ Verify the `pr-review` command already handles this — re-check in context of CI.
3118
+
3119
+ ---
3120
+
3121
+ ## REVIEW PASS 3 — AI PR Review: Cost and Safety
3122
+
3123
+ Read `ai-reviewer.md` and `review-prompt-templates.md`.
3124
+
3125
+ - [ ] **Daily limit check** (`checkDailyLimit`) reads from `.mindforge/metrics/ai-review-usage.jsonl`.
3126
+ But this file may not exist. Add graceful creation if missing.
3127
+ Also: the count logic needs to handle JSONL parse errors on individual lines.
3128
+
3129
+ - [ ] **Diff truncation at 12,000 characters** — large PRs get truncated.
3130
+ But the truncation might cut in the middle of a security-relevant code block.
3131
+ Better truncation strategy: truncate by number of FILES, not characters.
3132
+ Review the `REVIEW_LIMITS.maxFilesReviewed = 20` limit — this is better.
3133
+ But the implementation shows BOTH a character limit AND file limit.
3134
+ These should be coordinated: if diff is > 12K chars, reduce to the top 10 most-changed files.
3135
+
3136
+ - [ ] **The system prompt includes** `context.conventions` truncated to 2000 chars.
3137
+ For a large CONVENTIONS.md (which can be 5K+ chars), this loses important conventions.
3138
+ Better: extract only the "Forbidden patterns" and "Naming conventions" sections
3139
+ from CONVENTIONS.md — these are the most review-relevant.
3140
+
3141
+ - [ ] **Cost management** — the daily limit (50 reviews/day) is configurable via MINDFORGE.md?
3142
+ It's not currently listed in the schema. Add: `AI_REVIEW_DAILY_LIMIT` setting.
3143
+
3144
+ ---
3145
+
3146
+ ## REVIEW PASS 4 — SDK: Data Safety
3147
+
3148
+ Read all SDK source files.
3149
+
3150
+ - [ ] **`readHandoff()`** reads `.planning/HANDOFF.json` which contains sensitive project state.
3151
+ The SDK returns the raw parsed JSON to calling code.
3152
+ If the SDK is embedded in a web application or external tool, this data should be
3153
+ treated as sensitive. Add to SDK README: "HANDOFF.json may contain sensitive project
3154
+ state. Do not expose it to untrusted clients or log its contents."
3155
+
3156
+ - [ ] **`MindForgeEventStream`** starts an HTTP server on port 7337 with
3157
+ `Access-Control-Allow-Origin: http://localhost:*`.
3158
+ The wildcard `http://localhost:*` is not a valid CORS origin — browsers require
3159
+ exact origins. Fix: `Access-Control-Allow-Origin: *` (for localhost dev tools)
3160
+ OR implement origin allowlisting.
3161
+ Also: the server binds to all interfaces by default (`listen(port)`).
3162
+ In a shared development environment, this exposes MindForge state to other users.
3163
+ Fix: bind to localhost explicitly: `server.listen(port, '127.0.0.1', ...)`.
3164
+
3165
+ - [ ] **`watchAuditLog()`** uses `fs.watch()` which is known to have platform-specific
3166
+ behaviour (especially on Linux where inotify has limits).
3167
+ Add: "On Linux: if `fs.watch()` throws ENOSPC (inotify limit reached):
3168
+ fall back to polling with `fs.watchFile()` at 2-second intervals."
3169
+
3170
+ - [ ] **The SDK has no authentication** — any code that can access the local filesystem
3171
+ can read AUDIT.jsonl, HANDOFF.json, and session metrics.
3172
+ This is acceptable for a local development tool but should be documented:
3173
+ "The MindForge SDK operates on local files. It provides no network authentication.
3174
+ Do not expose SDK endpoints to the public internet."
3175
+
3176
+ ---
3177
+
3178
+ ## REVIEW PASS 5 — Monorepo: Cross-Package Correctness
3179
+
3180
+ Read `workspace-detector.md` and `cross-package-planner.md`.
3181
+
3182
+ - [ ] The workspace detector uses `npm info "${PACKAGE_NAME}" version` for update checks.
3183
+ But `npm info` makes a network request — in offline environments, this hangs.
3184
+ Add: `npm info "${PACKAGE_NAME}" version --prefer-offline` for the version check.
3185
+
3186
+ - [ ] **Affected package detection** uses `git diff --name-only | awk -F/ '{print $1"/"$2}'`
3187
+ This assumes packages are always at `apps/name` or `packages/name` (2 levels deep).
3188
+ For Nx with deeply nested libs (`libs/shared/utils/`), this produces wrong paths.
3189
+ Fix: compare against the package paths in WORKSPACE-MANIFEST.json rather than
3190
+ assuming a fixed depth. Match changed file paths against declared package paths.
3191
+
3192
+ ---
3193
+
3194
+ ## REVIEW PASS 6 — Test Suite Quality
3195
+
3196
+ - [ ] `tests/distribution.test.js` — the injection guard test checks that
3197
+ registry-client.md MENTIONS injection guard. But it doesn't test that a skill
3198
+ with injection patterns actually FAILS validation. Add a test that simulates
3199
+ a malicious SKILL.md and verifies it would be rejected.
3200
+
3201
+ - [ ] `tests/ci-mode.test.js` — the Tier 3 CI block test is correct.
3202
+ But there is no test for the CI timeout behaviour (exit code strategy).
3203
+ Add a test verifying that the ci-mode spec mentions the exit-code-0 approach
3204
+ (not exit-code-2) for timeouts.
3205
+
3206
+ - [ ] `tests/sdk.test.js` — the SSE server localhost binding test is missing.
3207
+ Add: verify that `events.ts` references `'127.0.0.1'` (localhost binding)
3208
+ not just `server.listen(port)` (all interfaces).
3209
+
3210
+ ---
3211
+
3212
+ ## REVIEW SUMMARY TABLE
3213
+
3214
+ ```
3215
+ ## Day 6 Review Summary
3216
+
3217
+ | Category | BLOCKING | MAJOR | MINOR | SUGGESTION |
3218
+ |-----------------|----------|-------|-------|------------|
3219
+ | Registry | | | | |
3220
+ | CI Mode | | | | |
3221
+ | AI PR Review | | | | |
3222
+ | SDK | | | | |
3223
+ | Monorepo | | | | |
3224
+ | Tests | | | | |
3225
+ | **TOTAL** | | | | |
3226
+
3227
+ ## Verdict
3228
+ [ ] ✅ APPROVED — Proceed to HARDEN section
3229
+ [ ] ⚠️ APPROVED WITH CONDITIONS
3230
+ [ ] ❌ NOT APPROVED
3231
+ ```
3232
+
3233
+ ---
3234
+
3235
+ # ═══════════════════════════════════════════════════════════════
3236
+ # PART 3: HARDENING PROMPT
3237
+ # ═══════════════════════════════════════════════════════════════
3238
+
3239
+ ---
3240
+
3241
+ ## DAY 6 HARDENING — Run after REVIEW is APPROVED
3242
+
3243
+ Confirm all review findings resolved:
3244
+ ```bash
3245
+ node tests/distribution.test.js && node tests/ci-mode.test.js && node tests/sdk.test.js
3246
+ ```
3247
+
3248
+ ---
3249
+
3250
+ ## HARDEN 1 — Fix registry TOCTOU race condition
3251
+
3252
+ Update `registry-client.md` Step 3:
3253
+
3254
+ ```markdown
3255
+ ### Step 3 — Secure temp directory creation
3256
+ ```bash
3257
+ # Create temp directory with user-only permissions (prevents TOCTOU attacks)
3258
+ TEMP_DIR=$(mktemp -d)
3259
+ chmod 700 "${TEMP_DIR}"
3260
+
3261
+ # All subsequent operations in this directory are protected
3262
+ npm pack "${PACKAGE_NAME}@latest" --pack-destination "${TEMP_DIR}" --quiet
3263
+
3264
+ # Verify the tarball was downloaded (not empty, not corrupted)
3265
+ TARBALL=$(ls "${TEMP_DIR}"/*.tgz 2>/dev/null | head -1)
3266
+ if [ -z "${TARBALL}" ]; then
3267
+ rm -rf "${TEMP_DIR}"
3268
+ echo "Error: Failed to download ${PACKAGE_NAME} — no tarball produced"
3269
+ exit 1
3270
+ fi
3271
+
3272
+ # Verify tarball size is reasonable (not 0 bytes, not suspiciously large)
3273
+ TARBALL_SIZE=$(wc -c < "${TARBALL}")
3274
+ if [ "${TARBALL_SIZE}" -lt 100 ]; then
3275
+ rm -rf "${TEMP_DIR}"
3276
+ echo "Error: Downloaded tarball is suspiciously small (${TARBALL_SIZE} bytes)"
3277
+ exit 1
3278
+ fi
3279
+
3280
+ tar -xzf "${TARBALL}" --strip-components=1 -C "${TEMP_DIR}"
3281
+ ```
3282
+ ```
3283
+
3284
+ **Commit:**
3285
+ ```bash
3286
+ git add .mindforge/distribution/registry-client.md
3287
+ git commit -m "harden(registry): fix TOCTOU race with chmod 700 temp dir and tarball size check"
3288
+ ```
3289
+
3290
+ ---
3291
+
3292
+ ## HARDEN 2 — Fix SSE server security issues
3293
+
3294
+ Update `sdk/src/events.ts`:
3295
+
3296
+ ```typescript
3297
+ start(port = 7337): Promise<void> {
3298
+ return new Promise((resolve, reject) => {
3299
+ this.server = http.createServer((req, res) => {
3300
+ if (req.url !== '/events') {
3301
+ res.writeHead(404);
3302
+ res.end();
3303
+ return;
3304
+ }
3305
+
3306
+ // SECURITY: Only allow connections from localhost
3307
+ const clientIp = req.socket.remoteAddress;
3308
+ const isLocalhost = clientIp === '127.0.0.1' ||
3309
+ clientIp === '::1' ||
3310
+ clientIp === '::ffff:127.0.0.1';
3311
+ if (!isLocalhost) {
3312
+ res.writeHead(403);
3313
+ res.end('Forbidden: MindForge event stream is localhost-only');
3314
+ return;
3315
+ }
3316
+
3317
+ // CORS: Only allow localhost origins (exact match, not wildcard)
3318
+ const origin = req.headers.origin;
3319
+ const allowedOriginPattern = /^https?:\/\/localhost(:\d+)?$/;
3320
+ const corsOrigin = origin && allowedOriginPattern.test(origin)
3321
+ ? origin
3322
+ : 'http://localhost'; // Default safe origin
3323
+
3324
+ res.writeHead(200, {
3325
+ 'Content-Type': 'text/event-stream',
3326
+ 'Cache-Control': 'no-cache',
3327
+ 'Connection': 'keep-alive',
3328
+ 'Access-Control-Allow-Origin': corsOrigin,
3329
+ 'X-Content-Type-Options': 'nosniff',
3330
+ });
3331
+
3332
+ // ... rest of handler
3333
+ });
3334
+
3335
+ // SECURITY: Bind to localhost ONLY — not all interfaces
3336
+ this.server.listen(port, '127.0.0.1', () => {
3337
+ console.log(`MindForge event stream: http://localhost:${port}/events (localhost only)`);
3338
+ resolve();
3339
+ });
3340
+
3341
+ this.server.on('error', (err: NodeJS.ErrnoException) => {
3342
+ if (err.code === 'EADDRINUSE') {
3343
+ reject(new Error(
3344
+ `Port ${port} is already in use. Use: new MindForgeEventStream().start(${port + 1})`
3345
+ ));
3346
+ } else {
3347
+ reject(err);
3348
+ }
3349
+ });
3350
+ });
3351
+ }
3352
+ ```
3353
+
3354
+ Also add Linux inotify fallback to `watchAuditLog`:
3355
+
3356
+ ```typescript
3357
+ watchAuditLog(projectRoot: string): void {
3358
+ const auditPath = path.join(projectRoot, '.planning', 'AUDIT.jsonl');
3359
+
3360
+ // ... existing setup ...
3361
+
3362
+ try {
3363
+ this.auditWatcher = fs.watch(auditPath, () => { /* ... */ });
3364
+ } catch (err: unknown) {
3365
+ if ((err as NodeJS.ErrnoException).code === 'ENOSPC') {
3366
+ // Linux inotify limit reached — fall back to polling
3367
+ console.warn('MindForge: inotify limit reached, falling back to 2s polling');
3368
+ setInterval(() => {
3369
+ const lines = fs.readFileSync(auditPath, 'utf8').split('\n').filter(Boolean);
3370
+ for (let i = this.lastAuditLine; i < lines.length; i++) {
3371
+ try { this.broadcast('audit_entry', JSON.parse(lines[i])); } catch { /* ignore */ }
3372
+ }
3373
+ this.lastAuditLine = lines.length;
3374
+ }, 2000);
3375
+ } else {
3376
+ throw err;
3377
+ }
3378
+ }
3379
+ }
3380
+ ```
3381
+
3382
+ **Commit:**
3383
+ ```bash
3384
+ git add sdk/src/events.ts
3385
+ git commit -m "harden(sdk): fix SSE server localhost-only binding, exact CORS origins, inotify fallback"
3386
+ ```
3387
+
3388
+ ---
3389
+
3390
+ ## HARDEN 3 — Fix CI timeout exit code
3391
+
3392
+ Update `ci-mode.md` — replace the timeout section:
3393
+
3394
+ ```markdown
3395
+ ### CI timeout and exit codes
3396
+
3397
+ **Exit code policy:**
3398
+ | Situation | Exit code | Meaning |
3399
+ |---|---|---|
3400
+ | All phases complete, gates passed | 0 | Success |
3401
+ | Quality gate failed | 1 | Hard failure — fix required |
3402
+ | Tier 2/3 governance block | 1 | Hard failure — approval required |
3403
+ | CI timeout reached | 0 | Soft stop — work saved, resume next run |
3404
+ | No MindForge project found | 1 | Configuration error |
3405
+
3406
+ **Important:** GitHub Actions (and most CI systems) treat ANY non-zero exit code
3407
+ as failure. Exit code 2 does NOT mean "warning" in CI — it means failure.
3408
+
3409
+ **Timeout handling (exit 0 with state preservation):**
3410
+ ```bash
3411
+ # Set up timeout trap
3412
+ CI_TIMEOUT_SECONDS=$((${CI_TIMEOUT_MINUTES:-60} * 60))
3413
+ timeout_handler() {
3414
+ echo "::warning::MindForge CI timeout reached after ${CI_TIMEOUT_MINUTES} minutes"
3415
+ echo "::warning::Progress saved. Next CI run will resume from: $(cat .planning/HANDOFF.json | python3 -c 'import sys,json; print(json.load(sys.stdin).get("next_task","unknown"))')"
3416
+
3417
+ # Write resume info to GitHub Actions step summary
3418
+ cat >> "${GITHUB_STEP_SUMMARY:-/dev/null}" << EOF
3419
+ ## ⏱️ MindForge CI Timeout
3420
+
3421
+ CI timeout reached. Progress has been saved.
3422
+
3423
+ Next run will resume from:
3424
+ $(cat .planning/HANDOFF.json | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get("next_task","unknown"))')
3425
+
3426
+ Run the CI pipeline again to continue.
3427
+ EOF
3428
+
3429
+ # Commit HANDOFF.json so next run can resume
3430
+ git add .planning/HANDOFF.json .planning/STATE.md
3431
+ git commit -m "ci: save MindForge progress on timeout [skip ci]" || true
3432
+ git push origin HEAD || true
3433
+
3434
+ exit 0 # Exit 0 — timeout is not a failure
3435
+ }
3436
+
3437
+ trap 'timeout_handler' TERM
3438
+ (sleep "${CI_TIMEOUT_SECONDS}"; kill -TERM $$) &
3439
+ TIMEOUT_PID=$!
3440
+ ```
3441
+ ```
3442
+
3443
+ **Commit:**
3444
+ ```bash
3445
+ git add .mindforge/ci/ci-mode.md
3446
+ git commit -m "harden(ci): fix timeout exit code to 0 (soft stop), add GitHub step summary"
3447
+ ```
3448
+
3449
+ ---
3450
+
3451
+ ## HARDEN 4 — Add Tier 3 CI error message
3452
+
3453
+ Update `github-actions-adapter.md` — add to the mindforge-quality job:
3454
+
3455
+ ```yaml
3456
+ - name: Check governance tier (Tier 3 blocks CI)
3457
+ run: |
3458
+ # Check if any pending Tier 3 approvals exist without approval
3459
+ PENDING_T3=$(find .planning/approvals/ -name "*.json" 2>/dev/null | \
3460
+ xargs grep -l '"tier": 3' 2>/dev/null | \
3461
+ xargs grep -l '"status": "pending"' 2>/dev/null | wc -l)
3462
+
3463
+ if [ "${PENDING_T3}" -gt 0 ]; then
3464
+ echo "::error title=Tier 3 Governance Block::$PENDING_T3 Tier 3 change(s) require compliance review."
3465
+ echo "::error::Tier 3 changes (auth/payment/PII) cannot be auto-approved in CI."
3466
+ echo "::error::To resolve: get human approval with /mindforge:approve [id], then push again."
3467
+ cat >> "${GITHUB_STEP_SUMMARY}" << 'EOF'
3468
+ ## 🔴 Governance Block: Tier 3 Approval Required
3469
+
3470
+ This PR contains changes that require compliance review (auth, payment, or PII handling).
3471
+
3472
+ **Next steps:**
3473
+ 1. Run `/mindforge:approve` to see pending approval requests
3474
+ 2. Have your compliance officer approve with `/mindforge:approve [id]`
3475
+ 3. Push again — CI will pass once the approval is recorded
3476
+
3477
+ See `.planning/approvals/` for details.
3478
+ EOF
3479
+ exit 1
3480
+ fi
3481
+
3482
+ echo "::notice::Governance check passed — no pending Tier 3 blocks ✅"
3483
+ ```
3484
+
3485
+ **Commit:**
3486
+ ```bash
3487
+ git add .mindforge/ci/github-actions-adapter.md .github/workflows/mindforge-ci.yml
3488
+ git commit -m "harden(ci): add clear Tier 3 CI block message with resolution steps"
3489
+ ```
3490
+
3491
+ ---
3492
+
3493
+ ## HARDEN 5 — Fix AI review daily limit and diff strategy
3494
+
3495
+ Update `ai-reviewer.md`:
3496
+
3497
+ ```javascript
3498
+ // Replace the daily limit check with robust implementation:
3499
+
3500
+ const AI_REVIEW_LOG = path.join(projectRoot, '.mindforge', 'metrics', 'ai-review-usage.jsonl');
3501
+
3502
+ function logAIReview(prSha) {
3503
+ const entry = JSON.stringify({
3504
+ timestamp: new Date().toISOString(),
3505
+ pr_sha: prSha,
3506
+ date: new Date().toISOString().slice(0, 10),
3507
+ model: 'claude-sonnet-4-6',
3508
+ }) + '\n';
3509
+
3510
+ // Create parent directory if it doesn't exist
3511
+ const dir = path.dirname(AI_REVIEW_LOG);
3512
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
3513
+
3514
+ fs.appendFileSync(AI_REVIEW_LOG, entry);
3515
+ }
3516
+
3517
+ function checkDailyLimit(maxReviews) {
3518
+ if (!fs.existsSync(AI_REVIEW_LOG)) return true; // No log = no limit hit
3519
+
3520
+ const today = new Date().toISOString().slice(0, 10);
3521
+ let count = 0;
3522
+
3523
+ const lines = fs.readFileSync(AI_REVIEW_LOG, 'utf8').split('\n').filter(Boolean);
3524
+ for (const line of lines) {
3525
+ try {
3526
+ const entry = JSON.parse(line);
3527
+ if (entry.date === today) count++;
3528
+ } catch {
3529
+ continue; // Skip malformed lines — don't let parse errors break the limit check
3530
+ }
3531
+ }
3532
+
3533
+ return count < maxReviews;
3534
+ }
3535
+
3536
+ // Replace diff truncation strategy:
3537
+
3538
+ function buildDiffForReview(fullDiff, changedFiles) {
3539
+ const MAX_CHARS = 12000;
3540
+ const MAX_FILES = 20;
3541
+
3542
+ if (fullDiff.length <= MAX_CHARS) return fullDiff;
3543
+
3544
+ // Prefer showing fewer complete files over more truncated ones
3545
+ // Sort files by change size (largest first — most important to review)
3546
+ const fileDiffs = splitDiffByFile(fullDiff);
3547
+ const sortedFiles = fileDiffs.sort((a, b) => b.content.length - a.content.length);
3548
+
3549
+ let result = '';
3550
+ let fileCount = 0;
3551
+ for (const fileDiff of sortedFiles.slice(0, MAX_FILES)) {
3552
+ if (result.length + fileDiff.content.length > MAX_CHARS) break;
3553
+ result += fileDiff.content + '\n';
3554
+ fileCount++;
3555
+ }
3556
+
3557
+ const omitted = sortedFiles.length - fileCount;
3558
+ if (omitted > 0) {
3559
+ result += `\n[${omitted} file(s) omitted from review — diff too large. Run review with --diff on individual files.]\n`;
3560
+ }
3561
+
3562
+ return result;
3563
+ }
3564
+
3565
+ function splitDiffByFile(diff) {
3566
+ const files = [];
3567
+ const parts = diff.split(/^diff --git/m).filter(Boolean);
3568
+ for (const part of parts) {
3569
+ const header = part.match(/^a\/(.+) b\//);
3570
+ files.push({
3571
+ filename: header ? header[1] : 'unknown',
3572
+ content: 'diff --git' + part,
3573
+ });
3574
+ }
3575
+ return files;
3576
+ }
3577
+ ```
3578
+
3579
+ **Commit:**
3580
+ ```bash
3581
+ git add .mindforge/pr-review/ai-reviewer.md
3582
+ git commit -m "harden(ai-review): robust daily limit with parse error tolerance, file-based diff truncation"
3583
+ ```
3584
+
3585
+ ---
3586
+
3587
+ ## HARDEN 6 — Fix monorepo affected package detection
3588
+
3589
+ Update `cross-package-planner.md`:
3590
+
3591
+ ```markdown
3592
+ ## Affected package detection (revised)
3593
+
3594
+ ```bash
3595
+ # CORRECTED: Match against declared package paths, not assume 2-level depth
3596
+ detect_affected_packages() {
3597
+ local MANIFEST=".planning/WORKSPACE-MANIFEST.json"
3598
+
3599
+ if [ ! -f "${MANIFEST}" ]; then
3600
+ echo "Run /mindforge:workspace detect first"
3601
+ return 1
3602
+ fi
3603
+
3604
+ # Get list of changed files
3605
+ CHANGED_FILES=$(git diff --name-only HEAD~1 2>/dev/null || git diff --cached --name-only)
3606
+
3607
+ # For each package in manifest, check if any changed file is within that package
3608
+ node -e "
3609
+ const fs = require('fs');
3610
+ const manifest = JSON.parse(fs.readFileSync('${MANIFEST}', 'utf8'));
3611
+ const changedFiles = \`${CHANGED_FILES}\`.split('\n').filter(Boolean);
3612
+
3613
+ const affected = new Set();
3614
+ manifest.packages.forEach(pkg => {
3615
+ // Check if any changed file is within this package's path
3616
+ const pkgPath = pkg.path.replace(/\/$/, ''); // remove trailing slash
3617
+ changedFiles.forEach(file => {
3618
+ if (file.startsWith(pkgPath + '/') || file === pkgPath) {
3619
+ affected.add(pkg.name);
3620
+ }
3621
+ });
3622
+ });
3623
+
3624
+ // Also add packages that depend on affected packages
3625
+ manifest.packages.forEach(pkg => {
3626
+ if (pkg.dependencies && pkg.dependencies.some(dep => affected.has(dep))) {
3627
+ affected.add(pkg.name);
3628
+ }
3629
+ });
3630
+
3631
+ console.log([...affected].join('\n'));
3632
+ "
3633
+ }
3634
+ ```
3635
+
3636
+ This correctly handles:
3637
+ - Packages at any nesting depth (`libs/shared/utils/` → 3 levels deep)
3638
+ - Packages whose path is a prefix of another (avoid false matches)
3639
+ - Transitive dependencies (packages that depend on changed packages)
3640
+ ```
3641
+
3642
+ **Commit:**
3643
+ ```bash
3644
+ git add .mindforge/monorepo/cross-package-planner.md
3645
+ git commit -m "harden(monorepo): fix affected package detection to use manifest paths, handle deep nesting"
3646
+ ```
3647
+
3648
+ ---
3649
+
3650
+ ## HARDEN 7 — Write 3 ADRs for Day 6 decisions
3651
+
3652
+ ### `.planning/decisions/ADR-015-npm-based-skill-registry.md`
3653
+
3654
+ ```markdown
3655
+ # ADR-015: npm as the MindForge Skills Registry
3656
+
3657
+ **Status:** Accepted
3658
+ **Date:** [today]
3659
+
3660
+ ## Context
3661
+ MindForge needs a way to distribute community and organisation skills.
3662
+ Options: custom registry server, GitHub releases, npm registry.
3663
+
3664
+ ## Decision
3665
+ Use the standard npm registry with `mindforge-skill-` package naming convention.
3666
+
3667
+ ## Rationale
3668
+ npm is the world's largest package registry with existing infrastructure for:
3669
+ versioning, authentication, access control, search, and deprecation.
3670
+ Building a custom registry duplicates all of this at significant cost.
3671
+ The npm ecosystem's supply chain security tooling (npm audit, Dependabot,
3672
+ Snyk) works natively. Private registries (Verdaccio, Artifactory, GitHub Packages)
3673
+ are npm-compatible — organisations with private skills don't need separate tooling.
3674
+
3675
+ ## Consequences
3676
+ - Skill names follow npm conventions (lowercase, hyphens)
3677
+ - Version management follows npm semver conventions
3678
+ - Private skills require a compatible private npm registry
3679
+ - The injection guard and validation pipeline are the primary
3680
+ supply chain security controls (npm audit is insufficient alone for SKILL.md content)
3681
+ ```
3682
+
3683
+ ### `.planning/decisions/ADR-016-ci-exit-code-0-on-timeout.md`
3684
+
3685
+ ```markdown
3686
+ # ADR-016: CI timeout exits with code 0 (soft stop)
3687
+
3688
+ **Status:** Accepted
3689
+ **Date:** [today]
3690
+
3691
+ ## Context
3692
+ MindForge CI may run out of time before completing all phases.
3693
+ The question is: should timeout exit with code 0 (success) or non-zero (failure)?
3694
+
3695
+ ## Decision
3696
+ Timeout exits with code 0. State is saved. Next CI run resumes.
3697
+
3698
+ ## Rationale
3699
+ A MindForge CI timeout is not a code failure — it is a resource limit.
3700
+ Failing the build on timeout would:
3701
+ 1. Block the PR with a failure that has no fix (the code is fine — time ran out)
3702
+ 2. Force teams to either increase CI limits or split phases artificially
3703
+ 3. Make MindForge feel unreliable ("it randomly fails when there's a lot to do")
3704
+
3705
+ The correct behaviour: save progress, exit cleanly, let the next run continue.
3706
+ The CI pipeline is designed for continuation, not completion in a single run.
3707
+
3708
+ ## Consequences
3709
+ - CI pipelines may run multiple times for a single phase
3710
+ - HANDOFF.json must be committed during CI runs (CI has write access)
3711
+ - Teams must monitor CI for timeout patterns (frequent timeouts → split phases)
3712
+ - GitHub Actions step summary provides visibility into timeout state
3713
+ ```
3714
+
3715
+ ### `.planning/decisions/ADR-017-sdk-localhost-only.md`
3716
+
3717
+ ```markdown
3718
+ # ADR-017: MindForge SDK event stream is localhost-only
3719
+
3720
+ **Status:** Accepted
3721
+ **Date:** [today]
3722
+
3723
+ ## Context
3724
+ The MindForge SDK includes an SSE event stream for real-time progress.
3725
+ The question is whether it should bind to all interfaces or localhost only.
3726
+
3727
+ ## Decision
3728
+ The event stream binds to 127.0.0.1 (localhost) only.
3729
+
3730
+ ## Rationale
3731
+ The event stream exposes:
3732
+ - AUDIT.jsonl entries (which contain sensitive project state)
3733
+ - Task completion events (which reveal code structure and timing)
3734
+ - Security finding events (which reveal vulnerability information)
3735
+
3736
+ Exposing this to all network interfaces in a shared development environment
3737
+ (VMs, shared cloud desktops, containers) would allow other users to monitor
3738
+ another developer's project state in real-time.
3739
+ Localhost binding provides adequate protection for the primary use case
3740
+ (local developer tooling) without requiring authentication infrastructure.
3741
+
3742
+ ## Consequences
3743
+ - Remote integrations cannot use the event stream directly
3744
+ - For remote monitoring: use the audit log query API via SSH tunnel
3745
+ - Container environments: map the port explicitly if remote access is needed
3746
+ ```
3747
+
3748
+ **Commit:**
3749
+ ```bash
3750
+ git add .planning/decisions/
3751
+ git commit -m "docs(adr): add ADR-015 npm registry, ADR-016 CI timeout, ADR-017 localhost SDK"
3752
+ ```
3753
+
3754
+ ---
3755
+
3756
+ ## HARDEN 8 — Add to test suites
3757
+
3758
+ ```javascript
3759
+ // Add to tests/distribution.test.js:
3760
+
3761
+ console.log('\nHardening-prompted distribution tests:');
3762
+
3763
+ test('registry client uses chmod 700 for temp directory', () => {
3764
+ const c = read('.mindforge/distribution/registry-client.md');
3765
+ assert.ok(c.includes('chmod 700') || c.includes('700'), 'Should use chmod 700 for temp dir security');
3766
+ });
3767
+
3768
+ test('registry client verifies tarball size', () => {
3769
+ const c = read('.mindforge/distribution/registry-client.md');
3770
+ assert.ok(c.includes('TARBALL_SIZE') || c.includes('size'), 'Should check tarball size');
3771
+ });
3772
+
3773
+ test('MINDFORGE-SCHEMA.json has number type with min/max', () => {
3774
+ const schema = JSON.parse(fs.readFileSync('.mindforge/MINDFORGE-SCHEMA.json', 'utf8'));
3775
+ const compaction = schema.properties.COMPACTION_THRESHOLD_PCT;
3776
+ assert.ok(compaction, 'COMPACTION_THRESHOLD_PCT should be in schema');
3777
+ assert.strictEqual(compaction.type, 'number');
3778
+ assert.strictEqual(compaction.minimum, 50);
3779
+ assert.strictEqual(compaction.maximum, 90);
3780
+ });
3781
+
3782
+ // Add to tests/ci-mode.test.js:
3783
+
3784
+ console.log('\nHardening-prompted CI tests:');
3785
+
3786
+ test('ci-mode uses exit code 0 for timeout (not 2)', () => {
3787
+ const c = read('.mindforge/ci/ci-mode.md');
3788
+ assert.ok(
3789
+ c.includes('exit 0') && (c.includes('timeout') || c.includes('Timeout')),
3790
+ 'Timeout should exit with code 0'
3791
+ );
3792
+ // Should NOT say exit 2 for timeout
3793
+ const exit2ForTimeout = c.match(/timeout.*exit 2|exit 2.*timeout/is);
3794
+ assert.ok(!exit2ForTimeout, 'Should not use exit 2 for timeout');
3795
+ });
3796
+
3797
+ test('github-actions adapter has Tier 3 governance block with clear message', () => {
3798
+ const c = read('.mindforge/ci/github-actions-adapter.md');
3799
+ assert.ok(
3800
+ c.includes('Tier 3') && c.includes('block'),
3801
+ 'Should explain Tier 3 CI block clearly'
3802
+ );
3803
+ });
3804
+
3805
+ // Add to tests/sdk.test.js:
3806
+
3807
+ console.log('\nHardening-prompted SDK tests:');
3808
+
3809
+ test('SDK SSE server binds to 127.0.0.1 (localhost only)', () => {
3810
+ const c = read('sdk/src/events.ts');
3811
+ assert.ok(
3812
+ c.includes("'127.0.0.1'") || c.includes('"127.0.0.1"'),
3813
+ 'SSE server should bind to 127.0.0.1 only'
3814
+ );
3815
+ });
3816
+
3817
+ test('SDK SSE server rejects non-localhost connections', () => {
3818
+ const c = read('sdk/src/events.ts');
3819
+ assert.ok(
3820
+ c.includes('isLocalhost') || c.includes('remoteAddress') || c.includes('Forbidden'),
3821
+ 'SSE server should reject non-localhost connections'
3822
+ );
3823
+ });
3824
+
3825
+ test('SDK has inotify fallback for Linux', () => {
3826
+ const c = read('sdk/src/events.ts');
3827
+ assert.ok(
3828
+ c.includes('ENOSPC') || c.includes('polling') || c.includes('watchFile'),
3829
+ 'SDK should handle Linux inotify limits'
3830
+ );
3831
+ });
3832
+ ```
3833
+
3834
+ **Commit:**
3835
+ ```bash
3836
+ git add tests/
3837
+ git commit -m "test(day6): add hardening-prompted tests for distribution, CI, and SDK security"
3838
+ ```
3839
+
3840
+ ---
3841
+
3842
+ ## HARDEN 9 — Update CHANGELOG.md, final commit
3843
+
3844
+ Update `CHANGELOG.md`:
3845
+
3846
+ ```markdown
3847
+ ## [0.6.0] — Day 6 Distribution Platform
3848
+
3849
+ ### Added
3850
+ - Public skills registry: `npx mindforge-skills install/publish/search` (npm-based)
3851
+ - Skill validator: 3-level validation schema (schema, content, quality)
3852
+ - MINDFORGE.md JSON Schema: validation with non-overridable field markers
3853
+ - MindForge CI mode: GitHub Actions / GitLab CI / Jenkins integration
3854
+ - GitHub Actions workflow: health, security, quality, AI review jobs
3855
+ - AI PR Review Engine: Claude API-powered code review with context loading
3856
+ - Monorepo/workspace support: npm/pnpm/Nx/Turborepo/Lerna detection
3857
+ - Cross-package planner: topological execution order for monorepo phases
3858
+ - @mindforge/sdk: TypeScript SDK with client, event stream, and command builders
3859
+ - SSE event stream: real-time progress events via Server-Sent Events
3860
+ - /mindforge:init-org — organisation-wide MindForge setup command
3861
+ - /mindforge:install-skill — install skill from public/private registry
3862
+ - /mindforge:publish-skill — publish skill to npm registry
3863
+ - /mindforge:pr-review — AI code review powered by Claude API
3864
+ - /mindforge:workspace — monorepo workspace management
3865
+ - /mindforge:benchmark — skill effectiveness benchmarking
3866
+ - 3 new ADRs: ADR-015 npm registry, ADR-016 CI timeout, ADR-017 localhost SDK
3867
+
3868
+ ### Hardened
3869
+ - Registry: TOCTOU-safe temp directory (chmod 700), tarball size verification
3870
+ - CI: timeout exits with code 0 (soft stop), clear Tier 3 block messages
3871
+ - SDK: localhost-only SSE binding, Linux inotify fallback
3872
+ - AI review: robust daily limit (parse error tolerant), file-based diff truncation
3873
+ - Monorepo: affected package detection uses manifest paths (not depth assumption)
3874
+ ```
3875
+
3876
+ ```bash
3877
+ git add CHANGELOG.md package.json
3878
+ git commit -m "chore(release): v0.6.0 complete with all hardening"
3879
+ git push origin feat/mindforge-distribution-platform
3880
+ ```
3881
+
3882
+ ---
3883
+
3884
+ ## DAY 6 COMPLETE — Final state of MindForge
3885
+
3886
+ | Metric | Day 1 | Day 2 | Day 3 | Day 4 | Day 5 | Day 6 |
3887
+ |---|---|---|---|---|---|---|
3888
+ | Commands | 6 | 10 | 15 | 21 | 25 | **31** |
3889
+ | Skills | 5 | 5 | 10 | 10 | 10 | **10+registry** |
3890
+ | ADRs | 3 | 5 | 8 | 11 | 14 | **17** |
3891
+ | Test suites | 1 | 4 | 5 | 7 | 9 | **12** |
3892
+ | Version | 0.1.0 | 0.2.0 | 0.3.0 | 0.4.0 | 0.5.0 | **0.6.0** |
3893
+ | MindForge version | — | — | — | — | — | **v0.6.0** |
3894
+
3895
+ **MindForge v0.6.0: 31 commands · 10 core skills + public registry · 8 personas**
3896
+ **17 ADRs · 12 test suites · SDK · CI integration · Monorepo support**
3897
+
3898
+ ---
3899
+
3900
+ ## DAY 7 PREVIEW
3901
+
3902
+ ```
3903
+ Branch: feat/mindforge-production-hardening
3904
+
3905
+ Day 7 scope (Production hardening & polish):
3906
+ - Complete installer: npx mindforge-cc fully functional end-to-end
3907
+ - Self-update mechanism: /mindforge:update with changelog preview
3908
+ - Migration tool: upgrade between MindForge versions with state migration
3909
+ - Plugin system: third-party extensions to MindForge commands
3910
+ - Performance profiling: identify slow phases and optimise agent token usage
3911
+ - Cross-version compatibility: HANDOFF.json schema migration
3912
+ - Complete documentation site: docs.mindforge.dev structure and content
3913
+ - Security penetration testing simulation: adversarial review of all governance
3914
+ - Production readiness checklist: final audit before public release
3915
+ - npx mindforge-cc publish: full end-to-end skill publication workflow
3916
+ ```
3917
+
3918
+ **Branch:** `feat/mindforge-distribution-platform`
3919
+ **Day 6 complete. Open PR → merge → tag v0.6.0**