@lannguyensi/harness 0.63.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (702) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +46 -42
  3. package/dist/cli/add/index.js +17 -21
  4. package/dist/cli/add/index.js.map +1 -1
  5. package/dist/cli/adopt/derive.d.ts +2 -2
  6. package/dist/cli/adopt/derive.js +2 -19
  7. package/dist/cli/adopt/derive.js.map +1 -1
  8. package/dist/cli/adopt/index.d.ts +1 -1
  9. package/dist/cli/adopt/index.js +1 -12
  10. package/dist/cli/adopt/index.js.map +1 -1
  11. package/dist/cli/apply/apply.d.ts +20 -35
  12. package/dist/cli/apply/apply.js +61 -136
  13. package/dist/cli/apply/apply.js.map +1 -1
  14. package/dist/cli/apply/generate-codex-config.js +10 -58
  15. package/dist/cli/apply/generate-codex-config.js.map +1 -1
  16. package/dist/cli/apply/generate-memory-index.js +1 -2
  17. package/dist/cli/apply/generate-memory-index.js.map +1 -1
  18. package/dist/cli/apply/generate-opencode-config.d.ts +2 -10
  19. package/dist/cli/apply/generate-opencode-config.js +74 -113
  20. package/dist/cli/apply/generate-opencode-config.js.map +1 -1
  21. package/dist/cli/apply/generate-settings.d.ts +11 -64
  22. package/dist/cli/apply/generate-settings.js +27 -132
  23. package/dist/cli/apply/generate-settings.js.map +1 -1
  24. package/dist/cli/apply/index.d.ts +1 -1
  25. package/dist/cli/apply/index.js +1 -1
  26. package/dist/cli/apply/index.js.map +1 -1
  27. package/dist/cli/apply/install-codex-config.d.ts +153 -1
  28. package/dist/cli/apply/install-codex-config.js +445 -70
  29. package/dist/cli/apply/install-codex-config.js.map +1 -1
  30. package/dist/cli/apply/next-steps.d.ts +7 -0
  31. package/dist/cli/apply/next-steps.js +13 -1
  32. package/dist/cli/apply/next-steps.js.map +1 -1
  33. package/dist/cli/bounded-stdin.d.ts +0 -23
  34. package/dist/cli/bounded-stdin.js +2 -49
  35. package/dist/cli/bounded-stdin.js.map +1 -1
  36. package/dist/cli/describe.d.ts +1 -1
  37. package/dist/cli/describe.js +0 -3
  38. package/dist/cli/describe.js.map +1 -1
  39. package/dist/cli/diff/engine.d.ts +0 -11
  40. package/dist/cli/diff/engine.js +1 -17
  41. package/dist/cli/diff/engine.js.map +1 -1
  42. package/dist/cli/diff/index.js +14 -25
  43. package/dist/cli/diff/index.js.map +1 -1
  44. package/dist/cli/doctor/claude-mcp.d.ts +4 -19
  45. package/dist/cli/doctor/claude-mcp.js +11 -22
  46. package/dist/cli/doctor/claude-mcp.js.map +1 -1
  47. package/dist/cli/doctor/codex.d.ts +12 -14
  48. package/dist/cli/doctor/codex.js +31 -144
  49. package/dist/cli/doctor/codex.js.map +1 -1
  50. package/dist/cli/doctor/format.js +23 -338
  51. package/dist/cli/doctor/format.js.map +1 -1
  52. package/dist/cli/doctor/hook-liveness.d.ts +56 -0
  53. package/dist/cli/doctor/hook-liveness.js +455 -0
  54. package/dist/cli/doctor/hook-liveness.js.map +1 -0
  55. package/dist/cli/doctor/index.d.ts +13 -87
  56. package/dist/cli/doctor/index.js +57 -705
  57. package/dist/cli/doctor/index.js.map +1 -1
  58. package/dist/cli/doctor/opencode.d.ts +2 -1
  59. package/dist/cli/doctor/opencode.js.map +1 -1
  60. package/dist/cli/doctor/types.d.ts +21 -378
  61. package/dist/cli/doctor/types.js.map +1 -1
  62. package/dist/cli/drain-stdio.d.ts +31 -0
  63. package/dist/cli/drain-stdio.js +76 -0
  64. package/dist/cli/drain-stdio.js.map +1 -0
  65. package/dist/cli/export.d.ts +3 -1
  66. package/dist/cli/export.js +7 -16
  67. package/dist/cli/export.js.map +1 -1
  68. package/dist/cli/gate/codex-disable.d.ts +29 -0
  69. package/dist/cli/gate/codex-disable.js +195 -0
  70. package/dist/cli/gate/codex-disable.js.map +1 -0
  71. package/dist/cli/gate/codex-enable.d.ts +41 -0
  72. package/dist/cli/gate/codex-enable.js +127 -0
  73. package/dist/cli/gate/codex-enable.js.map +1 -0
  74. package/dist/cli/gate/codex-snapshot.d.ts +208 -0
  75. package/dist/cli/gate/codex-snapshot.js +402 -0
  76. package/dist/cli/gate/codex-snapshot.js.map +1 -0
  77. package/dist/cli/gate/disable.d.ts +9 -0
  78. package/dist/cli/gate/disable.js +263 -28
  79. package/dist/cli/gate/disable.js.map +1 -1
  80. package/dist/cli/gate/enable.d.ts +26 -6
  81. package/dist/cli/gate/enable.js +152 -80
  82. package/dist/cli/gate/enable.js.map +1 -1
  83. package/dist/cli/gate/link-chain.d.ts +53 -0
  84. package/dist/cli/gate/link-chain.js +122 -0
  85. package/dist/cli/gate/link-chain.js.map +1 -0
  86. package/dist/cli/gate/snapshot.d.ts +289 -12
  87. package/dist/cli/gate/snapshot.js +481 -22
  88. package/dist/cli/gate/snapshot.js.map +1 -1
  89. package/dist/cli/index.d.ts +0 -9
  90. package/dist/cli/index.js +15 -2607
  91. package/dist/cli/index.js.map +1 -1
  92. package/dist/cli/init/composer.d.ts +3 -6
  93. package/dist/cli/init/composer.js +6 -370
  94. package/dist/cli/init/composer.js.map +1 -1
  95. package/dist/cli/init/dependencies.d.ts +1 -2
  96. package/dist/cli/init/dependencies.js +4 -80
  97. package/dist/cli/init/dependencies.js.map +1 -1
  98. package/dist/cli/init/detect.js +5 -4
  99. package/dist/cli/init/detect.js.map +1 -1
  100. package/dist/cli/init/interactive.d.ts +1 -23
  101. package/dist/cli/init/interactive.js +33 -247
  102. package/dist/cli/init/interactive.js.map +1 -1
  103. package/dist/cli/init/profiles.d.ts +2 -2
  104. package/dist/cli/init/profiles.js +51 -243
  105. package/dist/cli/init/profiles.js.map +1 -1
  106. package/dist/cli/init/templates.d.ts +2 -37
  107. package/dist/cli/init/templates.js +25 -1237
  108. package/dist/cli/init/templates.js.map +1 -1
  109. package/dist/cli/list.d.ts +1 -1
  110. package/dist/cli/list.js +1 -38
  111. package/dist/cli/list.js.map +1 -1
  112. package/dist/cli/loader.d.ts +15 -1
  113. package/dist/cli/loader.js +56 -39
  114. package/dist/cli/loader.js.map +1 -1
  115. package/dist/cli/main.js +7 -2
  116. package/dist/cli/main.js.map +1 -1
  117. package/dist/cli/migrate-home/index.js +2 -2
  118. package/dist/cli/migrate-home/index.js.map +1 -1
  119. package/dist/cli/pack/add.js +1 -1
  120. package/dist/cli/pack/add.js.map +1 -1
  121. package/dist/cli/pack/hook-bootstrap.d.ts +5 -164
  122. package/dist/cli/pack/hook-bootstrap.js +15 -291
  123. package/dist/cli/pack/hook-bootstrap.js.map +1 -1
  124. package/dist/cli/pack/hook-branch-protection.d.ts +28 -21
  125. package/dist/cli/pack/hook-branch-protection.js +365 -340
  126. package/dist/cli/pack/hook-branch-protection.js.map +1 -1
  127. package/dist/cli/pack/index.d.ts +0 -1
  128. package/dist/cli/pack/index.js +0 -1
  129. package/dist/cli/pack/index.js.map +1 -1
  130. package/dist/cli/pack/list.js +1 -6
  131. package/dist/cli/pack/list.js.map +1 -1
  132. package/dist/cli/pack/mutate.d.ts +7 -9
  133. package/dist/cli/pack/mutate.js +6 -9
  134. package/dist/cli/pack/mutate.js.map +1 -1
  135. package/dist/cli/pack/reseed.d.ts +2 -2
  136. package/dist/cli/pack/reseed.js +16 -22
  137. package/dist/cli/pack/reseed.js.map +1 -1
  138. package/dist/cli/register-gate-group.d.ts +5 -0
  139. package/dist/cli/register-gate-group.js +348 -0
  140. package/dist/cli/register-gate-group.js.map +1 -0
  141. package/dist/cli/register-inspect-group.d.ts +6 -0
  142. package/dist/cli/register-inspect-group.js +189 -0
  143. package/dist/cli/register-inspect-group.js.map +1 -0
  144. package/dist/cli/register-operator-lifecycle.d.ts +5 -0
  145. package/dist/cli/register-operator-lifecycle.js +20 -0
  146. package/dist/cli/register-operator-lifecycle.js.map +1 -0
  147. package/dist/cli/register-pack-group.d.ts +5 -0
  148. package/dist/cli/register-pack-group.js +134 -0
  149. package/dist/cli/register-pack-group.js.map +1 -0
  150. package/dist/cli/register-setup-group.d.ts +5 -0
  151. package/dist/cli/register-setup-group.js +495 -0
  152. package/dist/cli/register-setup-group.js.map +1 -0
  153. package/dist/cli/remove/index.d.ts +0 -14
  154. package/dist/cli/remove/index.js +2 -115
  155. package/dist/cli/remove/index.js.map +1 -1
  156. package/dist/cli/remove/mutate.d.ts +0 -2
  157. package/dist/cli/remove/mutate.js +1 -19
  158. package/dist/cli/remove/mutate.js.map +1 -1
  159. package/dist/cli/remove/register.d.ts +5 -0
  160. package/dist/cli/remove/register.js +25 -0
  161. package/dist/cli/remove/register.js.map +1 -0
  162. package/dist/cli/shell-quote.d.ts +7 -0
  163. package/dist/cli/shell-quote.js +17 -0
  164. package/dist/cli/shell-quote.js.map +1 -0
  165. package/dist/cli/uninstall/index.d.ts +4 -2
  166. package/dist/cli/uninstall/index.js +15 -7
  167. package/dist/cli/uninstall/index.js.map +1 -1
  168. package/dist/cli/uninstall/register.d.ts +5 -0
  169. package/dist/cli/uninstall/register.js +171 -0
  170. package/dist/cli/uninstall/register.js.map +1 -0
  171. package/dist/cli/uninstall/snapshot.d.ts +15 -0
  172. package/dist/cli/uninstall/snapshot.js +38 -0
  173. package/dist/cli/uninstall/snapshot.js.map +1 -1
  174. package/dist/cli/validate/checks.d.ts +0 -77
  175. package/dist/cli/validate/checks.js +3 -1049
  176. package/dist/cli/validate/checks.js.map +1 -1
  177. package/dist/cli/validate/index.js +19 -15
  178. package/dist/cli/validate/index.js.map +1 -1
  179. package/dist/index.d.ts +0 -3
  180. package/dist/index.js +0 -3
  181. package/dist/index.js.map +1 -1
  182. package/dist/io/claude-mcp.d.ts +1 -1
  183. package/dist/io/claude-mcp.js +27 -14
  184. package/dist/io/claude-mcp.js.map +1 -1
  185. package/dist/io/harness-lock.js +2 -2
  186. package/dist/io/harness-lock.js.map +1 -1
  187. package/dist/io/lock.d.ts +0 -26
  188. package/dist/io/lock.js +10 -27
  189. package/dist/io/lock.js.map +1 -1
  190. package/dist/io/merge-settings.js +6 -4
  191. package/dist/io/merge-settings.js.map +1 -1
  192. package/dist/io/project-name.d.ts +22 -39
  193. package/dist/io/project-name.js +25 -42
  194. package/dist/io/project-name.js.map +1 -1
  195. package/dist/io/read-regular-file.d.ts +103 -40
  196. package/dist/io/read-regular-file.js +196 -35
  197. package/dist/io/read-regular-file.js.map +1 -1
  198. package/dist/io/restart-hints.js +3 -6
  199. package/dist/io/restart-hints.js.map +1 -1
  200. package/dist/io/version-compare.d.ts +1 -3
  201. package/dist/io/version-compare.js +1 -3
  202. package/dist/io/version-compare.js.map +1 -1
  203. package/dist/io/write-regular-file.d.ts +30 -0
  204. package/dist/io/write-regular-file.js +85 -0
  205. package/dist/io/write-regular-file.js.map +1 -0
  206. package/dist/overrides/index.d.ts +1 -0
  207. package/dist/overrides/index.js +1 -0
  208. package/dist/overrides/index.js.map +1 -1
  209. package/dist/overrides/merge-layers.d.ts +43 -0
  210. package/dist/overrides/merge-layers.js +76 -0
  211. package/dist/overrides/merge-layers.js.map +1 -0
  212. package/dist/overrides/merge.d.ts +16 -0
  213. package/dist/overrides/merge.js +21 -8
  214. package/dist/overrides/merge.js.map +1 -1
  215. package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +4 -69
  216. package/dist/policy-packs/builtin/branch-protection-runtime.js +12 -84
  217. package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -1
  218. package/dist/policy-packs/builtin/branch-protection.d.ts +7 -30
  219. package/dist/policy-packs/builtin/branch-protection.js +56 -89
  220. package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
  221. package/dist/policy-packs/config-check.d.ts +7 -5
  222. package/dist/policy-packs/config-check.js +2 -2
  223. package/dist/policy-packs/config-check.js.map +1 -1
  224. package/dist/policy-packs/expand.d.ts +1 -3
  225. package/dist/policy-packs/expand.js +5 -42
  226. package/dist/policy-packs/expand.js.map +1 -1
  227. package/dist/policy-packs/index.d.ts +3 -3
  228. package/dist/policy-packs/index.js +2 -2
  229. package/dist/policy-packs/index.js.map +1 -1
  230. package/dist/policy-packs/registry.d.ts +9 -38
  231. package/dist/policy-packs/registry.js +5 -65
  232. package/dist/policy-packs/registry.js.map +1 -1
  233. package/dist/policy-packs/runtime.d.ts +0 -4
  234. package/dist/policy-packs/runtime.js +9 -22
  235. package/dist/policy-packs/runtime.js.map +1 -1
  236. package/dist/policy-packs/types.d.ts +0 -19
  237. package/dist/policy-packs/ux-compare.d.ts +1 -11
  238. package/dist/policy-packs/ux-compare.js +6 -42
  239. package/dist/policy-packs/ux-compare.js.map +1 -1
  240. package/dist/policy-packs/ux-drift-check.d.ts +5 -5
  241. package/dist/policy-packs/ux-drift-check.js +17 -22
  242. package/dist/policy-packs/ux-drift-check.js.map +1 -1
  243. package/dist/policy-packs/version-check.d.ts +5 -26
  244. package/dist/policy-packs/version-check.js +19 -74
  245. package/dist/policy-packs/version-check.js.map +1 -1
  246. package/dist/probes/memory.d.ts +1 -1
  247. package/dist/probes/memory.js +1 -1
  248. package/dist/probes/memory.js.map +1 -1
  249. package/dist/runtime/agent-facing.d.ts +9 -0
  250. package/dist/runtime/agent-facing.js +28 -14
  251. package/dist/runtime/agent-facing.js.map +1 -1
  252. package/dist/runtime/bounded-text.d.ts +15 -0
  253. package/dist/runtime/bounded-text.js +27 -0
  254. package/dist/runtime/bounded-text.js.map +1 -0
  255. package/dist/runtime/git-branch.d.ts +125 -0
  256. package/dist/runtime/git-branch.js +381 -0
  257. package/dist/runtime/git-branch.js.map +1 -0
  258. package/dist/runtime/hermetic-spawn-guard.d.ts +2 -2
  259. package/dist/runtime/hermetic-spawn-guard.js +24 -34
  260. package/dist/runtime/hermetic-spawn-guard.js.map +1 -1
  261. package/dist/runtime/home-dir.js +3 -2
  262. package/dist/runtime/home-dir.js.map +1 -1
  263. package/dist/runtime/tool-name-aliases.d.ts +0 -6
  264. package/dist/runtime/tool-name-aliases.js +5 -18
  265. package/dist/runtime/tool-name-aliases.js.map +1 -1
  266. package/dist/schema/grounding.d.ts +7 -54
  267. package/dist/schema/grounding.js +10 -12
  268. package/dist/schema/grounding.js.map +1 -1
  269. package/dist/schema/hooks.d.ts +39 -136
  270. package/dist/schema/hooks.js +3 -6
  271. package/dist/schema/hooks.js.map +1 -1
  272. package/dist/schema/index.d.ts +114 -3828
  273. package/dist/schema/index.js +41 -80
  274. package/dist/schema/index.js.map +1 -1
  275. package/dist/schema/memory.d.ts +54 -131
  276. package/dist/schema/memory.js +2 -2
  277. package/dist/schema/memory.js.map +1 -1
  278. package/dist/schema/policy-packs.d.ts +3 -45
  279. package/dist/schema/policy-packs.js +7 -13
  280. package/dist/schema/policy-packs.js.map +1 -1
  281. package/dist/schema/policy-ux.d.ts +7 -0
  282. package/dist/schema/policy-ux.js +18 -0
  283. package/dist/schema/policy-ux.js.map +1 -0
  284. package/dist/schema/removed-keys.d.ts +185 -0
  285. package/dist/schema/removed-keys.js +531 -0
  286. package/dist/schema/removed-keys.js.map +1 -0
  287. package/dist/schema/tools.d.ts +30 -268
  288. package/dist/schema/tools.js +4 -4
  289. package/dist/schema/tools.js.map +1 -1
  290. package/package.json +5 -16
  291. package/dist/cli/approve/branch-protection.d.ts +0 -69
  292. package/dist/cli/approve/branch-protection.js +0 -144
  293. package/dist/cli/approve/branch-protection.js.map +0 -1
  294. package/dist/cli/approve/risk.d.ts +0 -112
  295. package/dist/cli/approve/risk.js +0 -197
  296. package/dist/cli/approve/risk.js.map +0 -1
  297. package/dist/cli/approve/stdin-report.d.ts +0 -57
  298. package/dist/cli/approve/stdin-report.js +0 -145
  299. package/dist/cli/approve/stdin-report.js.map +0 -1
  300. package/dist/cli/approve/understanding.d.ts +0 -410
  301. package/dist/cli/approve/understanding.js +0 -996
  302. package/dist/cli/approve/understanding.js.map +0 -1
  303. package/dist/cli/audit.d.ts +0 -80
  304. package/dist/cli/audit.js +0 -252
  305. package/dist/cli/audit.js.map +0 -1
  306. package/dist/cli/delegate/index.d.ts +0 -76
  307. package/dist/cli/delegate/index.js +0 -443
  308. package/dist/cli/delegate/index.js.map +0 -1
  309. package/dist/cli/doctor/auto-approve-mode.d.ts +0 -37
  310. package/dist/cli/doctor/auto-approve-mode.js +0 -80
  311. package/dist/cli/doctor/auto-approve-mode.js.map +0 -1
  312. package/dist/cli/doctor/bypass-without-auto-approve.d.ts +0 -38
  313. package/dist/cli/doctor/bypass-without-auto-approve.js +0 -95
  314. package/dist/cli/doctor/bypass-without-auto-approve.js.map +0 -1
  315. package/dist/cli/doctor/codex-config-drift.d.ts +0 -28
  316. package/dist/cli/doctor/codex-config-drift.js +0 -240
  317. package/dist/cli/doctor/codex-config-drift.js.map +0 -1
  318. package/dist/cli/doctor/rogue-ledger.d.ts +0 -53
  319. package/dist/cli/doctor/rogue-ledger.js +0 -153
  320. package/dist/cli/doctor/rogue-ledger.js.map +0 -1
  321. package/dist/cli/doctor/session-start-preflight-setup-version.d.ts +0 -83
  322. package/dist/cli/doctor/session-start-preflight-setup-version.js +0 -114
  323. package/dist/cli/doctor/session-start-preflight-setup-version.js.map +0 -1
  324. package/dist/cli/doctor/settings-drift.d.ts +0 -25
  325. package/dist/cli/doctor/settings-drift.js +0 -213
  326. package/dist/cli/doctor/settings-drift.js.map +0 -1
  327. package/dist/cli/doctor/toolchain-parity.d.ts +0 -63
  328. package/dist/cli/doctor/toolchain-parity.js +0 -154
  329. package/dist/cli/doctor/toolchain-parity.js.map +0 -1
  330. package/dist/cli/doctor/ug-auto-approvals.d.ts +0 -40
  331. package/dist/cli/doctor/ug-auto-approvals.js +0 -91
  332. package/dist/cli/doctor/ug-auto-approvals.js.map +0 -1
  333. package/dist/cli/doctor/ug-delegations.d.ts +0 -26
  334. package/dist/cli/doctor/ug-delegations.js +0 -121
  335. package/dist/cli/doctor/ug-delegations.js.map +0 -1
  336. package/dist/cli/doctor/ug-inflight.d.ts +0 -35
  337. package/dist/cli/doctor/ug-inflight.js +0 -57
  338. package/dist/cli/doctor/ug-inflight.js.map +0 -1
  339. package/dist/cli/doctor/understanding-mode-env.d.ts +0 -51
  340. package/dist/cli/doctor/understanding-mode-env.js +0 -98
  341. package/dist/cli/doctor/understanding-mode-env.js.map +0 -1
  342. package/dist/cli/dry-run.d.ts +0 -46
  343. package/dist/cli/dry-run.js +0 -250
  344. package/dist/cli/dry-run.js.map +0 -1
  345. package/dist/cli/event-input.d.ts +0 -28
  346. package/dist/cli/event-input.js +0 -73
  347. package/dist/cli/event-input.js.map +0 -1
  348. package/dist/cli/explain-action.d.ts +0 -20
  349. package/dist/cli/explain-action.js +0 -27
  350. package/dist/cli/explain-action.js.map +0 -1
  351. package/dist/cli/explain-policy.d.ts +0 -135
  352. package/dist/cli/explain-policy.js +0 -266
  353. package/dist/cli/explain-policy.js.map +0 -1
  354. package/dist/cli/explain.d.ts +0 -31
  355. package/dist/cli/explain.js +0 -159
  356. package/dist/cli/explain.js.map +0 -1
  357. package/dist/cli/gc/index.d.ts +0 -63
  358. package/dist/cli/gc/index.js +0 -566
  359. package/dist/cli/gc/index.js.map +0 -1
  360. package/dist/cli/pack/approve-escape.d.ts +0 -19
  361. package/dist/cli/pack/approve-escape.js +0 -190
  362. package/dist/cli/pack/approve-escape.js.map +0 -1
  363. package/dist/cli/pack/auto-approve-path.d.ts +0 -146
  364. package/dist/cli/pack/auto-approve-path.js +0 -462
  365. package/dist/cli/pack/auto-approve-path.js.map +0 -1
  366. package/dist/cli/pack/hook-codex-post-tool-use.d.ts +0 -25
  367. package/dist/cli/pack/hook-codex-post-tool-use.js +0 -160
  368. package/dist/cli/pack/hook-codex-post-tool-use.js.map +0 -1
  369. package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +0 -48
  370. package/dist/cli/pack/hook-codex-pre-tool-use.js +0 -474
  371. package/dist/cli/pack/hook-codex-pre-tool-use.js.map +0 -1
  372. package/dist/cli/pack/hook-codex-stop.d.ts +0 -35
  373. package/dist/cli/pack/hook-codex-stop.js +0 -329
  374. package/dist/cli/pack/hook-codex-stop.js.map +0 -1
  375. package/dist/cli/pack/hook-codex-user-prompt-submit.d.ts +0 -24
  376. package/dist/cli/pack/hook-codex-user-prompt-submit.js +0 -93
  377. package/dist/cli/pack/hook-codex-user-prompt-submit.js.map +0 -1
  378. package/dist/cli/pack/hook-post-merge-gate-record.d.ts +0 -37
  379. package/dist/cli/pack/hook-post-merge-gate-record.js +0 -190
  380. package/dist/cli/pack/hook-post-merge-gate-record.js.map +0 -1
  381. package/dist/cli/pack/hook-post-merge-gate.d.ts +0 -34
  382. package/dist/cli/pack/hook-post-merge-gate.js +0 -277
  383. package/dist/cli/pack/hook-post-merge-gate.js.map +0 -1
  384. package/dist/cli/pack/hook-post-tool-use.d.ts +0 -45
  385. package/dist/cli/pack/hook-post-tool-use.js +0 -137
  386. package/dist/cli/pack/hook-post-tool-use.js.map +0 -1
  387. package/dist/cli/pack/hook-pre-tool-use.d.ts +0 -92
  388. package/dist/cli/pack/hook-pre-tool-use.js +0 -1328
  389. package/dist/cli/pack/hook-pre-tool-use.js.map +0 -1
  390. package/dist/cli/pack/hook-runtime-reality.d.ts +0 -63
  391. package/dist/cli/pack/hook-runtime-reality.js +0 -210
  392. package/dist/cli/pack/hook-runtime-reality.js.map +0 -1
  393. package/dist/cli/pack/hook-solution-acceptance-writeguard.d.ts +0 -32
  394. package/dist/cli/pack/hook-solution-acceptance-writeguard.js +0 -337
  395. package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +0 -1
  396. package/dist/cli/pack/hook-solution-acceptance.d.ts +0 -157
  397. package/dist/cli/pack/hook-solution-acceptance.js +0 -530
  398. package/dist/cli/pack/hook-solution-acceptance.js.map +0 -1
  399. package/dist/cli/pack/hook-stay-in-scope.d.ts +0 -37
  400. package/dist/cli/pack/hook-stay-in-scope.js +0 -128
  401. package/dist/cli/pack/hook-stay-in-scope.js.map +0 -1
  402. package/dist/cli/pack/hook-subagent-start.d.ts +0 -23
  403. package/dist/cli/pack/hook-subagent-start.js +0 -88
  404. package/dist/cli/pack/hook-subagent-start.js.map +0 -1
  405. package/dist/cli/pack/hook-subagent-stop.d.ts +0 -19
  406. package/dist/cli/pack/hook-subagent-stop.js +0 -41
  407. package/dist/cli/pack/hook-subagent-stop.js.map +0 -1
  408. package/dist/cli/pack/hook-track-active-claim.d.ts +0 -27
  409. package/dist/cli/pack/hook-track-active-claim.js +0 -275
  410. package/dist/cli/pack/hook-track-active-claim.js.map +0 -1
  411. package/dist/cli/pack/transcript-report-scan.d.ts +0 -71
  412. package/dist/cli/pack/transcript-report-scan.js +0 -359
  413. package/dist/cli/pack/transcript-report-scan.js.map +0 -1
  414. package/dist/cli/pack/understanding-report-schema-hint.d.ts +0 -26
  415. package/dist/cli/pack/understanding-report-schema-hint.js +0 -120
  416. package/dist/cli/pack/understanding-report-schema-hint.js.map +0 -1
  417. package/dist/cli/pack/upgrade.d.ts +0 -32
  418. package/dist/cli/pack/upgrade.js +0 -273
  419. package/dist/cli/pack/upgrade.js.map +0 -1
  420. package/dist/cli/pause/index.d.ts +0 -113
  421. package/dist/cli/pause/index.js +0 -251
  422. package/dist/cli/pause/index.js.map +0 -1
  423. package/dist/cli/pause-check.d.ts +0 -22
  424. package/dist/cli/pause-check.js +0 -54
  425. package/dist/cli/pause-check.js.map +0 -1
  426. package/dist/cli/policy/intercept.d.ts +0 -233
  427. package/dist/cli/policy/intercept.js +0 -1020
  428. package/dist/cli/policy/intercept.js.map +0 -1
  429. package/dist/cli/policy/risk-envelope-enrichment.d.ts +0 -40
  430. package/dist/cli/policy/risk-envelope-enrichment.js +0 -108
  431. package/dist/cli/policy/risk-envelope-enrichment.js.map +0 -1
  432. package/dist/cli/record/index.d.ts +0 -81
  433. package/dist/cli/record/index.js +0 -348
  434. package/dist/cli/record/index.js.map +0 -1
  435. package/dist/cli/resolve-env.d.ts +0 -32
  436. package/dist/cli/resolve-env.js +0 -47
  437. package/dist/cli/resolve-env.js.map +0 -1
  438. package/dist/cli/session-export/index.d.ts +0 -46
  439. package/dist/cli/session-export/index.js +0 -169
  440. package/dist/cli/session-export/index.js.map +0 -1
  441. package/dist/cli/session-export/redact.d.ts +0 -22
  442. package/dist/cli/session-export/redact.js +0 -47
  443. package/dist/cli/session-export/redact.js.map +0 -1
  444. package/dist/cli/session-export/transcript.d.ts +0 -24
  445. package/dist/cli/session-export/transcript.js +0 -164
  446. package/dist/cli/session-export/transcript.js.map +0 -1
  447. package/dist/cli/session-start/branch-check.d.ts +0 -18
  448. package/dist/cli/session-start/branch-check.js +0 -140
  449. package/dist/cli/session-start/branch-check.js.map +0 -1
  450. package/dist/cli/session-start/index.d.ts +0 -121
  451. package/dist/cli/session-start/index.js +0 -591
  452. package/dist/cli/session-start/index.js.map +0 -1
  453. package/dist/cli/session-start/shared-options.d.ts +0 -103
  454. package/dist/cli/session-start/shared-options.js +0 -107
  455. package/dist/cli/session-start/shared-options.js.map +0 -1
  456. package/dist/cli/session-start/stale-base-check.d.ts +0 -46
  457. package/dist/cli/session-start/stale-base-check.js +0 -352
  458. package/dist/cli/session-start/stale-base-check.js.map +0 -1
  459. package/dist/cli/session-start/toolchain-parity.d.ts +0 -267
  460. package/dist/cli/session-start/toolchain-parity.js +0 -797
  461. package/dist/cli/session-start/toolchain-parity.js.map +0 -1
  462. package/dist/cli/smoke/assertions.d.ts +0 -46
  463. package/dist/cli/smoke/assertions.js +0 -170
  464. package/dist/cli/smoke/assertions.js.map +0 -1
  465. package/dist/cli/smoke/index.d.ts +0 -76
  466. package/dist/cli/smoke/index.js +0 -245
  467. package/dist/cli/smoke/index.js.map +0 -1
  468. package/dist/cli/smoke/runner.d.ts +0 -55
  469. package/dist/cli/smoke/runner.js +0 -134
  470. package/dist/cli/smoke/runner.js.map +0 -1
  471. package/dist/cli/smoke/stream-parser.d.ts +0 -65
  472. package/dist/cli/smoke/stream-parser.js +0 -115
  473. package/dist/cli/smoke/stream-parser.js.map +0 -1
  474. package/dist/cli/test-risk.d.ts +0 -26
  475. package/dist/cli/test-risk.js +0 -34
  476. package/dist/cli/test-risk.js.map +0 -1
  477. package/dist/io/display-path.d.ts +0 -11
  478. package/dist/io/display-path.js +0 -29
  479. package/dist/io/display-path.js.map +0 -1
  480. package/dist/io/duration.d.ts +0 -5
  481. package/dist/io/duration.js +0 -50
  482. package/dist/io/duration.js.map +0 -1
  483. package/dist/io/extract.d.ts +0 -79
  484. package/dist/io/extract.js +0 -226
  485. package/dist/io/extract.js.map +0 -1
  486. package/dist/io/ledger-record.d.ts +0 -83
  487. package/dist/io/ledger-record.js +0 -301
  488. package/dist/io/ledger-record.js.map +0 -1
  489. package/dist/io/read-json-dir-entries.d.ts +0 -36
  490. package/dist/io/read-json-dir-entries.js +0 -48
  491. package/dist/io/read-json-dir-entries.js.map +0 -1
  492. package/dist/io/safe-json-parse.d.ts +0 -5
  493. package/dist/io/safe-json-parse.js +0 -21
  494. package/dist/io/safe-json-parse.js.map +0 -1
  495. package/dist/policies/index.d.ts +0 -5
  496. package/dist/policies/index.js +0 -6
  497. package/dist/policies/index.js.map +0 -1
  498. package/dist/policies/ledger-client.d.ts +0 -113
  499. package/dist/policies/ledger-client.js +0 -500
  500. package/dist/policies/ledger-client.js.map +0 -1
  501. package/dist/policies/producers.d.ts +0 -12
  502. package/dist/policies/producers.js +0 -61
  503. package/dist/policies/producers.js.map +0 -1
  504. package/dist/policies/requires.d.ts +0 -75
  505. package/dist/policies/requires.js +0 -240
  506. package/dist/policies/requires.js.map +0 -1
  507. package/dist/policies/timestamp.d.ts +0 -14
  508. package/dist/policies/timestamp.js +0 -36
  509. package/dist/policies/timestamp.js.map +0 -1
  510. package/dist/policy-packs/builtin/permission-profiles.d.ts +0 -11
  511. package/dist/policy-packs/builtin/permission-profiles.js +0 -74
  512. package/dist/policy-packs/builtin/permission-profiles.js.map +0 -1
  513. package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +0 -286
  514. package/dist/policy-packs/builtin/post-merge-gate-runtime.js +0 -397
  515. package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +0 -1
  516. package/dist/policy-packs/builtin/post-merge-gate.d.ts +0 -56
  517. package/dist/policy-packs/builtin/post-merge-gate.js +0 -347
  518. package/dist/policy-packs/builtin/post-merge-gate.js.map +0 -1
  519. package/dist/policy-packs/builtin/solution-acceptance-reconnect.d.ts +0 -50
  520. package/dist/policy-packs/builtin/solution-acceptance-reconnect.js +0 -151
  521. package/dist/policy-packs/builtin/solution-acceptance-reconnect.js.map +0 -1
  522. package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +0 -323
  523. package/dist/policy-packs/builtin/solution-acceptance-runtime.js +0 -672
  524. package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +0 -1
  525. package/dist/policy-packs/builtin/solution-acceptance.d.ts +0 -45
  526. package/dist/policy-packs/builtin/solution-acceptance.js +0 -226
  527. package/dist/policy-packs/builtin/solution-acceptance.js.map +0 -1
  528. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.d.ts +0 -25
  529. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js +0 -94
  530. package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js.map +0 -1
  531. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.d.ts +0 -35
  532. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js +0 -86
  533. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js.map +0 -1
  534. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.d.ts +0 -210
  535. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js +0 -361
  536. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js.map +0 -1
  537. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.d.ts +0 -304
  538. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +0 -734
  539. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +0 -1
  540. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.d.ts +0 -36
  541. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js +0 -73
  542. package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js.map +0 -1
  543. package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +0 -19
  544. package/dist/policy-packs/builtin/understanding-before-execution/index.js +0 -83
  545. package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +0 -1
  546. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.d.ts +0 -135
  547. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js +0 -618
  548. package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js.map +0 -1
  549. package/dist/policy-packs/builtin/understanding-before-execution/ledger.d.ts +0 -25
  550. package/dist/policy-packs/builtin/understanding-before-execution/ledger.js +0 -56
  551. package/dist/policy-packs/builtin/understanding-before-execution/ledger.js.map +0 -1
  552. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.d.ts +0 -20
  553. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js +0 -93
  554. package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js.map +0 -1
  555. package/dist/policy-packs/builtin/understanding-before-execution/markers.d.ts +0 -126
  556. package/dist/policy-packs/builtin/understanding-before-execution/markers.js +0 -245
  557. package/dist/policy-packs/builtin/understanding-before-execution/markers.js.map +0 -1
  558. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.d.ts +0 -29
  559. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js +0 -82
  560. package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js.map +0 -1
  561. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.d.ts +0 -71
  562. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js +0 -175
  563. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js.map +0 -1
  564. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.d.ts +0 -620
  565. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js +0 -1047
  566. package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js.map +0 -1
  567. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.d.ts +0 -128
  568. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js +0 -213
  569. package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js.map +0 -1
  570. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.d.ts +0 -129
  571. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js +0 -166
  572. package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js.map +0 -1
  573. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.d.ts +0 -164
  574. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js +0 -275
  575. package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js.map +0 -1
  576. package/dist/policy-packs/builtin/understanding-before-execution-runtime.d.ts +0 -1
  577. package/dist/policy-packs/builtin/understanding-before-execution-runtime.js +0 -10
  578. package/dist/policy-packs/builtin/understanding-before-execution-runtime.js.map +0 -1
  579. package/dist/policy-packs/builtin/understanding-before-execution.d.ts +0 -526
  580. package/dist/policy-packs/builtin/understanding-before-execution.js +0 -1074
  581. package/dist/policy-packs/builtin/understanding-before-execution.js.map +0 -1
  582. package/dist/policy-packs/permission-translator.d.ts +0 -9
  583. package/dist/policy-packs/permission-translator.js +0 -76
  584. package/dist/policy-packs/permission-translator.js.map +0 -1
  585. package/dist/runtime/action-envelope.d.ts +0 -64
  586. package/dist/runtime/action-envelope.js +0 -46
  587. package/dist/runtime/action-envelope.js.map +0 -1
  588. package/dist/runtime/approval-signing.d.ts +0 -111
  589. package/dist/runtime/approval-signing.js +0 -384
  590. package/dist/runtime/approval-signing.js.map +0 -1
  591. package/dist/runtime/bash-match-facts.d.ts +0 -60
  592. package/dist/runtime/bash-match-facts.js +0 -196
  593. package/dist/runtime/bash-match-facts.js.map +0 -1
  594. package/dist/runtime/bash-match-registry.d.ts +0 -112
  595. package/dist/runtime/bash-match-registry.js +0 -406
  596. package/dist/runtime/bash-match-registry.js.map +0 -1
  597. package/dist/runtime/bash-prefix-parse.d.ts +0 -31
  598. package/dist/runtime/bash-prefix-parse.js +0 -576
  599. package/dist/runtime/bash-prefix-parse.js.map +0 -1
  600. package/dist/runtime/command-normalize.d.ts +0 -658
  601. package/dist/runtime/command-normalize.js +0 -2410
  602. package/dist/runtime/command-normalize.js.map +0 -1
  603. package/dist/runtime/deletion-target-resolve.d.ts +0 -28
  604. package/dist/runtime/deletion-target-resolve.js +0 -1078
  605. package/dist/runtime/deletion-target-resolve.js.map +0 -1
  606. package/dist/runtime/destructive-shell-floor.d.ts +0 -19
  607. package/dist/runtime/destructive-shell-floor.js +0 -611
  608. package/dist/runtime/destructive-shell-floor.js.map +0 -1
  609. package/dist/runtime/environment-resolver.d.ts +0 -36
  610. package/dist/runtime/environment-resolver.js +0 -138
  611. package/dist/runtime/environment-resolver.js.map +0 -1
  612. package/dist/runtime/git-context.d.ts +0 -201
  613. package/dist/runtime/git-context.js +0 -422
  614. package/dist/runtime/git-context.js.map +0 -1
  615. package/dist/runtime/index.d.ts +0 -12
  616. package/dist/runtime/index.js +0 -13
  617. package/dist/runtime/index.js.map +0 -1
  618. package/dist/runtime/intercept.d.ts +0 -494
  619. package/dist/runtime/intercept.js +0 -1313
  620. package/dist/runtime/intercept.js.map +0 -1
  621. package/dist/runtime/kube-context.d.ts +0 -16
  622. package/dist/runtime/kube-context.js +0 -63
  623. package/dist/runtime/kube-context.js.map +0 -1
  624. package/dist/runtime/kubectl-target-parse.d.ts +0 -31
  625. package/dist/runtime/kubectl-target-parse.js +0 -249
  626. package/dist/runtime/kubectl-target-parse.js.map +0 -1
  627. package/dist/runtime/ledger-add.d.ts +0 -16
  628. package/dist/runtime/ledger-add.js +0 -150
  629. package/dist/runtime/ledger-add.js.map +0 -1
  630. package/dist/runtime/ledger-writer.d.ts +0 -27
  631. package/dist/runtime/ledger-writer.js +0 -46
  632. package/dist/runtime/ledger-writer.js.map +0 -1
  633. package/dist/runtime/pause-sentinel.d.ts +0 -60
  634. package/dist/runtime/pause-sentinel.js +0 -156
  635. package/dist/runtime/pause-sentinel.js.map +0 -1
  636. package/dist/runtime/pending-approval.d.ts +0 -23
  637. package/dist/runtime/pending-approval.js +0 -67
  638. package/dist/runtime/pending-approval.js.map +0 -1
  639. package/dist/runtime/read-only-bash.d.ts +0 -141
  640. package/dist/runtime/read-only-bash.js +0 -2204
  641. package/dist/runtime/read-only-bash.js.map +0 -1
  642. package/dist/runtime/recovery-git-commit.d.ts +0 -22
  643. package/dist/runtime/recovery-git-commit.js +0 -284
  644. package/dist/runtime/recovery-git-commit.js.map +0 -1
  645. package/dist/runtime/reject-malformed-session-id.d.ts +0 -8
  646. package/dist/runtime/reject-malformed-session-id.js +0 -16
  647. package/dist/runtime/reject-malformed-session-id.js.map +0 -1
  648. package/dist/runtime/risk-classifier.d.ts +0 -38
  649. package/dist/runtime/risk-classifier.js +0 -311
  650. package/dist/runtime/risk-classifier.js.map +0 -1
  651. package/dist/runtime/session-id.d.ts +0 -113
  652. package/dist/runtime/session-id.js +0 -193
  653. package/dist/runtime/session-id.js.map +0 -1
  654. package/dist/runtime/shell-word.d.ts +0 -62
  655. package/dist/runtime/shell-word.js +0 -410
  656. package/dist/runtime/shell-word.js.map +0 -1
  657. package/dist/runtime/task-providers/agent-tasks.d.ts +0 -103
  658. package/dist/runtime/task-providers/agent-tasks.js +0 -245
  659. package/dist/runtime/task-providers/agent-tasks.js.map +0 -1
  660. package/dist/runtime/when-eval.d.ts +0 -62
  661. package/dist/runtime/when-eval.js +0 -212
  662. package/dist/runtime/when-eval.js.map +0 -1
  663. package/dist/runtime/workflow-policies.d.ts +0 -207
  664. package/dist/runtime/workflow-policies.js +0 -596
  665. package/dist/runtime/workflow-policies.js.map +0 -1
  666. package/dist/schema/audit.d.ts +0 -71
  667. package/dist/schema/audit.js +0 -32
  668. package/dist/schema/audit.js.map +0 -1
  669. package/dist/schema/doctor.d.ts +0 -25
  670. package/dist/schema/doctor.js +0 -23
  671. package/dist/schema/doctor.js.map +0 -1
  672. package/dist/schema/environments.d.ts +0 -215
  673. package/dist/schema/environments.js +0 -101
  674. package/dist/schema/environments.js.map +0 -1
  675. package/dist/schema/extract.d.ts +0 -9
  676. package/dist/schema/extract.js +0 -86
  677. package/dist/schema/extract.js.map +0 -1
  678. package/dist/schema/permission-profiles.d.ts +0 -2292
  679. package/dist/schema/permission-profiles.js +0 -60
  680. package/dist/schema/permission-profiles.js.map +0 -1
  681. package/dist/schema/policies.d.ts +0 -974
  682. package/dist/schema/policies.js +0 -298
  683. package/dist/schema/policies.js.map +0 -1
  684. package/dist/schema/requires.d.ts +0 -131
  685. package/dist/schema/requires.js +0 -88
  686. package/dist/schema/requires.js.map +0 -1
  687. package/dist/schema/risk.d.ts +0 -144
  688. package/dist/schema/risk.js +0 -194
  689. package/dist/schema/risk.js.map +0 -1
  690. package/dist/schema/session-start-preflight.d.ts +0 -10
  691. package/dist/schema/session-start-preflight.js +0 -106
  692. package/dist/schema/session-start-preflight.js.map +0 -1
  693. package/dist/schema/stale-base-check.d.ts +0 -18
  694. package/dist/schema/stale-base-check.js +0 -37
  695. package/dist/schema/stale-base-check.js.map +0 -1
  696. package/dist/schema/toolchain-parity.d.ts +0 -21
  697. package/dist/schema/toolchain-parity.js +0 -48
  698. package/dist/schema/toolchain-parity.js.map +0 -1
  699. package/dist/schema/workflows.d.ts +0 -519
  700. package/dist/schema/workflows.js +0 -81
  701. package/dist/schema/workflows.js.map +0 -1
  702. package/scripts/runtime-reality-docker-probe.mjs +0 -71
