From da0f2cb42b6332b022a67fe2cb379486fdc0460a Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Wed, 22 Apr 2026 13:51:48 +0800 Subject: [PATCH] feat(hooks): runtime controls via KEI_DISABLED_HOOKS + KEI_HOOK_PROFILE (v0.14.2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 10 hooks get 21-line guard block: env-var short-circuit, 4 profiles (full/advisory-off/minimal/off), per-hook disable. Safety-critical preserved in 'minimal': no-hand-edit-agents, assemble-validate, git-pre-commit-genesis. Advisory off list: recurrence-suggest, citation-verify, error-spike-detector, milestone-commit-hook. skills/hooks-control/SKILL.md — click-only toggle emitting shell export commands. README +27 LOC 'Runtime hook controls' section with examples. --- hooks/agent-fork-logger.sh | 22 ++++++ hooks/assemble-agents.sh | 22 ++++++ hooks/assemble-validate.sh | 22 ++++++ hooks/error-spike-detector.sh | 22 ++++++ hooks/git-pre-commit-genesis.sh | 22 ++++++ hooks/milestone-commit-hook.sh | 22 ++++++ hooks/no-hand-edit-agents.sh | 22 ++++++ hooks/session-end-dump.sh | 22 ++++++ hooks/site-wysiwyd-check.sh | 22 ++++++ hooks/tomd-preread.sh | 22 ++++++ skills/hooks-control/SKILL.md | 117 ++++++++++++++++++++++++++++++++ 11 files changed, 337 insertions(+) create mode 100644 skills/hooks-control/SKILL.md diff --git a/hooks/agent-fork-logger.sh b/hooks/agent-fork-logger.sh index f45807f..8d5e435 100755 --- a/hooks/agent-fork-logger.sh +++ b/hooks/agent-fork-logger.sh @@ -8,6 +8,28 @@ command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu input="$(cat)" diff --git a/hooks/assemble-agents.sh b/hooks/assemble-agents.sh index ca42f7d..7577726 100755 --- a/hooks/assemble-agents.sh +++ b/hooks/assemble-agents.sh @@ -13,6 +13,28 @@ # Claude Code would refuse the tool call system-wide. command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu ASSEMBLER="$HOME/.claude/agents/_assembler/target/release/assemble" diff --git a/hooks/assemble-validate.sh b/hooks/assemble-validate.sh index 06de144..6b4906f 100755 --- a/hooks/assemble-validate.sh +++ b/hooks/assemble-validate.sh @@ -10,6 +10,28 @@ # Claude Code would refuse the tool call system-wide. command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu ASSEMBLER="$HOME/.claude/agents/_assembler/target/release/assemble" diff --git a/hooks/error-spike-detector.sh b/hooks/error-spike-detector.sh index adc2d04..40deaee 100755 --- a/hooks/error-spike-detector.sh +++ b/hooks/error-spike-detector.sh @@ -8,6 +8,28 @@ command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu input="$(cat)" diff --git a/hooks/git-pre-commit-genesis.sh b/hooks/git-pre-commit-genesis.sh index 47350c1..6370163 100755 --- a/hooks/git-pre-commit-genesis.sh +++ b/hooks/git-pre-commit-genesis.sh @@ -14,6 +14,28 @@ # 1 usage / binary missing # 2 leak detected (commit blocked) +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu SCANNER="${GENESIS_SCAN_BIN:-$HOME/.claude/agents/_primitives/_rust/target/release/genesis-scan}" diff --git a/hooks/milestone-commit-hook.sh b/hooks/milestone-commit-hook.sh index 96e57b9..ff5fa64 100755 --- a/hooks/milestone-commit-hook.sh +++ b/hooks/milestone-commit-hook.sh @@ -8,6 +8,28 @@ command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu input="$(cat)" diff --git a/hooks/no-hand-edit-agents.sh b/hooks/no-hand-edit-agents.sh index b12456d..49cf476 100755 --- a/hooks/no-hand-edit-agents.sh +++ b/hooks/no-hand-edit-agents.sh @@ -12,6 +12,28 @@ # Claude Code would refuse Edit/Write system-wide. command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu [ "${AGENT_MIGRATION:-0}" = "1" ] && exit 0 diff --git a/hooks/session-end-dump.sh b/hooks/session-end-dump.sh index 9cfdecd..574bb38 100755 --- a/hooks/session-end-dump.sh +++ b/hooks/session-end-dump.sh @@ -8,6 +8,28 @@ command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu input="$(cat)" diff --git a/hooks/site-wysiwyd-check.sh b/hooks/site-wysiwyd-check.sh index f715823..1bc1f98 100755 --- a/hooks/site-wysiwyd-check.sh +++ b/hooks/site-wysiwyd-check.sh @@ -13,6 +13,28 @@ command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu FILE=$(jq -r '.tool_input.file_path // empty' 2>/dev/null || true) diff --git a/hooks/tomd-preread.sh b/hooks/tomd-preread.sh index 362cf2a..834ef4a 100755 --- a/hooks/tomd-preread.sh +++ b/hooks/tomd-preread.sh @@ -11,6 +11,28 @@ # Claude Code would refuse Read system-wide. command -v jq >/dev/null 2>&1 || exit 0 +# --- RUNTIME CONTROLS (v0.14.2) --- +_hook_name="$(basename "$0" .sh)" +case "${KEI_DISABLED_HOOKS:-}" in + *"$_hook_name"*|*all*) exit 0 ;; +esac +case "${KEI_HOOK_PROFILE:-full}" in + off) exit 0 ;; + minimal) + case "$_hook_name" in + no-github-push|genesis-leak-guard|no-hand-edit-agents|secrets-guard|assemble-validate|git-pre-commit-genesis) ;; + *) exit 0 ;; + esac + ;; + advisory-off) + case "$_hook_name" in + recurrence-suggest|citation-verify|error-spike-detector|milestone-commit-hook) exit 0 ;; + esac + ;; + full|*) ;; +esac +# --- end runtime controls --- + set -eu TOMD="$HOME/.claude/agents/_primitives/tomd.sh" diff --git a/skills/hooks-control/SKILL.md b/skills/hooks-control/SKILL.md new file mode 100644 index 0000000..fc7f1ac --- /dev/null +++ b/skills/hooks-control/SKILL.md @@ -0,0 +1,117 @@ +--- +name: hooks-control +description: Runtime enable/disable of KeiSeiKit hooks via env vars (v0.14.2). Click-only wizard that emits shell `export` / `unset` commands for the user to paste. Supports per-hook disable, profile switch (full / advisory-off / minimal / off), or full re-enable. Does NOT execute anything — user controls their shell. +argument-hint: (none — fully click-driven) +--- + +# Hooks Control — Runtime Hook Enable/Disable + +Click-only wizard. Helps you toggle KeiSeiKit hooks **for the current shell +session** via env vars, without editing `~/.claude/settings.json`. The skill +emits shell commands; it NEVER runs them. + +Two env vars are honoured by every kit-shipped hook (v0.14.2+): + +| Var | Meaning | +|---|---| +| `KEI_DISABLED_HOOKS` | Comma- or space-list of hook base names (no `.sh`). `all` disables every hook. | +| `KEI_HOOK_PROFILE` | One of `full` (default), `advisory-off`, `minimal`, `off`. | + +| Profile | What stays on | +|---|---| +| `full` (default) | Every hook | +| `advisory-off` | Disables pure-stderr advisories: `recurrence-suggest`, `citation-verify`, `error-spike-detector`, `milestone-commit-hook`. | +| `minimal` | Safety-only: `no-github-push`, `genesis-leak-guard`, `no-hand-edit-agents`, `secrets-guard`, `assemble-validate`, `git-pre-commit-genesis`. | +| `off` | Every hook off (escape hatch — use when debugging hook interactions). | + +--- + +## Pipeline (one phase, up to 2 AskUserQuestion batches) + +### Phase 1 — Show state + pick action + +Print current state: +``` +Current KEI_DISABLED_HOOKS: +Current KEI_HOOK_PROFILE: +Active kit-shipped hooks: +``` + +`AskUserQuestion` — **What do you want to do?** +1. Disable specific hook(s) — this shell session only +2. Switch profile — `full` / `advisory-off` / `minimal` / `off` +3. Re-enable everything — clear both env vars +4. Show state only — emit no commands + +### Phase 2a — Hook multi-select (if picked 1) + +`AskUserQuestion` multi-select over the 10 kit-shipped hook names: +`assemble-agents`, `assemble-validate`, `no-hand-edit-agents`, `tomd-preread`, +`agent-fork-logger`, `site-wysiwyd-check`, `error-spike-detector`, +`milestone-commit-hook`, `session-end-dump`, `git-pre-commit-genesis`. + +Emit: +```sh +# Disable selected hooks for this shell session: +export KEI_DISABLED_HOOKS= +``` +For persistence, tell the user to paste into `~/.zshrc` / `~/.bashrc` by +hand. Do NOT edit rc files. + +### Phase 2b — Profile picker (if picked 2) + +`AskUserQuestion` over `full` / `advisory-off` / `minimal` / `off`. Emit: +```sh +# Switch profile for this shell session: +export KEI_HOOK_PROFILE= +``` + +### Phase 2c — Re-enable everything (if picked 3) + +Emit directly (no further question): +```sh +# Clear all runtime hook overrides (back to full / everything on): +unset KEI_DISABLED_HOOKS KEI_HOOK_PROFILE +``` + +### Phase 2d — State only (if picked 4) + +Stop after the state block. + +--- + +## Rules + +- **Click-only.** Every decision is `AskUserQuestion`. No free-text. +- **Never execute.** The skill prints shell commands as code blocks; the + user runs them. Any `export` from a tool call would evaporate at skill + exit — the shell running hooks is a subshell. +- **No rc edits.** If the user wants persistence, we say "paste into your + shell rc". The skill MUST NOT modify `~/.zshrc` / `~/.bashrc`. +- **RULE 0.4 — no invented hook names.** Only the 10 names in Phase 2a + are valid choices. Never suggest a name not in the kit. +- **RULE -1 — NO DOWNGRADE.** If the user asks "can I silence all safety + hooks?", present tradeoffs; point at `KEI_HOOK_PROFILE=off` with a + warning that patent-IP and generated-file protections also go down. + +--- + +## Final report + +``` +=== HOOKS-CONTROL REPORT === +Action: +Commands: +Scope: current shell session (unless pasted into rc) +Verify: `env | grep KEI_` after pasting +Undo: unset KEI_DISABLED_HOOKS KEI_HOOK_PROFILE +``` + +--- + +## References + +- `hooks/*.sh` — each kit hook sources the v0.14.2 runtime-controls block +- `README.md` → "Runtime hook controls" section +- `~/.claude/rules/recurrence-escalate.md` — severity ladder notes that + hooks can be silenced at runtime, no rule deletion required