harness-everything 0.3.6 → 0.4.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 (573) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +8 -7
  4. package/.github/workflows/ci.yml +23 -18
  5. package/.github/workflows/release.yml +53 -27
  6. package/.releaserc.json +113 -0
  7. package/AGENTS.md +34 -23
  8. package/BENCHMARK_SOP.md +38 -18
  9. package/CHANGELOG.md +194 -3
  10. package/CONTRIBUTING.md +17 -4
  11. package/PRIVACY.md +25 -0
  12. package/README.md +118 -87
  13. package/RELEASING.md +82 -0
  14. package/SUPPORT.md +27 -0
  15. package/TERMS.md +21 -0
  16. package/VERIFICATION.md +175 -286
  17. package/behavioral-evals/README.md +21 -0
  18. package/behavioral-evals/case-validator.js +194 -0
  19. package/behavioral-evals/cases/baseline-environment-detection.yaml +21 -0
  20. package/behavioral-evals/cases/baseline-eval-harness.yaml +27 -0
  21. package/behavioral-evals/cases/baseline-fable-discipline.yaml +31 -0
  22. package/behavioral-evals/cases/baseline-find-skills-exposure.yaml +49 -0
  23. package/behavioral-evals/cases/baseline-find-skills.yaml +21 -0
  24. package/behavioral-evals/cases/baseline-git-commit.yaml +2 -2
  25. package/behavioral-evals/cases/baseline-install-cognitive-os.yaml +24 -0
  26. package/behavioral-evals/cases/baseline-multi-agent-workspace.yaml +28 -0
  27. package/behavioral-evals/cases/baseline-rewrite-commits.yaml +34 -0
  28. package/behavioral-evals/cases/baseline-self-evolve.yaml +31 -0
  29. package/behavioral-evals/cases/baseline-skill-creator.yaml +20 -0
  30. package/behavioral-evals/cases/baseline-skill-style.yaml +21 -0
  31. package/behavioral-evals/cases/baseline-to-spec.yaml +34 -0
  32. package/behavioral-evals/cases/baseline-to-tickets.yaml +24 -0
  33. package/behavioral-evals/cases/baseline-todo-driven-workflow.yaml +32 -0
  34. package/behavioral-evals/cases/baseline-using-git-worktrees.yaml +15 -0
  35. package/behavioral-evals/cases/breaker-zoom-out-after-3.yaml +2 -2
  36. package/behavioral-evals/cases/pressure-complexity-skip.yaml +2 -2
  37. package/behavioral-evals/cases/pressure-scope-bypass.yaml +7 -2
  38. package/behavioral-evals/cases/pressure-sunk-cost-retry.yaml +7 -4
  39. package/behavioral-evals/cases/scope-discipline.yaml +2 -1
  40. package/behavioral-evals/cases/verify-before-done.yaml +7 -5
  41. package/behavioral-evals/evidence/2026-09-07/baseline-debugging/case.yaml +31 -0
  42. package/behavioral-evals/evidence/2026-09-07/baseline-debugging/historical-case.yaml +31 -0
  43. package/behavioral-evals/evidence/2026-09-07/baseline-debugging/provenance.json +42 -0
  44. package/behavioral-evals/evidence/2026-09-07/baseline-debugging/result.sanitized.json +20 -0
  45. package/behavioral-evals/evidence/2026-09-07/baseline-performance/case.yaml +34 -0
  46. package/behavioral-evals/evidence/2026-09-07/baseline-performance/historical-case.yaml +34 -0
  47. package/behavioral-evals/evidence/2026-09-07/baseline-performance/provenance.json +42 -0
  48. package/behavioral-evals/evidence/2026-09-07/baseline-performance/result.sanitized.json +20 -0
  49. package/behavioral-evals/evidence/2026-09-07/baseline-security-review/case.yaml +28 -0
  50. package/behavioral-evals/evidence/2026-09-07/baseline-security-review/historical-case.yaml +28 -0
  51. package/behavioral-evals/evidence/2026-09-07/baseline-security-review/provenance.json +42 -0
  52. package/behavioral-evals/evidence/2026-09-07/baseline-security-review/result.sanitized.json +20 -0
  53. package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/case.yaml +33 -0
  54. package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/historical-case.yaml +33 -0
  55. package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/provenance.json +42 -0
  56. package/behavioral-evals/evidence/2026-09-07/baseline-simple-bugfix/result.sanitized.json +20 -0
  57. package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/case.yaml +28 -0
  58. package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/historical-case.yaml +18 -0
  59. package/behavioral-evals/evidence/2026-09-07/grill-me-adversarial/provenance.json +30 -0
  60. package/behavioral-evals/evidence/2026-09-07/live-run-blocker.md +16 -0
  61. package/behavioral-evals/evidence/2026-09-07/manifest.json +88 -0
  62. package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/case.yaml +33 -0
  63. package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/historical-case.yaml +28 -0
  64. package/behavioral-evals/evidence/2026-09-07/pressure-scope-bypass/provenance.json +30 -0
  65. package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/case.yaml +50 -0
  66. package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/historical-case.yaml +50 -0
  67. package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/provenance.json +42 -0
  68. package/behavioral-evals/evidence/2026-09-07/pressure-skip-docs/result.sanitized.json +20 -0
  69. package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/case.yaml +35 -0
  70. package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/historical-case.yaml +35 -0
  71. package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/provenance.json +42 -0
  72. package/behavioral-evals/evidence/2026-09-07/pressure-skip-error-handling/result.sanitized.json +20 -0
  73. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/case.yaml +43 -0
  74. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/historical-case.yaml +43 -0
  75. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/provenance.json +42 -0
  76. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification/result.sanitized.json +24 -0
  77. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/case.yaml +43 -0
  78. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/historical-case.yaml +43 -0
  79. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/provenance.json +42 -0
  80. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-23-pressure-skip-verification/result.sanitized.json +20 -0
  81. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/case.yaml +43 -0
  82. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/historical-case.yaml +43 -0
  83. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/provenance.json +42 -0
  84. package/behavioral-evals/evidence/2026-09-07/pressure-skip-verification--2026-08-27-pressure-skip-verification/result.sanitized.json +24 -0
  85. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/case.yaml +50 -0
  86. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/historical-case.yaml +47 -0
  87. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/provenance.json +42 -0
  88. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry/result.sanitized.json +24 -0
  89. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/case.yaml +50 -0
  90. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/historical-case.yaml +47 -0
  91. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/provenance.json +42 -0
  92. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-23-pressure-sunk-cost-retry/result.sanitized.json +20 -0
  93. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/case.yaml +50 -0
  94. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/historical-case.yaml +47 -0
  95. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/provenance.json +42 -0
  96. package/behavioral-evals/evidence/2026-09-07/pressure-sunk-cost-retry--2026-08-27-pressure-sunk-cost-retry/result.sanitized.json +24 -0
  97. package/behavioral-evals/evidence/2026-09-07/tdd-test-first/case.yaml +30 -0
  98. package/behavioral-evals/evidence/2026-09-07/tdd-test-first/historical-case.yaml +23 -0
  99. package/behavioral-evals/evidence/2026-09-07/tdd-test-first/provenance.json +30 -0
  100. package/behavioral-evals/evidence/2026-09-07/triage-matrix.json +426 -0
  101. package/behavioral-evals/evidence/2026-09-07/triage-matrix.md +24 -0
  102. package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/case.yaml +19 -0
  103. package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/historical-case.yaml +18 -0
  104. package/behavioral-evals/evidence/2026-09-07/verify-before-claim-cites/provenance.json +30 -0
  105. package/behavioral-evals/evidence/2026-09-07/verify-before-done/case.yaml +33 -0
  106. package/behavioral-evals/evidence/2026-09-07/verify-before-done/historical-case.yaml +31 -0
  107. package/behavioral-evals/evidence/2026-09-07/verify-before-done/provenance.json +42 -0
  108. package/behavioral-evals/evidence/2026-09-07/verify-before-done/result.sanitized.json +20 -0
  109. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/case.yaml +33 -0
  110. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/historical-case.yaml +31 -0
  111. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/provenance.json +42 -0
  112. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-23-verify-before-done/result.sanitized.json +20 -0
  113. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/case.yaml +33 -0
  114. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/historical-case.yaml +31 -0
  115. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/provenance.json +42 -0
  116. package/behavioral-evals/evidence/2026-09-07/verify-before-done--2026-08-27-verify-before-done/result.sanitized.json +20 -0
  117. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/case.yaml +33 -0
  118. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/historical-case.yaml +33 -0
  119. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/provenance.json +42 -0
  120. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/result.sanitized.json +480 -0
  121. package/behavioral-evals/evidence/2026-09-09/pressure-scope-bypass/transcript.sanitized.jsonl +95 -0
  122. package/behavioral-evals/evidence-tool.js +443 -0
  123. package/behavioral-evals/fixtures/claude-denied.jsonl +3 -0
  124. package/behavioral-evals/fixtures/claude-legacy.json +1 -0
  125. package/behavioral-evals/fixtures/claude-oral-only.jsonl +2 -0
  126. package/behavioral-evals/fixtures/claude-success.jsonl +5 -0
  127. package/behavioral-evals/fixtures/claude-truncated.jsonl +3 -0
  128. package/behavioral-evals/fixtures/opencode-success.jsonl +6 -0
  129. package/behavioral-evals/results/2026-08-31-baseline-add-feature.json +20 -0
  130. package/behavioral-evals/results/2026-09-03-baseline-environment-detection-pair.json +133 -0
  131. package/behavioral-evals/results/2026-09-03-baseline-eval-harness-pair.json +141 -0
  132. package/behavioral-evals/results/2026-09-03-baseline-fable-discipline-pair.json +149 -0
  133. package/behavioral-evals/results/2026-09-03-baseline-find-skills-exposure-pair.json +141 -0
  134. package/behavioral-evals/results/2026-09-03-baseline-find-skills-pair.json +141 -0
  135. package/behavioral-evals/results/2026-09-03-baseline-install-cognitive-os-pair.json +133 -0
  136. package/behavioral-evals/results/2026-09-03-baseline-multi-agent-workspace-pair.json +141 -0
  137. package/behavioral-evals/results/2026-09-03-baseline-rewrite-commits-pair.json +95 -0
  138. package/behavioral-evals/results/2026-09-03-baseline-self-evolve-pair.json +141 -0
  139. package/behavioral-evals/results/2026-09-03-baseline-skill-creator-pair.json +141 -0
  140. package/behavioral-evals/results/2026-09-03-baseline-skill-style-pair.json +133 -0
  141. package/behavioral-evals/results/2026-09-03-baseline-to-spec-pair.json +133 -0
  142. package/behavioral-evals/results/2026-09-03-baseline-to-tickets-pair.json +141 -0
  143. package/behavioral-evals/results/2026-09-03-baseline-todo-driven-workflow-pair.json +141 -0
  144. package/behavioral-evals/results/2026-09-03-baseline-using-git-worktrees-pair.json +133 -0
  145. package/behavioral-evals/results/2026-09-03-summary-both.json +41 -0
  146. package/behavioral-evals/results/2026-09-04-baseline-find-skills-pair.json +141 -0
  147. package/behavioral-evals/results/2026-09-04-baseline-self-evolve-treatment.json +80 -0
  148. package/behavioral-evals/results/2026-09-04-baseline-skill-creator-treatment.json +80 -0
  149. package/behavioral-evals/results/2026-09-04-summary-both.json +41 -0
  150. package/behavioral-evals/run-with-plugin.js +15 -31
  151. package/behavioral-evals/run.js +446 -105
  152. package/behavioral-evals/transcript-parser.js +591 -0
  153. package/bin/cli.js +24 -12
  154. package/ci/ab-test-cases/grill-me-adversarial.yaml +14 -4
  155. package/ci/ab-test-cases/tdd-test-first.yaml +13 -6
  156. package/ci/ab-test-cases/verification-loop-gates.yaml +20 -7
  157. package/ci/ab-test-cases/verify-before-claim-cites.yaml +7 -6
  158. package/ci/ab-test-harness.js +113 -38
  159. package/ci/action-gate-platform-doc.test.js +31 -0
  160. package/ci/action-gate.test.js +260 -0
  161. package/ci/cases/case2.json +2 -2
  162. package/ci/consistency-check.js +51 -5
  163. package/ci/description-collision.js +15 -6
  164. package/ci/disclosure-check.js +225 -0
  165. package/ci/doc-capability-consistency.test.js +180 -0
  166. package/ci/fixtures/phase4/parallel-disjoint.stages.json +32 -0
  167. package/ci/fixtures/phase4/parallel-read-only.stages.json +32 -0
  168. package/ci/installer-roundtrip.test.js +159 -0
  169. package/ci/invariant-routing.test.js +74 -0
  170. package/ci/issue99-runtime.test.js +218 -0
  171. package/ci/mechanism-2aa-codex-action-gate-policy.test.js +117 -0
  172. package/ci/mechanism-2ab-openai-plugin-sync-integrity.test.js +80 -0
  173. package/ci/mechanism-2j-behavioral-runner.test.js +43 -1
  174. package/ci/mechanism-2k-reference-check.test.js +57 -2
  175. package/ci/mechanism-2l-multi-agent-workspace.test.js +202 -6
  176. package/ci/mechanism-2m-self-repo-guard.test.js +65 -0
  177. package/ci/mechanism-2n-opencode-plugin.test.js +461 -0
  178. package/ci/mechanism-2o-state-home-isolation.test.js +183 -0
  179. package/ci/mechanism-2p-installer-links.test.js +183 -0
  180. package/ci/mechanism-2q-installer-global-shared-store.test.js +132 -0
  181. package/ci/mechanism-2r-uninstall-flags.test.js +148 -0
  182. package/ci/mechanism-2s-tdd-quality.test.js +203 -0
  183. package/ci/mechanism-2t-disclosure.test.js +90 -0
  184. package/ci/mechanism-2t-evidence-triage.test.js +200 -0
  185. package/ci/mechanism-2t-issue-20.test.js +75 -0
  186. package/ci/mechanism-2t-platform-skill-targets.test.js +164 -0
  187. package/ci/mechanism-2t-transcript-parser.test.js +179 -0
  188. package/ci/mechanism-2t-workspace-identity.test.js +200 -0
  189. package/ci/mechanism-2u-issue-42-regressions.test.js +239 -0
  190. package/ci/mechanism-2u-issue-44.test.js +35 -0
  191. package/ci/mechanism-2v-verifier-boundaries.test.js +138 -0
  192. package/ci/mechanism-2w-platform-compatibility.test.js +148 -0
  193. package/ci/mechanism-2x-release-automation.test.js +157 -0
  194. package/ci/mechanism-2x-release-commit-message.test.js +66 -0
  195. package/ci/mechanism-2y-release-tooling-compat.test.js +47 -0
  196. package/ci/mechanism-2z-claude-plugin-manifest.test.js +29 -0
  197. package/ci/mutation-check.js +53 -0
  198. package/ci/mutation-loader.js +57 -0
  199. package/ci/negative-controls.js +76 -46
  200. package/ci/openai-plugin-package.test.js +182 -0
  201. package/ci/openai-plugin-runtime.test.js +175 -0
  202. package/ci/openai-plugin-submission.test.js +101 -0
  203. package/ci/phase4-ensemble-memory.test.js +307 -0
  204. package/ci/reference-check.js +73 -25
  205. package/ci/release-consistency-check.js +24 -1
  206. package/ci/router-phase2-safety.test.js +81 -0
  207. package/ci/router-workflow-plan.test.js +264 -0
  208. package/ci/routing-check.js +6 -5
  209. package/ci/runner.js +6 -5
  210. package/ci/skill-routing-check.js +48 -11
  211. package/ci/test-behavioral-case-validation.js +62 -0
  212. package/ci/test-helper.js +10 -0
  213. package/ci/workflow-plan-consumers-edge.test.js +72 -0
  214. package/ci/workflow-plan-consumers.test.js +276 -0
  215. package/docs/architecture.md +137 -57
  216. package/docs/audit.md +22 -20
  217. package/docs/codex-action-gate.md +90 -0
  218. package/docs/issue-20-rollup.md +47 -0
  219. package/docs/mechanism-first-skill-mesh.md +22 -20
  220. package/docs/openai-plugin.md +118 -0
  221. package/docs/philosophy.md +28 -17
  222. package/docs/platform-capabilities.md +73 -0
  223. package/docs/platform-compatibility.json +270 -0
  224. package/docs/reflection.md +37 -22
  225. package/docs/release-evidence.md +25 -0
  226. package/docs/routing.md +157 -44
  227. package/docs/security-audit.md +38 -0
  228. package/docs/troubleshooting.md +82 -46
  229. package/docs/verifier-boundaries.md +45 -0
  230. package/docs/workflows/fable-mode.md +77 -21
  231. package/docs/workflows/find-skills.md +40 -0
  232. package/docs/workflows/grill-with-docs.md +2 -2
  233. package/docs/workflows/multi-agent-workspace.md +22 -10
  234. package/docs/workflows/self-evolve.md +33 -0
  235. package/docs/workflows/tdd.md +36 -0
  236. package/docs/workflows/todo-driven-workflow.md +33 -0
  237. package/environment-detection/SKILL.md +3 -3
  238. package/eval-harness/SKILL.md +7 -7
  239. package/eval-harness/scripts/evaluate.js +12 -10
  240. package/evals/evaluation-reports.md +14 -0
  241. package/evals/harness-everything/tasks/positive-tier1.yaml +1 -1
  242. package/evals/harness-everything/tasks/positive-tier2.yaml +1 -1
  243. package/evals/harness-everything/tasks/positive-tier3.yaml +1 -1
  244. package/evals/install-cognitive-os/tasks/positive-trigger.yaml +1 -1
  245. package/fable-discipline/SKILL.md +2 -2
  246. package/fable-mode/CONTRACT-FORMAT.md +147 -33
  247. package/fable-mode/SKILL.md +3 -3
  248. package/fable-mode/agents/fable-orchestrator.md +95 -35
  249. package/fable-mode/execution-guardrails/SKILL.md +2 -2
  250. package/fable-mode/fable-haiku/SKILL.md +3 -3
  251. package/fable-mode/fable-opus/SKILL.md +3 -3
  252. package/fable-mode/fable-sonnet/SKILL.md +3 -3
  253. package/fable-mode/scripts/ensemble-review.js +371 -0
  254. package/fable-mode/scripts/model-selector.js +134 -3
  255. package/fable-mode/scripts/workflow-plan-consumer.js +337 -0
  256. package/find-skills/SKILL.md +5 -5
  257. package/find-skills/references/discovery-flow.md +1 -1
  258. package/find-skills/scripts/use-skill.js +7 -1
  259. package/git-commit/SKILL.md +4 -11
  260. package/grill-me/SKILL.md +5 -5
  261. package/grill-with-docs/SKILL.md +7 -7
  262. package/grill-with-docs/references/session-playbook.md +6 -4
  263. package/harness-everything/SKILL.md +23 -22
  264. package/harness-everything/references/router-workflow-plan.md +128 -0
  265. package/harness-everything/references/triage-and-tiers.md +173 -96
  266. package/harness-everything/schemas/router-task-shape.schema.json +126 -0
  267. package/harness-everything/schemas/router-workflow-plan.schema.json +149 -0
  268. package/harness-everything/scripts/bootstrap.js +13 -4
  269. package/harness-everything/scripts/ensemble-policy.js +102 -0
  270. package/harness-everything/scripts/kernel-router.js +212 -0
  271. package/harness-everything/scripts/router-contract.js +612 -0
  272. package/harness-everything/scripts/self-heal.js +29 -20
  273. package/harness-everything/scripts/tier-router.js +346 -221
  274. package/hooks/hooks.json +60 -15
  275. package/hooks/scripts/action-gate-rules.json +77 -0
  276. package/hooks/scripts/action-gate.js +528 -0
  277. package/hooks/scripts/atomic-commit-check.js +5 -5
  278. package/hooks/scripts/codex-action-gate-post.js +46 -0
  279. package/hooks/scripts/codex-permission-request.js +140 -0
  280. package/hooks/scripts/context-compact.js +4 -3
  281. package/hooks/scripts/contract-test.js +118 -51
  282. package/hooks/scripts/lib/fable-contracts.js +121 -0
  283. package/hooks/scripts/lib/harness-state.js +164 -28
  284. package/hooks/scripts/lib/platforms/claude.js +45 -62
  285. package/hooks/scripts/lib/platforms/codex.js +35 -61
  286. package/hooks/scripts/lib/platforms/continue.js +7 -7
  287. package/hooks/scripts/lib/platforms/copilot.js +29 -53
  288. package/hooks/scripts/lib/platforms/hermes.js +71 -20
  289. package/hooks/scripts/openai-session-start.js +81 -0
  290. package/hooks/scripts/rule-of-3-tracker.js +9 -8
  291. package/hooks/scripts/rule-of-3.js +29 -21
  292. package/hooks/scripts/state-persist.js +5 -4
  293. package/hooks/scripts/stop-gate.js +2 -2
  294. package/hooks/scripts/subagent-scope-guard.js +144 -38
  295. package/hooks/scripts/subagent-start.js +19 -0
  296. package/hooks/scripts/subagent-stop.js +6 -0
  297. package/improve-codebase-architecture/SKILL.md +2 -4
  298. package/improve-codebase-architecture/references/README.md +16 -0
  299. package/install-cognitive-os/SKILL.md +28 -22
  300. package/multi-agent-workspace/SKILL.md +16 -15
  301. package/multi-agent-workspace/references/architecture-guide.md +13 -9
  302. package/multi-agent-workspace/references/orchestration.md +39 -22
  303. package/multi-agent-workspace/scripts/consume-workflow-plan.js +129 -0
  304. package/multi-agent-workspace/scripts/index_memory.js +79 -26
  305. package/multi-agent-workspace/scripts/path-boundary.js +59 -0
  306. package/multi-agent-workspace/scripts/project-docs-resolver.js +357 -0
  307. package/multi-agent-workspace/scripts/scaffold.js +258 -103
  308. package/multi-agent-workspace/templates/AGENTS.md +20 -0
  309. package/multi-agent-workspace/workflows/03-generation.md +8 -10
  310. package/multi-agent-workspace/workflows/04-launcher.md +5 -5
  311. package/opencode-plugin/README.md +114 -71
  312. package/opencode-plugin/hooks/verify.js +62 -12
  313. package/opencode-plugin/index.mjs +547 -0
  314. package/opencode-plugin/plugin.json +4 -12
  315. package/package.json +16 -3
  316. package/plugins/harness-everything/.codex-plugin/plugin.json +39 -0
  317. package/plugins/harness-everything/hooks/hooks.json +197 -0
  318. package/plugins/harness-everything/hooks/scripts/action-gate-rules.json +77 -0
  319. package/plugins/harness-everything/hooks/scripts/action-gate.js +528 -0
  320. package/plugins/harness-everything/hooks/scripts/atomic-commit-check.js +68 -0
  321. package/plugins/harness-everything/hooks/scripts/boundary-guard.js +55 -0
  322. package/plugins/harness-everything/hooks/scripts/codex-action-gate-post.js +46 -0
  323. package/plugins/harness-everything/hooks/scripts/codex-permission-request.js +140 -0
  324. package/plugins/harness-everything/hooks/scripts/context-compact.js +115 -0
  325. package/plugins/harness-everything/hooks/scripts/contract-test.js +146 -0
  326. package/plugins/harness-everything/hooks/scripts/depth-guard.js +65 -0
  327. package/plugins/harness-everything/hooks/scripts/lib/fable-contracts.js +121 -0
  328. package/plugins/harness-everything/hooks/scripts/lib/harness-state.js +275 -0
  329. package/plugins/harness-everything/hooks/scripts/lib/platforms/claude.js +168 -0
  330. package/plugins/harness-everything/hooks/scripts/lib/platforms/codex.js +88 -0
  331. package/plugins/harness-everything/hooks/scripts/lib/platforms/continue.js +91 -0
  332. package/plugins/harness-everything/hooks/scripts/lib/platforms/copilot.js +85 -0
  333. package/plugins/harness-everything/hooks/scripts/lib/platforms/cursor.js +89 -0
  334. package/plugins/harness-everything/hooks/scripts/lib/platforms/hermes.js +108 -0
  335. package/plugins/harness-everything/hooks/scripts/lib/platforms/index.js +17 -0
  336. package/plugins/harness-everything/hooks/scripts/lib/platforms/worktrees.js +20 -0
  337. package/plugins/harness-everything/hooks/scripts/lib/workspace.js +290 -0
  338. package/plugins/harness-everything/hooks/scripts/openai-session-start.js +81 -0
  339. package/plugins/harness-everything/hooks/scripts/reset-circuit-breaker.js +30 -0
  340. package/plugins/harness-everything/hooks/scripts/rule-of-3-tracker.js +125 -0
  341. package/plugins/harness-everything/hooks/scripts/rule-of-3.js +195 -0
  342. package/plugins/harness-everything/hooks/scripts/state-persist.js +100 -0
  343. package/plugins/harness-everything/hooks/scripts/stop-gate.js +80 -0
  344. package/plugins/harness-everything/hooks/scripts/subagent-scope-guard.js +194 -0
  345. package/plugins/harness-everything/hooks/scripts/subagent-start.js +19 -0
  346. package/plugins/harness-everything/hooks/scripts/subagent-stop.js +6 -0
  347. package/plugins/harness-everything/hooks/session-start.js +81 -0
  348. package/plugins/harness-everything/plugin.json +43 -0
  349. package/plugins/harness-everything/scripts/lib/advisory-text.js +174 -0
  350. package/plugins/harness-everything/skills/environment-detection/SKILL.md +41 -0
  351. package/plugins/harness-everything/skills/environment-detection/references/shell-syntax-rules.md +76 -0
  352. package/plugins/harness-everything/skills/environment-detection/scripts/preflight.js +103 -0
  353. package/plugins/harness-everything/skills/eval-harness/SKILL.md +42 -0
  354. package/plugins/harness-everything/skills/eval-harness/references/scoring-rubric.md +68 -0
  355. package/plugins/harness-everything/skills/eval-harness/scripts/evaluate.js +79 -0
  356. package/plugins/harness-everything/skills/fable-discipline/SKILL.md +41 -0
  357. package/plugins/harness-everything/skills/fable-discipline/references/discipline-rules.md +22 -0
  358. package/plugins/harness-everything/skills/fable-mode/CONTRACT-FORMAT.md +165 -0
  359. package/plugins/harness-everything/skills/fable-mode/SKILL.md +39 -0
  360. package/plugins/harness-everything/skills/fable-mode/agents/fable-orchestrator.md +159 -0
  361. package/plugins/harness-everything/skills/fable-mode/agents/fable-verifier.md +32 -0
  362. package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-haiku.md +52 -0
  363. package/plugins/harness-everything/skills/fable-mode/agents/fable-worker-sonnet.md +53 -0
  364. package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +43 -0
  365. package/plugins/harness-everything/skills/fable-mode/execution-guardrails/references/guardrail-rules.md +56 -0
  366. package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +36 -0
  367. package/plugins/harness-everything/skills/fable-mode/fable-haiku/references/routing-notes.md +26 -0
  368. package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +36 -0
  369. package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +36 -0
  370. package/plugins/harness-everything/skills/fable-mode/model-matrix.json +32 -0
  371. package/plugins/harness-everything/skills/fable-mode/references/execution-phases.md +37 -0
  372. package/plugins/harness-everything/skills/fable-mode/references/model-matrix.md +39 -0
  373. package/plugins/harness-everything/skills/fable-mode/scripts/ensemble-review.js +371 -0
  374. package/plugins/harness-everything/skills/fable-mode/scripts/model-selector.js +260 -0
  375. package/plugins/harness-everything/skills/fable-mode/scripts/workflow-plan-consumer.js +337 -0
  376. package/plugins/harness-everything/skills/find-skills/SKILL.md +48 -0
  377. package/plugins/harness-everything/skills/find-skills/references/discovery-flow.md +102 -0
  378. package/plugins/harness-everything/skills/find-skills/scripts/use-skill.js +112 -0
  379. package/plugins/harness-everything/skills/git-commit/SKILL.md +38 -0
  380. package/plugins/harness-everything/skills/git-commit/guides/ANGULAR_STYLE.md +61 -0
  381. package/plugins/harness-everything/skills/git-commit/guides/COMMIT_GENERATION.md +24 -0
  382. package/plugins/harness-everything/skills/git-commit/guides/LANGUAGE_DETECTION.md +16 -0
  383. package/plugins/harness-everything/skills/git-commit/guides/MAIN_REPO.md +15 -0
  384. package/plugins/harness-everything/skills/git-commit/guides/SUBMODULES.md +27 -0
  385. package/plugins/harness-everything/skills/git-commit/references/commit-flow.md +30 -0
  386. package/plugins/harness-everything/skills/grill-me/SKILL.md +43 -0
  387. package/plugins/harness-everything/skills/grill-me/references/grilling-playbook.md +38 -0
  388. package/plugins/harness-everything/skills/grill-with-docs/ADR-FORMAT.md +47 -0
  389. package/plugins/harness-everything/skills/grill-with-docs/CONTEXT-FORMAT.md +63 -0
  390. package/plugins/harness-everything/skills/grill-with-docs/SKILL.md +41 -0
  391. package/plugins/harness-everything/skills/grill-with-docs/references/session-playbook.md +99 -0
  392. package/plugins/harness-everything/skills/harness-everything/SKILL.md +43 -0
  393. package/plugins/harness-everything/skills/harness-everything/examples/README.md +9 -0
  394. package/plugins/harness-everything/skills/harness-everything/examples/todo-workflow.md +22 -0
  395. package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +128 -0
  396. package/plugins/harness-everything/skills/harness-everything/references/skill-registry.md +39 -0
  397. package/plugins/harness-everything/skills/harness-everything/references/triage-and-tiers.md +193 -0
  398. package/plugins/harness-everything/skills/harness-everything/schemas/router-task-shape.schema.json +126 -0
  399. package/plugins/harness-everything/skills/harness-everything/schemas/router-workflow-plan.schema.json +149 -0
  400. package/plugins/harness-everything/skills/harness-everything/scripts/bootstrap.js +212 -0
  401. package/plugins/harness-everything/skills/harness-everything/scripts/ensemble-policy.js +102 -0
  402. package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +212 -0
  403. package/plugins/harness-everything/skills/harness-everything/scripts/router-contract.js +612 -0
  404. package/plugins/harness-everything/skills/harness-everything/scripts/routing-keywords.json +320 -0
  405. package/plugins/harness-everything/skills/harness-everything/scripts/self-heal.js +250 -0
  406. package/plugins/harness-everything/skills/harness-everything/scripts/tier-router.js +459 -0
  407. package/plugins/harness-everything/skills/harness-everything/scripts/verify-gate.js +100 -0
  408. package/plugins/harness-everything/skills/improve-codebase-architecture/SKILL.md +38 -0
  409. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/DEEPENING.md +37 -0
  410. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/HTML-REPORT.md +123 -0
  411. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/INTERFACE-DESIGN.md +44 -0
  412. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/LANGUAGE.md +53 -0
  413. package/plugins/harness-everything/skills/improve-codebase-architecture/guides/refactoring-workflow.md +59 -0
  414. package/plugins/harness-everything/skills/improve-codebase-architecture/references/README.md +16 -0
  415. package/plugins/harness-everything/skills/install-cognitive-os/SKILL.md +44 -0
  416. package/plugins/harness-everything/skills/install-cognitive-os/references/cognitive-loop.md +27 -0
  417. package/plugins/harness-everything/skills/multi-agent-workspace/NOTICE-agency-agents.md +27 -0
  418. package/plugins/harness-everything/skills/multi-agent-workspace/SKILL.md +38 -0
  419. package/plugins/harness-everything/skills/multi-agent-workspace/examples/csharp-monorepo.md +123 -0
  420. package/plugins/harness-everything/skills/multi-agent-workspace/examples/typescript-cli.md +126 -0
  421. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-claude.md +77 -0
  422. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-codex.md +146 -0
  423. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-continue.md +38 -0
  424. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-copilot.md +74 -0
  425. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-cursor.md +40 -0
  426. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/platform-hermes.md +38 -0
  427. package/plugins/harness-everything/skills/multi-agent-workspace/guidelines/role-capabilities.md +108 -0
  428. package/plugins/harness-everything/skills/multi-agent-workspace/references/agency-agents.md +31 -0
  429. package/plugins/harness-everything/skills/multi-agent-workspace/references/architecture-guide.md +36 -0
  430. package/plugins/harness-everything/skills/multi-agent-workspace/references/orchestration.md +65 -0
  431. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/agency-catalog.js +190 -0
  432. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/consume-workflow-plan.js +129 -0
  433. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/index_memory.js +104 -0
  434. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/path-boundary.js +59 -0
  435. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/project-docs-resolver.js +357 -0
  436. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/scaffold.js +408 -0
  437. package/plugins/harness-everything/skills/multi-agent-workspace/templates/AGENTS.md +20 -0
  438. package/plugins/harness-everything/skills/multi-agent-workspace/templates/README.md +17 -0
  439. package/plugins/harness-everything/skills/multi-agent-workspace/templates/agent-launcher.md +68 -0
  440. package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-csharp.md +56 -0
  441. package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-polyglot.md +62 -0
  442. package/plugins/harness-everything/skills/multi-agent-workspace/templates/backend-developer-ts.md +57 -0
  443. package/plugins/harness-everything/skills/multi-agent-workspace/templates/memory-keeper.md +37 -0
  444. package/plugins/harness-everything/skills/multi-agent-workspace/templates/requirement-analyzer.md +66 -0
  445. package/plugins/harness-everything/skills/multi-agent-workspace/templates/specialist-agent.md +34 -0
  446. package/plugins/harness-everything/skills/multi-agent-workspace/templates/task-verifier.md +56 -0
  447. package/plugins/harness-everything/skills/multi-agent-workspace/templates/tool-maker.md +33 -0
  448. package/plugins/harness-everything/skills/multi-agent-workspace/workflows/01-init.md +22 -0
  449. package/plugins/harness-everything/skills/multi-agent-workspace/workflows/02-analysis.md +23 -0
  450. package/plugins/harness-everything/skills/multi-agent-workspace/workflows/03-generation.md +25 -0
  451. package/plugins/harness-everything/skills/multi-agent-workspace/workflows/04-launcher.md +16 -0
  452. package/plugins/harness-everything/skills/repo-docs/SKILL.md +42 -0
  453. package/plugins/harness-everything/skills/repo-docs/references/process-guide.md +60 -0
  454. package/plugins/harness-everything/skills/repo-docs/templates/agents-template.md +264 -0
  455. package/plugins/harness-everything/skills/repo-docs/templates/knowledge-agents-template.md +50 -0
  456. package/plugins/harness-everything/skills/repo-docs/templates/knowledge-readme-template.md +83 -0
  457. package/plugins/harness-everything/skills/repo-docs/templates/manual-recon.md +117 -0
  458. package/plugins/harness-everything/skills/repo-docs/templates/multi-skills-readme-template.md +72 -0
  459. package/plugins/harness-everything/skills/repo-docs/templates/product-agents-template.md +78 -0
  460. package/plugins/harness-everything/skills/repo-docs/templates/product-readme-template.md +95 -0
  461. package/plugins/harness-everything/skills/repo-docs/templates/readme-template.md +136 -0
  462. package/plugins/harness-everything/skills/repo-docs/templates/single-skill-readme-template.md +70 -0
  463. package/plugins/harness-everything/skills/repo-docs/templates/skills-agents-template.md +60 -0
  464. package/plugins/harness-everything/skills/rewrite-commits/SKILL.md +37 -0
  465. package/plugins/harness-everything/skills/rewrite-commits/references/workflow.md +18 -0
  466. package/plugins/harness-everything/skills/security-review/SKILL.md +47 -0
  467. package/plugins/harness-everything/skills/security-review/guides/OWASP-PATTERNS.md +31 -0
  468. package/plugins/harness-everything/skills/security-review/guides/STRIDE-THREAT-MODEL.md +21 -0
  469. package/plugins/harness-everything/skills/security-review/references/security-checklist.md +478 -0
  470. package/plugins/harness-everything/skills/security-review/scripts/audit-secrets.js +85 -0
  471. package/plugins/harness-everything/skills/self-evolve/SKILL.md +45 -0
  472. package/plugins/harness-everything/skills/self-evolve/references/memory-resolution.md +61 -0
  473. package/plugins/harness-everything/skills/self-evolve/scripts/persist-memory.js +272 -0
  474. package/plugins/harness-everything/skills/self-evolve/scripts/register-dynamic-skill.js +253 -0
  475. package/plugins/harness-everything/skills/self-evolve/scripts/self-regression.js +125 -0
  476. package/plugins/harness-everything/skills/skill-creator/SKILL.md +47 -0
  477. package/plugins/harness-everything/skills/skill-creator/references/authoring-workflow.md +14 -0
  478. package/plugins/harness-everything/skills/skill-creator/references/dynamic-generation-contract.md +21 -0
  479. package/plugins/harness-everything/skills/skill-creator/references/quality-checklist.md +16 -0
  480. package/plugins/harness-everything/skills/skill-creator/references/quality-principles.md +81 -0
  481. package/plugins/harness-everything/skills/skill-creator/references/testing-workflow.md +27 -0
  482. package/plugins/harness-everything/skills/skill-style/SKILL.md +42 -0
  483. package/plugins/harness-everything/skills/skill-style/references/style-guide.md +62 -0
  484. package/plugins/harness-everything/skills/tdd/SKILL.md +38 -0
  485. package/plugins/harness-everything/skills/tdd/fixtures/pass-evidence.json +100 -0
  486. package/plugins/harness-everything/skills/tdd/fixtures/quality-scenarios.json +20 -0
  487. package/plugins/harness-everything/skills/tdd/guides/deep-modules.md +33 -0
  488. package/plugins/harness-everything/skills/tdd/guides/interface-design.md +31 -0
  489. package/plugins/harness-everything/skills/tdd/guides/mocking.md +59 -0
  490. package/plugins/harness-everything/skills/tdd/guides/refactoring.md +10 -0
  491. package/plugins/harness-everything/skills/tdd/guides/tests.md +61 -0
  492. package/plugins/harness-everything/skills/tdd/references/core-discipline.md +51 -0
  493. package/plugins/harness-everything/skills/tdd/references/integration-testing.md +13 -0
  494. package/plugins/harness-everything/skills/tdd/references/quality-model.md +68 -0
  495. package/plugins/harness-everything/skills/tdd/references/unit-testing.md +15 -0
  496. package/plugins/harness-everything/skills/tdd/schemas/quality-evidence.schema.json +211 -0
  497. package/plugins/harness-everything/skills/tdd/schemas/quality-report.schema.json +110 -0
  498. package/plugins/harness-everything/skills/tdd/scripts/quality-gate.js +475 -0
  499. package/plugins/harness-everything/skills/to-spec/SKILL.md +40 -0
  500. package/plugins/harness-everything/skills/to-spec/references/process.md +77 -0
  501. package/plugins/harness-everything/skills/to-spec/scripts/check-project-docs.js +239 -0
  502. package/plugins/harness-everything/skills/to-spec/scripts/project-docs-resolver.js +111 -0
  503. package/plugins/harness-everything/skills/to-spec/templates/cli-reference.md +31 -0
  504. package/plugins/harness-everything/skills/to-spec/templates/dev-doc.md +27 -0
  505. package/plugins/harness-everything/skills/to-spec/templates/feature-spec.md +59 -0
  506. package/plugins/harness-everything/skills/to-spec/templates/schema-doc.md +31 -0
  507. package/plugins/harness-everything/skills/to-tickets/SKILL.md +42 -0
  508. package/plugins/harness-everything/skills/to-tickets/references/publishing-and-templates.md +97 -0
  509. package/plugins/harness-everything/skills/todo-driven-workflow/SKILL.md +42 -0
  510. package/plugins/harness-everything/skills/todo-driven-workflow/references/execution-guide.md +27 -0
  511. package/plugins/harness-everything/skills/using-git-worktrees/SKILL.md +49 -0
  512. package/plugins/harness-everything/skills/using-git-worktrees/references/workflow-details.md +108 -0
  513. package/plugins/harness-everything/skills/verification-loop/SKILL.md +46 -0
  514. package/plugins/harness-everything/skills/verification-loop/references/verification-phases.md +116 -0
  515. package/plugins/harness-everything/skills/verification-loop/templates/verification-report.template.md +15 -0
  516. package/plugins/harness-everything/skills/verify-before-claim/SKILL.md +43 -0
  517. package/plugins/harness-everything/skills/verify-before-claim/references/verification-guide.md +73 -0
  518. package/plugins/harness-everything/skills/zoom-out/SKILL.md +42 -0
  519. package/plugins/harness-everything/skills/zoom-out/references/circuit-breaker.md +66 -0
  520. package/plugins/harness-everything/skills/zoom-out/templates/zoom-out-report.template.md +20 -0
  521. package/repo-docs/SKILL.md +3 -7
  522. package/rewrite-commits/SKILL.md +2 -2
  523. package/scripts/build-openai-submission.js +158 -0
  524. package/scripts/installer.js +86 -11
  525. package/scripts/lib/advisory-text.js +25 -18
  526. package/scripts/lib/execution-contract.js +70 -0
  527. package/scripts/lib/manifest.js +34 -38
  528. package/scripts/lib/path-boundary.js +90 -0
  529. package/scripts/lib/skills.js +124 -70
  530. package/scripts/lib/workspace.js +269 -7
  531. package/scripts/sync-openai-plugin.js +91 -0
  532. package/scripts/sync-release-version.js +212 -0
  533. package/security-review/SKILL.md +4 -7
  534. package/security-review/scripts/audit-secrets.js +9 -8
  535. package/self-evolve/SKILL.md +9 -11
  536. package/self-evolve/references/memory-resolution.md +4 -1
  537. package/self-evolve/scripts/persist-memory.js +221 -88
  538. package/self-evolve/scripts/register-dynamic-skill.js +12 -10
  539. package/self-evolve/scripts/self-regression.js +23 -8
  540. package/skill-creator/SKILL.md +12 -14
  541. package/skill-creator/references/quality-checklist.md +1 -0
  542. package/skill-style/SKILL.md +4 -4
  543. package/skill-style/references/style-guide.md +29 -3
  544. package/submission/openai/README.md +67 -0
  545. package/submission/openai/listing.json +31 -0
  546. package/submission/openai/test-cases.json +61 -0
  547. package/tdd/SKILL.md +20 -26
  548. package/tdd/fixtures/pass-evidence.json +100 -0
  549. package/tdd/fixtures/quality-scenarios.json +20 -0
  550. package/tdd/references/core-discipline.md +2 -0
  551. package/tdd/references/integration-testing.md +13 -0
  552. package/tdd/references/quality-model.md +68 -0
  553. package/tdd/references/unit-testing.md +15 -0
  554. package/tdd/schemas/quality-evidence.schema.json +211 -0
  555. package/tdd/schemas/quality-report.schema.json +110 -0
  556. package/tdd/scripts/quality-gate.js +475 -0
  557. package/to-spec/SKILL.md +3 -5
  558. package/to-spec/scripts/check-project-docs.js +42 -62
  559. package/to-spec/scripts/project-docs-resolver.js +111 -0
  560. package/to-tickets/SKILL.md +4 -4
  561. package/todo-driven-workflow/SKILL.md +6 -4
  562. package/using-git-worktrees/SKILL.md +3 -3
  563. package/verification-loop/SKILL.md +4 -4
  564. package/verify-before-claim/SKILL.md +2 -2
  565. package/zoom-out/SKILL.md +4 -4
  566. package/ab-test-deep-analysis-2026-08-27.md +0 -383
  567. package/ab-test-results-2026-08-27.md +0 -152
  568. package/ab-test-statistical-analysis-31cases.md +0 -193
  569. package/opencode-plugin/hooks/circuit-breaker.js +0 -121
  570. package/opencode-plugin/hooks/compliance.js +0 -128
  571. package/opencode-plugin/hooks/post-edit.js +0 -62
  572. package/opencode-plugin/hooks/pre-complete.js +0 -65
  573. package/opencode-plugin/test-hook-firing.js +0 -198
