A Claude Code hook that catches a real failure mode in the built-in Read
tool, plus a written-up, fact-checked reference on what actually reduces
Claude Code token/quota spend versus what's a myth.
Everything here is scoped so it only changes behavior for terminal CLI
sessions on a specific model (originally built around Claude "Fable 5") --
every other surface and model is left completely untouched. Swap the model
prefix in hooks/lib/model_terminal_gate.py to gate on whatever model you
actually want.
hooks/lib/model_terminal_gate.py-- shared detection: is this a terminal entrypoint, and is the active model the one you're gating on? Claude Code hook payloads don't include the current model directly, so this parses it out of the live session transcript instead.hooks/block-huge-reads.py-- aPreToolUsehook onReadthat warns above 500 lines and denies above 2000, forcing an explicitGrep+ targetedoffset/limitread instead of a blind full-file read. This exists because Claude Code's Read tool has a documented line cap that doesn't reliably self-enforce, and a separate confirmed bug where a large file can be partially read with no signal anything was missed. Seeskills/fable-cost-reduction-mdc/SKILL.mdfor the exact issue numbers and sourcing.hooks/logs_to_sqlite.py-- aPreToolUsehook onReadthat converts large log files (.logextension or common names likeapp.log) past 1000 lines into a cached, queryable SQLite db instead of dumping every line into context. Every line is kept verbatim in arawcolumn even when the generic timestamp/level parser doesn't match, so an unusual log format still ends up fully queryable rather than silently losing content. Runs ahead ofblock-huge-reads.pyin the same hook list; non-log files fall through untouched.skills/fable-cost-reduction-mdc/SKILL.md-- a Claude Code skill file: a ranked, sourced list of real cost/quota levers (subagent delegation, prompt-cache discipline, the 5-minute cache TTL, this Read guard) versus debunked non-levers (1M context has no price premium; MCP tool schemas are already deferred by default). Useful as a skill even if you don't install the hooks.
mkdir -p ~/.claude/hooks/lib ~/.claude/skills/fable-cost-reduction-mdc
cp hooks/block-huge-reads.py ~/.claude/hooks/
cp hooks/logs_to_sqlite.py ~/.claude/hooks/
cp hooks/lib/model_terminal_gate.py ~/.claude/hooks/lib/
cp skills/fable-cost-reduction-mdc/SKILL.md ~/.claude/skills/fable-cost-reduction-mdc/Then register the hook in ~/.claude/settings.json (merge into any existing
hooks.PreToolUse array):
{
"matcher": "Read",
"hooks": [
{ "type": "command", "command": "python3 $HOME/.claude/hooks/logs_to_sqlite.py" },
{ "type": "command", "command": "python3 $HOME/.claude/hooks/block-huge-reads.py" }
]
}Order matters: logs_to_sqlite.py runs first so it gets first crack at
log-shaped files; everything else falls through to block-huge-reads.py
untouched. See docs/settings-json-snippet.md
for details.
If you run one high-usage/premium model on a Max-plan-style quota, and want a
guardrail that fires only there without touching your other sessions, this
pattern (detect terminal entrypoint + detect model from the transcript, fail
open on any uncertainty) is the reusable piece -- the specific hook
(block-huge-reads.py) is just one example built on top of it.
Both hooks are built and unit-tested: block-huge-reads.py against all gate
combinations (gate off, small file, warn tier, deny tier, explicit
offset/limit bypass); logs_to_sqlite.py against small-log passthrough,
non-log passthrough, cache reuse, and gate-off. No external dependencies
beyond Python 3's standard library.
MIT, see LICENSE.