How I Cut Claude Code Costs by 53% with a 7-Layer Stack
I've been running Claude Code heavily for months. After the first billing cycle I realized I was burning through API credits faster than I expected. Most of it was going to Opus when Sonnet would have done the job fine, and a lot of it was raw terminal output flooding Claude's context window with noise it didn't need.
So I built a stack. Seven layers, each attacking waste from a different angle. Together they dropped my daily spend from about $27 to $13, a 53% reduction, while making Claude more capable in practice, not less.
Here's the full setup.
Claude Code is powerful but wasteful by default:
- Claude reads every line of
git status,npm install, log output, even when 90% of it is noise. - It defaults to expensive models for everything, including tasks Haiku handles in 200ms.
- Code search means grepping entire files into context, reading thousands of irrelevant lines.
- Fetching a Notion doc or GitHub issue dumps 60KB of raw HTML into your context window.
- Every new session starts with zero memory of what you did last week.
Each of these is a token tax you're paying silently on every single request.
| Layer | What it does | Savings |
|---|---|---|
| 1. Caveman mode | Compresses Claude's own responses | ~65% fewer output tokens |
| 2. RTK | Strips noise from CLI/Bash output before it hits context | 60-90% |
| 3. 3-tier model routing | Haiku for cheap tasks, Sonnet by default, Opus reserved | 40-60% cost |
| 4. Specialized subagents | Parallel, isolated agents with the right model per task | Avoids main-thread bloat |
| 5. mempalace | Semantic memory that persists across sessions | Eliminates re-explaining context |
| 6. semble | Local semantic code search, no API cost | 98% fewer tokens vs grep+read |
| 7. context-mode | Compresses URLs and docs before they enter context | 94-100% on fetched content |
Before starting, make sure you have these available:
node --version # need v18+
python3 --version # need 3.10+
uv --version # install from https://docs.astral.sh/uv/# Cost tracking: reads ~/.claude transcripts locally, no API needed
npm install -g ccusage
# Cross-session semantic memory
uv tool install mempalace
mempalace-mcp --install
# If that fails, try the full path:
# ~/.local/share/uv/tools/mempalace/bin/mempalace-mcp --install
# Note: you do NOT need to manually download mempalace's Stop/PreCompact hooks.
# The Claude Code plugin (installed in Step 6) already wires those internally.
# An older version of this guide had you curl-install standalone hook scripts here β
# those scripts use `#!/bin/bash`, which on macOS resolves to the system bash (3.2),
# missing the `mapfile` builtin the scripts need. They'd silently fail on every run
# while the plugin's real hook did the actual saving in parallel. Skip that step.
# Before/after cost comparison tool
uv tool install claude-cost-compare
# or: pip install claude-cost-compare
# Semantic code search: runs entirely on CPU, no API key required
uv tool install semble
claude mcp add semble -s user -- uvx --from "semble[mcp]" semble
# Bun: required for context-mode performance (3-5x faster than Node)
# Not available via Homebrew, use the official installer:
curl -fsSL https://bun.sh/install | bash
source ~/.zshrcRTK is an internal tool (Rust Token Killer) that proxies Bash commands and strips noise before output reaches Claude's context. If you have access to it, install it and confirm
rtk --versionworks. The hook wires in automatically in Step 4. No RTK? Remove thePreToolUseblock from Step 4.
This gives you a live status bar at the bottom of every Claude Code session showing the active caveman mode badge, which model is running, your current session cost, and a burn rate emoji. It looks like [CAVEMAN] | claude-sonnet-4-5 $0.23 π₯.
mkdir -p ~/.claude/hooks
cat > ~/.claude/hooks/caveman-with-quota-statusline.sh << 'SCRIPT'
#!/bin/bash
CAVEMAN=$(bash "$HOME/.claude/hooks/caveman-statusline.sh" 2>/dev/null || echo "")
STDIN_DATA=$(cat)
CCUSAGE_BIN=""
for v in $(ls -d "$HOME"/.nvm/versions/node/*/bin 2>/dev/null | sort -Vr); do
if [ -x "$v/ccusage" ]; then CCUSAGE_BIN="$v/ccusage"; break; fi
done
[ -z "$CCUSAGE_BIN" ] && CCUSAGE_BIN="$(command -v ccusage 2>/dev/null || echo "")"
CCUSAGE=""
[ -n "$CCUSAGE_BIN" ] && CCUSAGE=$(echo "$STDIN_DATA" | "$CCUSAGE_BIN" statusline --visual-burn-rate emoji 2>/dev/null || echo "")
OUT="$CAVEMAN"
[ -n "$CCUSAGE" ] && OUT="$OUT | $CCUSAGE"
echo "$OUT"
SCRIPT
chmod +x ~/.claude/hooks/caveman-with-quota-statusline.shThe caveman-statusline.sh part of this script is installed automatically by the caveman plugin in Step 6. If you run this before installing the plugin, the caveman badge just won't appear yet.
This is the instruction file Claude reads at the start of every session. It encodes your routing rules, memory integration, and behavioral defaults so you never have to re-explain them.
mkdir -p ~/.claude
cat > ~/.claude/CLAUDE.md << 'MD'
- Always make changes directly in the current branch. Do not create worktrees or
use them inside `<project>/.claude/`.
- When about to compact a conversation, create a handoff file in ~/.claude/handoffs/
with this structure:
# Goal / ## Current state / ## Files in flight / ## Changed / ## Failed attempts / ## Next step
# MemPalace Integration
Persistent semantic memory across sessions via mempalace MCP server.
Key tools (via ToolSearch): mempalace_search, mempalace_status, mempalace_list_wings, mempalace_kg_timeline.
Mine new content with `mempalace mine <dir>` (mode `projects` for code, `convos` for chat exports).
Search prior context with `mempalace search "<query>"`.
# 3-Tier Model Routing
Delegate aggressively to cheaper models. Main thread on Sonnet 4.6. Route subagent work:
- **Haiku 4.5** (cheapest, fast): `cavecrew-investigator` (locate code, grep, glob), `cavecrew-reviewer` (diff review), `Explore` (broad codebase search). Never inline on main thread.
- **Sonnet 4.6** (default): `cavecrew-builder` (1-2 file edits), `general-purpose`, most specialists, anything iterative with the user.
- **Opus 4.7** (reserve): `deep-planner` (architecture, multi-module refactor strategy, trade-off analysis), `Plan` agent for complex implementation planning.
Routing heuristics:
- Semantic code lookup β `semble search` via Bash. 98% fewer tokens than grep+read. Zero API cost. Always try semble first.
- Exact literal/regex match β `grep` via Bash (semble is semantic, not exhaustive).
- PR/diff review β `cavecrew-reviewer` (Haiku). Never inline.
- Reading multiple files to understand a pattern β `cavecrew-investigator` (Haiku). Never inline on main thread.
- Any read-only task semble can't answer β `cavecrew-investigator` (Haiku).
- Code edit β cavecrew-builder if 1-2 files, inline if you have full context.
- Design/architecture decision touching 3+ files β deep-planner (Opus).
- Default: stay on Sonnet. Opus only when reasoning depth is the bottleneck.
## HARD ROUTING RULES
**FORBIDDEN on main thread:**
- `Read` to explore or understand code: use `semble search` or `cavecrew-investigator`
- `Grep` / `Glob` to browse the codebase: use `semble search` first
- `find` via Bash for code exploration: use `semble search` first
- Inline review of diffs, PRs, or multi-file patterns: always `cavecrew-reviewer`
- Reading multiple files to understand "how does X work?": always `cavecrew-investigator`
**ALLOWED on main thread:**
- `Read` only when you know the exact file and are about to edit it
- `Grep` only for exhaustive literal/regex matches semble cannot do
- `semble search` scoped to a subdirectory (never `.` on large repos)
**Decision tree (follow in order):**
1. Code lookup: `semble search "./subdir" "<query>"` first
2. semble not enough: `cavecrew-investigator` (Haiku subagent)
3. Must be literal/regex: `grep` via Bash
4. About to edit: `Read` that specific file
**Additional rules:**
- NEVER re-read a file you already read this session. Read once, keep in mind or use semble.
- Notion READ: `notion-fetch` ONCE per session. Never re-fetch the same page.
- Public URLs (docs, GitHub, web pages): `ctx_fetch_and_index(url)` then `ctx_search`. Never WebFetch inline.
- Notion WRITE: `notion-update-page` only. Never re-fetch after write to verify.
# Code Search (semble)
Semantic code search: 98% fewer tokens than grep+read. Runs on CPU, no API key.
Use `semble search` instead of grep for semantic queries:
semble search "authentication flow" ./path/to/project
semble search "getUserById" ./app --top-k 10
Always scope to a subdirectory on large repos.
MDdeep-planner β the Opus-backed planning agent. Only fires when you need architecture-level reasoning.
mkdir -p ~/.claude/agents
cat > ~/.claude/agents/deep-planner.md << 'MD'
---
name: deep-planner
description: Architecture and design planning that needs deep reasoning. Use for system design, multi-service refactor strategy, trade-off analysis, and design decisions affecting multiple modules. Returns a structured plan with options, trade-offs, and recommended path. Do NOT use for simple edits, lookups, or single-file changes.
tools: Read, Grep, Glob, Bash, WebFetch, WebSearch
model: opus
---
Reserve for genuinely hard reasoning: architecture, multi-service refactors, weighing competing approaches.
Output shape:
1. Problem framing: what's actually being asked, hidden constraints
2. Options considered: at least 2, with cost in code/effort
3. Trade-offs: explicit; what each option gives up
4. Recommended path: picked option and why
5. Risks: what could go wrong, mitigation
6. Concrete next steps: files to touch, order of operations
Always cite file paths and line numbers. If unknown, say "Unknown". Do not fabricate.
MDcode-reviewer override β the comprehensive-review plugin ships code-reviewer with model: opus. Override it at the user level so it runs on Sonnet instead:
cat > ~/.claude/agents/code-reviewer.md << 'MD'
---
name: code-reviewer
description: Elite code review expert specializing in modern AI-powered code analysis, security vulnerabilities, performance optimization, and production reliability. Masters static analysis tools, security scanning, and configuration review with 2024/2025 best practices. Use PROACTIVELY for code quality assurance.
model: sonnet
---
Review code for security vulnerabilities, performance issues, architectural problems, and production reliability.
Output format: `path:line: <emoji> <severity>: <problem>. <fix>.`
Severity: π΄ critical, π high, π‘ medium, π΅ low, βͺ info
One finding per line. No praise. No preamble. Cite exact file and line. Skip formatting nits unless they change behavior.
MDReplace every HOME with your actual home directory path (e.g. /Users/yourname on macOS).
{
"permissions": { "defaultMode": "auto" },
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "node \"HOME/.claude/hooks/caveman-activate.js\"",
"timeout": 5,
"statusMessage": "Loading caveman mode..."
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "node \"HOME/.claude/hooks/caveman-mode-tracker.js\"",
"timeout": 5,
"statusMessage": "Tracking caveman mode..."
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "rtk hook claude"
}
]
}
]
},
"statusLine": {
"type": "command",
"command": "bash \"HOME/.claude/hooks/caveman-with-quota-statusline.sh\""
},
"enabledPlugins": {
"engineering@knowledge-work-plugins": true,
"caveman@caveman": true,
"mempalace@mempalace": true,
"context-mode@context-mode": true,
"python-development@claude-code-workflows": true,
"javascript-typescript@claude-code-workflows": true,
"frontend-mobile-development@claude-code-workflows": true,
"cicd-automation@claude-code-workflows": true,
"database-cloud-optimization@claude-code-workflows": true,
"comprehensive-review@claude-code-workflows": true,
"debugging-toolkit@claude-code-workflows": true
},
"extraKnownMarketplaces": {
"knowledge-work-plugins": {"source": {"source": "github", "repo": "anthropics/knowledge-work-plugins"}},
"caveman": {"source": {"source": "github", "repo": "JuliusBrussee/caveman"}},
"mempalace": {"source": {"source": "github", "repo": "MemPalace/mempalace"}},
"context-mode": {"source": {"source": "github", "repo": "mksglu/context-mode"}},
"claude-code-workflows": {"source": {"source": "github", "repo": "wshobson/agents"}}
},
"env": {"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"},
"teammateMode": "auto",
"theme": "dark",
"skipAutoPermissionPrompt": true
}No RTK? Remove the entire
PreToolUseblock. Ifrtkisn't present, it will fail every Bash command.Notice there's no
StoporPreCompactentry here for mempalace. The plugin (Step 6) wires both internally on its own β adding standalone hook entries on top of that just double-fires and, on macOS, the standalone half silently fails. See the note in Step 1.
If you don't have RTK, or want a backstop even with it, add this hook. It blocks known-noisy
commands outright instead of letting their output hit context, and points Claude at
context-mode's sandbox (ctx_batch_execute) instead.
cat > ~/.claude/hooks/route-bash-to-ctx.sh << 'SCRIPT'
#!/bin/bash
# PreToolUse hook (Bash matcher): hard-blocks known output-volume offenders
# so their raw output never lands in the main conversation.
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')
# Test runners and query plans β reliably verbose, rarely worth reading raw.
if echo "$command" | grep -qE '(^|[[:space:];&|]) *pytest\b' || echo "$command" | grep -qiE 'EXPLAIN[[:space:]]*\(?[[:space:]]*ANALYZE'; then
echo "Blocked: verbose test/query-plan output. Use ctx_batch_execute (context-mode MCP) instead." >&2
exit 2
fi
# Add whatever noisy CLIs you actually use. A few common ones:
# - Cloud CLI reads: gcloud (logs, describe, list)
# - Kubernetes reads: kubectl logs / describe / top / get -o yaml|json
# - Database CLIs: psql, mysql
# - GitHub CLI reads: gh api, gh run view/list
# Mutating commands (apply, delete, create, comment) are left alone on purpose β
# their output is short, blocking them adds friction with no savings.
if echo "$command" | grep -qE '(^|[[:space:];&|]) *(gcloud|psql|mysql)\b' \
|| echo "$command" | grep -qE '(^|[[:space:];&|]) *kubectl (logs|describe|top)\b' \
|| echo "$command" | grep -qE '(^|[[:space:];&|]) *kubectl .*(-o|--output)[[:space:]]*=?[[:space:]]*(yaml|json)' \
|| echo "$command" | grep -qE '(^|[[:space:];&|]) *gh (api|run (view|list))\b'; then
echo "Blocked: verbose CLI output. Use ctx_batch_execute (context-mode MCP) instead." >&2
exit 2
fi
exit 0
SCRIPT
chmod +x ~/.claude/hooks/route-bash-to-ctx.shWire it into the settings.json above, alongside (or instead of) the RTK hook:
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "HOME/.claude/hooks/route-bash-to-ctx.sh" },
{ "type": "command", "command": "rtk hook claude" }
]
}
]Heads up: the hook matches literal command text, not intent. A commit message or grep pattern that happens to contain one of these words (e.g.
"fix: block psql reads") will self-trigger. Keep text mentioning these tools out of your Bash command strings, or write it to a file first and run/commit from that.
Restart Claude Code first, then run these slash-commands one at a time:
/plugin install caveman@caveman
/plugin install mempalace@mempalace
/plugin install context-mode@context-mode
/plugin install python-development@claude-code-workflows
/plugin install javascript-typescript@claude-code-workflows
/plugin install frontend-mobile-development@claude-code-workflows
/plugin install cicd-automation@claude-code-workflows
/plugin install database-cloud-optimization@claude-code-workflows
/plugin install comprehensive-review@claude-code-workflows
/plugin install debugging-toolkit@claude-code-workflows
Installing the caveman plugin above does not, by itself, create the hook files the settings.json
in Step 5 points to. Caveman's plugin manifest ships with an empty hooks declaration on purpose β
the caveman-activate.js/caveman-mode-tracker.js hooks come from a separate standalone install.
Without this step, those settings.json entries point at files that don't exist, and caveman mode
does nothing.
mkdir -p ~/.claude/hooks
for f in caveman-activate.js caveman-mode-tracker.js caveman-config.js caveman-statusline.sh package.json; do
curl -fsSL "https://raw.githubusercontent.com/JuliusBrussee/caveman/main/hooks/$f" \
-o "$HOME/.claude/hooks/$f"
done
chmod +x ~/.claude/hooks/caveman-activate.js ~/.claude/hooks/caveman-mode-tracker.js ~/.claude/hooks/caveman-statusline.sh
# The hooks above look up SKILL.md by relative path to emit the full ruleset (intensity
# levels, worked examples). Without this symlink they silently fall back to a much weaker
# built-in ruleset instead of erroring, so caveman mode looks "on" but barely compresses.
mkdir -p ~/.claude/skills
ln -s ~/.claude/plugins/marketplaces/caveman/plugins/caveman/skills/caveman ~/.claude/skills/cavemanSet your default caveman intensity here, not in CLAUDE.md. Caveman's default mode is resolved by
caveman-config.jsat session start:CAVEMAN_DEFAULT_MODEenv var, then~/.config/caveman/config.json, then a hardcoded fallback offull. CLAUDE.md is never read for this. Pin whichever level you want:mkdir -p ~/.config/caveman cat > ~/.config/caveman/config.json << 'JSON' { "defaultMode": "full" } JSONValid values:
off,lite,full,ultra,wenyan-lite,wenyan-full,wenyan-ultra. Without this file, every restart resets the statusline badge back tofulleven after you changed it by hand with/caveman ultralast session.
The context-mode plugin adds its own hooks automatically. After installing, verify it's working:
/context-mode:ctx-doctor
It should report Performance: FAST (Bun) and show all hooks green. If it shows NORMAL, Bun isn't on your PATH yet. Restart your terminal and re-run ctx-doctor.
Then run semble init in each project you work in:
cd /path/to/your/project && semble init# Cost tracking
ccusage daily --since $(date -v-3d +%Y%m%d 2>/dev/null || date -d '3 days ago' +%Y%m%d)
# Before/after comparison
claude-cost-compare --range 5
# Semantic code search
semble search "hello world" .Restart Claude Code one final time. After a clean start you should see:
[CAVEMAN]badge in the statusline| <model> $X.XXlive cost from ccusage next to it/plugin listshows 11 active plugins/mcpshows mempalace, semble, and context-mode connectedctx-doctorreportsPerformance: FAST (Bun)with all hooks green
After you've run a few sessions with the stack active, you can retroactively index your conversation history:
mempalace mine ~/.claude/projects/ --mode convosThis indexes past conversations into searchable memory drawers. Future sessions can pull relevant context automatically, without you re-explaining what you were working on.
Using ai-cost-compare:
ai-cost-compare --range 7 --cutoff 2026-05-13What I saw after fully rolling this out:
- Before: ~$27/day, 92% Opus
- After: ~$13/day, ~5% Opus, 95% Sonnet
- 53% cost reduction with no drop in output quality
The biggest individual wins were RTK on CLI output (zero behavior change required, immediate savings) and the routing heuristics (stops Opus from firing on tasks Haiku handles in 200ms). Semble was the biggest surprise: replacing grep+read for code lookups eliminates an enormous amount of context bloat without any tradeoff in accuracy.
Each layer works independently. You don't have to adopt all seven at once. But the compounding effect is real.
aaah thank you @ayharano! I really didn't know this. I will update this one here in a bit