KeiSeiKit-1.0/hooks/no-python-without-approval.sh
KeiSei84 abae256c1d feat(install): opt-in hook packs + stack profiles (public posture)
A fresh install now activates only the safety pack; discipline hooks and
agents are opt-in via an onboarding step (step 6) or `kei configure`.
"People don't need Rust-only" — they pick their own stack.

- _primitives/hook-packs.toml: SSoT mapping pack -> hooks, stack -> packs +
  agent groups. safety always on; evidence/observability/epistemic/
  orchestration/git-guard/stack-rust opt-in. rust-first/no-python only under
  the systems stack; git-guard (no-github-push) opt-in only, pulled by no stack.
- lib-profile: extract generic _toml_array (reused by lib-packs); profile_members
  becomes a thin wrapper (no behavior change).
- lib-packs: pack/stack/agent resolvers + selection loader.
- lib-hooks: filter_snippet_by_packs (install-time allowlist) + prune_kit_hooks
  (reconfigure removes deselected kit hooks, keeps foreign ones); activate_hooks
  rewired to prune + filter + merge. No custom settings.json fields (/doctor safe).
- lib-agents: install_manifests filters by stack agent set (empty = install all).
- onboarding: pick_stack step (reuse _onb_read_choice), persists stack_profile +
  enabled_packs to onboarding.toml; i18n STR_* added.
- bin/kei configure -> scripts/kei-configure.sh (re-pick without reinstall);
  install stamps ~/.claude/.kei-kit-dir.
- numeric-claims-guard: money regex no longer matches shell positionals ($1..$9);
  requires decimal / unit / 2+ digits / tilde. Real money + time still caught.
- gate one-liner added to 8 discipline hooks (runtime toggle via hooks-control).

Verified end-to-end (scratch HOME): fresh=safety only; evidence pack adds
numeric+citation; systems stack wires rust-first + 14 base/systems agents (no
data-science/swift); reconfigure-shrink prunes kit hooks but keeps a foreign
hook; settings schema clean; assembler golden 3/3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 17:27:14 +08:00

62 lines
3.3 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Runtime gate (hooks-control skill / KEI_DISABLED_HOOKS / KEI_HOOK_PROFILE).
_KEI_LIB="$(dirname "$0")/_lib/gate.sh"; if [ -r "$_KEI_LIB" ]; then . "$_KEI_LIB"; kei_hook_gate "no-python-without-approval" || exit 0; fi
# Hard block on python/python3/python2 invocations in Bash tool.
# RULE 0.2 (Rust First) — Python requires explicit architectural reason.
# Claude кroнически нарушает RULE 0.2 inline-вызовами python3 для мелких расчётов.
# Этот хук форсирует: каждый python-вызов = отдельный approval через интерфейс.
#
# How to approve: user may add a one-off permission via Claude Code's
# "allow this command" prompt, OR prefix with RULE02_BYPASS=1.
# No silent bypass; no shell aliases.
#
# Installed: 2026-04-21 after repeated inline python3 abuse
# (Pantheon CF arithmetic, Gauss-Kuzmin — could have been Rust or awk+bc).
INPUT=$(cat)
CMD=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$CMD" ] && exit 0
# Explicit bypass env var (used rarely, visible in command text — not silent)
if echo "$CMD" | grep -qE 'RULE02_BYPASS=1'; then
exit 0
fi
# Match python invocations at token boundaries.
# Catches: python, python3, python2, python3.12, /usr/bin/python3, .venv/bin/python
# Also heredoc-only patterns: "python3 -c", "python3 << EOF", "python3 script.py"
# Also: uv run python, poetry run python, pipx run python
if echo "$CMD" | grep -qE '(^|[[:space:]/"=(|&;`])(python|python2|python3)([0-9]?\.[0-9]+)?([[:space:]]|$)'; then
cat >&2 <<'EOF'
═══════════════════════════════════════════════════════════════════
BLOCKED — Python invocation requires explicit approval (RULE 0.2).
═══════════════════════════════════════════════════════════════════
RULE 0.2 Rust First:
Python не разрешается по умолчанию. Для "одноразовых расчётов"
Claude должен предпочитать: Rust (cargo script), awk/bc/dc, jq,
node, или существующий Rust-код в проекте.
Approved alternatives BEFORE retrying:
• Rust one-shot: write my-project/examples/foo.rs, cargo run
• Shell math: awk 'BEGIN{printf "%.10f\n", ...}'
• Arbitrary prec: bc -l / dc
• JSON munge: jq '.path.to.value'
• Project Rust: find reusable crate function, call via cargo test
If Python is genuinely necessary (existing .py tool, library binding
that only exists in Python, one of the RULE 0.2 exceptions 1-7):
1. State the RULE 0.2 exception number in chat.
2. Re-run the command with prefix: RULE02_BYPASS=1 python3 ...
3. User will see the bypass marker in the command and can deny.
This hook installed 2026-04-21 by user request after repeated
repeated inline python3 use where Rust would suffice.
═══════════════════════════════════════════════════════════════════
EOF
exit 2
fi
exit 0