Files
roboco/docker/scripts/fable-bash-discipline-hook.sh
T

28 lines
1.3 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Fable tool discipline: deny pure shell file-reads; dedicated tools exist.
# Ported from opus-fable-playbook hooks/bash-discipline.sh (v0.1.3) — see
# docs/superpowers/plans/2026-07-04-v0.18.0-A-opus-fable-plan.md.
# PreToolUse[Bash], Claude-only (see the plan's grok risk section — a grok
# hook deny cancels the whole run, so this is not shipped to grok in V1).
# Fail-open: any internal error => exit 0 (allow).
set -u
INPUT="$(cat)" || exit 0
CMD="$(printf '%s' "$INPUT" | python3 -c \
'import json,sys; print(json.load(sys.stdin).get("tool_input",{}).get("command",""))' \
2>/dev/null || true)"
[ -z "$CMD" ] && exit 0
# Pipelines, compounds, redirects, heredocs are legitimate — allow.
printf '%s' "$CMD" | grep -qE '\||&&|;|>|<<' && exit 0
DENY=0
printf '%s' "$CMD" | grep -qE '^[[:space:]]*(cat|head|tail|less|more)[[:space:]]' && DENY=1
printf '%s' "$CMD" | grep -qE '^[[:space:]]*sed[[:space:]]+-n[[:space:]]' && DENY=1
[ "$DENY" -eq 0 ] && exit 0
cat <<'JSON'
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Fable tool discipline: use the dedicated Read/Grep tools instead of shell file-reads (cat/head/tail/less/sed -n). Read is paginated and line-numbered; Grep searches without loading whole files."}}
JSON
exit 0