@@ -1,43 +1,14 @@
1
- // D-004 (task 8f637efd, docs/decisions/2026-08-27-ug-auto-mode-approval.md,
2
- // "Amendment: install default"): the shipped `auto_approve` block, read
3
- // from the one canonical renderer so `harness init`, `harness pack
4
- // upgrade understanding-before-execution`, and `harness doctor`'s
5
- // missing-auto_approve finding cannot drift on the snippet's shape or
6
- // wording. See auto-approve-default.ts for the rationale.
7
- import { renderAutoApproveSnippet } from "../../policy-packs/builtin/understanding-before-execution-runtime.js";
8
- // Every template below nests `auto_approve:` at 6 spaces, a sibling of
9
- // `mode:` / `approval_lifecycle:` under the pack's `config:` key.
10
- const AUTO_APPROVE_SNIPPET = renderAutoApproveSnippet(6);
11
- // The `git-preflight` SessionStart hook's own generic `min_version`
12
- // floor, rendered below into FULL_TEMPLATE. Through task 6993d9b5 this
13
- // was the SAME constant as `harness doctor`'s
14
- // session_start_preflight.setup version check
15
- // (SESSION_START_PREFLIGHT_SETUP_BUILD_MIN_VERSION,
16
- // src/cli/doctor/session-start-preflight-setup-version.ts); split into
17
- // two independent constants by task 65952a0c
18
- // (docs/decisions/2026-09-08-preflight-floors.md) because the two
19
- // floors answer different questions and a future bump to one need not
20
- // move the other. Bump THIS constant when an agent-preflight release
21
- // changes something the `git-preflight` hook needs GENERICALLY
22
- // (independent of the opt-in `--setup` build step); bump the setup
23
- // floor instead when the change is `--setup`-specific. Both are
24
- // `"0.6.0"` today. `src/cli/init/dependencies.ts`'s wizard-facing
25
- // `preflight` dependency entry reads this SAME constant (not the setup
26
- // floor), so the wizard table can never advertise a floor lower than
27
- // what the generated manifest itself declares.
28
- export const GIT_PREFLIGHT_HOOK_MIN_VERSION = "0.6.0";
29
1
  export const MINIMAL_TEMPLATE = `# ~/.harness/harness.yaml (legacy: ~/.claude/harness.yaml)
30
2
  #
31
3
  # Bootstrapped by \`harness init --template minimal\`.
32
4
  #
33
5
  # This is the empty-but-valid manifest. Run \`harness validate\` to confirm it
34
- # parses, then add entries under the five top-level keys:
6
+ # parses, then add entries under the top-level keys:
35
7
  #
36
- # grounding: evidence-ledger + claim-gate config (see docs/ARCHITECTURE.md §2)
8
+ # grounding: evidence-ledger path for grounding-mcp (see docs/ARCHITECTURE.md §2)
37
9
  # tools: mcp / cli / skills / builtin inventory (§3)
38
10
  # memory: directories, retention, scopes (§4)
39
11
  # hooks: event-bound shell commands (§5)
40
- # policies: named rules that bind hooks to triggers (§6)
41
12
  #
42
13
  # Phase 2 verbs to add entries safely: \`harness add mcp <name> ...\`,
43
14
  # \`harness add cli\`, \`harness add hook\`, \`harness add skill\`.
@@ -51,18 +22,11 @@ version: 1
51
22
  export const FULL_TEMPLATE = `# ~/.harness/harness.yaml (legacy: ~/.claude/harness.yaml)
