My Claude Code Logs Ballooned to 22MB — Nightly Auto-Trimming with launchd A developer built a log-rotation script for macOS launchd to prevent Claude agent logs from ballooning to 22MB. The script truncates files over 5MB to the last 2000 lines and deletes artifacts older than 30 days, keeping the log directory at around 20MB. Nobody plans for log files. You wire up a background job, it works, and six weeks later a directory you never look at is quietly eating your disk. In my previous post on automating self-audits https://zenn.dev/bokuwalily/articles/cc-env-self-audit I built the skeleton of a nightly job. This post is about the side effect of that: the logs my resident agents keep spewing grew without bound , and how I designed a trimming script wired into launchd to keep things quiet. Once you have 20+ agents running as residents, logs pile up by hundreds of KB per day. Measured this morning right after the 03:45 automated run , ~/.claude/logs/ was 20M, and 21M as of now 10:43 . 188 files. It was only a matter of time before it crossed 22MB. The more launchd jobs there are, the more logs there are. Looking at the representative large files makes it obvious. 5.7M agentmemory.err.log 3.8M vault-auto-ingest.log 3.1M hook-latency.jsonl 2.7M cost-log.jsonl 728K dotfiles-snapshot.log Every one of them just streams errors and progress forever, and I almost never read the old lines . All I need is "what happened recently." And yet the logs keep accumulating, and the number from du -sh ~/.claude/logs/ jumps every day. Plain deletion is a problem — if the log is empty when I'm chasing down a recent error, I'm stuck. So instead of deleting, I went with keeping only the tail . The policy of log-rotate.sh fits in three lines. tail -n 2000 and overwriteI use the word "rotate," but it isn't rotation. It just truncates the file. No backups either. The latest 2000 lines are plenty to trace a recent failure. Here is the full text of ~/.claude/scripts/log-rotate.sh . It fits in 60 lines. bash /bin/bash log-rotate.sh — ~/.claude/logs の肥大防止(毎日03:45 launchd) 方針: 5MB超のログは末尾2000行だけ残して切詰め / 30日超の日付付き成果物・マーカー・bakは削除 set -uo pipefail LOGDIR="$HOME/.claude/logs" SELF LOG="$LOGDIR/log-rotate.log" MAX BYTES=$ 5 1024 1024 KEEP LINES=2000 echo " $ date '+%F %T' rotate start" "$SELF LOG" 1 肥大ログの切詰め(.log / .err / .out / .jsonl) find "$LOGDIR" -maxdepth 1 -type f \ -name ' .log' -o -name ' .err' -o -name ' .out' -o -name ' .jsonl' \ | while read -r f; do sz=$ stat -f%z "$f" 2 /dev/null || echo 0 if "$sz" -gt "$MAX BYTES" ; then tail -n "$KEEP LINES" "$f" "$f.tmp" && mv "$f.tmp" "$f" echo " $ date '+%F %T' truncated $ basename "$f" $sz bytes - $ stat -f%z "$f" bytes " "$SELF LOG" fi done 2 日付付き成果物・マーカー・バックアップの30日超削除 find "$LOGDIR" -maxdepth 1 -type f \ \ -name 'daily-brief-2 .md' -o -name 'project-health-2 .md' -o \ -name '. -done- ' -o -name '.vault-ingest- ' -o -name ' .plist.bak ' \ \ -mtime +30 -delete 2 /dev/null 3 自分自身のログも肥大防止 sz=$ stat -f%z "$SELF LOG" 2 /dev/null || echo 0 "$sz" -gt "$MAX BYTES" && tail -n "$KEEP LINES" "$SELF LOG" "$SELF LOG.tmp" && mv "$SELF LOG.tmp" "$SELF LOG" echo " $ date '+%F %T' rotate done dir=$ du -sh "$LOGDIR" | cut -f1 " "$SELF LOG" Truncation results are recorded in log-rotate.log . Here's actual output. php 2026-07-12 03:45:05 truncated agentmemory.err.log 5449070 bytes - 331336 bytes 2026-07-19 03:45:05 truncated hook-latency.jsonl 5376787 bytes - 178061 bytes 2026-07-19 03:45:05 truncated vault-auto-ingest.log 5255158 bytes - 105277 bytes 2026-07-26 03:45:05 rotate done dir=20M agentmemory.err.log shrank from 5.2MB → 324KB, and hook-latency.jsonl from 5.1MB → 174KB. Note The reason for the two-step tail -n 2000 "$f" "$f.tmp" && mv "$f.tmp" "$f" is to prevent a redirect to the same file from blowing away its contents. Never use a direct "$f" overwrite. Here is the full text of ~/Library/LaunchAgents/com.shun.log-rotate.plist .