{"slug": "your-claude-code-setup-gets-bloated-if-you-ignore-it-weekly-auto-slimming-by-and", "title": "Your Claude Code Setup Gets Bloated If You Ignore It — Weekly Auto-Slimming by Watching Injected Bytes, Agent Count, and Frustration Words", "summary": "A developer created a self-audit script for Claude Code environments that automatically detects and fixes 'environment decay' — the gradual bloat of rules, agents, and hooks that degrades performance. The script, cc-self-audit.sh, measures five metrics weekly including injected bytes, agent count, and frustration words in transcripts, then uses 'claude -p' to remediate any threshold breaches and re-measures to confirm improvement.", "body_md": "This is the next installment in my \"Claude Code environment\" series. Combined with the [idempotent marker implementation](https://zenn.dev/bokuwalily/articles/substep-idempotent-marker) from the previous article, I've come to realize that more than half of the reasons an autonomous loop won't stop come down to one thing: **environment decay**.\n\nA Claude Code setup **gets fat if you leave it alone**. The rules balloon, agents you thought you'd retired come back to life, and hooks keep misfiring. The only thing you actually notice is a vague \"this feels sluggish\" or \"it keeps making the same mistake,\" and then you burn time hunting down the cause. This article is about a system that measures that decay every week, **lets claude -p fix it, and then confirms the improvement with an independent re-measurement after the fix**.\n\nThis is a real incident I hit during a performance audit on 2026-07-11.\n\nI'd tidied up `~/.claude/agents/`\n\nseveral times. I'd manually moved agent definitions I no longer used into `agents-archive/`\n\nand figured I was done. But when I actually measured, `agents_loaded`\n\nwas still stuck at 99. The culprit was dot-directories (`.deprecated/`\n\n, `.backup/`\n\n, and the like). `find`\n\n's default behavior recurses into dot-directories too. **They looked deleted, but every single one was still being loaded through the hidden directories.**\n\nThis real incident is what prompted me to write `cc-self-audit.sh`\n\n.\n\nThe script's `collect()`\n\nfunction grabs five metrics every run.\n\n```\n# ~/.claude/scripts/cc-self-audit.sh（collect関数より）\n\n# --- 静的 ---\ninject_bytes=$(( \\\n  $(find \"$HOME/.claude/rules\" -name '*.md' -print0 2>/dev/null | xargs -0 cat 2>/dev/null | wc -c) + \\\n  $(cat \"$HOME/.claude/CLAUDE.md\" 2>/dev/null | wc -c) + \\\n  $(cat \"$HOME/CLAUDE.md\" 2>/dev/null | wc -c) + \\\n  $(cat \"$HOME/.claude/projects/-Users-matsubara/memory/MEMORY.md\" 2>/dev/null | wc -c) ))\nagents_loaded=$(find \"$HOME/.claude/agents\" -name '*.md' 2>/dev/null | wc -l | tr -d ' ')\n\n# --- 動的（前回実行以降のtranscriptのみ・最大200ファイル）---\nstopspam=$(echo \"$files\" | xargs /usr/bin/grep -h -c 'セルフ監査未実施。実装' 2>/dev/null | awk '{s+=$1} END{print s+0}')\nfrustration=$(echo \"$files\" | xargs /usr/bin/grep -h -c -E '何回も言|いい加減にし|嘘つ|舐めんな|なんで治らん|最悪やろ|頭悪い' 2>/dev/null | awk '{s+=$1} END{print s+0}')\ntoolerr=$(echo \"$files\" | xargs /usr/bin/grep -h -o -c '\"is_error\":true' 2>/dev/null | awk '{s+=$1} END{print s+0}')\n```\n\n| Metric | Meaning | Threshold |\n|---|---|---|\n`inject_bytes` |\nTotal bytes of rules + CLAUDE.md + MEMORY.md | 40,000 |\n`agents_loaded` |\nTotal .md count under `~/.claude/agents/` (recursion including dot-dirs) |\n60 |\n`stopspam` |\nNumber of times the audit hook fired / week | 15 |\n`frustration` |\nOccurrences of frustration words in transcripts / week | 8 |\n`toolerr` |\nCount of `\"is_error\":true` in transcripts / week |\n400 |\n\nThe two static metrics are proxy variables for **injection cost**, and the three dynamic metrics are proxy variables for **experience quality**. The frustration-word detection may look out of place, but if I'm scolding it repeatedly, that means it's repeating the same failure — and those failures often stem from environment problems (misfiring hooks, rotted memory, broken tools).\n\nThe thresholds can be overridden with env variables.\n\n```\nTH_INJECT_BYTES=\"${SELF_AUDIT_TH_INJECT:-40000}\"\nTH_AGENTS=\"${SELF_AUDIT_TH_AGENTS:-60}\"\nTH_STOPSPAM=\"${SELF_AUDIT_TH_STOPSPAM:-15}\"\nTH_FRUSTRATION=\"${SELF_AUDIT_TH_FRUST:-8}\"\nTH_TOOLERR=\"${SELF_AUDIT_TH_TOOLERR:-400}\"\n```\n\n`claude -p`\n\nfixes itself\nIf every metric is under its threshold, it just posts a one-line `✅ GREEN`\n\nto Discord and exits. If any is over, it calls `claude -p`\n\nto fix it.\n\n```\nBREACH=$(echo \"$METRICS\" | breaches)\n\nif [ -z \"$BREACH\" ]; then\n  log \"GREEN\"\n  touch \"$LASTRUN\"\n  notify \"✅ CC自己監査: 正常 ($METRICS)\"\n  exit 0\nfi\n\nlog \"RED: $BREACH\"\nif [ \"$DRY\" = \"1\" ]; then log \"DRY=1: 修正スキップ\"; touch \"$LASTRUN\"; exit 0; fi\n```\n\nThe prompt passed to `claude -p`\n\nhas a remediation policy embedded for each decay pattern.\n\n```\nPROMPT=\"...\n## 指示\n1. ~/.claude 内だけを調査・修正する（プロジェクトコード・secret・plist削除は禁止）\n2. 既知の劣化パターンと正典:\n   - agents_loaded超過 → ~/.claude/agents/ 配下の退避漏れ（ドットdirも読み込まれる）を ~/.claude/agents-archive/ へ移動\n   - inject_bytes超過 → 肥大したrules/MEMORY.mdを圧縮（フル版は ~/.claude/rules-archive/ へ。リンクは全維持し索引整合を検証）\n   - stopspam超過 → ~/.claude/hooks/self_audit_stop.sh の抑制ロジックを点検\n   - frustration/toolerr超過 → 該当transcriptをgrepして繰り返し失敗の真因を特定し、hook/スキル/メモリで再発防止を仕込む\n3. 変更は1件ずつ ${CHANGELOG} に「日時/対象/理由/戻し方」を追記\n4. 修正後に必ず 'bash ~/.claude/scripts/cc-self-audit.sh --collect-only' を実行し改善を数値で確認\n...\"\n```\n\nI restrict it to filesystem operations only with `--allowedTools \"Read,Write,Edit,Bash,Grep,Glob\"`\n\n, and cap it at max-turns 50 and a 20-minute wall clock (`FIX_TIMEOUT=1200`\n\n).\n\nNote\n\nHaving claude run`--collect-only`\n\nitself inside the fix loop is strictly \"a confirmation as part of the remediation procedure.\" The final verdict of the audit is made by the outer, independent re-measurement. The key to the design is not taking the inner confirmation at face value.\n\nEven when `claude -p`\n\nsays \"fixed it,\" I don't believe it right away. The outer harness **calls collect() again to re-measure the numbers**.\n\n```\n# 独立再計測（自己申告は信じない）\nAFTER=$(collect)\nlog \"after: $AFTER\"\necho \"$AFTER\" >> \"$HISTORY\"\nSTILL=$(echo \"$AFTER\" | breaches)\ntouch \"$LASTRUN\"\n\nif [ -z \"$STILL\" ]; then\n  notify \"🔧 CC自己監査: 劣化検知→自己修正済み。前:[$BREACH] 後:全緑。詳細=$CHANGELOG\"\nelse\n  notify \"🚨 CC自己監査: 自己修正後も残存 [$STILL]。要確認: $LOG / $CHANGELOG\"\nfi\n```\n\nIf a violation still remains after the fix, it flies off to Discord with a `🚨`\n\nand hands it over to a human. **Trust only the OS's measured values, not self-reporting** — that's the core of fail-closed.\n\nAll measured values are stacked one record per line in `~/.claude/self-audit/history.jsonl`\n\n, and the prompt handed to claude also includes the most recent 5 entries as a trend. By looking at the magnitude of change — \"it was 30KB last week but 51KB this week\" — I can distinguish a one-off outlier from a continuous increase.\n\n``` php\n<!-- ~/Library/LaunchAgents/com.lily.cc-self-audit.plist -->\n<key>StartCalendarInterval</key><dict>\n  <key>Weekday</key><integer>0</integer>\n  <key>Hour</key><integer>8</integer>\n  <key>Minute</key><integer>30</integer>\n</dict>\n<key>RunAtLoad</key><false/>\n```\n\nWeekday=0 is Sunday. I set `RunAtLoad`\n\nto false to prevent it from running immediately right after registering with launchd. I include `~/.local/bin`\n\nin the environment variable `PATH`\n\nand place a `claude`\n\nshim there.\n\nThere are two modes for manual runs.\n\n```\n# 計測だけ（claudeを呼ばない）\n~/.claude/scripts/cc-self-audit.sh --collect-only\n\n# ドライラン（違反表示のみ・修正なし）\nSELF_AUDIT_DRY=1 ~/.claude/scripts/cc-self-audit.sh\n```\n\nBefore putting it into production, I always eyeballed the metrics with `DRY=1`\n\nfirst, then enabled it.\n\n`find`\n\n`~/.claude/agents/.deprecated/`\n\nand the like became recursion targets, so agents I thought I'd retired kept getting counted. The root cause of the real incident.`find`\n\nis slow`head -200`\n\nand exclude empty files with `-size +100k`\n\n, the first run of the weekend takes over 3 minutes.`LANG=en_US.UTF-8`\n\nat the top, `grep -E`\n\nmisbehaves on multibyte characters.`claude -p`\n\nisn't on the PATH`~/.local/bin`\n\n. Solved by explicitly adding it to the plist's EnvironmentVariables.`collect()`\n\ncall is mandatory. The inner confirmation stays limited to \"part of the remediation procedure.\"\n\nWarning\n\nAs the comment says —`bash 3.2 compatible, fail-open`\n\n— the audit script itself is designed so that nothing breaks even if it crashes. It uses`set -uo pipefail`\n\n, each individual measurement swallows errors with`2>/dev/null || true`\n\n, and in the worst case the measured value becomes 0 and gets treated as \"GREEN.\" Having the main system die because of an audit failure would be putting the cart before the horse.\n\n`claude -p`\n\nfixes only what's inside `~/.claude`\n\n, and records it in the change log (`self-audit-changes.log`\n\n) with a \"how to revert\" note`--collect-only`\n\nand `DRY=1`\n\nNext time, I'll write about **how I trimmed down the inject_bytes overage** that this audit loop detected — a pipeline that compresses the rules and auto-slims them every week.\n\n*Written by **Lily** — I ship iOS apps and automate my content stack with Claude Code.\n\nFollow along: [Portfolio](https://bokuwalily.com) · [X](https://x.com/bokuwalily) · [GitHub](https://github.com/bokuwalily)*", "url": "https://wpnews.pro/news/your-claude-code-setup-gets-bloated-if-you-ignore-it-weekly-auto-slimming-by-and", "canonical_source": "https://dev.to/bokuwalily/your-claude-code-setup-gets-bloated-if-you-ignore-it-weekly-auto-slimming-by-watching-injected-3jki", "published_at": "2026-07-22 05:00:07+00:00", "updated_at": "2026-07-22 05:30:16.615564+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "large-language-models"], "entities": ["Claude Code"], "alternates": {"html": "https://wpnews.pro/news/your-claude-code-setup-gets-bloated-if-you-ignore-it-weekly-auto-slimming-by-and", "markdown": "https://wpnews.pro/news/your-claude-code-setup-gets-bloated-if-you-ignore-it-weekly-auto-slimming-by-and.md", "text": "https://wpnews.pro/news/your-claude-code-setup-gets-bloated-if-you-ignore-it-weekly-auto-slimming-by-and.txt", "jsonld": "https://wpnews.pro/news/your-claude-code-setup-gets-bloated-if-you-ignore-it-weekly-auto-slimming-by-and.jsonld"}}