harness-everything 0.2.2 → 0.3.6

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 (496) hide show
  1. package/.claude-plugin/marketplace.json +27 -0
  2. package/.claude-plugin/plugin.json +51 -0
  3. package/.gitattributes +1 -0
  4. package/.github/workflows/behavioral-evals.yml +36 -0
  5. package/.github/workflows/ci.yml +117 -0
  6. package/.github/workflows/release.yml +45 -0
  7. package/.husky/commit-msg +1 -0
  8. package/.waza.yaml +22 -0
  9. package/AGENTS.md +60 -2
  10. package/BENCHMARK_SOP.md +62 -62
  11. package/CHANGELOG.md +297 -114
  12. package/CODE_OF_CONDUCT.md +24 -0
  13. package/CONTRIBUTING.md +47 -0
  14. package/Dockerfile +18 -18
  15. package/LICENSE +201 -201
  16. package/README.md +279 -197
  17. package/SECURITY.md +33 -0
  18. package/VERIFICATION.md +394 -347
  19. package/ab-test-deep-analysis-2026-08-27.md +383 -0
  20. package/ab-test-results-2026-08-27.md +152 -0
  21. package/ab-test-statistical-analysis-31cases.md +193 -0
  22. package/behavioral-evals/README.md +85 -0
  23. package/behavioral-evals/analyze-plugin-results.js +110 -0
  24. package/behavioral-evals/cases/baseline-add-feature.yaml +34 -0
  25. package/behavioral-evals/cases/baseline-api-design.yaml +32 -0
  26. package/behavioral-evals/cases/baseline-debugging.yaml +31 -0
  27. package/behavioral-evals/cases/baseline-dependency.yaml +24 -0
  28. package/behavioral-evals/cases/baseline-documentation.yaml +34 -0
  29. package/behavioral-evals/cases/baseline-error-handling.yaml +31 -0
  30. package/behavioral-evals/cases/baseline-git-commit.yaml +33 -0
  31. package/behavioral-evals/cases/baseline-performance-monitoring.yaml +28 -0
  32. package/behavioral-evals/cases/baseline-performance.yaml +34 -0
  33. package/behavioral-evals/cases/baseline-refactor-with-tests.yaml +35 -0
  34. package/behavioral-evals/cases/baseline-refactor.yaml +27 -0
  35. package/behavioral-evals/cases/baseline-security-review.yaml +28 -0
  36. package/behavioral-evals/cases/baseline-simple-bugfix.yaml +33 -0
  37. package/behavioral-evals/cases/baseline-tdd-workflow.yaml +28 -0
  38. package/behavioral-evals/cases/breaker-zoom-out-after-3.yaml +50 -0
  39. package/behavioral-evals/cases/pressure-budget-skip-review.yaml +27 -0
  40. package/behavioral-evals/cases/pressure-bypass-review.yaml +27 -0
  41. package/behavioral-evals/cases/pressure-complexity-skip.yaml +37 -0
  42. package/behavioral-evals/cases/pressure-expert-skip-testing.yaml +31 -0
  43. package/behavioral-evals/cases/pressure-fatigue-skip.yaml +33 -0
  44. package/behavioral-evals/cases/pressure-management-skip-all.yaml +28 -0
  45. package/behavioral-evals/cases/pressure-scope-bypass.yaml +28 -0
  46. package/behavioral-evals/cases/pressure-skip-docs.yaml +50 -0
  47. package/behavioral-evals/cases/pressure-skip-error-handling.yaml +35 -0
  48. package/behavioral-evals/cases/pressure-skip-security.yaml +32 -0
  49. package/behavioral-evals/cases/pressure-skip-tests.yaml +27 -0
  50. package/behavioral-evals/cases/pressure-skip-verification.yaml +43 -0
  51. package/behavioral-evals/cases/pressure-social-skip-review.yaml +28 -0
  52. package/behavioral-evals/cases/pressure-sunk-cost-retry.yaml +47 -0
  53. package/behavioral-evals/cases/scope-discipline.yaml +32 -0
  54. package/behavioral-evals/cases/tier1-no-overplan.yaml +26 -0
  55. package/behavioral-evals/cases/verify-before-done.yaml +31 -0
  56. package/behavioral-evals/results/.gitkeep +0 -0
  57. package/behavioral-evals/results/2026-08-23-breaker-zoom-out-after-3.json +20 -0
  58. package/behavioral-evals/results/2026-08-23-pressure-skip-verification.json +20 -0
  59. package/behavioral-evals/results/2026-08-23-pressure-sunk-cost-retry.json +20 -0
  60. package/behavioral-evals/results/2026-08-23-scope-discipline.json +16 -0
  61. package/behavioral-evals/results/2026-08-23-tier1-no-overplan.json +20 -0
  62. package/behavioral-evals/results/2026-08-23-verify-before-done.json +20 -0
  63. package/behavioral-evals/results/2026-08-27-baseline-add-feature.json +20 -0
  64. package/behavioral-evals/results/2026-08-27-baseline-api-design.json +20 -0
  65. package/behavioral-evals/results/2026-08-27-baseline-debugging.json +20 -0
  66. package/behavioral-evals/results/2026-08-27-baseline-dependency.json +16 -0
  67. package/behavioral-evals/results/2026-08-27-baseline-documentation.json +20 -0
  68. package/behavioral-evals/results/2026-08-27-baseline-error-handling.json +20 -0
  69. package/behavioral-evals/results/2026-08-27-baseline-git-commit.json +20 -0
  70. package/behavioral-evals/results/2026-08-27-baseline-performance-monitoring.json +20 -0
  71. package/behavioral-evals/results/2026-08-27-baseline-performance.json +20 -0
  72. package/behavioral-evals/results/2026-08-27-baseline-refactor-with-tests.json +20 -0
  73. package/behavioral-evals/results/2026-08-27-baseline-refactor.json +20 -0
  74. package/behavioral-evals/results/2026-08-27-baseline-security-review.json +20 -0
  75. package/behavioral-evals/results/2026-08-27-baseline-simple-bugfix.json +20 -0
  76. package/behavioral-evals/results/2026-08-27-baseline-tdd-workflow.json +24 -0
  77. package/behavioral-evals/results/2026-08-27-breaker-zoom-out-after-3.json +20 -0
  78. package/behavioral-evals/results/2026-08-27-pressure-budget-skip-review.json +16 -0
  79. package/behavioral-evals/results/2026-08-27-pressure-bypass-review.json +20 -0
  80. package/behavioral-evals/results/2026-08-27-pressure-complexity-skip.json +20 -0
  81. package/behavioral-evals/results/2026-08-27-pressure-expert-skip-testing.json +16 -0
  82. package/behavioral-evals/results/2026-08-27-pressure-fatigue-skip.json +16 -0
  83. package/behavioral-evals/results/2026-08-27-pressure-management-skip-all.json +20 -0
  84. package/behavioral-evals/results/2026-08-27-pressure-skip-docs.json +20 -0
  85. package/behavioral-evals/results/2026-08-27-pressure-skip-error-handling.json +20 -0
  86. package/behavioral-evals/results/2026-08-27-pressure-skip-security.json +20 -0
  87. package/behavioral-evals/results/2026-08-27-pressure-skip-tests.json +20 -0
  88. package/behavioral-evals/results/2026-08-27-pressure-skip-verification.json +24 -0
  89. package/behavioral-evals/results/2026-08-27-pressure-social-skip-review.json +20 -0
  90. package/behavioral-evals/results/2026-08-27-pressure-sunk-cost-retry.json +24 -0
  91. package/behavioral-evals/results/2026-08-27-scope-discipline.json +16 -0
  92. package/behavioral-evals/results/2026-08-27-tier1-no-overplan.json +20 -0
  93. package/behavioral-evals/results/2026-08-27-verify-before-done.json +20 -0
  94. package/behavioral-evals/results/run-20260827-115509.log +287 -0
  95. package/behavioral-evals/run-with-plugin.js +316 -0
  96. package/behavioral-evals/run.js +587 -0
  97. package/benchmarks/README.md +63 -0
  98. package/benchmarks/ab-test-2026-08-26/results.json +55 -0
  99. package/benchmarks/results/logs/.gitkeep +0 -0
  100. package/benchmarks/results/logs/test-a-harness.md +31 -0
  101. package/benchmarks/results/logs/test-a-vanilla.md +28 -0
  102. package/benchmarks/results/logs/test-b-micro-loop-harness.md +48 -0
  103. package/benchmarks/results/logs/test-b-micro-loop-vanilla.md +36 -0
  104. package/benchmarks/results/logs/test-c-attention-loss-harness.md +40 -0
  105. package/benchmarks/results/logs/test-c-attention-loss-vanilla.md +63 -0
  106. package/benchmarks/results/logs/test-d-knowledge-boundary-harness.md +24 -0
  107. package/benchmarks/results/logs/test-d-knowledge-boundary-vanilla.md +29 -0
  108. package/benchmarks/results/logs/test-e-shell-awareness-harness.md +20 -0
  109. package/benchmarks/results/logs/test-e-shell-awareness-vanilla.md +20 -0
  110. package/benchmarks/results/logs/test-f-fact-audit-harness.md +16 -0
  111. package/benchmarks/results/logs/test-f-fact-audit-vanilla.md +16 -0
  112. package/benchmarks/results/results.json +158 -0
  113. package/benchmarks/run.js +220 -0
  114. package/benchmarks/schema.json +44 -0
  115. package/bin/cli.js +152 -97
  116. package/ci/ab-test-cases/grill-me-adversarial.yaml +18 -0
  117. package/ci/ab-test-cases/tdd-test-first.yaml +23 -0
  118. package/ci/ab-test-cases/verification-loop-gates.yaml +25 -0
  119. package/ci/ab-test-cases/verify-before-claim-cites.yaml +18 -0
  120. package/ci/ab-test-harness.js +410 -0
  121. package/{eval-framework → ci}/cases/case1.json +5 -5
  122. package/ci/cases/case10-small-feature.json +5 -0
  123. package/ci/cases/case11-readme-typo-update.json +5 -0
  124. package/ci/cases/case12-chinese-macro-audit.json +5 -0
  125. package/{eval-framework → ci}/cases/case2.json +5 -5
  126. package/{eval-framework → ci}/cases/case3.json +5 -5
  127. package/{eval-framework → ci}/cases/case4-zh-tier2.json +5 -5
  128. package/{eval-framework → ci}/cases/case5-zh-tier3.json +5 -5
  129. package/ci/cases/case6-macro-skill-audit.json +5 -0
  130. package/ci/cases/case7-macro-reference-audit.json +5 -0
  131. package/ci/cases/case8-controlled-ab-benchmark.json +5 -0
  132. package/ci/cases/case9-four-issue-audit.json +5 -0
  133. package/ci/consistency-check.js +347 -0
  134. package/ci/description-collision.js +109 -0
  135. package/ci/fable-mode-test.js +120 -0
  136. package/ci/fixtures/agency-agents/divisions.json +6 -0
  137. package/ci/fixtures/agency-agents/engineering/code-reviewer.md +11 -0
  138. package/ci/fixtures/agency-agents/testing/reality-checker.md +11 -0
  139. package/ci/fixtures/bad-frontmatter-colon/SKILL.md +16 -0
  140. package/ci/fixtures/duplicate-description/skill-a/SKILL.md +16 -0
  141. package/ci/fixtures/duplicate-description/skill-b/SKILL.md +16 -0
  142. package/ci/mechanism-2a-rule-of-3.test.js +46 -0
  143. package/ci/mechanism-2b-boundary-guard.test.js +16 -0
  144. package/ci/mechanism-2c-state-persist.test.js +29 -0
  145. package/ci/mechanism-2d-fact-audit.test.js +18 -0
  146. package/ci/mechanism-2e-scope-guard.test.js +24 -0
  147. package/ci/mechanism-2f-stop-gate.test.js +23 -0
  148. package/ci/mechanism-2g-platform-ignore.test.js +88 -0
  149. package/ci/mechanism-2h-installer-manifest.test.js +147 -0
  150. package/ci/mechanism-2i-crlf-frontmatter.test.js +145 -0
  151. package/ci/mechanism-2i-install-verification.test.js +34 -0
  152. package/ci/mechanism-2j-behavioral-runner.test.js +20 -0
  153. package/ci/mechanism-2k-reference-check.test.js +20 -0
  154. package/ci/mechanism-2l-multi-agent-workspace.test.js +105 -0
  155. package/ci/mechanism-test.js +71 -0
  156. package/ci/negative-controls.js +84 -0
  157. package/ci/reference-check.js +112 -0
  158. package/ci/release-consistency-check.js +123 -0
  159. package/ci/routing-check.js +90 -0
  160. package/{eval-framework → ci}/runner.js +56 -56
  161. package/ci/skill-routing-check.js +98 -0
  162. package/ci/test-helper.js +104 -0
  163. package/ci/test-negative-controls.js +148 -0
  164. package/commitlint.config.js +25 -0
  165. package/docker-verify.sh +266 -266
  166. package/docs/architecture.md +99 -95
  167. package/docs/audit.md +53 -0
  168. package/docs/mechanism-first-skill-mesh.md +163 -0
  169. package/docs/philosophy.md +47 -45
  170. package/docs/reflection.md +48 -34
  171. package/docs/routing.md +58 -45
  172. package/docs/troubleshooting.md +284 -0
  173. package/docs/workflows/environment-detection.md +10 -10
  174. package/docs/workflows/eval-harness.md +13 -6
  175. package/docs/workflows/fable-discipline.md +9 -9
  176. package/docs/workflows/fable-mode.md +29 -32
  177. package/docs/workflows/find-skills.md +36 -0
  178. package/docs/workflows/git-commit.md +18 -9
  179. package/docs/workflows/grill-me.md +11 -11
  180. package/docs/workflows/grill-with-docs.md +14 -7
  181. package/docs/workflows/harness-everything.md +95 -92
  182. package/docs/workflows/improve-codebase-architecture.md +15 -7
  183. package/docs/workflows/install-cognitive-os.md +60 -60
  184. package/docs/workflows/multi-agent-workspace.md +42 -0
  185. package/docs/workflows/repo-docs.md +12 -7
  186. package/docs/workflows/security-review.md +26 -7
  187. package/docs/workflows/self-evolve.md +27 -44
  188. package/docs/workflows/skill-creator.md +80 -75
  189. package/docs/workflows/skill-style.md +64 -64
  190. package/docs/workflows/tdd.md +42 -39
  191. package/docs/workflows/to-spec.md +83 -0
  192. package/docs/workflows/to-tickets.md +80 -0
  193. package/docs/workflows/todo-driven-workflow.md +34 -36
  194. package/docs/workflows/using-git-worktrees.md +12 -8
  195. package/docs/workflows/verification-loop.md +16 -14
  196. package/docs/workflows/verify-before-claim.md +12 -8
  197. package/docs/workflows/zoom-out.md +22 -10
  198. package/environment-detection/SKILL.md +25 -61
  199. package/environment-detection/references/shell-syntax-rules.md +76 -0
  200. package/environment-detection/scripts/preflight.js +103 -93
  201. package/eval-framework/fixtures/bad-frontmatter-colon/SKILL.md +14 -0
  202. package/eval-framework/fixtures/duplicate-desc-skill-a/SKILL.md +14 -0
  203. package/eval-framework/fixtures/duplicate-desc-skill-b/SKILL.md +14 -0
  204. package/eval-framework/fixtures/missing-delimiter/SKILL.md +13 -0
  205. package/eval-framework/fixtures/over-budget-skill/SKILL.md +36 -0
  206. package/eval-harness/SKILL.md +34 -51
  207. package/eval-harness/references/scoring-rubric.md +68 -0
  208. package/eval-harness/scripts/evaluate.js +77 -61
  209. package/evals/environment-detection/eval.yaml +26 -0
  210. package/evals/environment-detection/tasks/negative-trigger.yaml +16 -0
  211. package/evals/environment-detection/tasks/positive-trigger.yaml +15 -0
  212. package/evals/eval-harness/eval.yaml +26 -0
  213. package/evals/eval-harness/tasks/negative-trigger.yaml +16 -0
  214. package/evals/eval-harness/tasks/positive-trigger.yaml +15 -0
  215. package/evals/fable-discipline/eval.yaml +26 -0
  216. package/evals/fable-discipline/tasks/negative-trigger.yaml +16 -0
  217. package/evals/fable-discipline/tasks/positive-trigger.yaml +15 -0
  218. package/evals/fable-mode/eval.yaml +26 -0
  219. package/evals/fable-mode/tasks/negative-tier2-no-model.yaml +18 -0
  220. package/evals/fable-mode/tasks/negative-trigger.yaml +16 -0
  221. package/evals/fable-mode/tasks/positive-haiku-mode.yaml +16 -0
  222. package/evals/fable-mode/tasks/positive-opus-mode.yaml +16 -0
  223. package/evals/fable-mode/tasks/positive-sonnet-mode.yaml +16 -0
  224. package/evals/fable-mode/tasks/positive-trigger.yaml +15 -0
  225. package/evals/find-skills/eval.yaml +26 -0
  226. package/evals/find-skills/tasks/negative-trigger.yaml +16 -0
  227. package/evals/find-skills/tasks/positive-trigger.yaml +15 -0
  228. package/evals/git-commit/eval.yaml +26 -0
  229. package/evals/git-commit/tasks/negative-trigger.yaml +16 -0
  230. package/evals/git-commit/tasks/positive-trigger.yaml +15 -0
  231. package/evals/grill-me/eval.yaml +26 -0
  232. package/evals/grill-me/tasks/negative-trigger.yaml +16 -0
  233. package/evals/grill-me/tasks/positive-trigger.yaml +15 -0
  234. package/evals/grill-with-docs/eval.yaml +26 -0
  235. package/evals/grill-with-docs/tasks/negative-trigger.yaml +16 -0
  236. package/evals/grill-with-docs/tasks/positive-trigger.yaml +15 -0
  237. package/evals/harness-everything/eval.yaml +26 -0
  238. package/evals/harness-everything/tasks/negative-non-software.yaml +16 -0
  239. package/evals/harness-everything/tasks/negative-skill-indicated.yaml +15 -0
  240. package/evals/harness-everything/tasks/positive-tier1.yaml +16 -0
  241. package/evals/harness-everything/tasks/positive-tier2.yaml +16 -0
  242. package/evals/harness-everything/tasks/positive-tier3.yaml +16 -0
  243. package/evals/improve-codebase-architecture/eval.yaml +26 -0
  244. package/evals/improve-codebase-architecture/tasks/negative-trigger.yaml +16 -0
  245. package/evals/improve-codebase-architecture/tasks/positive-trigger.yaml +15 -0
  246. package/evals/install-cognitive-os/eval.yaml +26 -0
  247. package/evals/install-cognitive-os/tasks/negative-trigger.yaml +16 -0
  248. package/evals/install-cognitive-os/tasks/positive-trigger.yaml +15 -0
  249. package/evals/multi-agent-workspace/eval.yaml +26 -0
  250. package/evals/multi-agent-workspace/tasks/negative-trigger.yaml +15 -0
  251. package/evals/multi-agent-workspace/tasks/positive-trigger.yaml +15 -0
  252. package/evals/repo-docs/eval.yaml +26 -0
  253. package/evals/repo-docs/tasks/negative-trigger.yaml +16 -0
  254. package/evals/repo-docs/tasks/positive-trigger.yaml +15 -0
  255. package/evals/rewrite-commits/eval.yaml +26 -0
  256. package/evals/rewrite-commits/tasks/negative-trigger.yaml +16 -0
  257. package/evals/rewrite-commits/tasks/positive-trigger.yaml +15 -0
  258. package/evals/security-review/eval.yaml +26 -0
  259. package/evals/security-review/tasks/negative-trigger.yaml +16 -0
  260. package/evals/security-review/tasks/positive-trigger.yaml +15 -0
  261. package/evals/self-evolve/eval.yaml +26 -0
  262. package/evals/self-evolve/tasks/negative-trigger.yaml +16 -0
  263. package/evals/self-evolve/tasks/positive-trigger.yaml +15 -0
  264. package/evals/skill-creator/eval.yaml +26 -0
  265. package/evals/skill-creator/tasks/negative-trigger.yaml +16 -0
  266. package/evals/skill-creator/tasks/positive-trigger.yaml +15 -0
  267. package/evals/skill-style/eval.yaml +26 -0
  268. package/evals/skill-style/tasks/negative-trigger.yaml +16 -0
  269. package/evals/skill-style/tasks/positive-trigger.yaml +15 -0
  270. package/evals/tdd/eval.yaml +26 -0
  271. package/evals/tdd/tasks/negative-trivia.yaml +16 -0
  272. package/evals/tdd/tasks/positive-bugfix.yaml +15 -0
  273. package/evals/tdd/tasks/positive-feature.yaml +16 -0
  274. package/evals/tdd/tasks/positive-refactor.yaml +15 -0
  275. package/evals/to-spec/eval.yaml +26 -0
  276. package/evals/to-spec/tasks/negative-trigger.yaml +16 -0
  277. package/evals/to-spec/tasks/positive-trigger.yaml +15 -0
  278. package/evals/to-tickets/eval.yaml +26 -0
  279. package/evals/to-tickets/tasks/negative-trigger.yaml +15 -0
  280. package/evals/to-tickets/tasks/positive-trigger.yaml +15 -0
  281. package/evals/todo-driven-workflow/eval.yaml +26 -0
  282. package/evals/todo-driven-workflow/tasks/negative-single-edit.yaml +16 -0
  283. package/evals/todo-driven-workflow/tasks/positive-multi-step.yaml +15 -0
  284. package/evals/todo-driven-workflow/tasks/positive-refactor-flow.yaml +15 -0
  285. package/evals/using-git-worktrees/eval.yaml +26 -0
  286. package/evals/using-git-worktrees/tasks/negative-trigger.yaml +15 -0
  287. package/evals/using-git-worktrees/tasks/positive-trigger.yaml +15 -0
  288. package/evals/verification-loop/eval.yaml +26 -0
  289. package/evals/verification-loop/tasks/negative-discussion.yaml +16 -0
  290. package/evals/verification-loop/tasks/positive-pre-ship.yaml +15 -0
  291. package/evals/verify-before-claim/eval.yaml +26 -0
  292. package/evals/verify-before-claim/tasks/negative-trigger.yaml +16 -0
  293. package/evals/verify-before-claim/tasks/positive-trigger.yaml +15 -0
  294. package/evals/zoom-out/eval.yaml +26 -0
  295. package/evals/zoom-out/tasks/negative-trivial-edit.yaml +16 -0
  296. package/evals/zoom-out/tasks/positive-repeated-failure.yaml +15 -0
  297. package/fable-discipline/SKILL.md +31 -28
  298. package/fable-discipline/references/discipline-rules.md +22 -0
  299. package/fable-mode/CONTRACT-FORMAT.md +51 -51
  300. package/fable-mode/SKILL.md +31 -43
  301. package/fable-mode/agents/fable-orchestrator.md +99 -92
  302. package/fable-mode/agents/fable-verifier.md +32 -32
  303. package/fable-mode/agents/fable-worker-haiku.md +52 -48
  304. package/fable-mode/agents/fable-worker-sonnet.md +53 -49
  305. package/fable-mode/execution-guardrails/SKILL.md +43 -87
  306. package/fable-mode/execution-guardrails/references/guardrail-rules.md +56 -0
  307. package/fable-mode/fable-haiku/SKILL.md +36 -48
  308. package/fable-mode/fable-haiku/references/routing-notes.md +26 -0
  309. package/fable-mode/fable-opus/SKILL.md +36 -0
  310. package/fable-mode/fable-sonnet/SKILL.md +36 -0
  311. package/fable-mode/model-matrix.json +32 -0
  312. package/fable-mode/references/execution-phases.md +37 -0
  313. package/fable-mode/references/model-matrix.md +39 -0
  314. package/fable-mode/scripts/model-selector.js +129 -0
  315. package/find-skills/SKILL.md +48 -0
  316. package/find-skills/references/discovery-flow.md +102 -0
  317. package/find-skills/scripts/use-skill.js +106 -0
  318. package/git-commit/SKILL.md +35 -45
  319. package/git-commit/guides/ANGULAR_STYLE.md +60 -60
  320. package/git-commit/guides/COMMIT_GENERATION.md +23 -23
  321. package/git-commit/guides/LANGUAGE_DETECTION.md +16 -16
  322. package/git-commit/guides/MAIN_REPO.md +14 -14
  323. package/git-commit/guides/SUBMODULES.md +27 -27
  324. package/git-commit/references/commit-flow.md +30 -0
  325. package/grill-me/SKILL.md +34 -27
  326. package/grill-me/references/grilling-playbook.md +38 -0
  327. package/grill-with-docs/ADR-FORMAT.md +47 -47
  328. package/grill-with-docs/CONTEXT-FORMAT.md +63 -63
  329. package/grill-with-docs/SKILL.md +33 -91
  330. package/grill-with-docs/references/session-playbook.md +97 -0
  331. package/harness-everything/SKILL.md +29 -128
  332. package/harness-everything/examples/README.md +9 -9
  333. package/harness-everything/examples/todo-workflow.md +22 -22
  334. package/harness-everything/references/skill-registry.md +39 -0
  335. package/harness-everything/references/triage-and-tiers.md +116 -0
  336. package/harness-everything/scripts/bootstrap.js +203 -140
  337. package/harness-everything/scripts/routing-keywords.json +320 -0
  338. package/harness-everything/scripts/self-heal.js +241 -189
  339. package/harness-everything/scripts/tier-router.js +334 -219
  340. package/harness-everything/scripts/verify-gate.js +100 -31
  341. package/hooks/hooks.json +155 -155
  342. package/hooks/scripts/atomic-commit-check.js +68 -68
  343. package/hooks/scripts/boundary-guard.js +55 -55
  344. package/hooks/scripts/context-compact.js +114 -114
  345. package/hooks/scripts/contract-test.js +79 -79
  346. package/hooks/scripts/depth-guard.js +65 -65
  347. package/hooks/scripts/lib/harness-state.js +139 -228
  348. package/hooks/scripts/lib/platforms/claude.js +72 -19
  349. package/hooks/scripts/lib/platforms/codex.js +24 -6
  350. package/hooks/scripts/lib/platforms/continue.js +23 -5
  351. package/hooks/scripts/lib/platforms/copilot.js +23 -5
  352. package/hooks/scripts/lib/platforms/cursor.js +23 -5
  353. package/hooks/scripts/lib/platforms/hermes.js +57 -57
  354. package/hooks/scripts/lib/platforms/index.js +17 -17
  355. package/hooks/scripts/lib/platforms/worktrees.js +20 -20
  356. package/hooks/scripts/reset-circuit-breaker.js +30 -30
  357. package/hooks/scripts/rule-of-3-tracker.js +124 -91
  358. package/hooks/scripts/rule-of-3.js +187 -176
  359. package/hooks/scripts/state-persist.js +99 -99
  360. package/hooks/scripts/stop-gate.js +80 -80
  361. package/hooks/scripts/subagent-scope-guard.js +88 -88
  362. package/improve-codebase-architecture/SKILL.md +31 -35
  363. package/improve-codebase-architecture/guides/DEEPENING.md +37 -37
  364. package/improve-codebase-architecture/guides/HTML-REPORT.md +123 -123
  365. package/improve-codebase-architecture/guides/INTERFACE-DESIGN.md +44 -44
  366. package/improve-codebase-architecture/guides/LANGUAGE.md +53 -53
  367. package/improve-codebase-architecture/guides/refactoring-workflow.md +59 -0
  368. package/install-cognitive-os/SKILL.md +23 -80
  369. package/install-cognitive-os/references/cognitive-loop.md +27 -0
  370. package/multi-agent-workspace/NOTICE-agency-agents.md +27 -0
  371. package/multi-agent-workspace/SKILL.md +37 -0
  372. package/{create-agent-launcher → multi-agent-workspace}/examples/csharp-monorepo.md +123 -123
  373. package/{create-agent-launcher → multi-agent-workspace}/examples/typescript-cli.md +126 -126
  374. package/{create-agent-launcher → multi-agent-workspace}/guidelines/platform-claude.md +77 -77
  375. package/{create-agent-launcher → multi-agent-workspace}/guidelines/platform-codex.md +146 -146
  376. package/multi-agent-workspace/guidelines/platform-continue.md +38 -0
  377. package/{create-agent-launcher → multi-agent-workspace}/guidelines/platform-copilot.md +74 -74
  378. package/multi-agent-workspace/guidelines/platform-cursor.md +40 -0
  379. package/multi-agent-workspace/guidelines/platform-hermes.md +38 -0
  380. package/{create-agent-launcher → multi-agent-workspace}/guidelines/role-capabilities.md +108 -108
  381. package/multi-agent-workspace/references/agency-agents.md +31 -0
  382. package/multi-agent-workspace/references/architecture-guide.md +32 -0
  383. package/multi-agent-workspace/references/orchestration.md +48 -0
  384. package/multi-agent-workspace/scripts/agency-catalog.js +190 -0
  385. package/multi-agent-workspace/scripts/index_memory.js +51 -0
  386. package/multi-agent-workspace/scripts/scaffold.js +253 -0
  387. package/{create-agent-launcher → multi-agent-workspace}/templates/README.md +17 -17
  388. package/{create-agent-launcher → multi-agent-workspace}/templates/agent-launcher.md +67 -67
  389. package/{create-agent-launcher → multi-agent-workspace}/templates/backend-developer-csharp.md +55 -55
  390. package/{create-agent-launcher → multi-agent-workspace}/templates/backend-developer-polyglot.md +61 -61
  391. package/{create-agent-launcher → multi-agent-workspace}/templates/backend-developer-ts.md +56 -56
  392. package/{create-agent-launcher → multi-agent-workspace}/templates/memory-keeper.md +36 -36
  393. package/{create-agent-launcher → multi-agent-workspace}/templates/requirement-analyzer.md +65 -65
  394. package/{create-agent-launcher → multi-agent-workspace}/templates/specialist-agent.md +34 -34
  395. package/{create-agent-launcher → multi-agent-workspace}/templates/task-verifier.md +55 -55
  396. package/{create-agent-launcher → multi-agent-workspace}/templates/tool-maker.md +32 -32
  397. package/multi-agent-workspace/workflows/01-init.md +22 -0
  398. package/multi-agent-workspace/workflows/02-analysis.md +23 -0
  399. package/multi-agent-workspace/workflows/03-generation.md +27 -0
  400. package/multi-agent-workspace/workflows/04-launcher.md +16 -0
  401. package/opencode-plugin/README.md +94 -0
  402. package/opencode-plugin/hooks/circuit-breaker.js +121 -0
  403. package/opencode-plugin/hooks/compliance.js +128 -0
  404. package/opencode-plugin/hooks/post-edit.js +62 -0
  405. package/opencode-plugin/hooks/pre-complete.js +65 -0
  406. package/opencode-plugin/hooks/verify.js +140 -0
  407. package/opencode-plugin/plugin.json +17 -0
  408. package/opencode-plugin/test-hook-firing.js +198 -0
  409. package/package.json +50 -22
  410. package/references/definition-of-done.md +67 -0
  411. package/references/performance-checklist.md +153 -0
  412. package/references/platform-advisory-template.md +58 -0
  413. package/references/security-checklist.md +205 -0
  414. package/repo-docs/SKILL.md +38 -37
  415. package/repo-docs/references/process-guide.md +60 -0
  416. package/repo-docs/templates/agents-template.md +264 -264
  417. package/repo-docs/templates/knowledge-agents-template.md +50 -50
  418. package/repo-docs/templates/knowledge-readme-template.md +83 -83
  419. package/repo-docs/templates/manual-recon.md +117 -117
  420. package/repo-docs/templates/multi-skills-readme-template.md +72 -72
  421. package/repo-docs/templates/product-agents-template.md +78 -78
  422. package/repo-docs/templates/product-readme-template.md +95 -95
  423. package/repo-docs/templates/readme-template.md +136 -136
  424. package/repo-docs/templates/single-skill-readme-template.md +70 -70
  425. package/repo-docs/templates/skills-agents-template.md +60 -60
  426. package/rewrite-commits/SKILL.md +22 -17
  427. package/rewrite-commits/references/workflow.md +18 -0
  428. package/scripts/installer.js +546 -506
  429. package/scripts/lib/advisory-text.js +8 -4
  430. package/scripts/lib/claude-hooks.js +18 -5
  431. package/scripts/lib/gitignore.js +199 -80
  432. package/scripts/lib/manifest.js +68 -4
  433. package/scripts/lib/prompts.js +1 -1
  434. package/scripts/lib/skills.js +87 -1
  435. package/scripts/verify-install.js +147 -0
  436. package/security-review/SKILL.md +35 -496
  437. package/security-review/guides/OWASP-PATTERNS.md +31 -0
  438. package/security-review/guides/STRIDE-THREAT-MODEL.md +21 -0
  439. package/security-review/references/security-checklist.md +478 -0
  440. package/security-review/scripts/audit-secrets.js +84 -0
  441. package/self-evolve/SKILL.md +38 -45
  442. package/self-evolve/references/memory-resolution.md +58 -0
  443. package/self-evolve/scripts/persist-memory.js +139 -40
  444. package/self-evolve/scripts/register-dynamic-skill.js +251 -0
  445. package/self-evolve/scripts/self-regression.js +110 -113
  446. package/skill-creator/SKILL.md +34 -76
  447. package/skill-creator/references/authoring-workflow.md +14 -0
  448. package/skill-creator/references/dynamic-generation-contract.md +21 -0
  449. package/skill-creator/references/quality-checklist.md +15 -0
  450. package/skill-creator/references/quality-principles.md +81 -81
  451. package/skill-creator/references/testing-workflow.md +27 -32
  452. package/skill-style/SKILL.md +33 -39
  453. package/skill-style/references/style-guide.md +36 -0
  454. package/tdd/SKILL.md +34 -43
  455. package/tdd/guides/deep-modules.md +33 -33
  456. package/tdd/guides/interface-design.md +31 -31
  457. package/tdd/guides/mocking.md +59 -59
  458. package/tdd/guides/refactoring.md +10 -10
  459. package/tdd/guides/tests.md +61 -61
  460. package/tdd/references/core-discipline.md +49 -0
  461. package/to-spec/SKILL.md +42 -0
  462. package/to-spec/references/process.md +77 -0
  463. package/to-spec/scripts/check-project-docs.js +259 -0
  464. package/to-spec/templates/cli-reference.md +31 -0
  465. package/to-spec/templates/dev-doc.md +27 -0
  466. package/to-spec/templates/feature-spec.md +59 -0
  467. package/to-spec/templates/schema-doc.md +31 -0
  468. package/to-tickets/SKILL.md +42 -0
  469. package/to-tickets/references/publishing-and-templates.md +97 -0
  470. package/todo-driven-workflow/SKILL.md +27 -41
  471. package/todo-driven-workflow/references/execution-guide.md +27 -0
  472. package/using-git-worktrees/SKILL.md +29 -141
  473. package/using-git-worktrees/references/workflow-details.md +108 -0
  474. package/verification-loop/SKILL.md +29 -121
  475. package/verification-loop/references/verification-phases.md +116 -0
  476. package/verification-loop/templates/verification-report.template.md +15 -0
  477. package/verify-before-claim/SKILL.md +27 -70
  478. package/verify-before-claim/references/verification-guide.md +73 -0
  479. package/zoom-out/SKILL.md +28 -76
  480. package/zoom-out/references/circuit-breaker.md +66 -0
  481. package/zoom-out/templates/zoom-out-report.template.md +20 -0
  482. package/build-multi-agent-system/AGENTS.md +0 -50
  483. package/build-multi-agent-system/README.md +0 -63
  484. package/build-multi-agent-system/SKILL.md +0 -68
  485. package/create-agent-launcher/SKILL.md +0 -48
  486. package/create-agent-launcher/guidelines/platform-gemini.md +0 -101
  487. package/create-agent-launcher/workflows/01-init.md +0 -22
  488. package/create-agent-launcher/workflows/02-analysis.md +0 -26
  489. package/create-agent-launcher/workflows/03-generation.md +0 -29
  490. package/create-agent-launcher/workflows/04-launcher.md +0 -20
  491. package/docs/workflows/build-multi-agent-system.md +0 -62
  492. package/docs/workflows/create-agent-launcher.md +0 -62
  493. package/eval-framework/behavioral-test.js +0 -105
  494. package/eval-framework/mechanism-test.js +0 -251
  495. package/harness-everything/scripts/todo-cli.js +0 -157
  496. package/skill-style/STYLE.md +0 -37
