@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.
- package/CHANGELOG.md +90 -0
- package/README.md +46 -42
- package/dist/cli/add/index.js +17 -21
- package/dist/cli/add/index.js.map +1 -1
- package/dist/cli/adopt/derive.d.ts +2 -2
- package/dist/cli/adopt/derive.js +2 -19
- package/dist/cli/adopt/derive.js.map +1 -1
- package/dist/cli/adopt/index.d.ts +1 -1
- package/dist/cli/adopt/index.js +1 -12
- package/dist/cli/adopt/index.js.map +1 -1
- package/dist/cli/apply/apply.d.ts +20 -35
- package/dist/cli/apply/apply.js +61 -136
- package/dist/cli/apply/apply.js.map +1 -1
- package/dist/cli/apply/generate-codex-config.js +10 -58
- package/dist/cli/apply/generate-codex-config.js.map +1 -1
- package/dist/cli/apply/generate-memory-index.js +1 -2
- package/dist/cli/apply/generate-memory-index.js.map +1 -1
- package/dist/cli/apply/generate-opencode-config.d.ts +2 -10
- package/dist/cli/apply/generate-opencode-config.js +74 -113
- package/dist/cli/apply/generate-opencode-config.js.map +1 -1
- package/dist/cli/apply/generate-settings.d.ts +11 -64
- package/dist/cli/apply/generate-settings.js +27 -132
- package/dist/cli/apply/generate-settings.js.map +1 -1
- package/dist/cli/apply/index.d.ts +1 -1
- package/dist/cli/apply/index.js +1 -1
- package/dist/cli/apply/index.js.map +1 -1
- package/dist/cli/apply/install-codex-config.d.ts +153 -1
- package/dist/cli/apply/install-codex-config.js +445 -70
- package/dist/cli/apply/install-codex-config.js.map +1 -1
- package/dist/cli/apply/next-steps.d.ts +7 -0
- package/dist/cli/apply/next-steps.js +13 -1
- package/dist/cli/apply/next-steps.js.map +1 -1
- package/dist/cli/bounded-stdin.d.ts +0 -23
- package/dist/cli/bounded-stdin.js +2 -49
- package/dist/cli/bounded-stdin.js.map +1 -1
- package/dist/cli/describe.d.ts +1 -1
- package/dist/cli/describe.js +0 -3
- package/dist/cli/describe.js.map +1 -1
- package/dist/cli/diff/engine.d.ts +0 -11
- package/dist/cli/diff/engine.js +1 -17
- package/dist/cli/diff/engine.js.map +1 -1
- package/dist/cli/diff/index.js +14 -25
- package/dist/cli/diff/index.js.map +1 -1
- package/dist/cli/doctor/claude-mcp.d.ts +4 -19
- package/dist/cli/doctor/claude-mcp.js +11 -22
- package/dist/cli/doctor/claude-mcp.js.map +1 -1
- package/dist/cli/doctor/codex.d.ts +12 -14
- package/dist/cli/doctor/codex.js +31 -144
- package/dist/cli/doctor/codex.js.map +1 -1
- package/dist/cli/doctor/format.js +23 -338
- package/dist/cli/doctor/format.js.map +1 -1
- package/dist/cli/doctor/hook-liveness.d.ts +56 -0
- package/dist/cli/doctor/hook-liveness.js +455 -0
- package/dist/cli/doctor/hook-liveness.js.map +1 -0
- package/dist/cli/doctor/index.d.ts +13 -87
- package/dist/cli/doctor/index.js +57 -705
- package/dist/cli/doctor/index.js.map +1 -1
- package/dist/cli/doctor/opencode.d.ts +2 -1
- package/dist/cli/doctor/opencode.js.map +1 -1
- package/dist/cli/doctor/types.d.ts +21 -378
- package/dist/cli/doctor/types.js.map +1 -1
- package/dist/cli/drain-stdio.d.ts +31 -0
- package/dist/cli/drain-stdio.js +76 -0
- package/dist/cli/drain-stdio.js.map +1 -0
- package/dist/cli/export.d.ts +3 -1
- package/dist/cli/export.js +7 -16
- package/dist/cli/export.js.map +1 -1
- package/dist/cli/gate/codex-disable.d.ts +29 -0
- package/dist/cli/gate/codex-disable.js +195 -0
- package/dist/cli/gate/codex-disable.js.map +1 -0
- package/dist/cli/gate/codex-enable.d.ts +41 -0
- package/dist/cli/gate/codex-enable.js +127 -0
- package/dist/cli/gate/codex-enable.js.map +1 -0
- package/dist/cli/gate/codex-snapshot.d.ts +208 -0
- package/dist/cli/gate/codex-snapshot.js +402 -0
- package/dist/cli/gate/codex-snapshot.js.map +1 -0
- package/dist/cli/gate/disable.d.ts +9 -0
- package/dist/cli/gate/disable.js +263 -28
- package/dist/cli/gate/disable.js.map +1 -1
- package/dist/cli/gate/enable.d.ts +26 -6
- package/dist/cli/gate/enable.js +152 -80
- package/dist/cli/gate/enable.js.map +1 -1
- package/dist/cli/gate/link-chain.d.ts +53 -0
- package/dist/cli/gate/link-chain.js +122 -0
- package/dist/cli/gate/link-chain.js.map +1 -0
- package/dist/cli/gate/snapshot.d.ts +289 -12
- package/dist/cli/gate/snapshot.js +481 -22
- package/dist/cli/gate/snapshot.js.map +1 -1
- package/dist/cli/index.d.ts +0 -9
- package/dist/cli/index.js +15 -2607
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/composer.d.ts +3 -6
- package/dist/cli/init/composer.js +6 -370
- package/dist/cli/init/composer.js.map +1 -1
- package/dist/cli/init/dependencies.d.ts +1 -2
- package/dist/cli/init/dependencies.js +4 -80
- package/dist/cli/init/dependencies.js.map +1 -1
- package/dist/cli/init/detect.js +5 -4
- package/dist/cli/init/detect.js.map +1 -1
- package/dist/cli/init/interactive.d.ts +1 -23
- package/dist/cli/init/interactive.js +33 -247
- package/dist/cli/init/interactive.js.map +1 -1
- package/dist/cli/init/profiles.d.ts +2 -2
- package/dist/cli/init/profiles.js +51 -243
- package/dist/cli/init/profiles.js.map +1 -1
- package/dist/cli/init/templates.d.ts +2 -37
- package/dist/cli/init/templates.js +25 -1237
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/list.d.ts +1 -1
- package/dist/cli/list.js +1 -38
- package/dist/cli/list.js.map +1 -1
- package/dist/cli/loader.d.ts +15 -1
- package/dist/cli/loader.js +56 -39
- package/dist/cli/loader.js.map +1 -1
- package/dist/cli/main.js +7 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/migrate-home/index.js +2 -2
- package/dist/cli/migrate-home/index.js.map +1 -1
- package/dist/cli/pack/add.js +1 -1
- package/dist/cli/pack/add.js.map +1 -1
- package/dist/cli/pack/hook-bootstrap.d.ts +5 -164
- package/dist/cli/pack/hook-bootstrap.js +15 -291
- package/dist/cli/pack/hook-bootstrap.js.map +1 -1
- package/dist/cli/pack/hook-branch-protection.d.ts +28 -21
- package/dist/cli/pack/hook-branch-protection.js +365 -340
- package/dist/cli/pack/hook-branch-protection.js.map +1 -1
- package/dist/cli/pack/index.d.ts +0 -1
- package/dist/cli/pack/index.js +0 -1
- package/dist/cli/pack/index.js.map +1 -1
- package/dist/cli/pack/list.js +1 -6
- package/dist/cli/pack/list.js.map +1 -1
- package/dist/cli/pack/mutate.d.ts +7 -9
- package/dist/cli/pack/mutate.js +6 -9
- package/dist/cli/pack/mutate.js.map +1 -1
- package/dist/cli/pack/reseed.d.ts +2 -2
- package/dist/cli/pack/reseed.js +16 -22
- package/dist/cli/pack/reseed.js.map +1 -1
- package/dist/cli/register-gate-group.d.ts +5 -0
- package/dist/cli/register-gate-group.js +348 -0
- package/dist/cli/register-gate-group.js.map +1 -0
- package/dist/cli/register-inspect-group.d.ts +6 -0
- package/dist/cli/register-inspect-group.js +189 -0
- package/dist/cli/register-inspect-group.js.map +1 -0
- package/dist/cli/register-operator-lifecycle.d.ts +5 -0
- package/dist/cli/register-operator-lifecycle.js +20 -0
- package/dist/cli/register-operator-lifecycle.js.map +1 -0
- package/dist/cli/register-pack-group.d.ts +5 -0
- package/dist/cli/register-pack-group.js +134 -0
- package/dist/cli/register-pack-group.js.map +1 -0
- package/dist/cli/register-setup-group.d.ts +5 -0
- package/dist/cli/register-setup-group.js +495 -0
- package/dist/cli/register-setup-group.js.map +1 -0
- package/dist/cli/remove/index.d.ts +0 -14
- package/dist/cli/remove/index.js +2 -115
- package/dist/cli/remove/index.js.map +1 -1
- package/dist/cli/remove/mutate.d.ts +0 -2
- package/dist/cli/remove/mutate.js +1 -19
- package/dist/cli/remove/mutate.js.map +1 -1
- package/dist/cli/remove/register.d.ts +5 -0
- package/dist/cli/remove/register.js +25 -0
- package/dist/cli/remove/register.js.map +1 -0
- package/dist/cli/shell-quote.d.ts +7 -0
- package/dist/cli/shell-quote.js +17 -0
- package/dist/cli/shell-quote.js.map +1 -0
- package/dist/cli/uninstall/index.d.ts +4 -2
- package/dist/cli/uninstall/index.js +15 -7
- package/dist/cli/uninstall/index.js.map +1 -1
- package/dist/cli/uninstall/register.d.ts +5 -0
- package/dist/cli/uninstall/register.js +171 -0
- package/dist/cli/uninstall/register.js.map +1 -0
- package/dist/cli/uninstall/snapshot.d.ts +15 -0
- package/dist/cli/uninstall/snapshot.js +38 -0
- package/dist/cli/uninstall/snapshot.js.map +1 -1
- package/dist/cli/validate/checks.d.ts +0 -77
- package/dist/cli/validate/checks.js +3 -1049
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/cli/validate/index.js +19 -15
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/io/claude-mcp.d.ts +1 -1
- package/dist/io/claude-mcp.js +27 -14
- package/dist/io/claude-mcp.js.map +1 -1
- package/dist/io/harness-lock.js +2 -2
- package/dist/io/harness-lock.js.map +1 -1
- package/dist/io/lock.d.ts +0 -26
- package/dist/io/lock.js +10 -27
- package/dist/io/lock.js.map +1 -1
- package/dist/io/merge-settings.js +6 -4
- package/dist/io/merge-settings.js.map +1 -1
- package/dist/io/project-name.d.ts +22 -39
- package/dist/io/project-name.js +25 -42
- package/dist/io/project-name.js.map +1 -1
- package/dist/io/read-regular-file.d.ts +103 -40
- package/dist/io/read-regular-file.js +196 -35
- package/dist/io/read-regular-file.js.map +1 -1
- package/dist/io/restart-hints.js +3 -6
- package/dist/io/restart-hints.js.map +1 -1
- package/dist/io/version-compare.d.ts +1 -3
- package/dist/io/version-compare.js +1 -3
- package/dist/io/version-compare.js.map +1 -1
- package/dist/io/write-regular-file.d.ts +30 -0
- package/dist/io/write-regular-file.js +85 -0
- package/dist/io/write-regular-file.js.map +1 -0
- package/dist/overrides/index.d.ts +1 -0
- package/dist/overrides/index.js +1 -0
- package/dist/overrides/index.js.map +1 -1
- package/dist/overrides/merge-layers.d.ts +43 -0
- package/dist/overrides/merge-layers.js +76 -0
- package/dist/overrides/merge-layers.js.map +1 -0
- package/dist/overrides/merge.d.ts +16 -0
- package/dist/overrides/merge.js +21 -8
- package/dist/overrides/merge.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +4 -69
- package/dist/policy-packs/builtin/branch-protection-runtime.js +12 -84
- package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection.d.ts +7 -30
- package/dist/policy-packs/builtin/branch-protection.js +56 -89
- package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
- package/dist/policy-packs/config-check.d.ts +7 -5
- package/dist/policy-packs/config-check.js +2 -2
- package/dist/policy-packs/config-check.js.map +1 -1
- package/dist/policy-packs/expand.d.ts +1 -3
- package/dist/policy-packs/expand.js +5 -42
- package/dist/policy-packs/expand.js.map +1 -1
- package/dist/policy-packs/index.d.ts +3 -3
- package/dist/policy-packs/index.js +2 -2
- package/dist/policy-packs/index.js.map +1 -1
- package/dist/policy-packs/registry.d.ts +9 -38
- package/dist/policy-packs/registry.js +5 -65
- package/dist/policy-packs/registry.js.map +1 -1
- package/dist/policy-packs/runtime.d.ts +0 -4
- package/dist/policy-packs/runtime.js +9 -22
- package/dist/policy-packs/runtime.js.map +1 -1
- package/dist/policy-packs/types.d.ts +0 -19
- package/dist/policy-packs/ux-compare.d.ts +1 -11
- package/dist/policy-packs/ux-compare.js +6 -42
- package/dist/policy-packs/ux-compare.js.map +1 -1
- package/dist/policy-packs/ux-drift-check.d.ts +5 -5
- package/dist/policy-packs/ux-drift-check.js +17 -22
- package/dist/policy-packs/ux-drift-check.js.map +1 -1
- package/dist/policy-packs/version-check.d.ts +5 -26
- package/dist/policy-packs/version-check.js +19 -74
- package/dist/policy-packs/version-check.js.map +1 -1
- package/dist/probes/memory.d.ts +1 -1
- package/dist/probes/memory.js +1 -1
- package/dist/probes/memory.js.map +1 -1
- package/dist/runtime/agent-facing.d.ts +9 -0
- package/dist/runtime/agent-facing.js +28 -14
- package/dist/runtime/agent-facing.js.map +1 -1
- package/dist/runtime/bounded-text.d.ts +15 -0
- package/dist/runtime/bounded-text.js +27 -0
- package/dist/runtime/bounded-text.js.map +1 -0
- package/dist/runtime/git-branch.d.ts +125 -0
- package/dist/runtime/git-branch.js +381 -0
- package/dist/runtime/git-branch.js.map +1 -0
- package/dist/runtime/hermetic-spawn-guard.d.ts +2 -2
- package/dist/runtime/hermetic-spawn-guard.js +24 -34
- package/dist/runtime/hermetic-spawn-guard.js.map +1 -1
- package/dist/runtime/home-dir.js +3 -2
- package/dist/runtime/home-dir.js.map +1 -1
- package/dist/runtime/tool-name-aliases.d.ts +0 -6
- package/dist/runtime/tool-name-aliases.js +5 -18
- package/dist/runtime/tool-name-aliases.js.map +1 -1
- package/dist/schema/grounding.d.ts +7 -54
- package/dist/schema/grounding.js +10 -12
- package/dist/schema/grounding.js.map +1 -1
- package/dist/schema/hooks.d.ts +39 -136
- package/dist/schema/hooks.js +3 -6
- package/dist/schema/hooks.js.map +1 -1
- package/dist/schema/index.d.ts +114 -3828
- package/dist/schema/index.js +41 -80
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/memory.d.ts +54 -131
- package/dist/schema/memory.js +2 -2
- package/dist/schema/memory.js.map +1 -1
- package/dist/schema/policy-packs.d.ts +3 -45
- package/dist/schema/policy-packs.js +7 -13
- package/dist/schema/policy-packs.js.map +1 -1
- package/dist/schema/policy-ux.d.ts +7 -0
- package/dist/schema/policy-ux.js +18 -0
- package/dist/schema/policy-ux.js.map +1 -0
- package/dist/schema/removed-keys.d.ts +185 -0
- package/dist/schema/removed-keys.js +531 -0
- package/dist/schema/removed-keys.js.map +1 -0
- package/dist/schema/tools.d.ts +30 -268
- package/dist/schema/tools.js +4 -4
- package/dist/schema/tools.js.map +1 -1
- package/package.json +5 -16
- package/dist/cli/approve/branch-protection.d.ts +0 -69
- package/dist/cli/approve/branch-protection.js +0 -144
- package/dist/cli/approve/branch-protection.js.map +0 -1
- package/dist/cli/approve/risk.d.ts +0 -112
- package/dist/cli/approve/risk.js +0 -197
- package/dist/cli/approve/risk.js.map +0 -1
- package/dist/cli/approve/stdin-report.d.ts +0 -57
- package/dist/cli/approve/stdin-report.js +0 -145
- package/dist/cli/approve/stdin-report.js.map +0 -1
- package/dist/cli/approve/understanding.d.ts +0 -410
- package/dist/cli/approve/understanding.js +0 -996
- package/dist/cli/approve/understanding.js.map +0 -1
- package/dist/cli/audit.d.ts +0 -80
- package/dist/cli/audit.js +0 -252
- package/dist/cli/audit.js.map +0 -1
- package/dist/cli/delegate/index.d.ts +0 -76
- package/dist/cli/delegate/index.js +0 -443
- package/dist/cli/delegate/index.js.map +0 -1
- package/dist/cli/doctor/auto-approve-mode.d.ts +0 -37
- package/dist/cli/doctor/auto-approve-mode.js +0 -80
- package/dist/cli/doctor/auto-approve-mode.js.map +0 -1
- package/dist/cli/doctor/bypass-without-auto-approve.d.ts +0 -38
- package/dist/cli/doctor/bypass-without-auto-approve.js +0 -95
- package/dist/cli/doctor/bypass-without-auto-approve.js.map +0 -1
- package/dist/cli/doctor/codex-config-drift.d.ts +0 -28
- package/dist/cli/doctor/codex-config-drift.js +0 -240
- package/dist/cli/doctor/codex-config-drift.js.map +0 -1
- package/dist/cli/doctor/rogue-ledger.d.ts +0 -53
- package/dist/cli/doctor/rogue-ledger.js +0 -153
- package/dist/cli/doctor/rogue-ledger.js.map +0 -1
- package/dist/cli/doctor/session-start-preflight-setup-version.d.ts +0 -83
- package/dist/cli/doctor/session-start-preflight-setup-version.js +0 -114
- package/dist/cli/doctor/session-start-preflight-setup-version.js.map +0 -1
- package/dist/cli/doctor/settings-drift.d.ts +0 -25
- package/dist/cli/doctor/settings-drift.js +0 -213
- package/dist/cli/doctor/settings-drift.js.map +0 -1
- package/dist/cli/doctor/toolchain-parity.d.ts +0 -63
- package/dist/cli/doctor/toolchain-parity.js +0 -154
- package/dist/cli/doctor/toolchain-parity.js.map +0 -1
- package/dist/cli/doctor/ug-auto-approvals.d.ts +0 -40
- package/dist/cli/doctor/ug-auto-approvals.js +0 -91
- package/dist/cli/doctor/ug-auto-approvals.js.map +0 -1
- package/dist/cli/doctor/ug-delegations.d.ts +0 -26
- package/dist/cli/doctor/ug-delegations.js +0 -121
- package/dist/cli/doctor/ug-delegations.js.map +0 -1
- package/dist/cli/doctor/ug-inflight.d.ts +0 -35
- package/dist/cli/doctor/ug-inflight.js +0 -57
- package/dist/cli/doctor/ug-inflight.js.map +0 -1
- package/dist/cli/doctor/understanding-mode-env.d.ts +0 -51
- package/dist/cli/doctor/understanding-mode-env.js +0 -98
- package/dist/cli/doctor/understanding-mode-env.js.map +0 -1
- package/dist/cli/dry-run.d.ts +0 -46
- package/dist/cli/dry-run.js +0 -250
- package/dist/cli/dry-run.js.map +0 -1
- package/dist/cli/event-input.d.ts +0 -28
- package/dist/cli/event-input.js +0 -73
- package/dist/cli/event-input.js.map +0 -1
- package/dist/cli/explain-action.d.ts +0 -20
- package/dist/cli/explain-action.js +0 -27
- package/dist/cli/explain-action.js.map +0 -1
- package/dist/cli/explain-policy.d.ts +0 -135
- package/dist/cli/explain-policy.js +0 -266
- package/dist/cli/explain-policy.js.map +0 -1
- package/dist/cli/explain.d.ts +0 -31
- package/dist/cli/explain.js +0 -159
- package/dist/cli/explain.js.map +0 -1
- package/dist/cli/gc/index.d.ts +0 -63
- package/dist/cli/gc/index.js +0 -566
- package/dist/cli/gc/index.js.map +0 -1
- package/dist/cli/pack/approve-escape.d.ts +0 -19
- package/dist/cli/pack/approve-escape.js +0 -190
- package/dist/cli/pack/approve-escape.js.map +0 -1
- package/dist/cli/pack/auto-approve-path.d.ts +0 -146
- package/dist/cli/pack/auto-approve-path.js +0 -462
- package/dist/cli/pack/auto-approve-path.js.map +0 -1
- package/dist/cli/pack/hook-codex-post-tool-use.d.ts +0 -25
- package/dist/cli/pack/hook-codex-post-tool-use.js +0 -160
- package/dist/cli/pack/hook-codex-post-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +0 -48
- package/dist/cli/pack/hook-codex-pre-tool-use.js +0 -474
- package/dist/cli/pack/hook-codex-pre-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-codex-stop.d.ts +0 -35
- package/dist/cli/pack/hook-codex-stop.js +0 -329
- package/dist/cli/pack/hook-codex-stop.js.map +0 -1
- package/dist/cli/pack/hook-codex-user-prompt-submit.d.ts +0 -24
- package/dist/cli/pack/hook-codex-user-prompt-submit.js +0 -93
- package/dist/cli/pack/hook-codex-user-prompt-submit.js.map +0 -1
- package/dist/cli/pack/hook-post-merge-gate-record.d.ts +0 -37
- package/dist/cli/pack/hook-post-merge-gate-record.js +0 -190
- package/dist/cli/pack/hook-post-merge-gate-record.js.map +0 -1
- package/dist/cli/pack/hook-post-merge-gate.d.ts +0 -34
- package/dist/cli/pack/hook-post-merge-gate.js +0 -277
- package/dist/cli/pack/hook-post-merge-gate.js.map +0 -1
- package/dist/cli/pack/hook-post-tool-use.d.ts +0 -45
- package/dist/cli/pack/hook-post-tool-use.js +0 -137
- package/dist/cli/pack/hook-post-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-pre-tool-use.d.ts +0 -92
- package/dist/cli/pack/hook-pre-tool-use.js +0 -1328
- package/dist/cli/pack/hook-pre-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-runtime-reality.d.ts +0 -63
- package/dist/cli/pack/hook-runtime-reality.js +0 -210
- package/dist/cli/pack/hook-runtime-reality.js.map +0 -1
- package/dist/cli/pack/hook-solution-acceptance-writeguard.d.ts +0 -32
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js +0 -337
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +0 -1
- package/dist/cli/pack/hook-solution-acceptance.d.ts +0 -157
- package/dist/cli/pack/hook-solution-acceptance.js +0 -530
- package/dist/cli/pack/hook-solution-acceptance.js.map +0 -1
- package/dist/cli/pack/hook-stay-in-scope.d.ts +0 -37
- package/dist/cli/pack/hook-stay-in-scope.js +0 -128
- package/dist/cli/pack/hook-stay-in-scope.js.map +0 -1
- package/dist/cli/pack/hook-subagent-start.d.ts +0 -23
- package/dist/cli/pack/hook-subagent-start.js +0 -88
- package/dist/cli/pack/hook-subagent-start.js.map +0 -1
- package/dist/cli/pack/hook-subagent-stop.d.ts +0 -19
- package/dist/cli/pack/hook-subagent-stop.js +0 -41
- package/dist/cli/pack/hook-subagent-stop.js.map +0 -1
- package/dist/cli/pack/hook-track-active-claim.d.ts +0 -27
- package/dist/cli/pack/hook-track-active-claim.js +0 -275
- package/dist/cli/pack/hook-track-active-claim.js.map +0 -1
- package/dist/cli/pack/transcript-report-scan.d.ts +0 -71
- package/dist/cli/pack/transcript-report-scan.js +0 -359
- package/dist/cli/pack/transcript-report-scan.js.map +0 -1
- package/dist/cli/pack/understanding-report-schema-hint.d.ts +0 -26
- package/dist/cli/pack/understanding-report-schema-hint.js +0 -120
- package/dist/cli/pack/understanding-report-schema-hint.js.map +0 -1
- package/dist/cli/pack/upgrade.d.ts +0 -32
- package/dist/cli/pack/upgrade.js +0 -273
- package/dist/cli/pack/upgrade.js.map +0 -1
- package/dist/cli/pause/index.d.ts +0 -113
- package/dist/cli/pause/index.js +0 -251
- package/dist/cli/pause/index.js.map +0 -1
- package/dist/cli/pause-check.d.ts +0 -22
- package/dist/cli/pause-check.js +0 -54
- package/dist/cli/pause-check.js.map +0 -1
- package/dist/cli/policy/intercept.d.ts +0 -233
- package/dist/cli/policy/intercept.js +0 -1020
- package/dist/cli/policy/intercept.js.map +0 -1
- package/dist/cli/policy/risk-envelope-enrichment.d.ts +0 -40
- package/dist/cli/policy/risk-envelope-enrichment.js +0 -108
- package/dist/cli/policy/risk-envelope-enrichment.js.map +0 -1
- package/dist/cli/record/index.d.ts +0 -81
- package/dist/cli/record/index.js +0 -348
- package/dist/cli/record/index.js.map +0 -1
- package/dist/cli/resolve-env.d.ts +0 -32
- package/dist/cli/resolve-env.js +0 -47
- package/dist/cli/resolve-env.js.map +0 -1
- package/dist/cli/session-export/index.d.ts +0 -46
- package/dist/cli/session-export/index.js +0 -169
- package/dist/cli/session-export/index.js.map +0 -1
- package/dist/cli/session-export/redact.d.ts +0 -22
- package/dist/cli/session-export/redact.js +0 -47
- package/dist/cli/session-export/redact.js.map +0 -1
- package/dist/cli/session-export/transcript.d.ts +0 -24
- package/dist/cli/session-export/transcript.js +0 -164
- package/dist/cli/session-export/transcript.js.map +0 -1
- package/dist/cli/session-start/branch-check.d.ts +0 -18
- package/dist/cli/session-start/branch-check.js +0 -140
- package/dist/cli/session-start/branch-check.js.map +0 -1
- package/dist/cli/session-start/index.d.ts +0 -121
- package/dist/cli/session-start/index.js +0 -591
- package/dist/cli/session-start/index.js.map +0 -1
- package/dist/cli/session-start/shared-options.d.ts +0 -103
- package/dist/cli/session-start/shared-options.js +0 -107
- package/dist/cli/session-start/shared-options.js.map +0 -1
- package/dist/cli/session-start/stale-base-check.d.ts +0 -46
- package/dist/cli/session-start/stale-base-check.js +0 -352
- package/dist/cli/session-start/stale-base-check.js.map +0 -1
- package/dist/cli/session-start/toolchain-parity.d.ts +0 -267
- package/dist/cli/session-start/toolchain-parity.js +0 -797
- package/dist/cli/session-start/toolchain-parity.js.map +0 -1
- package/dist/cli/smoke/assertions.d.ts +0 -46
- package/dist/cli/smoke/assertions.js +0 -170
- package/dist/cli/smoke/assertions.js.map +0 -1
- package/dist/cli/smoke/index.d.ts +0 -76
- package/dist/cli/smoke/index.js +0 -245
- package/dist/cli/smoke/index.js.map +0 -1
- package/dist/cli/smoke/runner.d.ts +0 -55
- package/dist/cli/smoke/runner.js +0 -134
- package/dist/cli/smoke/runner.js.map +0 -1
- package/dist/cli/smoke/stream-parser.d.ts +0 -65
- package/dist/cli/smoke/stream-parser.js +0 -115
- package/dist/cli/smoke/stream-parser.js.map +0 -1
- package/dist/cli/test-risk.d.ts +0 -26
- package/dist/cli/test-risk.js +0 -34
- package/dist/cli/test-risk.js.map +0 -1
- package/dist/io/display-path.d.ts +0 -11
- package/dist/io/display-path.js +0 -29
- package/dist/io/display-path.js.map +0 -1
- package/dist/io/duration.d.ts +0 -5
- package/dist/io/duration.js +0 -50
- package/dist/io/duration.js.map +0 -1
- package/dist/io/extract.d.ts +0 -79
- package/dist/io/extract.js +0 -226
- package/dist/io/extract.js.map +0 -1
- package/dist/io/ledger-record.d.ts +0 -83
- package/dist/io/ledger-record.js +0 -301
- package/dist/io/ledger-record.js.map +0 -1
- package/dist/io/read-json-dir-entries.d.ts +0 -36
- package/dist/io/read-json-dir-entries.js +0 -48
- package/dist/io/read-json-dir-entries.js.map +0 -1
- package/dist/io/safe-json-parse.d.ts +0 -5
- package/dist/io/safe-json-parse.js +0 -21
- package/dist/io/safe-json-parse.js.map +0 -1
- package/dist/policies/index.d.ts +0 -5
- package/dist/policies/index.js +0 -6
- package/dist/policies/index.js.map +0 -1
- package/dist/policies/ledger-client.d.ts +0 -113
- package/dist/policies/ledger-client.js +0 -500
- package/dist/policies/ledger-client.js.map +0 -1
- package/dist/policies/producers.d.ts +0 -12
- package/dist/policies/producers.js +0 -61
- package/dist/policies/producers.js.map +0 -1
- package/dist/policies/requires.d.ts +0 -75
- package/dist/policies/requires.js +0 -240
- package/dist/policies/requires.js.map +0 -1
- package/dist/policies/timestamp.d.ts +0 -14
- package/dist/policies/timestamp.js +0 -36
- package/dist/policies/timestamp.js.map +0 -1
- package/dist/policy-packs/builtin/permission-profiles.d.ts +0 -11
- package/dist/policy-packs/builtin/permission-profiles.js +0 -74
- package/dist/policy-packs/builtin/permission-profiles.js.map +0 -1
- package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +0 -286
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js +0 -397
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/post-merge-gate.d.ts +0 -56
- package/dist/policy-packs/builtin/post-merge-gate.js +0 -347
- package/dist/policy-packs/builtin/post-merge-gate.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.d.ts +0 -50
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.js +0 -151
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +0 -323
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js +0 -672
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance.d.ts +0 -45
- package/dist/policy-packs/builtin/solution-acceptance.js +0 -226
- package/dist/policy-packs/builtin/solution-acceptance.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.d.ts +0 -25
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js +0 -94
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.d.ts +0 -35
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js +0 -86
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.d.ts +0 -210
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js +0 -361
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.d.ts +0 -304
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +0 -734
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.d.ts +0 -36
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js +0 -73
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +0 -19
- package/dist/policy-packs/builtin/understanding-before-execution/index.js +0 -83
- package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.d.ts +0 -135
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js +0 -618
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.d.ts +0 -25
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.js +0 -56
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.d.ts +0 -20
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js +0 -93
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/markers.d.ts +0 -126
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js +0 -245
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.d.ts +0 -29
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js +0 -82
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.d.ts +0 -71
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js +0 -175
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.d.ts +0 -620
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js +0 -1047
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.d.ts +0 -128
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js +0 -213
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.d.ts +0 -129
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js +0 -166
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.d.ts +0 -164
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js +0 -275
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.d.ts +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.js +0 -10
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution.d.ts +0 -526
- package/dist/policy-packs/builtin/understanding-before-execution.js +0 -1074
- package/dist/policy-packs/builtin/understanding-before-execution.js.map +0 -1
- package/dist/policy-packs/permission-translator.d.ts +0 -9
- package/dist/policy-packs/permission-translator.js +0 -76
- package/dist/policy-packs/permission-translator.js.map +0 -1
- package/dist/runtime/action-envelope.d.ts +0 -64
- package/dist/runtime/action-envelope.js +0 -46
- package/dist/runtime/action-envelope.js.map +0 -1
- package/dist/runtime/approval-signing.d.ts +0 -111
- package/dist/runtime/approval-signing.js +0 -384
- package/dist/runtime/approval-signing.js.map +0 -1
- package/dist/runtime/bash-match-facts.d.ts +0 -60
- package/dist/runtime/bash-match-facts.js +0 -196
- package/dist/runtime/bash-match-facts.js.map +0 -1
- package/dist/runtime/bash-match-registry.d.ts +0 -112
- package/dist/runtime/bash-match-registry.js +0 -406
- package/dist/runtime/bash-match-registry.js.map +0 -1
- package/dist/runtime/bash-prefix-parse.d.ts +0 -31
- package/dist/runtime/bash-prefix-parse.js +0 -576
- package/dist/runtime/bash-prefix-parse.js.map +0 -1
- package/dist/runtime/command-normalize.d.ts +0 -658
- package/dist/runtime/command-normalize.js +0 -2410
- package/dist/runtime/command-normalize.js.map +0 -1
- package/dist/runtime/deletion-target-resolve.d.ts +0 -28
- package/dist/runtime/deletion-target-resolve.js +0 -1078
- package/dist/runtime/deletion-target-resolve.js.map +0 -1
- package/dist/runtime/destructive-shell-floor.d.ts +0 -19
- package/dist/runtime/destructive-shell-floor.js +0 -611
- package/dist/runtime/destructive-shell-floor.js.map +0 -1
- package/dist/runtime/environment-resolver.d.ts +0 -36
- package/dist/runtime/environment-resolver.js +0 -138
- package/dist/runtime/environment-resolver.js.map +0 -1
- package/dist/runtime/git-context.d.ts +0 -201
- package/dist/runtime/git-context.js +0 -422
- package/dist/runtime/git-context.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -12
- package/dist/runtime/index.js +0 -13
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/intercept.d.ts +0 -494
- package/dist/runtime/intercept.js +0 -1313
- package/dist/runtime/intercept.js.map +0 -1
- package/dist/runtime/kube-context.d.ts +0 -16
- package/dist/runtime/kube-context.js +0 -63
- package/dist/runtime/kube-context.js.map +0 -1
- package/dist/runtime/kubectl-target-parse.d.ts +0 -31
- package/dist/runtime/kubectl-target-parse.js +0 -249
- package/dist/runtime/kubectl-target-parse.js.map +0 -1
- package/dist/runtime/ledger-add.d.ts +0 -16
- package/dist/runtime/ledger-add.js +0 -150
- package/dist/runtime/ledger-add.js.map +0 -1
- package/dist/runtime/ledger-writer.d.ts +0 -27
- package/dist/runtime/ledger-writer.js +0 -46
- package/dist/runtime/ledger-writer.js.map +0 -1
- package/dist/runtime/pause-sentinel.d.ts +0 -60
- package/dist/runtime/pause-sentinel.js +0 -156
- package/dist/runtime/pause-sentinel.js.map +0 -1
- package/dist/runtime/pending-approval.d.ts +0 -23
- package/dist/runtime/pending-approval.js +0 -67
- package/dist/runtime/pending-approval.js.map +0 -1
- package/dist/runtime/read-only-bash.d.ts +0 -141
- package/dist/runtime/read-only-bash.js +0 -2204
- package/dist/runtime/read-only-bash.js.map +0 -1
- package/dist/runtime/recovery-git-commit.d.ts +0 -22
- package/dist/runtime/recovery-git-commit.js +0 -284
- package/dist/runtime/recovery-git-commit.js.map +0 -1
- package/dist/runtime/reject-malformed-session-id.d.ts +0 -8
- package/dist/runtime/reject-malformed-session-id.js +0 -16
- package/dist/runtime/reject-malformed-session-id.js.map +0 -1
- package/dist/runtime/risk-classifier.d.ts +0 -38
- package/dist/runtime/risk-classifier.js +0 -311
- package/dist/runtime/risk-classifier.js.map +0 -1
- package/dist/runtime/session-id.d.ts +0 -113
- package/dist/runtime/session-id.js +0 -193
- package/dist/runtime/session-id.js.map +0 -1
- package/dist/runtime/shell-word.d.ts +0 -62
- package/dist/runtime/shell-word.js +0 -410
- package/dist/runtime/shell-word.js.map +0 -1
- package/dist/runtime/task-providers/agent-tasks.d.ts +0 -103
- package/dist/runtime/task-providers/agent-tasks.js +0 -245
- package/dist/runtime/task-providers/agent-tasks.js.map +0 -1
- package/dist/runtime/when-eval.d.ts +0 -62
- package/dist/runtime/when-eval.js +0 -212
- package/dist/runtime/when-eval.js.map +0 -1
- package/dist/runtime/workflow-policies.d.ts +0 -207
- package/dist/runtime/workflow-policies.js +0 -596
- package/dist/runtime/workflow-policies.js.map +0 -1
- package/dist/schema/audit.d.ts +0 -71
- package/dist/schema/audit.js +0 -32
- package/dist/schema/audit.js.map +0 -1
- package/dist/schema/doctor.d.ts +0 -25
- package/dist/schema/doctor.js +0 -23
- package/dist/schema/doctor.js.map +0 -1
- package/dist/schema/environments.d.ts +0 -215
- package/dist/schema/environments.js +0 -101
- package/dist/schema/environments.js.map +0 -1
- package/dist/schema/extract.d.ts +0 -9
- package/dist/schema/extract.js +0 -86
- package/dist/schema/extract.js.map +0 -1
- package/dist/schema/permission-profiles.d.ts +0 -2292
- package/dist/schema/permission-profiles.js +0 -60
- package/dist/schema/permission-profiles.js.map +0 -1
- package/dist/schema/policies.d.ts +0 -974
- package/dist/schema/policies.js +0 -298
- package/dist/schema/policies.js.map +0 -1
- package/dist/schema/requires.d.ts +0 -131
- package/dist/schema/requires.js +0 -88
- package/dist/schema/requires.js.map +0 -1
- package/dist/schema/risk.d.ts +0 -144
- package/dist/schema/risk.js +0 -194
- package/dist/schema/risk.js.map +0 -1
- package/dist/schema/session-start-preflight.d.ts +0 -10
- package/dist/schema/session-start-preflight.js +0 -106
- package/dist/schema/session-start-preflight.js.map +0 -1
- package/dist/schema/stale-base-check.d.ts +0 -18
- package/dist/schema/stale-base-check.js +0 -37
- package/dist/schema/stale-base-check.js.map +0 -1
- package/dist/schema/toolchain-parity.d.ts +0 -21
- package/dist/schema/toolchain-parity.js +0 -48
- package/dist/schema/toolchain-parity.js.map +0 -1
- package/dist/schema/workflows.d.ts +0 -519
- package/dist/schema/workflows.js +0 -81
- package/dist/schema/workflows.js.map +0 -1
- 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
|
|
6
|
+
# parses, then add entries under the top-level keys:
|
|
35
7
|
#
|
|
36
|
-
# grounding: evidence-ledger
|
|
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
|
-
#
|
|
55
|
-
#
|
|
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)
|
|
1049
|
-
#
|
|
1050
|
-
#
|
|
1051
|
-
# branch
|
|
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
|
-
#
|
|
1055
|
-
#
|
|
1056
|
-
#
|
|
1057
|
-
#
|
|
1058
|
-
#
|
|
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
|
-
#
|
|
1063
|
-
#
|
|
1064
|
-
#
|
|
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
|
|
1073
|
-
# "branch-protection: refusing ..."
|
|
1074
|
-
#
|
|
1075
|
-
#
|
|
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
|
|
1080
|
-
#
|
|
1081
|
-
# Pinned by
|
|
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
|