52
23
  #
53
24
  # Bootstrapped by \`harness init --template full\`. The reference manifest:
54
- # every example policy from docs/examples/full-manifest.yaml wired through
55
- # the generic \`harness policy intercept\` engine, so no external shell
56
- # scripts under ~/.claude/hooks/ are required.
57
- #
58
- # Canonical source for the policy + policy_packs sections is
59
- # docs/examples/full-manifest.yaml. A parity vitest
60
- # (tests/cli/init-full-template-parity.test.ts) fails the build if the
61
- # two diverge on policy names or load-bearing fields.
25
+ # grounding, the tool inventory, memory and the branch-protection policy
26
+ # pack. No policies and no policy-intercept hooks are written.
62
27
  #
63
28
  # What you still need on PATH (the wizard offers to \`npm i -g\` these on
64
- # init): agent-tasks-mcp-bridge, grounding-mcp, memory-router-*,
65
- # understanding-gate-claude-*.
29
+ # init): agent-tasks-mcp-bridge, grounding-mcp, memory-router-*.
66
30
 
67
31
  version: 1
68
32
 
@@ -72,8 +36,6 @@ grounding:
72
36
  id_format: "gs-{repo}-{rand:8}"
73
37
  evidence_ledger:
74
38
  path: ~/.evidence-ledger/ledger.db
