chenglou/claude-config-learnings: The Shell Hooks That Turn Claude Code Into a Permission Firewall
A tiny Bash toolkit shows how Claude Code’s hook layer can override rigid permissions, repair dontAsk mode, and make safety decisions from live context.
- Claude Code’s hook layer is the real enforcement surface, because it can decide at runtime instead of only declaring defaults.
- A one-line allow hook shows how non-interactive mode can be repaired when the native permission path gets in the way.
- The repo’s core idea is a three-tier permission firewall that combines allowlists, regexes, and transcript-aware model judgment.
- The broader lesson is that agent safety can be built with shell middleware, not just larger config files.
The control layer Claude Code does not advertise
The interesting part of this repo is not the scripts themselves. It is the discovery that Claude Code’s permission behavior is not just a settings file with three moods. The hooks, especially PreToolUse, can sit in front of tool execution and make a live decision from stdin, which means enforcement is programmable.
That changes the mental model. settings.json sets defaults, but hooks can act like policy middleware. In this repo, the hook is not decoration. It is the place where permission can be denied, forced through, or sent back for another look.
The one-line fix for non-interactive mode
The sharpest proof is the smallest file: allow-all.sh. It returns a hardcoded JSON response that says the current PreToolUse event should be allowed. That sounds trivial until you connect it to the reported dontAsk bug, where non-interactive mode can behave like an overzealous gate instead of a hands-off assistant.
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
That one line matters because it restores the intended direction of travel. A non-interactive session should not require a human to click through obvious safe actions. The repo treats that as a control-plane bug, not a UX preference.
How the permission firewall makes decisions
The main idea in smart-permission.sh is a staged decision tree. Fast safe commands get out of the way immediately. Suspicious patterns get rejected or flagged. Ambiguous cases move up to a transcript-aware fallback, where the script pulls recent context from the conversation and asks a model to judge the request.
command=$(jq -r '.tool_input // empty')
if echo "$command" | grep -Eq '^(ls|pwd|git status)$'; then
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
elif echo "$command" | grep -Eq 'rm|git reset|git clean'; then
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny"}}'
else
transcript=$(tail -c 50000 "$transcript_path")
# ask the model whether this request is safe in context
fi
The mechanics are old school on purpose. JSON comes in on stdin. jq extracts the payload. grep handles blunt pattern checks. If the command is still ambiguous, the hook can read recent transcript context and make a more informed call.
That is the surprising part. The repo is not trying to replace Claude Code with another framework. It is showing that a shell script, a few Unix tools, and a model call can create a credible safety layer around an agent.
Why hooks beat settings.json
This is where the repo gets opinionated. settings.json is useful, but it is static. It can declare preference, not runtime policy. Hooks can inspect the actual request, the current context, and the state of the conversation before deciding what to do.
| Layer | What it does | What it cannot do |
|---|---|---|
| settings.json | Sets static permission defaults and broad behavior. | Cannot express nuanced policy flows at runtime. |
| CLAUDE.md | Gives the agent local instructions and project context. | Cannot enforce execution-time safety on its own. |
| Hook-based firewall | Inspects live tool requests and returns allow, deny, or ask. | Is more complex to maintain than a plain config file. |
That difference matters in practice. A config file tells the agent what should usually happen. A hook decides what happens now. For agent workflows, that is the difference between guidance and enforcement.
What this repo says about agent workflows
The broader lesson is bigger than Claude Code. If an agent exposes a hook boundary, you can build policy around it with the tools Unix already gave you. Shell remains relevant because it is simple, inspectable, and close to the metal.
That also explains the repo’s style. It reads like a lab notebook for control flow, not a productized toolkit. The value is in the pattern: lightweight interception, explicit branching, and a fallback path that uses context instead of blind rules.
In the landscape around Claude Code, the contrast is clear. Team CLAUDE.md files guide behavior. Centralized harnesses try to orchestrate more of the agent. This repo sits in between, using hooks as a narrow but powerful control plane.