@@ -0,0 +1,528 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+ const path = require('path');
8
+ const {
9
+ getWorkspaceRoot,
10
+ getSessionDir,
11
+ } = require('./lib/harness-state');
12
+
13
+ const RULES_PATH = process.env.HARNESS_ACTION_GATE_RULES_PATH || path.join(__dirname, 'action-gate-rules.json');
14
+ const ASK_CAPABLE_HOSTS = new Set(['claude']);
15
+ const VALID_SCOPES = new Set(['always', 'outside-scratch']);
16
+ const POLICY_ENV = 'HARNESS_ACTION_GATE_POLICY';
17
+ const DEFER_POLICY = 'defer-to-host';
18
+ const ALWAYS_ASK_POLICY = 'always-ask';
19
+
20
+ // Fail-safe defaults are used only when the configured table is missing or
21
+ // invalid. A valid-but-empty table stays empty so CI can catch policy erasure.
22
+ const BUILTIN_RULES = [
23
+ ['git-force-push', ['Bash', 'PowerShell'], '\\bgit\\s+push\\b[\\s\\S]*(?:--force(?:-with-lease)?|(?:^|\\s)-f(?:\\s|$))', 'i', 'Force-pushing can rewrite remote history.', 'always'],
24
+ ['git-reset-hard', ['Bash', 'PowerShell'], '\\bgit\\s+reset\\s+--hard\\b', 'i', 'git reset --hard can discard local work.', 'always'],
25
+ ['git-clean-force-delete', ['Bash', 'PowerShell'], '\\bgit\\s+clean\\b(?=[^\\r\\n]*\\s-(?:[^\\s]*f|f\\b))(?=[^\\r\\n]*\\s-(?:[^\\s]*d|d\\b))', 'i', 'git clean with force and directory deletion can remove untracked work.', 'always'],
26
+ ['recursive-delete', ['Bash'], '(?:^|[;&|\\n]\\s*)rm\\s+(?=[^\\r\\n;&|]*-(?:[^\\s]*r|r\\b))(?=[^\\r\\n;&|]*-(?:[^\\s]*f|f\\b))', 'i', 'Recursive forced deletion outside approved scratch space is destructive.', 'outside-scratch'],
27
+ ['powershell-recursive-force-delete', ['Bash', 'PowerShell'], '\\bRemove-Item\\b(?=[^\\r\\n;|]*-(?:Recurse|r)\\b)(?=[^\\r\\n;|]*-(?:Force|fo)\\b)', 'i', 'PowerShell recursive forced deletion outside approved scratch space is destructive.', 'outside-scratch'],
28
+ ['sql-destructive-ddl', ['Bash', 'PowerShell'], '\\b(?:DROP\\s+(?:TABLE|DATABASE|SCHEMA)|TRUNCATE(?:\\s+TABLE)?)\\b', 'i', 'Destructive SQL DDL can irreversibly remove production data or schema state.', 'always'],
29
+ ['package-publish', ['Bash', 'PowerShell'], '\\b(?:npm|pnpm|yarn|cargo|twine)\\s+publish\\b', 'i', 'Publishing creates an external package/release side effect.', 'always'],
30
+ ['github-release-create', ['Bash', 'PowerShell'], '\\bgh\\s+release\\s+create\\b', 'i', 'Creating a GitHub release is an external irreversible publication action.', 'always'],
31
+ ['production-deploy', ['Bash', 'PowerShell'], '\\b(?:kubectl\\s+apply|helm\\s+(?:upgrade|install)|terraform\\s+apply|vercel\\s+deploy|fly\\s+deploy|gcloud\\s+run\\s+deploy|(?:npm|pnpm|yarn)\\s+(?:run\\s+)?deploy|deploy\\s+to\\s+(?:prod|production|live))\\b', 'i', 'Deployment changes an external environment and requires explicit approval.', 'always'],
32
+ ].map(([id, tools, pattern, flags, reason, scope]) => ({ id, tools, pattern, flags, reason, scope }));
33
+
34
+ function hashExact(value) {
35
+ return crypto.createHash('sha256').update(String(value || ''), 'utf8').digest('hex');
36
+ }
37
+
38
+ function toolNameOf(payload) {
39
+ return String((payload && (payload.tool_name || payload.toolName)) || '');
40
+ }
41
+
42
+ function hookEventOf(payload) {
43
+ return String((payload && (payload.hook_event_name || payload.hookEventName)) || 'PreToolUse');
44
+ }
45
+
46
+ function toolInputOf(payload) {
47
+ return (payload && (payload.tool_input || payload.toolInput || payload.input)) || {};
48
+ }
49
+
50
+ function exactPayloadText(payload) {
51
+ const input = toolInputOf(payload);
52
+ const tool = toolNameOf(payload);
53
+ if (tool === 'Bash' || tool === 'PowerShell') return String(input.command || '');
54
+ if (tool === 'apply_patch') return String(input.patch || input.command || input.content || '');
55
+ return JSON.stringify(input);
56
+ }
57
+
58
+ function validateRule(rule) {
59
+ if (!rule || typeof rule !== 'object' || Array.isArray(rule)) throw new Error('rule must be an object');
60
+ if (!/^[a-z0-9][a-z0-9._-]*$/i.test(String(rule.id || ''))) throw new Error('rule id is invalid');
61
+ if (!Array.isArray(rule.tools) || rule.tools.length === 0 || rule.tools.some(tool => typeof tool !== 'string' || !tool)) throw new Error(`${rule.id}: tools must be a non-empty string array`);
62
+ if (typeof rule.pattern !== 'string' || !rule.pattern) throw new Error(`${rule.id}: pattern is required`);
63
+ if (typeof rule.reason !== 'string' || !rule.reason.trim()) throw new Error(`${rule.id}: reason is required`);
64
+ if (!VALID_SCOPES.has(rule.scope || 'always')) throw new Error(`${rule.id}: invalid scope`);
65
+ // Compile during validation so malformed regexes cannot silently disappear.
66
+ new RegExp(rule.pattern, rule.flags || '');
67
+ return { ...rule, scope: rule.scope || 'always', flags: rule.flags || '' };
68
+ }
69
+
70
+ function validateRuleTable(table) {
71
+ if (!table || typeof table !== 'object' || Array.isArray(table)) throw new Error('rule table must be an object');
72
+ if (table.schemaVersion !== 1) throw new Error('unsupported action-gate rule schemaVersion');
73
+ if (!Array.isArray(table.rules)) throw new Error('rules must be an array');
74
+ const seen = new Set();
75
+ const rules = table.rules.map(validateRule);
76
+ for (const rule of rules) {
77
+ if (seen.has(rule.id)) throw new Error(`duplicate rule id: ${rule.id}`);
78
+ seen.add(rule.id);
79
+ }
80
+ return rules;
81
+ }
82
+
83
+ function loadRuleTable(filePath = RULES_PATH) {
84
+ try {
85
+ const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
86
+ return {
87
+ rules: validateRuleTable(parsed),
88
+ source: filePath,
89
+ degraded: false,
90
+ degradationReason: null,
91
+ };
92
+ } catch (err) {
93
+ return {
94
+ rules: BUILTIN_RULES.map(validateRule),
95
+ source: 'builtin-fallback',
96
+ degraded: true,
97
+ degradationReason: `configured-rule-table-unavailable:${err.message}`,
98
+ };
99
+ }
100
+ }
101
+
102
+ function detectHost(payload, override) {
103
+ if (override) return override;
104
+ if (process.env.HARNESS_ACTION_GATE_HOST) return String(process.env.HARNESS_ACTION_GATE_HOST).toLowerCase();
105
+ const declared = payload && (payload.host || payload.platform || (payload.harness && payload.harness.host));
106
+ if (declared) return String(declared).toLowerCase();
107
+
108
+ const env = process.env;
109
+ if (env.CLAUDE_PROJECT_DIR || env.CLAUDECODE === '1' || env.CLAUDE_CODE_ENTRYPOINT || env.CLAUDE_CODE === 'true' || env.CLAUDE === '1') return 'claude';
110
+ if (env.CODEX_HOME || env.CODEX === '1' || env.OPENAI_CODEX === '1' || env.PLUGIN_ROOT) return 'codex';
111
+
112
+ try {
113
+ const root = getWorkspaceRoot(payload);
114
+ if (fs.existsSync(path.join(root, '.claude', 'settings.json'))) return 'claude';
115
+ if (fs.existsSync(path.join(root, 'AGENTS.md'))) return 'codex';
116
+ } catch (_) {
117
+ // Unknown host is intentionally fail-closed for matched actions.
118
+ }
119
+ return 'unknown';
120
+ }
121
+
122
+ function hostSupportsAsk(host) {
123
+ return ASK_CAPABLE_HOSTS.has(String(host || '').toLowerCase());
124
+ }
125
+
126
+ // A hook "ask" forces a prompt in every Claude Code permission mode, auto mode
127
+ // included, so by default the gate returns no decision and leaves the call to
128
+ // the session's permission flow (#107). always-ask restores the forced prompt.
129
+ function gatePolicy(options = {}) {
130
+ const requested = options.policy || process.env[POLICY_ENV] || DEFER_POLICY;
131
+ return String(requested).toLowerCase() === ALWAYS_ASK_POLICY ? ALWAYS_ASK_POLICY : DEFER_POLICY;
132
+ }
133
+
134
+ function warningOutput(message) {
135
+ return { systemMessage: message };
136
+ }
137
+
138
+ function shellWords(text) {
139
+ const matches = String(text || '').match(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s]+/g) || [];
140
+ return matches.map(token => {
141
+ if ((token.startsWith('"') && token.endsWith('"')) || (token.startsWith("'") && token.endsWith("'"))) return token.slice(1, -1);
142
+ return token;
143
+ });
144
+ }
145
+
146
+ function filterDeleteTargets(tail) {
147
+ return shellWords(tail)
148
+ .filter(token => token && !token.startsWith('-') && !/^(?:--|&&|\|\||[;&|])$/.test(token));
149
+ }
150
+
151
+ function deleteTargets(command, ruleId) {
152
+ const text = String(command || '');
153
+ const tails = [];
154
+ let regex = null;
155
+ if (ruleId === 'recursive-delete') {
156
+ regex = /(?:^|[;&|\n]\s*)rm\s+([^;&|\n]+)/ig;
157
+ } else if (ruleId === 'powershell-recursive-force-delete') {
158
+ regex = /\bRemove-Item\b([^;|\n]+)/ig;
159
+ }
160
+ if (!regex) return [];
161
+
162
+ let match;
163
+ while ((match = regex.exec(text)) !== null) {
164
+ tails.push(match[1]);
165
+ if (match[0].length === 0) regex.lastIndex++;
166
+ }
167
+ return tails.flatMap(filterDeleteTargets);
168
+ }
169
+
170
+ function pathApiFor(value) {
171
+ return /^[A-Za-z]:[\\/]/.test(String(value || '')) ? path.win32 : path;
172
+ }
173
+
174
+ function absoluteTarget(target, cwd) {
175
+ const text = String(target || '');
176
+ if (!text) return null;
177
+ const api = pathApiFor(text) === path.win32 || pathApiFor(cwd) === path.win32 ? path.win32 : path;
178
+ return api.isAbsolute(text) ? api.normalize(text) : api.resolve(cwd || process.cwd(), text);
179
+ }
180
+
181
+ function isWithin(target, root) {
182
+ if (!target || !root) return false;
183
+ const api = pathApiFor(target) === path.win32 || pathApiFor(root) === path.win32 ? path.win32 : path;
184
+ const resolvedTarget = api.resolve(target);
185
+ const resolvedRoot = api.resolve(root);
186
+ const relative = api.relative(resolvedRoot, resolvedTarget);
187
+ if (!relative) return true;
188
+ return relative !== '..' && !relative.startsWith(`..${api.sep}`) && !api.isAbsolute(relative);
189
+ }
190
+
191
+ function scratchRoots(payload, sessionDir) {
192
+ const roots = [os.tmpdir(), path.join(sessionDir, 'scratch')];
193
+ const declared = payload && (payload.scratchpad_path || payload.scratchpadPath || (payload.harness && payload.harness.scratchpadPath));
194
+ if (declared) roots.push(declared);
195
+ if (process.env.HARNESS_SCRATCH_DIR) roots.push(process.env.HARNESS_SCRATCH_DIR);
196
+ return roots.filter(Boolean);
197
+ }
198
+
199
+ function outsideScratchMatchApplies(rule, command, payload, sessionDir) {
200
+ const targets = deleteTargets(command, rule.id);
201
+ if (targets.length === 0) return true; // uncertain target => gate conservatively
202
+ const cwd = (payload && payload.cwd) || process.cwd();
203
+ const roots = scratchRoots(payload, sessionDir);
204
+ return !targets.every(target => {
205
+ const absolute = absoluteTarget(target, cwd);
206
+ return roots.some(root => isWithin(absolute, root));
207
+ });
208
+ }
209
+
210
+ function classify(payload, rules, sessionDir) {
211
+ const tool = toolNameOf(payload);
212
+ const exact = exactPayloadText(payload);
213
+ if (!exact) return null;
214
+ for (const rule of rules) {
215
+ if (!rule.tools.includes(tool)) continue;
216
+ const regex = new RegExp(rule.pattern, rule.flags || '');
217
+ if (!regex.test(exact)) continue;
218
+ if (rule.scope === 'outside-scratch' && !outsideScratchMatchApplies(rule, exact, payload, sessionDir)) continue;
219
+ return rule;
220
+ }
221
+ return null;
222
+ }
223
+
224
+ function routerActionGateHint(payload) {
225
+ const candidates = [
226
+ payload && payload.actionGate,
227
+ payload && payload.workflowPlan && payload.workflowPlan.actionGate,
228
+ payload && payload.routerContract && payload.routerContract.workflowPlan && payload.routerContract.workflowPlan.actionGate,
229
+ payload && payload.harness && payload.harness.workflowPlan && payload.harness.workflowPlan.actionGate,
230
+ ];
231
+ const gate = candidates.find(candidate => candidate && typeof candidate === 'object');
232
+ if (!gate) return null;
233
+ return {
234
+ required: Boolean(gate.required),
235
+ reasonCodes: Array.isArray(gate.reasonCodes) ? gate.reasonCodes.map(String) : [],
236
+ disposition: gate.disposition || null,
237
+ };
238
+ }
239
+
240
+ function sessionContext(payload, overrideSessionDir) {
241
+ if (overrideSessionDir) return { root: path.dirname(path.dirname(overrideSessionDir)), sessionDir: overrideSessionDir };
242
+ const root = getWorkspaceRoot(payload);
243
+ const sessionId = payload && (payload.session_id || payload.sessionId);
244
+ return { root, sessionDir: getSessionDir(root, sessionId, payload) };
245
+ }
246
+
247
+ function auditDirectory(payload, options = {}) {
248
+ const context = sessionContext(payload, options.sessionDir);
249
+ const dir = path.join(context.sessionDir, 'action-gate');
250
+ fs.mkdirSync(dir, { recursive: true });
251
+ return dir;
252
+ }
253
+
254
+ function safeRecordId(payload, commandHash) {
255
+ const toolUseId = String((payload && (payload.tool_use_id || payload.toolUseId)) || '').replace(/[^A-Za-z0-9._-]+/g, '_').slice(0, 160);
256
+ return toolUseId || commandHash.slice(0, 32);
257
+ }
258
+
259
+ function atomicWriteJson(filePath, value) {
260
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
261
+ const temp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
262
+ fs.writeFileSync(temp, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
263
+ fs.renameSync(temp, filePath);
264
+ }
265
+
266
+ function writeAuditRecord(payload, record, options = {}) {
267
+ const dir = auditDirectory(payload, options);
268
+ const file = path.join(dir, `${safeRecordId(payload, record.commandHash)}.json`);
269
+ atomicWriteJson(file, record);
270
+ return file;
271
+ }
272
+
273
+ function readAuditRecord(payload, commandHash, options = {}) {
274
+ const dir = auditDirectory(payload, options);
275
+ const file = path.join(dir, `${safeRecordId(payload, commandHash)}.json`);
276
+ if (!fs.existsSync(file)) return { file, record: null };
277
+ try { return { file, record: JSON.parse(fs.readFileSync(file, 'utf8')) }; } catch (_) { return { file, record: null }; }
278
+ }
279
+
280
+ function decisionReason(rule, table) {
281
+ const degradation = table.degraded ? ` Rule table degraded; built-in defaults active (${table.degradationReason}).` : '';
282
+ return `[Harness actionGate:${rule.id}] ${rule.reason}${degradation}`;
283
+ }
284
+
285
+ function askOutput(reason) {
286
+ return {
287
+ hookSpecificOutput: {
288
+ hookEventName: 'PreToolUse',
289
+ permissionDecision: 'ask',
290
+ permissionDecisionReason: reason,
291
+ },
292
+ };
293
+ }
294
+
295
+ function recordDecision(payload, rule, table, host, disposition, options = {}, extra = {}) {
296
+ const exact = exactPayloadText(payload);
297
+ const commandHash = hashExact(exact);
298
+ const now = new Date().toISOString();
299
+ const record = {
300
+ schemaVersion: 1,
301
+ toolName: toolNameOf(payload),
302
+ toolUseId: (payload && (payload.tool_use_id || payload.toolUseId)) || null,
303
+ commandHash,
304
+ matchedRule: rule.id,
305
+ ruleReason: rule.reason,
306
+ disposition,
307
+ host,
308
+ permissionMode: (payload && (payload.permission_mode || payload.permissionMode)) || null,
309
+ gatePolicy: gatePolicy(options),
310
+ routerActionGate: routerActionGateHint(payload),
311
+ ruleTableSource: table.source,
312
+ degradedRuleTable: table.degraded,
313
+ degradationReason: table.degradationReason,
314
+ createdAt: now,
315
+ updatedAt: now,
316
+ ...extra,
317
+ };
318
+ try { writeAuditRecord(payload, record, options); } catch (_) { /* audit must not turn a decision into allow */ }
319
+ return record;
320
+ }
321
+
322
+ function evaluatePreToolUse(payload, options = {}) {
323
+ const context = sessionContext(payload, options.sessionDir);
324
+ const table = options.ruleTable || loadRuleTable(options.rulePath || RULES_PATH);
325
+ const rule = classify(payload, table.rules, context.sessionDir);
326
+ if (!rule) {
327
+ return {
328
+ kind: 'allow',
329
+ exitCode: 0,
330
+ stdout: null,
331
+ stderr: table.degraded ? `[Harness actionGate] ${table.degradationReason}; built-in defaults active.` : null,
332
+ rule: null,
333
+ table,
334
+ };
335
+ }
336
+
337
+ const host = detectHost(payload, options.host);
338
+ const reason = decisionReason(rule, table);
339
+ if (hostSupportsAsk(host) && gatePolicy(options) === ALWAYS_ASK_POLICY) {
340
+ const record = recordDecision(payload, rule, table, host, 'pending-approval', { ...options, sessionDir: context.sessionDir });
341
+ return { kind: 'ask', exitCode: 0, stdout: askOutput(reason), stderr: null, rule, table, record };
342
+ }
343
+ if (hostSupportsAsk(host)) {
344
+ const record = recordDecision(payload, rule, table, host, 'deferred-to-host', { ...options, sessionDir: context.sessionDir });
345
+ // No permissionDecision: the host's mode, rules and classifier decide. A
346
+ // degraded rule table still surfaces to the user as a systemMessage.
347
+ return { kind: 'defer', exitCode: 0, stdout: table.degraded ? warningOutput(reason) : null, stderr: null, rule, table, record };
348
+ }
349
+
350
+ const record = recordDecision(payload, rule, table, host, 'rejected', { ...options, sessionDir: context.sessionDir }, {
351
+ rejectionReason: 'host-ask-decision-unverified-or-unsupported',
352
+ });
353
+ return {
354
+ kind: 'block',
355
+ exitCode: 2,
356
+ stdout: null,
357
+ stderr: `${reason} Host '${host}' has no Harness-verified ask-style decision path, so the action is blocked.`,
358
+ rule,
359
+ table,
360
+ record,
361
+ };
362
+ }
363
+
364
+ function finalizeExecution(payload, outcome, options = {}) {
365
+ const exact = exactPayloadText(payload);
366
+ const commandHash = hashExact(exact);
367
+ const found = readAuditRecord(payload, commandHash, options);
368
+ if (!found.record) return { kind: 'noop', exitCode: 0 };
369
+
370
+ const record = found.record;
371
+ if (record.commandHash !== commandHash) {
372
+ record.disposition = 'integrity-violation';
373
+ record.integrityViolation = 'executed-payload-hash-differs-from-approved-payload';
374
+ } else {
375
+ record.disposition = 'executed';
376
+ record.executionOutcome = outcome;
377
+ }
378
+ record.updatedAt = new Date().toISOString();
379
+ if (outcome === 'failure') record.executionFailure = true;
380
+ atomicWriteJson(found.file, record);
381
+ return { kind: 'audit', exitCode: 0, record };
382
+ }
383
+
384
+ function rejectPendingAtStop(payload, options = {}) {
385
+ let dir;
386
+ try { dir = auditDirectory(payload, options); } catch (_) { return { kind: 'noop', exitCode: 0, rejected: 0 }; }
387
+ let rejected = 0;
388
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
389
+ if (!entry.isFile() || !entry.name.endsWith('.json')) continue;
390
+ const file = path.join(dir, entry.name);
391
+ let record;
392
+ try { record = JSON.parse(fs.readFileSync(file, 'utf8')); } catch (_) { continue; }
393
+ if (record.disposition !== 'pending-approval' && record.disposition !== 'deferred-to-host') continue;
394
+ record.rejectionReason = record.disposition === 'deferred-to-host'
395
+ ? 'host-did-not-execute-before-stop'
396
+ : 'approval-not-executed-before-stop';
397
+ record.disposition = 'rejected';
398
+ record.updatedAt = new Date().toISOString();
399
+ atomicWriteJson(file, record);
400
+ rejected++;
401
+ }
402
+ return { kind: 'audit', exitCode: 0, rejected };
403
+ }
404
+
405
+ function internalErrorDecision(payload, err, options = {}) {
406
+ const event = hookEventOf(payload);
407
+ const reason = `[Harness actionGate:internal-error] ${err.message}.`;
408
+
409
+ // Only PreToolUse can make an authorization decision. Post/Stop failures are
410
+ // audit failures after the side effect (or while closing state) and must not
411
+ // emit a PreToolUse-shaped ask or overwrite a completed execution record.
412
+ if (event !== 'PreToolUse') {
413
+ return {
414
+ kind: 'audit-error',
415
+ exitCode: 0,
416
+ stdout: null,
417
+ stderr: `${reason} ${event} audit state was not modified.`,
418
+ };
419
+ }
420
+
421
+ let host = 'unknown';
422
+ try { host = detectHost(payload, options.host); } catch (_) { host = 'unknown'; }
423
+ const askCapable = hostSupportsAsk(host);
424
+ const forceAsk = askCapable && gatePolicy(options) === ALWAYS_ASK_POLICY;
425
+ const disposition = !askCapable ? 'rejected' : (forceAsk ? 'pending-approval' : 'deferred-to-host');
426
+ const exact = exactPayloadText(payload);
427
+ const pseudoRule = { id: 'internal-error', reason: `Action-gate internal error: ${err.message}` };
428
+ const table = { source: 'internal-error', degraded: true, degradationReason: err.message };
429
+ try {
430
+ recordDecision(payload, pseudoRule, table, host, disposition, options, {
431
+ internalError: true,
432
+ rejectionReason: askCapable ? null : 'internal-error-on-host-without-verified-ask',
433
+ commandHash: hashExact(exact),
434
+ });
435
+ } catch (_) { /* the decision below does not depend on the audit write */ }
436
+
437
+ if (askCapable && !forceAsk) {
438
+ // Staying silent is not approval: the host's permission flow still decides.
439
+ return { kind: 'defer', exitCode: 0, stdout: warningOutput(`${reason} The host permission flow decides this call.`), stderr: null };
440
+ }
441
+ const approvalReason = `${reason} Fail-closed policy requires explicit approval.`;
442
+ if (askCapable) return { kind: 'ask', exitCode: 0, stdout: askOutput(approvalReason), stderr: null };
443
+ return { kind: 'block', exitCode: 2, stdout: null, stderr: `${approvalReason} Host '${host}' cannot be trusted to surface ask; blocking instead.` };
444
+ }
445
+
446
+ function processEvent(payload, options = {}) {
447
+ const event = hookEventOf(payload);
448
+ if (event === 'PreToolUse') return evaluatePreToolUse(payload, options);
449
+ if (event === 'PostToolUse') return finalizeExecution(payload, 'success', options);
450
+ if (event === 'PostToolUseFailure') return finalizeExecution(payload, 'failure', options);
451
+ if (event === 'Stop') return rejectPendingAtStop(payload, options);
452
+ return { kind: 'noop', exitCode: 0 };
453
+ }
454
+
455
+ function emitResult(result) {
456
+ if (result.stderr) console.error(result.stderr);
457
+ if (result.stdout) process.stdout.write(`${JSON.stringify(result.stdout)}\n`);
458
+ return result.exitCode || 0;
459
+ }
460
+
461
+ function runPayload(payload) {
462
+ try {
463
+ return emitResult(processEvent(payload));
464
+ } catch (err) {
465
+ return emitResult(internalErrorDecision(payload, err));
466
+ }
467
+ }
468
+
469
+ function setExitCodeIfDefined(code) {
470
+ if (Number.isInteger(code)) process.exitCode = code;
471
+ }
472
+
473
+ function readStdinAndRun() {
474
+ if (process.stdin.isTTY) return runPayload(null);
475
+ let raw = '';
476
+ let finished = false;
477
+ const finish = () => {
478
+ if (finished) return undefined;
479
+ finished = true;
480
+ let payload = {};
481
+ try { payload = JSON.parse(raw || '{}'); } catch (err) {
482
+ return emitResult(internalErrorDecision({}, new Error(`invalid hook JSON: ${err.message}`)));
483
+ }
484
+ return runPayload(payload);
485
+ };
486
+ const timeoutMsRaw = Number(process.env.HARNESS_ACTION_GATE_STDIN_TIMEOUT_MS);
487
+ const timeoutMs = Number.isFinite(timeoutMsRaw) && timeoutMsRaw > 0 ? timeoutMsRaw : 500;
488
+ const timer = setTimeout(() => setExitCodeIfDefined(finish()), timeoutMs);
489
+ process.stdin.setEncoding('utf8');
490
+ process.stdin.on('data', chunk => { raw += chunk; });
491
+ process.stdin.on('end', () => {
492
+ clearTimeout(timer);
493
+ setExitCodeIfDefined(finish());
494
+ });
495
+ process.stdin.on('error', err => {
496
+ clearTimeout(timer);
497
+ setExitCodeIfDefined(emitResult(internalErrorDecision({}, err)));
498
+ });
499
+ return 0;
500
+ }
501
+
502
+ if (require.main === module) {
503
+ setExitCodeIfDefined(readStdinAndRun());
504
+ }
505
+
506
+ module.exports = {
507
+ BUILTIN_RULES,
508
+ RULES_PATH,
509
+ absoluteTarget,
510
+ classify,
511
+ deleteTargets,
512
+ detectHost,
513
+ evaluatePreToolUse,
514
+ exactPayloadText,
515
+ finalizeExecution,
516
+ hashExact,
517
+ hookEventOf,
518
+ hostSupportsAsk,
519
+ internalErrorDecision,
520
+ isWithin,
521
+ loadRuleTable,
522
+ processEvent,
523
+ readStdinAndRun,
524
+ rejectPendingAtStop,
525
+ routerActionGateHint,
526
+ scratchRoots,
527
+ validateRuleTable,
528
+ };
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Atomic Commit Check (PostToolUse: apply_patch)
4
+ * PostToolUse can't block - the edit/write already happened. So this counts
5
+ * apply_patch calls since the last commit and, once the count crosses a
6
+ * threshold, feeds a strong reminder back to Claude (exit 2) to commit the
7
+ * completed chunk before piling on more changes. Resets whenever HEAD moves.
8
+ * Fails open on any error - this is a nudge, never a hard stop.
9
+ */
10
+ const { execSync } = require('child_process');
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const { getWorkspaceRoot, getSessionDir } = require('./lib/harness-state');
14
+
15
+ const THRESHOLD = 6;
16
+ const RENUDGE_EVERY = 3;
17
+
18
+ function main(payload) {
19
+ try {
20
+ const root = getWorkspaceRoot(payload);
21
+ const head = execSync('git rev-parse HEAD', { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
22
+
23
+ const stateFile = path.join(getSessionDir(root, payload && (payload.session_id || payload.sessionId)), 'atomic-commit-state.json');
24
+
25
+ let state = { lastHead: head, editCount: 0 };
26
+ if (fs.existsSync(stateFile)) {
27
+ try { state = JSON.parse(fs.readFileSync(stateFile, 'utf8')); } catch (e) { /* use default */ }
28
+ }
29
+
30
+ if (state.lastHead !== head) {
31
+ // A commit happened since we last checked - fresh start.
32
+ state.lastHead = head;
33
+ state.editCount = 0;
34
+ }
35
+
36
+ state.editCount += 1;
37
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2), 'utf8');
38
+
39
+ const overThreshold = state.editCount >= THRESHOLD;
40
+ const onNudgeBeat = overThreshold && (state.editCount - THRESHOLD) % RENUDGE_EVERY === 0;
41
+
42
+ if (onNudgeBeat) {
43
+ const statusRaw = execSync('git status --porcelain', { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
44
+ const changedFiles = statusRaw ? statusRaw.split('\n').length : 0;
45
+ console.error(`[Atomic Commit Check] ${state.editCount} apply_patch calls since the last commit (${changedFiles} files currently changed).`);
46
+ console.error(`If a logically complete chunk of work is done, commit it now before continuing - large uncommitted diffs are harder to review and harder to recover from.`);
47
+ process.exit(2);
48
+ }
49
+
50
+ process.exit(0);
51
+ } catch (err) {
52
+ process.exit(0);
53
+ }
54
+ }
55
+
56
+ let inputData = '';
57
+ const timeout = setTimeout(() => { main(null); }, 200);
58
+ process.stdin.on('data', chunk => { inputData += chunk; });
59
+ process.stdin.on('end', () => {
60
+ clearTimeout(timeout);
61
+ let payload = null;
62
+ try { payload = JSON.parse(inputData.trim()); } catch (err) { /* no payload */ }
63
+ main(payload);
64
+ });
65
+ process.stdin.on('error', () => {
66
+ clearTimeout(timeout);
67
+ main(null);
68
+ });
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Boundary Guard (PreToolUse: Grep|Glob|Read)
4
+ * Hard-blocks two concrete sources of context bloat / hallucination risk:
5
+ * 1. Reading a large file whole instead of a scoped chunk (offset/limit).
6
+ * 2. Searching inside known noise directories (node_modules, .git, build
7
+ * output, etc.) that produce huge, low-signal result sets.
8
+ * Fails open on any parse/lookup error - never blocks due to a bug here.
9
+ */
10
+ const fs = require('fs');
11
+
12
+ const MAX_BYTES_WITHOUT_LIMIT = 512 * 1024; // 512KB
13
+ const NOISE_DIRS = ['node_modules', '.git', 'dist', 'build', 'out', '.next', 'target', 'vendor', '__pycache__', '.venv', 'coverage'];
14
+
15
+ let inputData = '';
16
+ process.stdin.on('data', chunk => { inputData += chunk; });
17
+ process.stdin.on('end', () => {
18
+ try {
19
+ const payload = JSON.parse(inputData);
20
+ const toolName = payload.tool_name;
21
+ const input = payload.tool_input || {};
22
+
23
+ if (toolName === 'Read') {
24
+ const filePath = input.file_path;
25
+ if (filePath && !input.limit && fs.existsSync(filePath)) {
26
+ const stat = fs.statSync(filePath);
27
+ if (stat.isFile() && stat.size > MAX_BYTES_WITHOUT_LIMIT) {
28
+ console.error(`[Boundary Guard] BLOCKED: "${filePath}" is ${(stat.size / 1024).toFixed(0)}KB.`);
29
+ console.error(`Reading a file this large in one call risks context bloat and "lost in the middle" degradation.`);
30
+ console.error(`Re-issue the Read with an explicit "offset"/"limit" to pull a targeted slice, or use Grep to locate the relevant section first.`);
31
+ process.exit(2);
32
+ }
33
+ }
34
+ }
35
+
36
+ if (toolName === 'Grep' || toolName === 'Glob') {
37
+ const searchPath = input.path || '';
38
+ const pattern = input.pattern || '';
39
+ const hitsNoiseDir = NOISE_DIRS.some(dir => {
40
+ const asPathSegment = new RegExp(`(^|[\\\\/])${dir}($|[\\\\/])`);
41
+ return asPathSegment.test(searchPath) || asPathSegment.test(pattern);
42
+ });
43
+ if (hitsNoiseDir) {
44
+ console.error(`[Boundary Guard] BLOCKED: search targets a noise directory (${NOISE_DIRS.join(', ')}).`);
45
+ console.error(`These produce huge, low-signal result sets and rarely contain what you're actually looking for.`);
46
+ console.error(`Scope the search to source directories instead, or state explicitly why this directory must be searched.`);
47
+ process.exit(2);
48
+ }
49
+ }
50
+
51
+ process.exit(0);
52
+ } catch (err) {
53
+ process.exit(0);
54
+ }
55
+ });