KeiSeiKit-1.0/hooks/no-python-without-approval.sh
KeiSei84 742822a499 feat: opt-in hook packs + stack profiles + public-prep repoint (#44)
Mirror of keigit main — Phase 2 (abae256c) + public-prep repoint (518d95df).

Phase 2: safety on by default, discipline packs opt-in; stack profiles
(minimal/web/ml/systems/mobile) pull packs + agent sets; SSoT in
_primitives/hook-packs.toml; filter+prune via lib-hooks.sh; re-runnable
via `kei configure`; 8 hooks gated via _lib/gate.sh.

Public-prep: .gitmodules + README clone + plugin homepage + web-install.sh
repointed to github.com/KeiSeiLab. ADR in DECISIONS.md 2026-05-25.
2026-05-26 13:26:09 +07:00

62 lines
3.2 KiB
Bash
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 kрoнически нарушает 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