The Bigger Your CLAUDE.md Gets, the Slower Claude Code Runs — Measuring Context Injection Bytes Weekly to Catch Degradation Early A developer found that bloated CLAUDE.md files and orphaned agent configurations were causing Claude Code to run slowly, with context injection exceeding 40KB and 99 archived agents still being loaded. To catch degradation early, they built a weekly self-audit script that measures injection bytes, agent count, stop-hook spam, frustration keywords, and tool errors, automatically attempting fixes when thresholds are breached. This is the next installment in my "Claude Code environment" series. In the previous post on the self-audit frustration loop https://zenn.dev/bokuwalily/articles/selfaudit-frustration-loop , I wrote about a "never-ending improvement loop." This time I want to dig into what sits at the root of it: detecting and self-correcting context injection bloat . At the start of every session, Claude Code unconditionally injects the full contents of rules/ .md , ~/.claude/CLAUDE.md , ~/CLAUDE.md , and MEMORY.md . Every time you add a rule, this byte count silently grows. In an audit on 2026-07-11, I found that total injection had exceeded 40KB, and 99 agents I thought I had archived were still being loaded — the main cause of my performance degradation. Since then, I've kept a permanent loop running that measures this automatically every week and attempts self-correction when thresholds are exceeded. Adding rules to CLAUDE.md is a good thing. But "adding" only moves in one direction. After half a year, forgotten sections get duplicated, an archive you thought was compressed turns out to still be live, and files you moved to .agents/ keep getting loaded anyway. The core issue is that degradation is invisible unless you measure it . Claude's gut feeling of "this seems sluggish" may be correct, but nobody routinely checks how many KB are being injected. I needed a mechanism that produces the numbers weekly and automatically attempts a fix when a human-defined threshold is exceeded. The collect function in ~/.claude/scripts/cc-self-audit.sh assembles the metrics. There are two axes: static and dynamic measurement. inject bytes=$ \ $ find "$HOME/.claude/rules" -name ' .md' -print0 2 /dev/null | xargs -0 cat 2 /dev/null | wc -c + \ $ cat "$HOME/.claude/CLAUDE.md" 2 /dev/null | wc -c + \ $ cat "$HOME/CLAUDE.md" 2 /dev/null | wc -c + \ $ cat "$HOME/.claude/projects/-Users-matsubara/memory/MEMORY.md" 2 /dev/null | wc -c agents loaded=$ find "$HOME/.claude/agents" -name ' .md' 2 /dev/null | wc -l | tr -d ' ' find ... -name ' .md' recurses into dot directories too. Even if you think "I moved them to agents-archive/ , so it's fine," if that directory lives under ~/.claude/agents/ as a dot directory, the files keep getting loaded — that's the trap this is exactly how 99 agents survived on 2026-07-11 . Three metrics are aggregated from the transcripts .jsonl since the last run. STOP MARKER = 'Stop hook feedback:\\n ~/.claude/hooks/self audit stop.sh : ' FRUST RE = re.compile r'何回も言|いい加減にし|嘘つ|舐めんな|なんで治らん|最悪やろ|頭悪い' stopspam counts only "lines that the Stop hook actually injected into the prompt." A naive grep also picks up the same string when it happens to appear inside a tool result, inflating the number 6–10x over reality I fixed exactly this on 2026-07-12, correcting 40 → 6 . For frustration, only text blocks of type=user that are not isMeta — i.e., the human's own raw utterances — are counted. TH INJECT BYTES="${SELF AUDIT TH INJECT:-40000}" rules+CLAUDE.md+MEMORY.md 合計 TH AGENTS="${SELF AUDIT TH AGENTS:-60}" ~/.claude/agents 配下 .md 総数 TH STOPSPAM="${SELF AUDIT TH STOPSPAM:-15}" 監査hook発火/週 TH FRUSTRATION="${SELF AUDIT TH FRUST:-8}" 不満ワード/週 TH TOOLERR="${SELF AUDIT TH TOOLERR:-400}" tool失敗/週 They're overridable via environment variables, so tuning them later never requires touching the script. breaches lists the items that exceeded their thresholds and hands them to claude -p . BREACH=$ echo "$METRICS" | breaches if -z "$BREACH" ; then log "GREEN" notify "✅ CC自己監査: 正常 $METRICS " exit 0 fi When there are breaches, the prompt restricts fixes to inside ~/.claude only touching project code, secrets, or deleting plists is explicitly forbidden . PROMPT="あなたはClaude Code環境の自己監査・自己修復エージェント。週次監査で劣化を検知した。 ... 1. ~/.claude 内だけを調査・修正する(プロジェクトコード・secret・plist削除は禁止) 2. 既知の劣化パターンと正典: - agents loaded超過 → ~/.claude/agents/ 配下の退避漏れを ~/.claude/agents-archive/ へ移動 - inject bytes超過 → 肥大したrules/MEMORY.mdを圧縮(フル版は ~/.claude/rules-archive/ へ) ... 4. 修正後に必ず 'bash ~/.claude/scripts/cc-self-audit.sh --collect-only' を実行し改善を数値で確認 ..." After claude -p finishes, the script itself calls collect once more for an independent re-measurement . Claude's self-reporting is not trusted. 独立再計測(自己申告は信じない) AFTER=$ collect STILL=$ echo "$AFTER" | breaches if -z "$STILL" ; then notify "🔧 CC自己監査: 劣化検知→自己修正済み。前: $BREACH 後:全緑。" else notify "🚨 CC自己監査: 自己修正後も残存 $STILL 。要確認: $LOG" fi When everything is green, it sends ✅ a single line ; breach followed by a successful fix sends 🔧 with before/after numbers ; breaches remaining after the fix sends 🚨 — all to the 01 alerts channel on Discord. Since it's weekly, it never gets noisy — a low-noise setup that doubles as a liveness check. Here's the core of ~/Library/LaunchAgents/com.lily.cc-self-audit.plist .