75
- retention_days: 90
76
- policies_source: ~/.claude/harness.d/policies/claim-gate.yaml
77
39
 
78
40
  tools:
79
41
  mcp:
@@ -153,1135 +115,45 @@ memory:
153
115
  default: project
154
116
  allowed: [project, user]
155
117
 
156
- # All PreToolUse hooks share the generic \`harness policy intercept\` CLI
157
- # entrypoint. The engine reads the tool event on stdin, evaluates whichever
158
- # policy below has a matching trigger (\`match\` + optional \`bash_match\`),
159
- # and emits Claude Code's deny envelope when the required ledger tag is
160
- # absent. No external shell scripts are required.
161
- #
162
- # The \`git-preflight\` SessionStart hook is the producer side of the
163
- # \`preflight-before-*\` policies: \`harness session-start preflight\` runs
164
- # agent-preflight against the session cwd and, on a ready:true result,
165
- # records \`preflight:\${REPO}\` to the evidence ledger. It needs the
166
- # \`preflight\` binary on PATH (\`npm i -g @lannguyensi/agent-preflight\`); when
167
- # that is absent the hook logs to stderr and exits 0, so the session is
168
- # never broken — the preflight gates just stay closed until a tag is
169
- # produced some other way.
170
- hooks:
171
- - name: git-preflight
172
- event: SessionStart
173
- command: harness session-start preflight
174
- blocking: false
175
- # 70s budget gives the wrapped preflight (default 60s) headroom plus
176
- # ledger-write time. Was 30s through v0.17.4, but a healthy preflight
177
- # on a medium-size repo takes ~28s and the old 25s wrapper ceiling
178
- # blew through it. Bumped together with DEFAULT_PREFLIGHT_TIMEOUT_MS
179
- # (agent-tasks/7265599e).
180
- budget_ms: 70000
181
- # Floor raised to agent-preflight ${GIT_PREFLIGHT_HOOK_MIN_VERSION}
182
- # (was 0.2.0): 0.2.0 was the release that made secret
183
- # detection git-aware and diff-scoped: a gitignored+untracked .env,
184
- # a .md doc, a non-git dir, or a secret in a tracked file the branch
185
- # never touched is a non-blocking warn, not a hard fail. Pre-0.2.0
186
- # installs hard-fail preflight on the normal correct state (a
187
- # gitignored .env holding real credentials), so this SessionStart
188
- # producer never writes a preflight: tag and the preflight-before-*
189
- # policies stay closed forever on any repo with a local .env. (0.1.1
190
- # had already fixed the wrapper-script "tool not installed" false
191
- # positive.) ${GIT_PREFLIGHT_HOOK_MIN_VERSION} is also the release
192
- # that made \`session_start_preflight.setup\` build code, not only
193
- # install dependencies (agent-preflight PR #72, tag v0.6.0);
194
- # \`harness doctor\` warns independently, off its own floor, when an
195
- # existing manifest's own floor is stale
196
- # (src/cli/doctor/session-start-preflight-setup-version.ts), this
197
- # template bump only affects a freshly generated manifest.
198
- # version_command points at the source-of-truth preflight binary,
199
- # not at the \`harness session-start preflight\` wrapper.
200
- min_version: "${GIT_PREFLIGHT_HOOK_MIN_VERSION}"
201
- version_command: ["preflight", "--version"]
202
-
203
- # toolchain-parity (PATH-shim incident 2026-07-22 follow-up): writes THIS
204
- # machine's toolchain snapshot (node version, npm globals, OW-Kit
205
- # version, MCP server names) to \`toolchain_parity.machine_state_dir\`
206
- # and advisorily compares it against every peer machine's snapshot
207
- # already there, warning on drift (version mismatches, missing
208
- # packages, node/OW-Kit drift, MCP-name differences). Purely advisory —
209
- # no policy consumes the \`toolchain-parity:\` ledger fact this writes,
210
- # it exists for \`harness audit\`/operator visibility only. If a policy
211
- # ever does consume it, match with the \`:unparseable-peer:<n>\` suffix
212
- # in mind: requires-matching is substring-based, so a bare
213
- # \`toolchain-parity:ok\` tag would also match \`ok:unparseable-peer:2\`
214
- # (a partial comparison). DISABLED by
215
- # default (no \`toolchain_parity:\` block above): opt in with
216
- # \`toolchain_parity: { enabled: true }\` (machine_state_dir/profile/
217
- # workspace_root all have sane defaults — see docs/CLI.md). No external
218
- # binary to floor-check (node/npm are assumed present already), so
219
- # unlike git-preflight this hook carries no min_version/version_command.
220
- - name: toolchain-parity
221
- event: SessionStart
222
- command: harness session-start toolchain-parity
223
- blocking: false
224
- # node --version + npm ls -g run in PARALLEL (bounded ~2s/~4s each, so
225
- # max(2s,4s)=4s worst case for that pair), plus two near-instant file
226
- # reads; the ledger write runs SEQUENTIALLY after those and carries its
227
- # own timeout floor (resolveManifestLedgerWriter's default 5s absent an
228
- # explicit grounding-mcp health.timeout_ms or a bound
229
- # SessionStartToolchainParityOptions.ledgerTimeoutMs). Worst case is
230
- # therefore additive, ~4s + 5s = 9s, not the sub-5s the collectors alone
231
- # would suggest — 10s still clears it, but with only ~1s of margin, not
232
- # the "comfortable" headroom an earlier version of this comment claimed
233
- # (task c1b5ade5). Nowhere near git-preflight's 70s (which wraps a full
234
- # external test suite, a fundamentally heavier operation this hook
235
- # never performs).
236
- budget_ms: 10000
237
-
238
- # Budget note (task 7bf47554, follow-up to the ms/seconds unit fix
239
- # f2d2a29): every \`harness policy intercept\` hook below down through
240
- # \`risk-gate\` carries \`budget_ms: 15000\`, i.e. a Claude Code outer
241
- # kill-timeout of \`ceil(15000/1000) = 15\` seconds (generate-settings.ts's
242
- # \`hookTimeoutSeconds\`). This is deliberately UNIFORM across all thirteen
243
- # of them, for two independent reasons:
244
- #
245
- # 1. FAIL-CLOSED MARGIN. \`harness policy intercept\` evaluates its FULL
246
- # \`policies:\` list against the incoming event (src/runtime/intercept.ts,
247
- # \`intercept()\`), not just the one named policy this hook happens to
248
- # also register. Every policy in that evaluation loop that reaches a
249
- # verdict has its decision written to the evidence ledger via
250
- # \`options.ledger.record()\` BEFORE \`intercept()\` returns and stdout is
251
- # flushed (intercept.ts ~L1362-1377) — this includes \`operator_only\`
252
- # policies (the three kill-switch denies below), whose VERDICT needs no
253
- # ledger read but whose AUDIT WRITE is still a live grounding-mcp
254
- # round-trip on the critical path. A \`requires:\`-based policy (the
255
- # require-*-evidence / risk-gate policies) additionally QUERIES the
256
- # ledger for its verdict (intercept.ts's \`evaluateOnePolicy\`,
257
- # ~L752-777) and, on a \`deny-degraded\` outcome, may retry the audit
258
- # write once more on a fresh session (\`realLedgerClient\`,
259
- # src/cli/policy/intercept.ts ~L276-306). Measured worst case with the
260
- # grounding-mcp health.timeout_ms=5000 default: query (~5s) + one
261
- # fresh-session deny-degraded retry (initialize + ledger_add, each
262
- # bounded by \`auditRetryTimeoutMs(5000)\` ~=1.25s) is ~10.8-13.75s. If
263
- # Claude Code's outer timeout fires FIRST, it kills the subprocess
264
- # before the deny JSON reaches stdout — a hook that Claude Code cannot
265
- # read in time is treated as ALLOW, silently turning a computed,
266
- # fail-closed \`deny\`/\`deny-degraded\` verdict into an unintended
267
- # fail-open one. 15000ms clears the measured worst case with margin,
268
- # for BOTH the evidence-requiring policies (their own query+retry) AND
269
- # the pure pattern-deny policies (bounded lower, ~1x
270
- # health.timeout_ms=~5s via the mandatory record() alone, but still
271
- # above the pre-fix 1-2s floor).
272
- # 2. DEDUP-SAFETY. \`generate-settings.ts\`'s \`buildGroups\` collapses
273
- # multiple manifest hooks that share the same \`match\` (settings.json's
274
- # tool-name matcher — \`bash_match\` is NOT projected there) AND the same
275
- # \`(command, timeout)\` fingerprint into ONE settings.json hook entry,
276
- # specifically so Claude Code spawns \`harness policy intercept\` ONCE
277
- # per matching tool call instead of once per manifest hook name (the
278
- # comment on \`buildGroups\` names this explicitly: avoiding "redundant
279
- # Node bootstraps and ledger queries per tool call"). All nine
280
- # \`match: "Bash"\` hooks below share one settings.json matcher group;
281
- # giving them a NON-uniform budget_ms would make their computed
282
- # \`timeout\` values diverge, split that one group into several entries,
283
- # and reintroduce exactly the redundant-invocation cost the dedup
284
- # exists to avoid — on top of leaving whichever entry keeps a low
285
- # timeout still exposed to the fail-open risk above. Keeping all
286
- # thirteen at the identical 15000ms budget_ms preserves the existing
287
- # one-invocation-per-matcher-group collapse (previously they all
288
- # collapsed onto the shared 2s floor; now they collapse onto 15s).
289
- - name: require-review-evidence
290
- event: PreToolUse
291
- match: "mcp__agent-tasks__pull_requests_merge"
292
- command: harness policy intercept
293
- blocking: hard
294
- budget_ms: 15000
295
-
296
- # Tool-agnostic parallel of require-review-evidence for operators on the
297
- # gh-cli workflow (\`gh pr merge\`) instead of agent-tasks MCP. Same generic
298
- # \`harness policy intercept\` entrypoint; the matching review-before-merge-bash
299
- # policy below picks up the trigger. A PolicyTrigger can only AND-match one
300
- # surface (MCP tool-name OR Bash command), so two parallel definitions are
301
- # the minimum-scope way to cover both PR surfaces without bumping the schema.
302
- - name: require-review-evidence-bash
303
- event: PreToolUse
304
- match: "Bash"
305
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*gh pr merge\\b'
306
- command: harness policy intercept
307
- blocking: hard
308
- budget_ms: 15000
309
-
310
- # The two OTHER agent-tasks verbs that land a PR (task 2699b476).
311
- # \`pull_requests_merge\` is not the only merge surface the MCP server
312
- # exposes: \`task_merge\` merges the PR attached to a task, and
313
- # \`task_finish\` with \`autoMerge: true\` merges as part of finishing
314
- # (both of its auto-merge modes, the soloMode work claim and the review
315
- # claim + approve). Each needs its OWN hook entry because a hook's
316
- # \`match\` is what \`harness apply\` projects into settings.json's
317
- # tool-name matcher, and a matcher for \`pull_requests_merge\` never
318
- # spawns \`harness policy intercept\` for either of these. Same
319
- # 15000ms budget_ms as every other blocking intercept hook, for the
320
- # same two reasons the note above gives.
321
- - name: require-review-evidence-task-merge
322
- event: PreToolUse
323
- match: "mcp__agent-tasks__task_merge"
324
- command: harness policy intercept
325
- blocking: hard
326
- budget_ms: 15000
327
-
328
- - name: require-review-evidence-task-finish
329
- event: PreToolUse
330
- match: "mcp__agent-tasks__task_finish"
331
- command: harness policy intercept
332
- blocking: hard
333
- budget_ms: 15000
334
-
335
- - name: require-dogfood-evidence
336
- event: PreToolUse
337
- match: "Bash"
338
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*(npm publish\\b|git( -C \\S+)* tag v)'
339
- command: harness policy intercept
340
- blocking: hard
341
- budget_ms: 15000
342
-
343
- - name: require-preflight-evidence
344
- event: PreToolUse
345
- match: "Bash"
346
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*git( -C \\S+)* (status|log|diff|branch)\\b'
347
- command: harness policy intercept
348
- blocking: hard
349
- budget_ms: 15000
350
-
351
- - name: require-review-subagent-evidence
352
- event: PreToolUse
353
- match: "mcp__agent-tasks__pull_requests_create"
354
- command: harness policy intercept
355
- blocking: hard
356
- budget_ms: 15000
357
-
358
- # Bash-surface parallel of require-review-subagent-evidence for operators
359
- # who open PRs with \`gh pr create\` instead of agent-tasks MCP. The matching
360
- # review-subagent-before-pr-create-bash policy below tags by branch
361
- # (\`review-subagent:\${BRANCH}\`) because no task UUID is in \`gh pr create\`
362
- # arguments; the working branch is the closest stable handle for "the
363
- # PR-in-progress" at this point in the cycle.
364
- - name: require-review-subagent-evidence-bash
365
- event: PreToolUse
366
- match: "Bash"
367
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*gh pr create\\b'
368
- command: harness policy intercept
369
- blocking: hard
370
- budget_ms: 15000
371
-
372
- - name: require-preflight-push-evidence
373
- event: PreToolUse
374
- match: "Bash"
375
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*git( -C \\S+)* push\\b'
376
- command: harness policy intercept
377
- blocking: hard
378
- budget_ms: 15000
379
-
380
- # deny-kill-switch-bash / deny-session-env-strip-bash / deny-sentinel-write-bash
381
- # (task cf1fde6d): \`harness pause\` / \`harness resume\` refuse to run inside an
382
- # agent shell in CODE, but that CLI check is a speed bump, not a boundary: a
383
- # Claude Code \`! \`-prefixed shell inherits this session's env AND its non-TTY
384
- # stdin, so it is indistinguishable from an agent Bash call and trips the same
385
- # check the agent would trip (verified live; see
386
- # docs/okf/pause-vs-gate-kill-switch.md). The actual enforcement point that
387
- # runs BEFORE the agent's Bash executes is this PreToolUse deny-policy layer.
388
- # These three hooks/policies below deny, from Bash: the kill-switch verbs
389
- # themselves, the env-stripping wrappers that would otherwise defeat
390
- # \`refuseIfAgentShell\`, and direct writes to the unsigned pause sentinel file.
391
- - name: deny-kill-switch-bash
392
- event: PreToolUse
393
- match: "Bash"
394
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S*\\s+)*(?:npx\\s+|\\S*/)?harness\\s+(["\\x27]?)(?:pause|resume|gate\\s+(["\\x27]?)(?:disable|enable)\\4)\\3(?![\\w-])'
395
- command: harness policy intercept
396
- blocking: hard
397
- # 15000, not a smaller pattern-only budget: see the budget note above
398
- # require-review-evidence. This policy's own verdict (operator_only)
399
- # needs no ledger read, but intercept()'s audit-record call for that
400
- # verdict is still a live grounding-mcp round-trip on the critical
401
- # path, AND this hook shares its settings.json matcher group with the
402
- # evidence-requiring Bash hooks above (dedup-safety).
403
- budget_ms: 15000
404
-
405
- - name: deny-session-env-strip-bash
406
- event: PreToolUse
407
- match: "Bash"
408
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S*\\s+)*(env\\b[^;\\n|&]*-u\\s*(CLAUDE_CODE_SESSION_ID|CLAUDE_SESSION_ID|CODEX_SESSION_ID)\\b|env\\b[^;\\n|&]*--unset(?:=|\\s+)(CLAUDE_CODE_SESSION_ID|CLAUDE_SESSION_ID|CODEX_SESSION_ID)\\b|unset\\s+(\\S+\\s+)*(CLAUDE_CODE_SESSION_ID|CLAUDE_SESSION_ID|CODEX_SESSION_ID)\\b|(CLAUDE_CODE_SESSION_ID|CLAUDE_SESSION_ID|CODEX_SESSION_ID)=(?=\\s))'
409
- command: harness policy intercept
410
- blocking: hard
411
- # 15000: same rationale as deny-kill-switch-bash immediately above.
412
- budget_ms: 15000
413
-
414
- # Known gap, deliberately not faked as coverage: this only catches the
415
- # obvious shell shapes (\`> .harness-paused\`, \`tee .harness-paused\`,
416
- # \`cp ... .harness-paused\`). A regex over the raw command string cannot
417
- # see through a heredoc, \`sh -c '...'\`, \`bash -lc\`, \`eval\`,
418
- # \`python -c\`, base64-decoded payloads, an fs.write call inside a script
419
- # file the agent creates and then executes, a symlink swap, or the
420
- # sentinel-write equivalents of \`cp\`/\`>\` done via \`mv\`, \`ln\`,
421
- # \`install\`, or \`dd\`. These are NOT covered on purpose (regex whack-a-
422
- # mole against every file-write-capable tool does not meaningfully close
423
- # this class); closing it for real needs either signing the sentinel
424
- # (HMAC) or a filesystem-level write guard, neither of which is in scope
425
- # here; both are noted as follow-ups.
426
- - name: deny-sentinel-write-bash
427
- event: PreToolUse
428
- match: "Bash"
429
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S*\\s+)*(tee|cp)\\b[^;\\n|&]*\\.harness-paused\\b|>{1,2}\\s*\\S*\\.harness-paused\\b'
430
- command: harness policy intercept
431
- blocking: hard
432
- # 15000: same rationale as deny-kill-switch-bash above.
433
- budget_ms: 15000
434
-
435
- # risk-gate (Phase 7 #6): the Risk Gate enforcement hook. The
436
- # gate-prod-destructive policies below reference it. Same generic
437
- # \`harness policy intercept\` entrypoint as every other policy hook;
438
- # the interceptor builds the Action Envelope, classifies risk against
439
- # \`risk.classifiers[]\`, resolves the environment against
440
- # \`environments.resolvers[]\`, and evaluates the policies' \`when:\`.
441
- - name: risk-gate
442
- event: PreToolUse
443
- match: "Bash"
444
- command: harness policy intercept
445
- blocking: hard
446
- # 15000: same rationale as the budget note above require-review-evidence.
447
- budget_ms: 15000
448
-
449
- # Optional: runtime-reality drift gate (NOT enabled by default).
450
- # Blocks destructive runtime commands (compose down/restart, systemctl,
451
- # kill/pkill, ./deploy-*) when the live process state has drifted from what
452
- # your expectations file says should be running. Left COMMENTED on purpose:
453
- # the hook is host-coupled and, without RUNTIME_REALITY_KEYWORD + an
454
- # expectations file + RUNTIME_REALITY_PROBE_CMD, degrades silently to allow,
455
- # a no-op that looks like protection. To arm it, uncomment the entry and
456
- # fill in the three env values. The expectations-file format and how to
457
- # install the probe are documented in docs/runtime-reality-hook.md.
458
- #
459
- # - name: runtime-reality
460
- # event: PreToolUse
461
- # command: >-
462
- # RUNTIME_REALITY_KEYWORD=<your-stack>
463
- # RUNTIME_REALITY_EXPECTATIONS_DIR=$HOME/.runtime-reality/expectations
464
- # RUNTIME_REALITY_PROBE_CMD="node $HOME/.runtime-reality/probes/runtime-reality-docker-probe.mjs"
465
- # harness pack hook runtime-reality
466
- # blocking: hard
467
- # description: Block destructive runtime commands on critical process drift
468
-
469
- policies:
470
- - name: review-before-merge
471
- description: Block PR merges unless a ledger entry tagged review:<pr-number> exists for this session.
472
- trigger:
473
- event: PreToolUse
474
- match: "mcp__agent-tasks__pull_requests_merge"
475
- extract:
476
- PR_NUMBER: "toolArgs.prNumber"
477
- requires:
478
- ledger_tag: "review:\${PR_NUMBER}"
479
- hook: require-review-evidence
480
- enforcement: block
481
- producers:
482
- - kind: mcp
483
- verb: mcp__grounding-mcp__ledger_add
484
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"review:\${PR_NUMBER} — <verdict + key findings + nits>", source:"Agent(general-purpose) review"}'
485
- description: Spawn a review subagent against the PR diff, capture its verdict, then persist a ledger entry tagged with the PR number. The content should be self-contained enough for an auditor to read without re-opening the chat.
486
- ux:
487
- cannot: "You cannot merge PR #\${PR_NUMBER} yet."
488
- required:
489
- - "a recorded review of PR #\${PR_NUMBER}"
490
- run:
491
- - 'harness record review --pr \${PR_NUMBER} "<summary>"'
492
-
493
- # Bash-surface parallel of review-before-merge for operators on the gh-cli
494
- # workflow. Two scope notes:
495
- # 1. Tag shape: \`review:\${BRANCH}\` instead of \`review:\${PR_NUMBER}\`. The
496
- # \`gh pr merge\` invocation can target the PR by number, by URL, or by
497
- # the current branch (default), and PR_NUMBER is not extractable from
498
- # \`tool_input.command\` with today's JSONPath-only extract DSL. BRANCH
499
- # is the stable identifier the producer can record at review time.
500
- # 2. This sits ALONGSIDE review-before-merge — not as a replacement. An
501
- # operator using both surfaces (e.g. agent-tasks MCP for most repos
502
- # + gh-cli for a quick hotfix) will have both gates active, each with
503
- # its own tag shape, which is semantically honest.
504
- - name: review-before-merge-bash
505
- description: Block \`gh pr merge\` unless a ledger entry tagged review:<branch> exists for this session.
506
- trigger:
507
- event: PreToolUse
508
- match: "Bash"
509
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*gh pr merge\\b'
510
- requires:
511
- ledger_tag: "review:\${BRANCH}"
512
- hook: require-review-evidence-bash
513
- enforcement: block
514
- producers:
515
- - kind: mcp
516
- verb: mcp__grounding-mcp__ledger_add
517
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"review:\${BRANCH} — <verdict + key findings + nits>", source:"Agent(general-purpose) review"}'
518
- description: Spawn a review subagent against the branch diff, capture its verdict, then persist a ledger entry tagged with the branch name. Mirror of the review-before-merge producer for the gh-cli surface.
519
- ux:
520
- cannot: "You cannot merge the PR for branch \${BRANCH} via \`gh pr merge\` yet."
521
- required:
522
- - "a recorded review of the PR for branch \${BRANCH}"
523
- run:
524
- - 'harness record review --pr <pr> "<summary>"'
525
-
526
- # The two agent-tasks verbs that ALSO land a PR (task 2699b476, closing
527
- # the residual 99f47307 Slice 1 named twice in the CHANGELOG). Same
528
- # shape as review-before-merge, three scope notes:
529
- # 1. Tag shape: \`review:\${TASK_ID}\` rather than \`review:\${PR_NUMBER}\`.
530
- # Both verbs are task-scoped: they derive owner/repo/PR number from
531
- # the task, so \`taskId\` is the only identifier in the tool payload.
532
- # \`harness record review --pr <pr> --task <id> "<summary>"\` writes
533
- # the PR, branch, base AND task tags in ONE ledger fact, so a single
534
- # recorded review satisfies all four merge gates at once.
535
- # 2. task_finish is gated ONLY in its auto-merge mode. The verb is
536
- # polymorphic: a plain \`task_finish\` advances the task and merges
537
- # nothing, while \`autoMerge: true\` merges the PR (both modes do,
538
- # the soloMode work claim and the review claim + approve). Gating
539
- # the whole verb would block the ordinary finish call for no reason;
540
- # \`input_match\` narrows the trigger to the merging mode alone.
541
- # A missing \`autoMerge\` never matches, so an omitted argument
542
- # leaves the gate out of the way rather than arming it.
543
- # 3. These sit ALONGSIDE review-before-merge / -bash, same rationale
544
- # as the bash variant above: an operator may use any of the four
545
- # merge surfaces, and each carries its own tag shape.
546
- - name: review-before-task-merge
547
- description: Block agent-tasks task_merge unless a ledger entry tagged review:<task-id> exists for this session.
548
- trigger:
549
- event: PreToolUse
550
- match: "mcp__agent-tasks__task_merge"
551
- extract:
552
- TASK_ID: "toolArgs.taskId"
553
- requires:
554
- ledger_tag: "review:\${TASK_ID}"
555
- hook: require-review-evidence-task-merge
556
- enforcement: block
557
- producers:
558
- - kind: mcp
559
- verb: mcp__grounding-mcp__ledger_add
560
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"review:\${TASK_ID}: <verdict + key findings + nits>", source:"Agent(general-purpose) review"}'
561
- description: Spawn a review subagent against the PR diff, capture its verdict, then persist a ledger entry tagged with the task id. Mirror of the review-before-merge producer for the task-scoped merge surface.
562
- ux:
563
- cannot: "You cannot merge the PR for task \${TASK_ID} yet."
564
- required:
565
- - "a recorded review of task \${TASK_ID}"
566
- run:
567
- - 'harness record review --pr <pr> --task \${TASK_ID} "<summary>"'
568
-
569
- - name: review-before-task-finish-automerge
570
- description: 'Block agent-tasks task_finish with autoMerge: true unless a ledger entry tagged review:<task-id> exists for this session.'
571
- trigger:
572
- event: PreToolUse
573
- match: "mcp__agent-tasks__task_finish"
574
- input_match:
575
- toolArgs.autoMerge: true
576
- extract:
577
- TASK_ID: "toolArgs.taskId"
578
- requires:
579
- ledger_tag: "review:\${TASK_ID}"
580
- hook: require-review-evidence-task-finish
581
- enforcement: block
582
- producers:
583
- - kind: mcp
584
- verb: mcp__grounding-mcp__ledger_add
585
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"review:\${TASK_ID}: <verdict + key findings + nits>", source:"Agent(general-purpose) review"}'
586
- description: Spawn a review subagent against the PR diff, capture its verdict, then persist a ledger entry tagged with the task id. Same evidence the task_merge gate reads, so one recorded review opens both.
587
- ux:
588
- cannot: "You cannot finish task \${TASK_ID} with autoMerge yet."
589
- required:
590
- - "a recorded review of task \${TASK_ID}"
591
- run:
592
- - 'harness record review --pr <pr> --task \${TASK_ID} "<summary>"'
593
-
594
- - name: dogfood-before-release
595
- description: Block npm publish / git tag v* without a recent dogfood ledger entry.
596
- trigger:
597
- event: PreToolUse
598
- match: "Bash"
599
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*(npm publish\\b|git( -C \\S+)* tag v)'
600
- requires:
601
- ledger_tag: "dogfood:\${SESSION_ID}"
602
- within: 24h
603
- hook: require-dogfood-evidence
604
- enforcement: block
605
- producers:
606
- - kind: mcp
607
- verb: mcp__grounding-mcp__ledger_add
608
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"dogfood:\${SESSION_ID} — <end-to-end smoke summary against the live system>", source:"manual smoke test"}'
609
- description: Before tagging or publishing, run the release path end-to-end against the live system (not just unit tests) and persist the result as a session-tagged ledger entry. Document what you exercised (install, CLI happy path, MCP handshake, etc.) so a future auditor can tell whether the smoke covered the change.
610
- ux:
611
- cannot: "You cannot publish a release yet."
612
- required:
613
- - "an end-to-end dogfood run in this session"
614
- run:
615
- - 'harness record dogfood "<was wurde real ausprobiert>"'
616
-
617
- - name: two-reviewers-required
618
- description: At least two distinct reviewer ledger entries must exist for the PR.
619
- trigger:
620
- event: PreToolUse
621
- match: "mcp__agent-tasks__pull_requests_merge"
622
- extract:
623
- PR_NUMBER: "toolArgs.prNumber"
624
- requires:
625
- ledger_tag: "review:\${PR_NUMBER}"
626
- count:
627
- min: 2
628
- hook: require-review-evidence
629
- enforcement: warn
630
- producers:
631
- - kind: mcp
632
- verb: mcp__grounding-mcp__ledger_add
633
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"review:\${PR_NUMBER} — <verdict + key findings + nits>", source:"Agent(general-purpose) review (reviewer 2)"}'
634
- description: Same shape as review-before-merge but TWO DISTINCT reviewer entries must exist before the gate is satisfied (count.min 2). Distinguish reviewers by source so the count is honest. Warn-level enforcement, so the agent CAN merge with one reviewer but should consider spawning a second for load-bearing changes.
635
-
636
- - name: preflight-before-investigation
637
- description: Block investigative git reads (status/log/diff/branch) when agent-preflight has not run recently with ready:true for the current repo.
638
- trigger:
639
- event: PreToolUse
640
- match: "Bash"
641
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*git( -C \\S+)* (status|log|diff|branch)\\b'
642
- requires:
643
- ledger_tag: "preflight:\${REPO}"
644
- within: 1h
645
- hook: require-preflight-evidence
646
- enforcement: block
647
- producers:
648
- - kind: bash
649
- command: harness session-start preflight
650
- description: Runs agent-preflight against the current cwd; on ready:true, records preflight:\${REPO} to the ledger. Standard producer.
651
- - kind: mcp
652
- verb: mcp__grounding-mcp__ledger_add
653
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"preflight:\${REPO}", source:"manual"}'
654
- description: Direct ledger write. Use when the Bash hook is locked down (e.g. understanding-gate active) or when the standard producer is unavailable.
655
- ux:
656
- cannot: "You cannot investigate this repository yet."
657
- required:
658
- - "verified repository preflight"
659
- - "an approved Understanding Report, if the Understanding Gate is still active (it blocks \`harness preflight\` itself)"
660
- run:
661
- - "harness preflight"
662
-
663
- - name: review-subagent-before-pr-create
664
- description: Block agent-tasks PR creation unless a review-subagent ledger entry tagged for this task already exists. Forces the rigorous review BEFORE the PR opens, not after.
665
- trigger:
666
- event: PreToolUse
667
- match: "mcp__agent-tasks__pull_requests_create"
668
- extract:
669
- TASK_ID: "toolArgs.taskId"
670
- requires:
671
- ledger_tag: "review-subagent:\${TASK_ID}"
672
- hook: require-review-subagent-evidence
673
- enforcement: block
674
- producers:
675
- - kind: mcp
676
- verb: mcp__grounding-mcp__ledger_add
677
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"review-subagent:\${TASK_ID} — <verdict + key findings + nits>", source:"Agent(general-purpose) review"}'
678
- description: After running a review subagent against the staged diff, persist its verdict + load-bearing findings as a ledger entry tagged with the task UUID. The content should be self-contained enough to audit later without re-reading the chat.
679
- ux:
680
- cannot: "You cannot open a pull request for task \${TASK_ID} yet."
681
- required:
682
- - "a completed review-subagent pass on this task"
683
- run:
684
- - 'harness record review-subagent --task \${TASK_ID} --verdict <verdict>'
685
-
686
- # Bash-surface parallel of review-subagent-before-pr-create. Tag shape is
687
- # \`review-subagent:\${BRANCH}\` because TASK_ID is an agent-tasks-only
688
- # concept; for the gh-cli workflow the working branch is the closest stable
689
- # handle for "the PR-in-progress" at this point. Same rationale as
690
- # review-before-merge-bash: sits alongside the MCP variant, not as a
691
- # replacement.
692
- - name: review-subagent-before-pr-create-bash
693
- description: Block \`gh pr create\` unless a review-subagent ledger entry tagged review-subagent:<branch> exists for this session. Forces the rigorous review BEFORE the PR opens.
694
- trigger:
695
- event: PreToolUse
696
- match: "Bash"
697
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*gh pr create\\b'
698
- requires:
699
- ledger_tag: "review-subagent:\${BRANCH}"
700
- hook: require-review-subagent-evidence-bash
701
- enforcement: block
702
- producers:
703
- - kind: mcp
704
- verb: mcp__grounding-mcp__ledger_add
705
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"review-subagent:\${BRANCH} — <verdict + key findings + nits>", source:"Agent(general-purpose) review"}'
706
- description: After running a review subagent against the staged diff for the working branch, persist its verdict + load-bearing findings as a ledger entry tagged with the branch name. Mirror of the review-subagent-before-pr-create producer for the gh-cli surface.
707
- ux:
708
- cannot: "You cannot open a pull request for branch \${BRANCH} via \`gh pr create\` yet."
709
- required:
710
- - "a completed review-subagent pass on branch \${BRANCH}"
711
- run:
712
- - 'harness record review-subagent --task <task-id> --verdict <verdict>'
713
-
714
- - name: preflight-before-push
715
- description: Block git push unless a fresh preflight ledger entry exists for the current branch. Catches the stale-checkout class of incident at the last reversible step.
716
- trigger:
717
- event: PreToolUse
718
- match: "Bash"
719
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*git( -C \\S+)* push\\b'
720
- requires:
721
- ledger_tag: "preflight:\${BRANCH}"
722
- within: 10m
723
- # at_head:true lets a preflight at the current HEAD satisfy the
724
- # gate at any age (the standard producer writes head:<sha> into
725
- # the tag content). The 10m window remains the freshness ceiling
726
- # for the head-mismatch case (operator switched branch, preflight
727
- # predates HEAD shift, runtime couldn't resolve a sha).
728
- at_head: true
729
- hook: require-preflight-push-evidence
730
- enforcement: block
731
- producers:
732
- - kind: bash
733
- command: harness session-start preflight
734
- description: Runs agent-preflight against the current cwd; on ready:true, records preflight:\${BRANCH} ready:true confidence:<n> head:<sha> to the ledger. Standard producer.
735
- - kind: mcp
736
- verb: mcp__grounding-mcp__ledger_add
737
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"preflight:\${BRANCH} head:<full-sha> — <summary of what is on the branch + smoke results>", source:"manual"}'
738
- description: Direct ledger write. Include head:<full-sha> if you want the entry to count under at_head; the branch is the WIP review surface and the content should summarise what is staged + the smoke evidence so a reviewer can audit later without re-reading the chat.
739
- ux:
740
- cannot: "You cannot push branch \${BRANCH} yet."
741
- required:
742
- - "a preflight for \${BRANCH} at the current HEAD (any age) OR any preflight within the last 10 minutes. Re-run \`harness preflight\` if you committed since the last preflight AND it has been more than 10 minutes."
743
- - "if solution-acceptance is enabled, a ready HEAD-pinned verdict at the SAME commit too (run \`solution_evaluate\`). \`git push\` trips both gates, so commit first if the tree is dirty, then satisfy both at one HEAD."
744
- - "an approved Understanding Report, if the Understanding Gate is still active (it blocks \`harness preflight\` itself)"
745
- run:
746
- - "harness preflight"
747
-
748
- # Phase 7 Risk Gate — the canonical built-in worked example. These two
749
- # policies, with the dangerous-shell classifier and production-signals
750
- # resolver below, are the Risk Gate's default stance: a destructive
751
- # shell action whose target environment resolves to production is
752
- # gated before the runtime fires it. Both fire ONLY when the
753
- # environment resolves to production (a main / release branch, a
754
- # prod-looking DATABASE_URL, or a prod kube context); on an ordinary
755
- # feature branch the environment is unknown and neither fires. Ordered
756
- # deny-first so a critical action (which also matches the high
757
- # threshold) gets the hard-deny envelope. See docs/risk-gate.md.
758
- - name: gate-prod-destructive
759
- description: Deny critical-severity destructive shell actions against a production target.
760
- trigger:
761
- event: PreToolUse
762
- match: "Bash"
763
- when:
764
- risk.severity_at_least: critical
765
- environment.name: production
766
- requires:
767
- ledger_tag: "risk-override:\${SESSION_ID}"
768
- hook: risk-gate
769
- enforcement: block
770
- # Operator-in-the-loop gate: the override tag is written by the
771
- # operator verb (ask semantics), not by the agent. See
772
- # writing-custom-policies.md, tripwire 4 (the trust model).
773
- producers:
774
- - kind: ask
775
- command: harness approve risk --force <reason>
776
- description: Deliberate operator override for a critical production mutation; run from the operator shell.
777
- - kind: mcp
778
- verb: mcp__grounding-mcp__ledger_add
779
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"risk-override:\${SESSION_ID} — operator-authorized <reason>", source:"operator"}'
780
- description: Recovery path if the approve verb is unavailable; only meaningful when the OPERATOR authorizes the content.
781
- ux:
782
- cannot: "You cannot run this critical destructive action against production."
783
- required:
784
- - "a deliberate operator override: a critical production mutation has no benign reading"
785
- run:
786
- - "Choose a non-destructive alternative, or ask the OPERATOR to run the command themselves, outside the agent."
787
- - "Operator override (deliberate): the OPERATOR runs \`harness approve risk --force <reason>\` from their own shell (\`! \` prefix in Claude Code, with --i-am-the-operator to acknowledge a non-TTY invocation)."
788
- - name: gate-prod-destructive-approval
789
- description: Require operator approval for high-severity destructive shell actions against a production target.
790
- trigger:
791
- event: PreToolUse
792
- match: "Bash"
793
- when:
794
- risk.severity_at_least: high
795
- environment.name: production
796
- requires:
797
- ledger_tag: "risk-approved:\${SESSION_ID}"
798
- hook: risk-gate
799
- enforcement: require_approval
800
- producers:
801
- - kind: ask
802
- command: harness approve risk
803
- description: Operator approves this Risk Gate decision from their own shell.
804
- - kind: mcp
805
- verb: mcp__grounding-mcp__ledger_add
806
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"risk-approved:\${SESSION_ID} — operator-authorized", source:"operator"}'
807
- description: Recovery path if the approve verb is unavailable; only meaningful when the OPERATOR authorizes the content.
808
- ux:
809
- cannot: "You cannot run this destructive production action yet."
810
- required:
811
- - "operator approval of this Risk Gate decision"
812
- run:
813
- - "harness approve risk"
814
-
815
- # gate-dev-unsafe-deletion (task d03af8f6): the two policies above fire
816
- # ONLY when the environment resolves to production — on an ordinary
817
- # task branch (environment: unknown) a deletion command runs
818
- # unconfirmed even when its target is a stray variable or a relative
819
- # path pointing somewhere unintended. This policy is deliberately
820
- # environment-INDEPENDENT (no environment.name clause) and gates on the
821
- # new \`action.deletion_target_unresolvable\` clause instead of
822
- # \`risk.severity_at_least\`/\`risk.category_in\` specifically because
823
- # those fail-close to matched=true for ANY unclassified action —
824
- # unscoped, that would gate every unrelated unclassified Bash call in
825
- # every environment. \`action.deletion_target_unresolvable\` only fires
826
- # for a recognized deletion verb (\`rm -r*\`/\`-f*\`, \`find ... -delete\`,
827
- # \`git clean -f*\`) whose target(s) cannot be statically proven inside
828
- # \`risk.safe_deletion_roots\` (below). See docs/risk-gate.md.
829
- #
830
- # This policy consults its OWN ledger tag
831
- # (\`risk-approved:deletion:\${SESSION_ID}\`), never the tag
832
- # \`gate-prod-destructive-approval\` above consults — a routine dev-
833
- # context deletion approval must not also clear the production
834
- # approval gate. \`harness approve risk --scope deletion\` writes this
835
- # tag; the bare \`harness approve risk\` (no \`--scope\`) keeps writing
836
- # only the production tag. See CHANGELOG.md task d03af8f6 for the
837
- # measured incident this fixed.
838
- - name: gate-dev-unsafe-deletion
839
- description: Require approval for a deletion-verb command whose target cannot be statically proven safe, in every environment.
840
- trigger:
841
- event: PreToolUse
842
- match: "Bash"
843
- when:
844
- action.deletion_target_unresolvable: true
845
- requires:
846
- ledger_tag: "risk-approved:deletion:\${SESSION_ID}"
847
- hook: risk-gate
848
- enforcement: require_approval
849
- producers:
850
- - kind: ask
851
- command: harness approve risk --scope deletion
852
- description: Operator approves this Risk Gate decision from their own shell.
853
- - kind: mcp
854
- verb: mcp__grounding-mcp__ledger_add
855
- example: '{sessionId:"\${SESSION_ID}", type:"fact", content:"risk-approved:deletion:\${SESSION_ID} — operator-authorized", source:"operator"}'
856
- description: Recovery path if the approve verb is unavailable; only meaningful when the OPERATOR authorizes the content.
857
- ux:
858
- cannot: "You cannot run this deletion command yet — its target cannot be statically proven safe."
859
- required:
860
- - "operator approval of this Risk Gate decision, OR an absolute target inside a declared risk.safe_deletion_roots entry"
861
- run:
862
- - "harness approve risk --scope deletion"
863
- - "Or point the command at a path under risk.safe_deletion_roots (default: /tmp, /private/tmp) instead of an unresolved variable, relative path, or traversal."
864
-
865
- # deny-kill-switch-bypass / deny-session-env-strip / deny-pause-sentinel-forgery
866
- # (task cf1fde6d): \`harness pause\`/\`harness resume\` refuse to run inside an
867
- # agent shell in CODE, but that CLI check (refuseIfAgentShell / refuseIfNonTTY
868
- # in src/cli/pause/index.ts) is a speed bump, not a boundary: a Claude Code
869
- # \`! \`-prefixed shell inherits this session's env AND its non-TTY stdin, so
870
- # it is indistinguishable from an agent Bash call and trips the same checks
871
- # (verified live; docs/okf/pause-vs-gate-kill-switch.md). This PreToolUse
872
- # layer is the enforcement point that actually runs BEFORE the agent's Bash
873
- # executes.
874
- #
875
- # UPDATE (task 2cc73f55, closes the gap the HONESTY NOTE below used to
876
- # document): these three now declare \`operator_only: true\` instead of a
877
- # requires.ledger_tag. Every requires:-based policy in this engine is, by
878
- # construction, satisfiable by the SAME agent it gates: nothing stops it
879
- # from calling mcp__grounding-mcp__ledger_add with content matching the
880
- # tag for its own session before running the denied command, which used to
881
- # flip deny to allow (src/runtime/intercept.ts, the satisfied-requires
882
- # branch). \`operator_only: true\` closes that specific hole: the policy
883
- # declares NO requires: at all, and intercept() short-circuits to an
884
- # unconditional deny before the requires pipeline runs — no ledger query,
885
- # no template substitution, so no ledger write, marker file, or flag can
886
- # ever flip it to allow. See docs/writing-custom-policies.md tripwire 4 and
887
- # the "Operator-only unconditional deny" section for the schema contract,
888
- # and tests/cli/init-full-template-kill-switch-deny.test.ts for a test that
889
- # forges every ledger-evidence shape available to intercept() and asserts
890
- # the block holds.
891
- #
892
- # RESIDUAL GAP (still open, out of scope for task 2cc73f55): bash_match is
893
- # still a regex over the raw command string, matched BEFORE evaluation ever
894
- # reaches operator_only:, so it still cannot see through a heredoc,
895
- # \`sh -c '...'\`, \`eval\`, a base64-decoded payload, or a script file the
896
- # agent writes and then executes — an agent that defeats the TRIGGER match
897
- # never reaches this deny at all. That is a bash_match coverage gap, not a
898
- # requires-satisfaction gap, and is unrelated to the fix here (see PR #341
899
- # for the known uncoverable shapes). \`harness validate\` no longer warns
900
- # "declares no producers" on these three (checkPolicySelfAttestation now
901
- # recognises operator_only: true as correct-by-construction).
902
- #
903
- # UPDATE (task 432db3d3, 2026-07-28, follow-up to ea8becf5): PARTIALLY
904
- # closed — for THIS policy only. \`src/runtime/command-normalize.ts\` now
905
- # peels wrapper prefixes (\`env\`, \`nice\`, \`command\`, \`sudo\`, \`doas\`,
906
- # \`time\`, \`timeout\`, \`stdbuf\`, \`setsid\`, \`exec\`, \`nohup\`, leading
907
- # VAR=value) and
908
- # collapses whitespace runs for the closed head-token set
909
- # \`git\`/\`gh\`/\`npm\`/\`harness\`, so \`env harness pause\`, \`nice harness
910
- # gate disable\` and the like now reach this deny via the raw-OR-normalised
911
- # match — measured 2026-07-28 against the real trigger regex through the
912
- # real hook entry point, pinned in tests/runtime/intercept-cli.test.ts.
913
- # The OTHER TWO kill switches are NOT covered by that closed set:
914
- # deny-session-env-strip keys on \`env\`/\`unset\` head tokens, and \`env\`
915
- # is STRUCTURALLY unreachable for the normaliser (its peeling loop
916
- # consumes \`env -u <VAR>\` while hunting for a gated command behind it,
917
- # erasing the very text this trigger keys on); deny-pause-sentinel-forgery
918
- # keys on \`tee\`/\`cp\`. Both remain wrapper-bypassable (\`nice env -u
919
- # CLAUDE_CODE_SESSION_ID ...\`, \`nice tee <sentinel>\`), measured
920
- # 2026-07-28 and pinned as explicit not-covered tests plus a head-token
921
- # drift guard (tests/runtime/bash-match-head-token-drift.test.ts) that
922
- # goes red when a future bash_match policy gates a new head token.
923
- - name: deny-kill-switch-bypass
924
- description: Deny harness pause, harness resume, harness gate disable, and harness gate enable from the agent's Bash tool. These are operator-only kill switches.
925
- trigger:
926
- event: PreToolUse
927
- match: "Bash"
928
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S*\\s+)*(?:npx\\s+|\\S*/)?harness\\s+(["\\x27]?)(?:pause|resume|gate\\s+(["\\x27]?)(?:disable|enable)\\4)\\3(?![\\w-])'
929
- operator_only: true
930
- hook: deny-kill-switch-bash
931
- enforcement: block
932
- ux:
933
- cannot: "You cannot run \`harness pause\`, \`harness resume\`, \`harness gate disable\`, or \`harness gate enable\`."
934
- required:
935
- - "the OPERATOR to run this from a terminal genuinely outside your agent session, not a \`! \`-prefixed Claude Code shell, which inherits this session's env and stdin and does not count"
936
- run:
937
- - "Stop. Explain to the operator what you were trying to do and why, and let THEM decide whether to run that command from their own terminal. This is the only way to unblock this gate: it is an unconditional deny (operator_only: true) that no in-session evidence — a ledger write, a marker file, a flag — can ever satisfy; the only remaining gap is bash_match's regex coverage of exotic shell shapes, not this evaluation (see docs/okf/pause-vs-gate-kill-switch.md)."
938
-
939
- - name: deny-session-env-strip
940
- description: Deny Bash attempts to strip or unset the agent-session env vars that harness pause/resume check (\$CLAUDE_CODE_SESSION_ID, \$CLAUDE_SESSION_ID, \$CODEX_SESSION_ID). Closes the one-liner that otherwise defeats refuseIfAgentShell.
941
- trigger:
942
- event: PreToolUse
943
- match: "Bash"
944
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S*\\s+)*(env\\b[^;\\n|&]*-u\\s*(CLAUDE_CODE_SESSION_ID|CLAUDE_SESSION_ID|CODEX_SESSION_ID)\\b|env\\b[^;\\n|&]*--unset(?:=|\\s+)(CLAUDE_CODE_SESSION_ID|CLAUDE_SESSION_ID|CODEX_SESSION_ID)\\b|unset\\s+(\\S+\\s+)*(CLAUDE_CODE_SESSION_ID|CLAUDE_SESSION_ID|CODEX_SESSION_ID)\\b|(CLAUDE_CODE_SESSION_ID|CLAUDE_SESSION_ID|CODEX_SESSION_ID)=(?=\\s))'
945
- operator_only: true
946
- hook: deny-session-env-strip-bash
947
- enforcement: block
948
- ux:
949
- cannot: "You cannot strip or unset your own agent-session id env vars from Bash."
950
- required:
951
- - "no legitimate reason from inside this session: stripping \$CLAUDE_CODE_SESSION_ID / \$CLAUDE_SESSION_ID / \$CODEX_SESSION_ID is recognised as an attempt to defeat the harness pause/resume agent-shell check"
952
- run:
953
- - "Stop. If you believe you have a legitimate reason to run a command without one of these env vars set, ask the OPERATOR to do it from their own terminal instead. This gate is an unconditional deny (operator_only: true); see docs/okf/pause-vs-gate-kill-switch.md for the honest trust model and the residual bash_match coverage gap."
954
-
955
- - name: deny-pause-sentinel-forgery
956
- description: Deny Bash writes (redirect, tee, cp) to the harness pause sentinel file (.harness-paused). The sentinel is unsigned JSON; a forged file silences every gate exactly like a real operator pause. Reads (cat, stat) are unaffected.
957
- trigger:
958
- event: PreToolUse
959
- match: "Bash"
960
- bash_match: '(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S*\\s+)*(tee|cp)\\b[^;\\n|&]*\\.harness-paused\\b|>{1,2}\\s*\\S*\\.harness-paused\\b'
961
- operator_only: true
962
- hook: deny-sentinel-write-bash
963
- enforcement: block
964
- ux:
965
- cannot: "You cannot write to the harness pause sentinel file (.harness-paused)."
966
- required:
967
- - "the OPERATOR to run \`harness pause\`/\`harness resume\` themselves, from a terminal outside your agent session, never a direct write to the sentinel file"
968
- run:
969
- - "Stop. Do not write, redirect, tee, or copy anything to .harness-paused. Ask the OPERATOR to silence the gates themselves, from their own terminal, using the operator-only command named under Required, if the session genuinely needs it. This gate is an unconditional deny (operator_only: true); see docs/okf/pause-vs-gate-kill-switch.md for the honest trust model and the residual bash_match coverage gap."
970
-
971
- # Full inherits the Solo/Team understanding-gate stack: the Stop hook
972
- # persists each Understanding Report and the PreToolUse pre-tool-use
973
- # blocker refuses Edit/Write/Bash until the report is approved. Drop
974
- # this block if you want the reference policies above without the
975
- # baseline gate.
976
118
  policy_packs:
977
- - name: understanding-before-execution
978
- source: builtin
979
- enabled: true
980
- description: Force agents to expose their task interpretation and wait for explicit human approval before any write-capable tool fires.
981
- config:
982
- mode: grill_me
983
- # Producers (agent-tasks/25bced52): rendered into the gate's deny
984
- # envelope by the same engine as policy producers. Constraint at
985
- # this layer: at-least-one \`ask\`. Post-v0.14.0 the gate signal
986
- # is a filesystem marker and the mcp ledger_add path no longer
987
- # satisfies the gate; the canonical unblock surface is the
988
- # operator-approval prompt.
989
- #
990
- # KEEP IN SYNC (task 68b9ad9c): this text must match
991
- # defaultProducers() in
992
- # src/policy-packs/builtin/understanding-before-execution.ts —
993
- # that function is what \`harness pack reseed\` and \`harness doctor\`'s
994
- # divergence warning treat as "the shipped template". A wording fix
995
- # landed here without updating defaultProducers() would make reseed
996
- # silently pull operators BACK to the stale wording. Pinned by
997
- # tests/cli/init-templates-ux-parity.test.ts.
998
- producers:
999
- - kind: ask
1000
- command: harness approve understanding
1001
- description: "Bare command, no pipes or chaining. The hook recognises it via isEscapeCommand and emits permissionDecision:ask; the operator's go on that prompt IS the gate approval. Golden path."
1002
- - kind: bash
1003
- command: harness approve understanding
1004
- description: Same command from any un-hooked terminal (operator only, not reachable from inside the gated session). Writes the canonical marker at harness.generated/.approvals/\${SESSION_ID}.
1005
- # ux (agent-tasks/e48e3b45): replaces the legacy engine-vocabulary
1006
- # deny envelope with the plain-language { cannot, required, run }
1007
- # shape. Engine details (the BLOCK reason naming session id /
1008
- # marker / report state) still land in stderr for operator audit;
1009
- # the agent only sees this.
1010
- #
1011
- # KEEP IN SYNC (task 68b9ad9c): see the producers: comment above —
1012
- # same rationale applies here, against defaultUx("grill_me") in the
1013
- # same builtin module.
1014
- ux:
1015
- cannot: "You cannot use write-capable tools yet."
1016
- required:
1017
- - "an approved Understanding Report for this session"
1018
- run:
1019
- - "Write an Understanding Report covering: Current Understanding, Intended Outcome, Derived Todos, Acceptance Criteria, Assumptions, Open Questions, Out Of Scope, Risks, Verification Plan, Prior Art (state what you searched for an existing solution and what you found, with an explicit adopt-or-build judgment)"
1020
- - "Run \`harness approve understanding\` with the report attached as a quoted heredoc (harness approve understanding <<'UNDERSTANDING_REPORT' ...report... UNDERSTANDING_REPORT) so it is persisted for audit, then approve the prompt; the heredoc is the only extra shell shape the gate allows (no pipes, chaining, or other redirection)"
1021
- # approval_lifecycle (agent-tasks/d8ee60ca + harness/f54e0ecb,
1022
- # v0.18.0+): expire the approval marker on task-completion
1023
- # boundaries so a multi-task session re-prompts for an
1024
- # Understanding Report between tasks. Without this the legacy
1025
- # "one approval per session" contract lets a stale interpretation
1026
- # drive the next task's edits.
1027
- #
1028
- # Full ships both boundary kinds: the agent-tasks MCP verbs for
1029
- # operators on that workflow, plus a Bash regex list for hybrid
1030
- # operators who also use gh-cli for PR mechanics. \`max_age\` is
1031
- # the safety net. Operators who prefer the legacy per-session
1032
- # behaviour opt out with \`approval_lifecycle: { mode: session }\`.
1033
- # Operators on other task systems override the matchers.
1034
- approval_lifecycle:
1035
- expire_on_tool_match:
1036
- - mcp__agent-tasks__task_finish
1037
- - mcp__agent-tasks__task_abandon
1038
- - mcp__agent-tasks__task_merge
1039
- - mcp__agent-tasks__pull_requests_merge
1040
- - mcp__agent-tasks__tasks_transition
1041
- expire_on_bash_match:
1042
- - '^gh pr (merge|close)\\b'
1043
- - '^git push origin (master|main)\\b'
1044
- max_age: 4h
1045
- ${AUTO_APPROVE_SNIPPET}
1046
-
1047
119
  # branch-protection (agent-tasks/2fdc5bbe, default-enabled since v0.17.2):
1048
- # blocks Write/Edit (claude-code) or apply_patch (codex) on protected
1049
- # branches (default: master, main, develop). Complements
1050
- # preflight-before-push, which fires at the LAST reversible step;
1051
- # branch-protection fires at the FIRST source mutation, catching the
1052
- # \"forgot to branch off master\" pattern earlier in the cycle.
120
+ # blocks Write/Edit (claude-code) or apply_patch (codex) when git names a
121
+ # protected branch (default: master, main, develop) for the directory the
122
+ # call writes into. It fires at the FIRST source mutation, catching the
123
+ # \"forgot to branch off master\" pattern before any edit lands.
1053
124
  #
1054
- # Two satisfying signals: a fresh \`branch:non-protected:<branch>\` tag
1055
- # from the SessionStart producer (\`harness session-start branch-check\`),
1056
- # or the operator-only override marker written by
1057
- # \`harness approve branch-protection --session <id>\` for deliberate
1058
- # protected-branch edits (version bumps, CI workflow patches, hotfixes).
1059
- # A branch-protection-ack ledger tag is no longer a sufficient override
1060
- # on its own (it is agent-writable); the marker file is the trusted signal.
125
+ # The hook asks git (\`git -C <dir> symbolic-ref -q HEAD\`) on every call;
126
+ # the way forward for the agent is a feature branch
127
+ # (\`git checkout -b <feature>\`). Fails closed: a manifest that does not
128
+ # load or a git that cannot answer refuses the call. Outside a repository
129
+ # and on a detached HEAD the call is allowed.
1061
130
  #
1062
- # Fails closed (any load / parse / ledger error refuses). Disable by
1063
- # setting \`enabled: false\` or removing this entry if your workflow
1064
- # routinely edits master directly. Override the protected list via
1065
- # \`config.protected_branches\`. Full reference:
131
+ # Disable by setting \`enabled: false\` or removing this entry if your
132
+ # workflow routinely edits master directly. Override the protected list
133
+ # via \`config.protected_branches\`. Full reference:
1066
134
  # docs/policy-packs/branch-protection.md.
1067
135
  - name: branch-protection
1068
136
  source: builtin
1069
137
  enabled: true
1070
138
  description: Block Write/Edit on protected branches (master, main, develop) at the first source mutation.
1071
139
  config:
1072
- # ux (agent-tasks/9806d4f8): replaces the legacy
1073
- # "branch-protection: refusing ..." envelope with the
1074
- # plain-language { cannot, required, run } shape. Engine details
1075
- # (the BLOCK reason naming session id / freshness window) stay
1076
- # on stderr for operator audit.
140
+ # ux (agent-tasks/9806d4f8): replaces the default
141
+ # "branch-protection: refusing ..." text with the plain-language
142
+ # { cannot, required, run } shape. Engine details (the directory
143
+ # git was asked about) stay on stderr for operator audit.
1077
144
  #
1078
145
  # KEEP IN SYNC (task 68b9ad9c): this text must match defaultUx() in
1079
- # src/policy-packs/builtin/branch-protection.ts — see the identical
1080
- # note on the understanding-before-execution pack above for why.
1081
- # Pinned by tests/cli/init-templates-ux-parity.test.ts.
146
+ # src/policy-packs/builtin/branch-protection.ts: that function is
147
+ # what \`harness pack reseed\` and \`harness doctor\`'s divergence
148
+ # warning treat as \"the shipped template\". Pinned by
149
+ # tests/cli/init-templates-ux-parity.test.ts.
1082
150
  ux:
1083
151
  cannot: "You cannot edit files on protected branch \${BRANCH} yet."
1084
152
  required:
1085
153
  - "a checkout of a non-protected branch (current \`\${BRANCH}\` is protected)"
1086
154
  run:
1087
155
  - "git checkout -b feat/<your-task>"
1088
- - "harness session-start branch-check"
1089
-
1090
- # solution-acceptance (harness cc43c7a4): Verifier-gated Done. Gates the
1091
- # task-finishing tools (agent-tasks completion verbs + git push / gh pr
1092
- # merge) on a ready, HEAD-pinned verdict that the grounding-mcp producer
1093
- # (solution_evaluate) derives from a real preflight run, plus an
1094
- # anti-forgery write-guard on the verdict marker. DISABLED by default: it
1095
- # is a hard completion-gate and needs grounding-mcp (>= 0.3.2) under
1096
- # tools.mcp plus the preflight binary on PATH. Flip enabled: true once the
1097
- # producer is wired and you want completion earned, not claimed. The pack
1098
- # emits its own instructions.md on apply; harness validate warns if you
1099
- # enable it without the producer.
1100
- - name: solution-acceptance
1101
- source: builtin
1102
- enabled: false
1103
- description: Gate task completion on a ready, HEAD-pinned solution-acceptance verdict earned from a real preflight run.
1104
-
1105
- # post-merge-gate (harness T-001, post-merge-gate): catches "kept working
1106
- # on a branch after it was already merged" — a PostToolUse producer
1107
- # records a merged-tip fact on a successful \`gh pr merge\`; a PreToolUse
1108
- # blocker denies curated history-mutating commands (git commit/add/push/
1109
- # merge/rebase/cherry-pick/revert/reset/stash pop|apply, gh pr create/
1110
- # merge) while the current branch tip still exactly matches that
1111
- # recorded tip. The recovery vocabulary (git switch/checkout/pull/fetch,
1112
- # git branch -d/-D, git stash list/show, any \`harness ...\` command)
1113
- # always passes as its OWN command, classified before any manifest or
1114
- # ledger access — the recovery path this gate itself recommends can never
1115
- # be starved. Chaining one of those with a curated mutation does NOT
1116
- # exempt the mutation (task 19356be7).
1117
- # Fails OPEN (unlike branch-protection) when the ledger is unreachable.
1118
- # DISABLED by default: a fresh gate, opt in once you've reviewed the
1119
- # curated command list for your workflow. Full reference:
1120
- # docs/policy-packs/post-merge-gate.md.
1121
- - name: post-merge-gate
1122
- source: builtin
1123
- enabled: false
1124
- description: Deny curated history-mutating git/gh commands on a branch whose current tip was already merged.
1125
- config:
1126
- # ux: replaces the legacy "post-merge-gate: refusing ..." envelope
1127
- # with the plain-language { cannot, required, run } shape.
1128
- #
1129
- # KEEP IN SYNC: this text must match defaultUx() in
1130
- # src/policy-packs/builtin/post-merge-gate.ts — see the identical
1131
- # note on the branch-protection pack above for why. Pinned by
1132
- # tests/cli/init-templates-ux-parity.test.ts.
1133
- ux:
1134
- cannot: "You cannot run \${TOOL_NAME} on branch \${BRANCH} yet — its current tip was already merged."
1135
- required:
1136
- - "a branch tip that is not sitting at an already-merged commit (switch off \`\${BRANCH}\`, or move its tip with a new commit)"
1137
- run:
1138
- - "git switch \${DEFAULT_BRANCH}"
1139
- - "git pull --ff-only"
1140
- - "git branch -d \${BRANCH} # optional cleanup"
1141
-
1142
- # Phase 7 Risk Gate vocabulary. The dangerous-shell classifier and
1143
- # production-signals resolver feed the gate-prod-destructive policies
1144
- # above: \`harness policy intercept\` builds the Action Envelope,
1145
- # classifies the action against \`risk.classifiers[]\`, resolves the
1146
- # target environment against \`environments.resolvers[]\`, and evaluates
1147
- # each policy's \`when:\` clauses against the result. Full design and the
1148
- # decision model: docs/risk-gate.md.
1149
- risk:
1150
- # Fail posture when a policy's evidence cannot be READ (ledger timeout,
1151
- # spawn failure, unresolved template): with \`preserve_enforcement\`
1152
- # (the default) block/require_approval policies fail CLOSED
1153
- # (\`deny-degraded\`) while warn policies stay non-blocking. Set
1154
- # \`fail_open\` to restore the pre-0.45 availability-first behaviour
1155
- # where EVERY degraded evaluation was a non-blocking \`warn-degraded\`.
1156
- # Kept COMMENTED OUT on purpose: the schema is strict, so a manifest
1157
- # carrying this key fails to parse on a pre-0.45 binary, and a manifest
1158
- # load failure is ALLOW at the hook layer — on a mixed-version fleet an
1159
- # emitted default would turn a downgrade into a silent full fail-open
1160
- # (review 2026-08-08). See docs/okf/gate-fail-posture-matrix.md.
1161
- # degraded_fail_posture: preserve_enforcement
1162
- # Safe-deletion-root allowlist for gate-dev-unsafe-deletion's
1163
- # \`action.deletion_target_unresolvable\` clause (task d03af8f6): an
1164
- # absolute deletion target inside one of these roots is allowed; a
1165
- # relative path, an unexpanded \$VAR/~, or a traversal that normalizes
1166
- # outside every root is gated. Shown explicitly even though it matches
1167
- # the schema default (\`/tmp\`, \`/private/tmp\` — the two spellings this
1168
- # harness's own scratchpad convention can use, macOS symlinks /tmp to
1169
- # /private/tmp) so an operator sees the live config surface here rather
1170
- # than having to know the schema default exists. An override REPLACES
1171
- # this list, it does not merge with it. See docs/risk-gate.md.
1172
- safe_deletion_roots:
1173
- - /tmp
1174
- - /private/tmp
1175
- classifiers:
1176
- - name: dangerous-shell
1177
- tool: Bash
1178
- patterns:
1179
- - pattern: 'rm\\s+-rf\\s+(/|/var|/data|/mnt|~)'
1180
- categories: [destructive, data_loss]
1181
- severity: critical
1182
- - pattern: 'DROP\\s+TABLE|TRUNCATE\\s+TABLE|DELETE\\s+FROM'
1183
- categories: [destructive, data_loss]
1184
- severity: high
1185
- # Token-based, flag-tolerant: a flag between \`kubectl\` and
1186
- # \`delete\` (e.g. \`kubectl --context=x delete namespace payments\`)
1187
- # must not defeat the match, without matching \`kubectl
1188
- # get\`/\`describe\` and without exponential-backtracking on a long
1189
- # flag run. \`(?:\\s+-\\S+(?:\\s+(?!delete\\b)(?!-)\\S+)?)*\` consumes
1190
- # zero or more \`-\`/\`--\` flag tokens (each optionally taking one
1191
- # following, non-flag, non-"delete" value token), linear in
1192
- # command length. See docs/risk-gate.md for the full rationale
1193
- # and the earlier quadratic-alternation form this replaced.
1194
- - pattern: 'kubectl(?:\\s+-\\S+(?:\\s+(?!delete\\b)(?!-)\\S+)?)*\\s+delete\\s+(namespace|deployment|statefulset|pvc)'
1195
- categories: [destructive, infrastructure_change]
1196
- severity: high
1197
- # Same flag-tolerance treatment for terraform's own \`-chdir=DIR\`
1198
- # global flag, which sits between the tool name and the
1199
- # subcommand (\`terraform -chdir=infra destroy\`).
1200
- - pattern: 'terraform(?:\\s+-\\S+(?:\\s+(?!destroy\\b)(?!-)\\S+)?)*\\s+destroy'
1201
- categories: [destructive, infrastructure_change]
1202
- severity: critical
1203
- # Task 2929c5b7: unclassified commands no longer trivially
1204
- # satisfy risk.severity_at_least: critical (see when-eval.ts and
1205
- # docs/risk-gate.md's "Unclassified actions and the fail-close
1206
- # rule") — kept in lockstep with docs/examples/full-manifest.yaml
1207
- # by tests/cli/init-full-template-parity.test.ts.
1208
- #
1209
- # These patterns are the OPERATOR-EDITABLE MIRROR of the built-in
1210
- # destructive floor (src/runtime/destructive-shell-floor.ts),
1211
- # not the only line of defence: the floor ships in the binary and
1212
- # already classifies these heads for an EXISTING manifest that
1213
- # never adopts the patterns below. Edit, narrow, or raise these
1214
- # freely: an operator pattern composes with the floor under
1215
- # highest-severity-wins, so it can only add. The floor is
1216
- # argv-aware where a regex cannot be (path-qualified and wrapped
1217
- # spellings: /bin/dd, sudo dd, sh -c "dd ...", git -C <dir> push
1218
- # -f), so a few spellings are caught by the floor alone; the
1219
- # parity test in tests/runtime/destructive-shell-floor.test.ts
1220
- # pins that everything caught HERE is also caught THERE, at the
1221
- # same severity or higher.
1222
- - pattern: '\\bdd\\s[^\\n]*\\bof='
1223
- categories: [destructive, data_loss]
1224
- severity: critical
1225
- - pattern: '\\btruncate\\b[^\\n]*(\\s-[a-zA-Z]*s|--size)'
1226
- categories: [destructive, data_loss]
1227
- severity: critical
1228
- - pattern: '\\bshred\\b'
1229
- categories: [destructive, data_loss, irreversible_action]
1230
- severity: critical
1231
- - pattern: '\\bmkfs(\\.\\w+)?\\b'
1232
- categories: [destructive, data_loss, infrastructure_change]
1233
- severity: critical
1234
- - pattern: '\\bfind\\b[^\\n]*-delete\\b'
1235
- categories: [destructive, data_loss]
1236
- severity: critical
1237
- - pattern: '\\bfind\\b[^\\n]*-exec(dir)?\\s+rm\\b'
1238
- categories: [destructive, data_loss]
1239
- severity: critical
1240
- - pattern: '\\bgit\\s+reset\\b[^\\n]*--hard\\b'
1241
- categories: [destructive, data_loss]
1242
- severity: high
1243
- - pattern: '\\bgit\\s+push\\b[^\\n]*(--force(-with-lease)?\\b|\\s-f\\b)'
1244
- categories: [destructive, production_mutation, deployment_change]
1245
- severity: high
1246
- - pattern: '\\bgit\\s+clean\\b[^\\n]*(--force\\b|\\s-[a-zA-Z]*f[a-zA-Z]*\\b)'
1247
- categories: [destructive, data_loss]
1248
- severity: high
1249
- - pattern: '\\bgit\\s+checkout\\s+--\\s+\\.'
1250
- categories: [destructive, data_loss]
1251
- severity: high
1252
- - pattern: '\\bgit\\s+restore\\s+\\.(\\s|$)'
1253
- categories: [destructive, data_loss]
1254
- severity: high
1255
- - pattern: '\\b(chmod|chown)\\b[^\\n]*(\\s-[a-zA-Z]*R|--recursive\\b)'
1256
- categories: [mass_update]
1257
- severity: high
1258
- - pattern: '\\bcurl\\b[^\\n]*(-X\\s*|--request[\\s=])(?![Gg][Ee][Tt]\\b)(?![Hh][Ee][Aa][Dd]\\b)[A-Za-z]'
1259
- categories: [production_mutation, network_exfiltration]
1260
- severity: high
1261
- - pattern: '\\bcurl\\b[^\\n]*(\\s-[a-zA-Z]*[dFT]|--data\\b|--json\\b|--form(-string)?\\b|--upload-file\\b)'
1262
- categories: [production_mutation, network_exfiltration]
1263
- severity: high
1264
- - pattern: '\\bcurl\\b[^\\n]*(\\s-[a-zA-Z]*[oODcK]|--output(-dir)?\\b|--remote-name\\b|--remote-header-name\\b|--dump-header\\b|--cookie-jar\\b|--config\\b|--create-dirs\\b|--etag-save\\b|--trace(-ascii)?\\b|--stderr\\b|(\\s-[a-zA-Z]*w\\b|--write-out\\b)[^\\n]*%output)'
1265
- categories: [destructive, data_loss]
1266
- severity: high
1267
- - pattern: '\\bsed\\b[^\\n]*(\\s-[a-zA-Z]*i[a-zA-Z]*\\b|--in-place\\b)'
1268
- categories: [destructive, data_loss]
1269
- severity: high
1270
-
1271
- environments:
1272
- resolvers:
1273
- - name: production-signals
1274
- environment: production
1275
- signals:
1276
- branch_patterns: [main, "release/*"]
1277
- env_var_patterns:
1278
- - var: DATABASE_URL
1279
- patterns: [prod, production]
1280
- kube_context_patterns: [".*prod.*"]
1281
- kube_namespace_patterns: [prod, production]
1282
156
  `;