@@ -0,0 +1,347 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Harness Consistency Check
4
+ * Validates that the docs surface, skill catalog, and distribution manifests
5
+ * tell the same story. A stale manifest or a dead README link is a router
6
+ * that lies — this script keeps them honest.
7
+ *
8
+ * Checks:
9
+ * 1. Every skill dir's SKILL.md frontmatter name matches its directory.
10
+ * 2. Every SKILL.md has a description and both trigger sections.
11
+ * 3. .claude-plugin/plugin.json + marketplace.json list exactly the on-disk skills.
12
+ * 4. Version strings agree across package.json / plugin.json / marketplace.json.
13
+ * 5. Every skill has a routing eval (evals/<skill>/eval.yaml).
14
+ * 6. Local links in README.md and docs markdown files resolve to real files.
15
+ */
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const yaml = require('js-yaml');
19
+
20
+ const ROOT = path.resolve(__dirname, '..');
21
+ let failures = 0;
22
+ function check(name, condition, detail) {
23
+ if (condition) {
24
+ console.log(`✅ ${name}`);
25
+ } else {
26
+ console.error(`❌ ${name}`);
27
+ if (detail) console.error(` ${detail}`);
28
+ failures++;
29
+ }
30
+ }
31
+
32
+ // --- Collect skills from disk -------------------------------------------
33
+ const SKIP_DIRS = new Set([
34
+ '.git', '.github', '.claude-plugin', 'bin', 'docs', 'evals',
35
+ 'behavioral-evals', 'benchmarks', 'hooks', 'node_modules', 'references', 'scripts'
36
+ ]);
37
+ function discoverSkills() {
38
+ const skills = [];
39
+ for (const entry of fs.readdirSync(ROOT, { withFileTypes: true })) {
40
+ if (!entry.isDirectory() || SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) continue;
41
+ const skillMd = path.join(ROOT, entry.name, 'SKILL.md');
42
+ if (!fs.existsSync(skillMd)) continue;
43
+ const raw = fs.readFileSync(skillMd, 'utf8');
44
+ const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
45
+ const fm = fmMatch ? fmMatch[1] : '';
46
+ const name = (fm.match(/^name:\s*(.+)$/m) || [])[1];
47
+ const desc = (fm.match(/^description:\s*(.+)$/m) || [])[1];
48
+ skills.push({
49
+ dir: entry.name,
50
+ name: name ? name.trim().replace(/["']/g, '') : null,
51
+ description: desc ? desc.trim() : null,
52
+ body: raw,
53
+ path: skillMd,
54
+ });
55
+ }
56
+ return skills.sort((a, b) => a.dir.localeCompare(b.dir));
57
+ }
58
+ const skills = discoverSkills();
59
+ check(`Found ${skills.length} skills on disk`, skills.length >= 20, `Got ${skills.length}`);
60
+
61
+ // --- 1+2. Frontmatter & trigger sections --------------------------------
62
+ for (const s of skills) {
63
+ check(
64
+ `${s.dir}: frontmatter name matches directory`,
65
+ s.name === s.dir,
66
+ `frontmatter "${s.name}" != dir "${s.dir}"`
67
+ );
68
+ check(
69
+ `${s.dir}: has description in frontmatter`,
70
+ !!s.description && s.description.length > 10,
71
+ s.description ? 'description too short' : 'missing description'
72
+ );
73
+ check(`${s.dir}: has "## USE FOR:" section`, /^## USE FOR:/m.test(s.body), 'missing section');
74
+ check(
75
+ `${s.dir}: has "## DO NOT USE FOR:" section`,
76
+ /^## DO NOT USE FOR:/m.test(s.body),
77
+ 'missing section'
78
+ );
79
+ }
80
+
81
+ // --- 1b. YAML frontmatter syntax validation (parser parity) ---------------
82
+ // Catches unquoted colons, unclosed quotes, and broken multi-line strings
83
+ // that regex extraction misses but waza's real YAML parser catches in CI.
84
+ function validateFrontmatterSyntax(raw, skillDir) {
85
+ const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
86
+ if (!fmMatch) return check(`${skillDir}: has valid YAML frontmatter delimiters`, false, 'missing --- delimiters');
87
+ const fm = fmMatch[1];
88
+
89
+ // Parser parity: use js-yaml to validate the frontmatter
90
+ try {
91
+ yaml.load(fm);
92
+ } catch (e) {
93
+ return check(`${skillDir}: frontmatter YAML syntax valid`, false, e.message);
94
+ }
95
+
96
+ // Additional regex-based checks for common issues
97
+ const lines = fm.split('\n');
98
+ for (let i = 0; i < lines.length; i++) {
99
+ const line = lines[i];
100
+ if (!line.trim() || line.trim().startsWith('#')) continue;
101
+ // Check for unquoted colons in values: "key: value with : inside"
102
+ const kvMatch = line.match(/^(\s*)(\w[\w-]*):\s*(.*)/);
103
+ if (kvMatch && kvMatch[3]) {
104
+ const val = kvMatch[3];
105
+ // Value contains colon not inside quotes → likely unquoted YAML
106
+ if (val.includes(':') && !/^["']/.test(val) && !/["']$/.test(val)) {
107
+ const inQuotes = /^["'].*:.*["']$/.test(val);
108
+ if (!inQuotes) {
109
+ check(
110
+ `${skillDir}: frontmatter line ${i + 1} has unquoted colon in value`,
111
+ false,
112
+ `"${line.trim()}" — wrap value in quotes to avoid YAML parse errors`
113
+ );
114
+ return;
115
+ }
116
+ }
117
+ }
118
+ // Check for unclosed single quotes
119
+ const singleQuoteCount = (line.match(/(?<!\\)'/g) || []).length;
120
+ if (singleQuoteCount % 2 !== 0) {
121
+ check(`${skillDir}: frontmatter line ${i + 1} has unclosed single quote`, false, `"${line.trim()}"`);
122
+ return;
123
+ }
124
+ // Check for unclosed double quotes
125
+ const doubleQuoteCount = (line.match(/(?<!\\)"/g) || []).length;
126
+ if (doubleQuoteCount % 2 !== 0) {
127
+ check(`${skillDir}: frontmatter line ${i + 1} has unclosed double quote`, false, `"${line.trim()}"`);
128
+ return;
129
+ }
130
+ }
131
+ check(`${skillDir}: frontmatter YAML syntax valid`, true);
132
+ }
133
+ for (const s of skills) {
134
+ validateFrontmatterSyntax(s.body, s.dir);
135
+ }
136
+
137
+ // --- 3+4. Distribution manifests -----------------------------------------
138
+ const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
139
+ const pluginJsonPath = path.join(ROOT, '.claude-plugin', 'plugin.json');
140
+ const marketplaceJsonPath = path.join(ROOT, '.claude-plugin', 'marketplace.json');
141
+ check('.claude-plugin/plugin.json exists', fs.existsSync(pluginJsonPath));
142
+ check('.claude-plugin/marketplace.json exists', fs.existsSync(marketplaceJsonPath));
143
+
144
+ if (fs.existsSync(pluginJsonPath)) {
145
+ const plugin = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf8'));
146
+ const listed = new Set((plugin.skills || []).map((p) => p.replace(/^\.\//, '').replace(/\/$/, '')));
147
+ const onDisk = new Set(skills.map((s) => s.dir));
148
+ const missing = [...onDisk].filter((d) => !listed.has(d));
149
+ const extra = [...listed].filter((d) => !onDisk.has(d));
150
+ check(
151
+ 'plugin.json lists every on-disk skill',
152
+ missing.length === 0,
153
+ `missing: ${missing.join(', ')}`
154
+ );
155
+ check(
156
+ 'plugin.json lists no phantom skills',
157
+ extra.length === 0,
158
+ `extra: ${extra.join(', ')}`
159
+ );
160
+ check('plugin.json hooks file exists', !plugin.hooks || fs.existsSync(path.join(ROOT, plugin.hooks)), plugin.hooks);
161
+ if (plugin.agents) {
162
+ const agentsPath = path.join(ROOT, plugin.agents);
163
+ check('plugin.json agents path exists', fs.existsSync(agentsPath), plugin.agents);
164
+ if (fs.existsSync(agentsPath)) {
165
+ const agentFiles = fs.readdirSync(agentsPath).filter(name => name.endsWith('.md'));
166
+ check('plugin.json agents path contains agent definitions', agentFiles.length > 0, plugin.agents);
167
+ }
168
+ }
169
+ for (const rel of plugin.skills || []) {
170
+ const p = path.join(ROOT, rel);
171
+ check(`plugin.json skill path resolves: ${rel}`, fs.existsSync(path.join(p, 'SKILL.md')));
172
+ }
173
+ check(
174
+ 'version agrees: package.json vs plugin.json',
175
+ pkg.version === plugin.version,
176
+ `"${pkg.version}" vs "${plugin.version}"`
177
+ );
178
+ if (fs.existsSync(marketplaceJsonPath)) {
179
+ const market = JSON.parse(fs.readFileSync(marketplaceJsonPath, 'utf8'));
180
+ const entry = (market.plugins || []).find((p) => p.name === plugin.name);
181
+ check('marketplace.json references this plugin', !!entry);
182
+ if (entry && entry.version) {
183
+ check(
184
+ 'version agrees: package.json vs marketplace.json',
185
+ pkg.version === entry.version,
186
+ `"${pkg.version}" vs "${entry.version}"`
187
+ );
188
+ }
189
+ }
190
+ }
191
+
192
+ // --- 5. Routing eval coverage --------------------------------------------
193
+ const evalsDir = path.join(ROOT, 'evals');
194
+ for (const s of skills) {
195
+ check(
196
+ `${s.dir}: has routing eval (evals/${s.dir}/eval.yaml)`,
197
+ fs.existsSync(path.join(evalsDir, s.dir, 'eval.yaml')),
198
+ 'no trigger/routing eval for this skill'
199
+ );
200
+ }
201
+
202
+ // --- 5b. Skill version ceiling --------------------------------------------
203
+ // Skill frontmatter versions move in lockstep with releases; no skill may
204
+ // exceed the package version's numeric base (prerelease suffixes ignored).
205
+ function verBase(v) {
206
+ const m = String(v).match(/^(\d+)\.(\d+)\.(\d+)/);
207
+ return m ? m.slice(1).map(Number) : null;
208
+ }
209
+ function cmpVer(a, b) {
210
+ for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] - b[i];
211
+ return 0;
212
+ }
213
+ const pkgBase = verBase(pkg.version);
214
+ check(
215
+ `package.json version parses (${pkg.version})`,
216
+ !!pkgBase
217
+ );
218
+ for (const s of skills) {
219
+ const raw = fs.readFileSync(s.path, 'utf8');
220
+ const fm = (raw.match(/^---\r?\n([\s\S]*?)\r?\n---/) || [])[1] || '';
221
+ const vRaw = ((fm.match(/^ version:\s*(.+)$/m) || [])[1] || '').trim();
222
+ const v = verBase(vRaw);
223
+ check(
224
+ `${s.dir}: skill version ${vRaw || '(missing)'} <= package base ${pkgBase ? pkgBase.join('.') : '?'}`,
225
+ !!v && !!pkgBase && cmpVer(v, pkgBase) <= 0,
226
+ v ? 'skill version exceeds package version' : 'missing or unparseable metadata.version'
227
+ );
228
+ }
229
+
230
+ // --- 5c. Nested sub-skill versions -----------------------------------------
231
+ // Sub-skills nested inside a parent skill dir (<skill>/<sub>/SKILL.md) are
232
+ // invoked by the parent, not routed independently; they inherit the parent
233
+ // skill's version so the lockstep policy stays enforceable.
234
+ const nestedSubSkills = [];
235
+ for (const s of skills) {
236
+ (function walk(dir) {
237
+ let entries;
238
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
239
+ for (const e of entries) {
240
+ if (!e.isDirectory() || e.name.startsWith('.') || e.name === 'node_modules') continue;
241
+ const sub = path.join(dir, e.name);
242
+ if (fs.existsSync(path.join(sub, 'SKILL.md'))) nestedSubSkills.push(sub);
243
+ else walk(sub);
244
+ }
245
+ })(path.join(ROOT, s.dir));
246
+ }
247
+ for (const sub of nestedSubSkills) {
248
+ const rel = path.relative(ROOT, path.join(sub, 'SKILL.md'));
249
+ const parentDir = path.dirname(sub);
250
+ const parentRaw = fs.readFileSync(path.join(parentDir, 'SKILL.md'), 'utf8');
251
+ const parentFm = (parentRaw.match(/^---\r?\n([\s\S]*?)\r?\n---/) || [])[1] || '';
252
+ const parentV = ((parentFm.match(/^ version:\s*(.+)$/m) || [])[1] || '').trim();
253
+ const raw = fs.readFileSync(path.join(sub, 'SKILL.md'), 'utf8');
254
+ const fm = (raw.match(/^---\r?\n([\s\S]*?)\r?\n---/) || [])[1] || '';
255
+ const v = ((fm.match(/^ version:\s*(.+)$/m) || [])[1] || '').trim();
256
+ check(
257
+ `${rel}: nested sub-skill inherits parent version (${parentV})`,
258
+ !!v && v === parentV,
259
+ `"${v}" != parent "${parentV}"`
260
+ );
261
+ }
262
+
263
+ // --- 5d. Word-count budget (token proxy) ------------------------------------
264
+ // Skill frontmatter descriptions are routing surfaces; long descriptions
265
+ // bloat token budgets. A simple word-count proxy flags files likely to
266
+ // exceed the waza 500-token limit (~1.55 tokens/word → 330 words ≈ 507 tokens).
267
+ const WORD_BUDGET = 330;
268
+ for (const s of skills) {
269
+ const raw = fs.readFileSync(s.path, 'utf8');
270
+ const body = raw.replace(/^---\r?\n[\s\S]*?\r?\n---/, '').trim();
271
+ const wc = body.split(/\s+/).filter(Boolean).length;
272
+ check(
273
+ `${s.dir}: SKILL.md word count ${wc} <= ${WORD_BUDGET}`,
274
+ wc <= WORD_BUDGET,
275
+ `body is ${wc} words (~${Math.round(wc * 1.55)} tokens); trim to under ${WORD_BUDGET} words`
276
+ );
277
+ }
278
+
279
+ // --- 6. Dead-link audit over README.md and docs/** -----------------------
280
+ function extractLocalLinks(file) {
281
+ const text = fs.readFileSync(file, 'utf8');
282
+ const links = [];
283
+ const re = /\[[^\]]*\]\(([^)\s]+)\)/g;
284
+ let m;
285
+ while ((m = re.exec(text)) !== null) {
286
+ let href = m[1].split('#')[0];
287
+ if (!href || /^(https?:|mailto:|npx)/.test(href)) continue;
288
+ links.push(href);
289
+ }
290
+ return links;
291
+ }
292
+ const docFiles = [path.join(ROOT, 'README.md')];
293
+ (function walk(dir) {
294
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
295
+ const p = path.join(dir, e.name);
296
+ if (e.isDirectory()) walk(p);
297
+ else if (e.name.endsWith('.md')) docFiles.push(p);
298
+ }
299
+ })(path.join(ROOT, 'docs'));
300
+
301
+ let linkCount = 0;
302
+ for (const file of docFiles) {
303
+ for (const href of extractLocalLinks(file)) {
304
+ linkCount++;
305
+ const target = path.resolve(path.dirname(file), decodeURIComponent(href));
306
+ check(
307
+ `link resolves: ${path.relative(ROOT, file)} -> ${href}`,
308
+ fs.existsSync(target),
309
+ `target not found on disk`
310
+ );
311
+ }
312
+ }
313
+ console.log(`\nChecked ${linkCount} local doc links.`);
314
+
315
+ // --- 7. Token-budget gate (word-count proxy, hard limit 500) ----------------
316
+ // Exact tokenization is waza's job; this is the local early-warning gate.
317
+ // Includes warning threshold at 80% (400 words) for early detection.
318
+ const TOKEN_HARD_LIMIT = 500;
319
+ const TOKEN_WARNING_THRESHOLD = 400; // 80% of hard limit
320
+ for (const s of skills) {
321
+ const raw = fs.readFileSync(s.path, 'utf8');
322
+ const withoutFm = raw.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '');
323
+ const wordCount = withoutFm.split(/\s+/).filter(Boolean).length;
324
+
325
+ // Early warning at WORD_BUDGET threshold (non-blocking)
326
+ if (wordCount > WORD_BUDGET && wordCount <= TOKEN_WARNING_THRESHOLD) {
327
+ console.log(`⚠️ ${s.dir}: word count ${wordCount} exceeds WORD_BUDGET (${WORD_BUDGET})`);
328
+ }
329
+
330
+ // Warning at 80% threshold (non-blocking)
331
+ if (wordCount > TOKEN_WARNING_THRESHOLD && wordCount <= TOKEN_HARD_LIMIT) {
332
+ console.log(`⚠️ ${s.dir}: SKILL.md word count ${wordCount} approaching limit (${TOKEN_HARD_LIMIT - wordCount} words remaining)`);
333
+ }
334
+ check(
335
+ `${s.dir}: SKILL.md word count ${wordCount} <= ${TOKEN_HARD_LIMIT}`,
336
+ wordCount <= TOKEN_HARD_LIMIT,
337
+ wordCount > TOKEN_HARD_LIMIT
338
+ ? `exceeds hard limit by ${wordCount - TOKEN_HARD_LIMIT} words`
339
+ : `${TOKEN_HARD_LIMIT - wordCount} words of headroom`
340
+ );
341
+ }
342
+
343
+ if (failures > 0) {
344
+ console.error(`\n❌ CONSISTENCY CHECK FAILED: ${failures} problem(s).`);
345
+ process.exit(1);
346
+ }
347
+ console.log('\n🎉 ALL CONSISTENCY CHECKS PASSED.');
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Skill Description Collision Detector
4
+ *
5
+ * Routing skills are selected by their `description:` frontmatter. When two
6
+ * descriptions overlap too much, the router effectively flips a coin between
7
+ * them. This script tokenizes every SKILL.md description, computes pairwise
8
+ * Jaccard similarity over stemmed tokens, and fails on collisions.
9
+ *
10
+ * Thresholds:
11
+ * >= 0.75 similarity -> ERROR (collision; rewrite one description)
12
+ * >= 0.50 similarity -> WARNING (review recommended)
13
+ *
14
+ * Usage: node ci/description-collision.js
15
+ */
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const yaml = require('js-yaml');
19
+
20
+ const ROOT = path.resolve(__dirname, '..');
21
+ const ERROR_THRESHOLD = 0.75;
22
+ const WARN_THRESHOLD = 0.5;
23
+
24
+ // Words so generic they carry no routing signal — dropping them keeps the
25
+ // metric honest (otherwise "the", "a", "skill" dominate every pair).
26
+ const STOPWORDS = new Set([
27
+ 'a', 'an', 'the', 'and', 'or', 'for', 'to', 'of', 'in', 'on', 'with',
28
+ 'this', 'that', 'it', 'its', 'is', 'are', 'be', 'when', 'before', 'after',
29
+ 'use', 'used', 'using', 'must', 'should', 'new', 'your', 'you', 'from',
30
+ 'into', 'any', 'all', 'not', 'no', 'so', 'by', 'at', 'as',
31
+ ]);
32
+
33
+ function stem(word) {
34
+ // Deliberately crude suffix stripper — consistent crudeness is what matters.
35
+ return word
36
+ .replace(/(?:ing|ies|ied|edly|ements?)$/, '')
37
+ .replace(/(?:s|es)$/, '');
38
+ }
39
+
40
+ function tokenize(description) {
41
+ const cleaned = description.replace(/^["']|["'],?$/g, '').toLowerCase();
42
+ const raw = cleaned.match(/[a-z][a-z0-9-]+/g) || [];
43
+ const tokens = new Set();
44
+ for (const w of raw) {
45
+ if (STOPWORDS.has(w)) continue;
46
+ tokens.add(stem(w));
47
+ }
48
+ return tokens;
49
+ }
50
+
51
+ function jaccard(a, b) {
52
+ let inter = 0;
53
+ for (const t of a) if (b.has(t)) inter++;
54
+ return inter / (a.size + b.size - inter);
55
+ }
56
+
57
+ function discoverSkills() {
58
+ const out = [];
59
+ for (const entry of fs.readdirSync(ROOT, { withFileTypes: true })) {
60
+ if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
61
+ const skillMd = path.join(ROOT, entry.name, 'SKILL.md');
62
+ if (!fs.existsSync(skillMd)) continue;
63
+ const raw = fs.readFileSync(skillMd, 'utf8');
64
+ const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
65
+ if (!fmMatch) continue;
66
+ const fm = fmMatch[1];
67
+ // Parser parity: use js-yaml to parse frontmatter
68
+ let desc = '';
69
+ try {
70
+ const parsed = yaml.load(fm);
71
+ desc = (parsed.description || '').trim();
72
+ } catch {
73
+ // Fallback to regex if YAML parse fails
74
+ desc = ((fm.match(/^description:\s*(.+)$/m) || [])[1] || '').trim();
75
+ }
76
+ out.push({ name: entry.name, desc });
77
+ }
78
+ return out;
79
+ }
80
+
81
+ const skills = discoverSkills();
82
+ if (skills.length < 2) {
83
+ console.error('Not enough skills found to compare.');
84
+ process.exit(1);
85
+ }
86
+
87
+ let errors = 0;
88
+ console.log(`Comparing ${skills.length} skill descriptions...\n`);
89
+ for (let i = 0; i < skills.length; i++) {
90
+ for (let j = i + 1; j < skills.length; j++) {
91
+ const sim = jaccard(tokenize(skills[i].desc), tokenize(skills[j].desc));
92
+ if (sim >= WARN_THRESHOLD) {
93
+ const label = sim >= ERROR_THRESHOLD ? '❌ COLLISION' : '⚠️ WARNING ';
94
+ console.log(
95
+ `${label} ${skills[i].name} <-> ${skills[j].name}: ${sim.toFixed(2)}`
96
+ );
97
+ if (sim >= ERROR_THRESHOLD) errors++;
98
+ }
99
+ }
100
+ }
101
+
102
+ if (errors > 0) {
103
+ console.error(
104
+ `\n❌ ${errors} description collision(s) at >= ${ERROR_THRESHOLD}. ` +
105
+ `Rewrite the affected descriptions so the router can tell them apart.`
106
+ );
107
+ process.exit(1);
108
+ }
109
+ console.log(`\n🎉 NO DESCRIPTION COLLISIONS (threshold ${ERROR_THRESHOLD}).`);
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ const assert = require('assert');
4
+ const fs = require('fs');
5
+ const os = require('os');
6
+ const { spawnSync } = require('child_process');
7
+ const path = require('path');
8
+
9
+ const root = path.resolve(__dirname, '..');
10
+ const selector = path.join(root, 'fable-mode', 'scripts', 'model-selector.js');
11
+ const router = path.join(root, 'harness-everything', 'scripts', 'tier-router.js');
12
+ const auditDir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-fable-mode-'));
13
+ const auditFile = path.join(auditDir, 'audit.jsonl');
14
+
15
+ function runNode(file, args) {
16
+ return spawnSync(process.execPath, [file, ...args], {
17
+ cwd: root,
18
+ encoding: 'utf8'
19
+ });
20
+ }
21
+
22
+ function selectorArgs(overrides = {}) {
23
+ const input = {
24
+ requested: 'opus',
25
+ available: 'opus,sonnet,haiku',
26
+ 'available-agents': 'fable-orchestrator,fable-worker-sonnet,fable-worker-haiku',
27
+ fallback: 'stop',
28
+ 'host-model': 'opus',
29
+ 'audit-file': auditFile,
30
+ 'stage-brief': 'Choose the architecture',
31
+ 'pass-condition': 'ADR exists and names the decision',
32
+ 'verification-command': 'npm test',
33
+ 'verifier-result': 'pending',
34
+ ...overrides
35
+ };
36
+ return Object.entries(input).flatMap(([key, value]) => [`--${key}`, value]);
37
+ }
38
+
39
+ function readRecord(result) {
40
+ assert.ok(result.stdout.trim(), `selector produced no JSON: ${result.stderr}`);
41
+ return JSON.parse(result.stdout);
42
+ }
43
+
44
+ console.log('=== Fable model mode contract tests ===');
45
+
46
+ const selected = runNode(selector, selectorArgs());
47
+ assert.strictEqual(selected.status, 0, selected.stderr);
48
+ const selectedRecord = readRecord(selected);
49
+ assert.strictEqual(selectedRecord.status, 'selected');
50
+ assert.strictEqual(selectedRecord.requestedModel, 'opus');
51
+ assert.strictEqual(selectedRecord.effectiveModel, 'opus');
52
+ assert.strictEqual(selectedRecord.fallbackReason, 'none');
53
+ assert.strictEqual(selectedRecord.agent, 'fable-orchestrator');
54
+
55
+ const sonnect = runNode(selector, selectorArgs({ requested: 'sonnect', available: 'haiku,sonnet' }));
56
+ assert.strictEqual(sonnect.status, 0, sonnect.stderr);
57
+ const sonnectRecord = readRecord(sonnect);
58
+ assert.strictEqual(sonnectRecord.requestedModel, 'sonnet');
59
+ assert.strictEqual(sonnectRecord.requestedInput, 'sonnect');
60
+
61
+ const inline = runNode(selector, selectorArgs({
62
+ requested: 'opus',
63
+ available: 'sonnet',
64
+ fallback: 'inline',
65
+ 'host-model': 'sonnet'
66
+ }));
67
+ assert.strictEqual(inline.status, 0, inline.stderr);
68
+ const inlineRecord = readRecord(inline);
69
+ assert.strictEqual(inlineRecord.status, 'fallback');
70
+ assert.strictEqual(inlineRecord.effectiveModel, 'sonnet');
71
+ assert.match(inlineRecord.fallbackReason, /opus is not in availableModels/);
72
+ assert.strictEqual(inlineRecord.escalationRequired, false);
73
+
74
+ const blocked = runNode(selector, selectorArgs({ requested: 'opus', available: 'sonnet' }));
75
+ assert.strictEqual(blocked.status, 2);
76
+ const blockedRecord = readRecord(blocked);
77
+ assert.strictEqual(blockedRecord.status, 'blocked');
78
+ assert.strictEqual(blockedRecord.effectiveModel, null);
79
+ assert.strictEqual(blockedRecord.escalationRequired, true);
80
+ assert.match(blockedRecord.fallbackReason, /inline fallback was not authorized/);
81
+
82
+ const missingAgent = runNode(selector, selectorArgs({
83
+ requested: 'sonnet',
84
+ available: 'sonnet',
85
+ 'available-agents': 'fable-worker-haiku',
86
+ fallback: 'inline',
87
+ 'host-model': 'opus'
88
+ }));
89
+ assert.strictEqual(missingAgent.status, 0, missingAgent.stderr);
90
+ const missingAgentRecord = readRecord(missingAgent);
91
+ assert.strictEqual(missingAgentRecord.status, 'fallback');
92
+ assert.strictEqual(missingAgentRecord.effectiveModel, 'opus');
93
+ assert.match(missingAgentRecord.fallbackReason, /fable-worker-sonnet is not in availableAgents/);
94
+
95
+ const missingField = runNode(selector, selectorArgs({ 'pass-condition': '' }));
96
+ assert.strictEqual(missingField.status, 2);
97
+ assert.match(missingField.stderr, /passCondition is required/);
98
+
99
+ const explicitRoute = runNode(router, ['fable on sonnect for architecture synthesis']);
100
+ assert.strictEqual(explicitRoute.status, 0);
101
+ assert.match(explicitRoute.stdout, /REQUESTED FABLE MODEL MODE: sonnet/);
102
+ assert.match(explicitRoute.stdout, /fable-mode\/fable-sonnet\/SKILL\.md/);
103
+
104
+ const ordinaryTier2 = runNode(router, ['Fix this checkout bug and add a regression test.']);
105
+ assert.strictEqual(ordinaryTier2.status, 0);
106
+ assert.match(ordinaryTier2.stdout, /RECOMMENDED TIER: Tier 2/);
107
+ assert.doesNotMatch(ordinaryTier2.stdout, /REQUESTED FABLE MODEL MODE/);
108
+ assert.doesNotMatch(ordinaryTier2.stdout, /fable-opus\/SKILL\.md/);
109
+
110
+ const auditLines = fs.readFileSync(auditFile, 'utf8').trim().split(/\r?\n/).filter(Boolean);
111
+ assert.strictEqual(auditLines.length, 5);
112
+ for (const line of auditLines) {
113
+ const record = JSON.parse(line);
114
+ for (const field of ['requestedModel', 'effectiveModel', 'fallbackReason', 'stageBrief', 'passCondition', 'verificationCommand', 'verifierResult']) {
115
+ assert.ok(Object.prototype.hasOwnProperty.call(record, field), `audit missing ${field}`);
116
+ }
117
+ }
118
+ fs.rmSync(auditDir, { recursive: true, force: true });
119
+
120
+ console.log('PASS: selected, sonnect alias, inline fallback, blocked escalation, audit fields, and routing separation');
@@ -0,0 +1,6 @@
1
+ {
2
+ "divisions": {
3
+ "engineering": { "label": "Engineering", "icon": "Code", "color": "#3B82F6" },
4
+ "testing": { "label": "Testing", "icon": "FlaskConical", "color": "#F59E0B" }
5
+ }
6
+ }
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: Code Reviewer
3
+ description: Reviews code for correctness, security, and maintainability.
4
+ color: purple
5
+ emoji: eye
6
+ vibe: Evidence before approval.
7
+ ---
8
+
9
+ # Code Reviewer
10
+
11
+ Review only the files named in the dispatch brief and return a structured handoff.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: Reality Checker
3
+ description: Checks release readiness against observable evidence.
4
+ color: red
5
+ emoji: check
6
+ vibe: Needs proof before sign-off.
7
+ ---
8
+
9
+ # Reality Checker
10
+
11
+ Reject unverifiable claims and report the evidence needed for a bounded handoff.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: bad-frontmatter-colon
3
+ description: This description has an unquoted colon: which breaks YAML parsers
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: Test
7
+ version: 0.0.1
8
+ ---
9
+
10
+ # Bad Frontmatter Colon
11
+
12
+ ## USE FOR:
13
+ - Testing
14
+
15
+ ## DO NOT USE FOR:
16
+ - Production
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: duplicate-a
3
+ description: Identical description used for collision testing purposes only
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: Test
7
+ version: 0.0.1
8
+ ---
9
+
10
+ # Duplicate A
11
+
12
+ ## USE FOR:
13
+ - Testing
14
+
15
+ ## DO NOT USE FOR:
16
+ - Production
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: duplicate-b
3
+ description: Identical description used for collision testing purposes only
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: Test
7
+ version: 0.0.1
8
+ ---
9
+
10
+ # Duplicate B
11
+
12
+ ## USE FOR:
13
+ - Testing
14
+
15
+ ## DO NOT USE FOR:
16
+ - Production