I love using Claude Code. The promise is undeniable: rapid refactoring, lightning-fast debugging, and a highly capable AI agent operating right in the terminal.
But a few sessions in, I hit a massive roadblock. My token usage was skyrocketing, the agent was slowing down, and I was burning through usage limits at a frustrating pace.
When I dug into the logs to see where my context was going, the culprit wasn't complex coding problems. It was pure context bloat. The agent was acting like a data hoarder. It would run an unbounded grep across the repository, dumping thousands of lines of terminal output into the chat. Or worse, it would use the Read tool to slurp a massive 2,000-line file just to modify a single, isolated function.
Because LLMs resend the entire conversation history on every single turn, a sloppy full-file read on turn three isn't a one-time fee. I was paying to replay that same giant haystack on turn four, five, six, and all the way down the session.
I needed to stop asking the AI nicely to be efficient and start enforcing boundaries at the system level. But I quickly learned that simply blocking the AI isn't enough—if you slam the door in its face, it wastes even more tokens guessing how to fix its mistake. You have to feed it the solution.
Moving Beyond Prompt Politeness: The Auto-Suggest Hook
Initially, I tried adding rules to a global CLAUDE.md file, telling the agent to "always use line limits." But context drift is real. In longer sessions, the model gets distracted and drifts back to its lazy, token-hogging habits.
To fix it permanently, I built a dedicated Claude Code Plugin using a behavioral PreToolUse hook. Instead of a soft suggestion, it acts as an automated gatekeeper that checks the AI's commands before they run.
Crucially, when the hook blocks a command, it doesn't just say "No." It intercepts the intent, rewrites the syntax properly, and hands the corrected command back to the model as an auto-suggestion. This prevents the model from entering a costly "retry loop" trying to guess the rules.
The Token-Saving Intercept Script
Here is the exact enforce-limits.sh script I package into the plugin. It handles grep dumps and massive file reads, instantly transforming bad habits into surgical behavior:
```
!/bin/bash
token-optimizer-plugin/hooks/enforce-limits.sh
PAYLOAD=$(cat)
TOOL_NAME=$(echo "$PAYLOAD" | jq -r '.tool_name')
1. Grep Output Discipline with Auto-Correction
if [ "$TOOL_NAME" = "Bash" ]; then
COMMAND=$(echo "$PAYLOAD" | jq -r '.tool_input.command')
if echo "$COMMAND" | grep -qE "^(grep|rg) "; then
# Reject the search if it isn't piped to head
if ! echo "$COMMAND" | grep -qE "\|\s*head\b"; then
# Generate the exact corrected command for the AI
SUGGESTION="${COMMAND} | head -50"
jq -n --arg reason "Token Policy: Unbounded searches flood context. Auto-fix: Run exactly this command instead: \`$SUGGESTION\`" '{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": $reason
}
}'
exit 2
fi
fi
fi
2. Surgical File Reads with Auto-Correction
if [ "$TOOL_NAME" = "Read" ]; then
OFFSET=$(echo "$PAYLOAD" | jq -r '.tool_input.offset // empty')
LIMIT=$(echo "$PAYLOAD" | jq -r '.tool_input.limit // empty')
# Reject the read if the AI tries to slurp the whole file
if [ -z "$OFFSET" ] || [ -z "$LIMIT" ]; then
jq -n '{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Token Policy: Full file reads are disabled. Auto-fix: Please retry this tool using offset: 0 and limit: 150 to inspect the file header first."
}
}'
exit 2
fi
fi
exit 0
```
By registering this script inside a custom .claude-plugin/plugin.json manifest, Claude Code is forced to play by these rules across every project workspace.
Measuring the ROI: A Quick Tracker
To prove this wasn't just "compression theater," I wrote a companion utility script to track exactly how much context memory (and money) this plugin saves across a typical coding session:
```
!/bin/bash
token-optimizer-plugin/scripts/track-savings.sh
echo "📊 Claude Token Savings Calculator"
echo "----------------------------------"
read -p "Estimated lines of code blocked (e.g., 2000): " LINES
read -p "Number of chat turns remaining in session (e.g., 10): " TURNS
Rough estimation: 1 line of code ≈ 10 tokens
TOKENS_PER_TURN=$((LINES * 10))
TOTAL_TOKENS_SAVED=$((TOKENS_PER_TURN * TURNS))
Approximate Claude 3.5 Sonnet Pricing per 1M input tokens
COST_PER_MILLION=3.00
SAVINGS=$(echo "scale=4; ($TOTAL_TOKENS_SAVED / 1000000) * $COST_PER_MILLION" | bc)
echo ""
echo "✅ Total Context Blocked: $TOTAL_TOKENS_SAVED tokens"
echo "💰 Estimated Cost Saved: \$${SAVINGS}"
echo "⚡ Note: This also kept the context clean, drastically reducing model hallucinations!"
```
The Payoff: 80% Leaner Sessions
The change in behavior was instant. Because the agent receives an explicit auto-correction prompt the moment it slips up, it doesn't fumble. It instantly self-corrects on the very next turn, adapting its workflow without wasting tokens on a retry cycle. It finds the target files using a quick filename search, and then pulls exactly the 30 lines it needs using precise offset and limit parameters.
- Context Reduction:Token usage on heavy editing tasks plummeted by an estimated- 75% to 80%.
- Speed Boost:Because the context window stays incredibly lean, Claude responds significantly faster. It doesn't have to chew through megabytes of old terminal output on every turn.
- Fewer Hallucinations:Keeping stale, irrelevant code out of the replay tail keeps the agent focused entirely on the problem at hand.
If you are running into token limits or experiencing performance degradation with AI CLI agents, stop relying on your system prompt. Treat your context window like production memory, build an auto-suggesting hook, and let the tool police itself.