1283
- import { parse as parseYaml } from "yaml";
1284
- import { parseManifest } from "../../schema/index.js";
1285
157
  import { SOLO_TEMPLATE, TEAM_TEMPLATE } from "./profiles.js";
1286
158
  export function getTemplate(name) {
1287
159
  switch (name) {
@@ -1295,88 +167,4 @@ export function getTemplate(name) {
1295
167
  return MINIMAL_TEMPLATE;
1296
168
  }
1297
169
  }
1298
- /**
1299
- * The NAMES of `operator_only` (kill-switch / security) policies the
1300
- * current full template ships (task adf037c1). Parsed from FULL_TEMPLATE
1301
- * itself — the single source of truth, kept honest by
1302
- * tests/cli/init-full-template-parity.test.ts — so this set can never
1303
- * drift from what `harness init --template full` actually writes; adding a
1304
- * new operator_only policy to the template automatically extends it.
1305
- *
1306
- * Scope is deliberately operator_only-only (operator decision 2026-08-08):
1307
- * these are the profile-independent security floor (the kill-switch
1308
- * defenses) whose silent absence from an aged manifest is the incident
1309
- * this drift check exists to surface. Non-operator_only full-template
1310
- * policies are intentionally NOT enumerated here — flagging a solo/team
1311
- * install for lacking full-only convenience policies it never had would be
1312
- * noise. Memoized: the parse is pure and FULL_TEMPLATE is a build constant.
1313
- */
1314
- let shippedOperatorOnlyCache;
1315
- export function shippedOperatorOnlyPolicyNames() {
1316
- if (shippedOperatorOnlyCache === undefined) {
1317
- const manifest = parseManifest(parseYaml(FULL_TEMPLATE));
1318
- shippedOperatorOnlyCache = manifest.policies
1319
- .filter((p) => p.operator_only === true)
1320
- .map((p) => p.name);
1321
- }
1322
- return shippedOperatorOnlyCache;
1323
- }
1324
- // Matches the leading `(...)` group of a bash_match regex source string.
1325
- // Every shipped bash_match opens with the boundary-alternation group and
1326
- // none of its branches contain a literal `)` (parens inside are always
1327
- // escaped as `\(`), so a non-greedy scan to the first `)` is exact for
1328
- // every entry in FULL_TEMPLATE.
1329
- const BOUNDARY_GROUP_RE = /^\(([^)]*)\)/;
1330
- /**
1331
- * Extracts the leading boundary-alternation group from a `bash_match`
1332
- * regex source string (e.g. `"(^|\\n|;|\\||&|\\()..."` -> `"^|\\n|;|\\||&|\\("`).
1333
- * Returns `undefined` when the string does not open with a parenthesized
1334
- * group; defensive only, every shipped template entry does.
1335
- *
1336
- * Known limitation: the scan is not escape-aware, so an escaped closing
1337
- * paren (`\\)`) inside the group would truncate the match early at that
1338
- * `)` character instead of continuing past it. No shipped FULL_TEMPLATE
1339
- * boundary contains one today; a future boundary that needs a literal
1340
- * `)` inside the alternation would need this scan widened first.
1341
- */
1342
- export function extractBashMatchBoundary(bashMatch) {
1343
- return BOUNDARY_GROUP_RE.exec(bashMatch)?.[1];
1344
- }
1345
- /**
1346
- * Every FULL_TEMPLATE `hooks[]` / `policies[].trigger` entry that
1347
- * declares a `bash_match`, paired with its boundary-alternation group
1348
- * (task 037cfb7c). Parsed from FULL_TEMPLATE itself, the same
1349
- * single-source-of-truth pattern as `shippedOperatorOnlyPolicyNames`
1350
- * immediately above, so this list can never drift from what
1351
- * `harness init --template full` actually writes; unlike
1352
- * `shippedOperatorOnlyPolicyNames`, this one is pinned by its own
1353
- * fixed-point test in tests/cli/doctor-trigger-boundary-drift.test.ts
1354
- * (entry count and the literal shipped boundary), not by
1355
- * tests/cli/init-full-template-parity.test.ts, which does not reference
1356
- * it. Memoized: the parse is pure and FULL_TEMPLATE is a build constant.
1357
- */
1358
- let shippedBashMatchBoundariesCache;
1359
- export function shippedBashMatchBoundaries() {
1360
- if (shippedBashMatchBoundariesCache === undefined) {
1361
- const manifest = parseManifest(parseYaml(FULL_TEMPLATE));
1362
- const entries = [];
1363
- for (const hook of manifest.hooks) {
1364
- if (!hook.bash_match)
1365
- continue;
1366
- const boundary = extractBashMatchBoundary(hook.bash_match);
1367
- if (boundary !== undefined)
1368
- entries.push({ level: "hook", name: hook.name, boundary });
1369
- }
1370
- for (const policy of manifest.policies) {
1371
- const bashMatch = policy.trigger.bash_match;
1372
- if (!bashMatch)
1373
- continue;
1374
- const boundary = extractBashMatchBoundary(bashMatch);
1375
- if (boundary !== undefined)
1376
- entries.push({ level: "policy", name: policy.name, boundary });
1377
- }
1378
- shippedBashMatchBoundariesCache = entries;
1379
- }
1380
- return shippedBashMatchBoundariesCache;
1381
- }
1382
170
  //# sourceMappingURL=templates.js.map