Host Disk Cleanup
Overview
Use this for emergency local disk cleanup on the user's machine. The core rule is: inspect first, reclaim obvious rebuildable or disposable data, preserve continuity, and never delete personal/project artifacts just because they are old.
The concrete macOS pattern learned on this host: a single active Codex log (~/.codex/log/codex-tui.log) can grow past 150 GiB while many Codex processes keep it open. The right response is not broad deletion; preserve a tail, truncate the active log, then verify free space.
When to Use
Use when the user says any of:
- 本地空间不足
- 磁盘满了
- 空间不够
- 清理空间
- 清理本地垃圾
- 把不用的删掉
- 删一周内不用的
- 删没标签的
- 清理未打标签文件
- Codex 日志太大
- Hermes state snapshots 太大
- macOS 缓存太大
Do not use for:
- deciding which personal documents, books, screenshots, or Downloads to delete without a candidate list
- deleting repos, worktrees, session history, memories, skills, plugins, cron jobs, auth, or credentials
- destructive cleanup without a manifest and before/after verification
Safety Contract
- Baseline first:
df -h / /System/Volumes/Data 2>/dev/null || df -h /
du -xhd1 "$HOME" 2>/dev/null | sort -h | tail -30
- Treat Finder tags as keep signals. Before deleting user-facing files, check
com.apple.metadata:_kMDItemUserTags.
- Default safe deletion scope:
- rebuildable caches:
~/.cache, ~/Library/Caches, package-manager caches
- temp folders explicitly named temp/tmp
- old Hermes pre-update snapshots or legacy checkpoints beyond retention
- oversized logs, but truncate with tail preservation rather than blind delete
- Default protected scope:
~/Downloads, ~/Documents, ~/Desktop, repo roots, credentials, session transcripts, memories, skills, plugins, cron state
- For active logs opened by a running process, use
lsof first and preserve a tail before truncation.
- Write a cleanup manifest under
~/.hermes/logs/ with removed paths, byte counts, skipped tagged paths, command outputs, and errors.
- Verify after cleanup with
df and targeted du.
Triage Commands
Session References
references/macos-disk-candidates-20260530.md records observed Codex SQLite log behavior, Chrome model-cache targets, Hermes state caveats, and targeted macOS scan commands from a real cleanup run.
Triage Commands
# Filesystem pressure
df -h / /System/Volumes/Data 2>/dev/null || df -h /
# Largest top-level roots under home
du -xhd1 "$HOME" 2>/dev/null | sort -h | tail -30
# Common local-state roots
du -xhd1 "$HOME"/.codex "$HOME"/.hermes "$HOME"/.cache "$HOME"/Library 2>/dev/null | sort -h | tail -50
# Largest files in a suspect root
python3 - <<'PY'
import os, time, heapq
root=os.path.expanduser('~/.codex/log')
heap=[]
for dp, dns, fns in os.walk(root):
for fn in fns:
p=os.path.join(dp,fn)
try: st=os.stat(p)
except OSError: continue
item=(st.st_size,p,st.st_mtime)
if len(heap)<30: heapq.heappush(heap,item)
else: heapq.heappushpop(heap,item)
for size,p,mt in sorted(heap, reverse=True):
print(f'{size/1024/1024/1024:8.2f}G {((time.time()-mt)/86400):6.1f}d {p}')
PY
# Who is writing an oversized log
lsof "$HOME/.codex/log/codex-tui.log" 2>/dev/null | head -20
Safe Active Log Truncation
Use this pattern when a log is huge and active. It keeps the last bytes for evidence and truncates the same inode so open writers continue safely.
python3 - <<'PY'
from pathlib import Path
import time
path = Path.home()/'.codex/log/codex-tui.log'
keep_bytes = 20 * 1024 * 1024
archive_dir = Path.home()/'.codex/archived_logs'
archive_dir.mkdir(parents=True, exist_ok=True)
stamp = time.strftime('%Y%m%d-%H%M%S')
tail_path = archive_dir / f'{path.name}.{stamp}.tail'
size = path.stat().st_size
with open(path, 'rb') as f:
f.seek(max(0, size - keep_bytes))
data = f.read()
with open(tail_path, 'wb') as out:
out.write(data)
with open(path, 'r+b') as f:
f.truncate(0)
print(f'truncated={path} old_bytes={size} kept_tail={tail_path} kept_bytes={len(data)}')
PY
Also check Hermes MCP stderr when Hermes logs are large:
lsof "$HOME/.hermes/logs/mcp-stderr.log" 2>/dev/null | head -20
Apply the same preserve-tail-and-truncate pattern, with keep_bytes = 5 * 1024 * 1024 and archive dir ~/.hermes/logs/archived.
Older-than-7-Days Untagged Cleanup
For this user's phrasing, "一周内不用" means candidates older than 7 days. Do not apply it to all of $HOME. Apply only to safe classes unless the user explicitly approves a candidate list for personal files.
Safe classes:
~/.cache/* older than 7 days and untagged
~/Library/Caches/* older than 7 days and untagged
~/tmp/* older than 7 days and untagged
~/.hermes/state-snapshots/YYYYMMDD-*-pre-update older than 7 days and untagged
~/.hermes/checkpoints/legacy-* older than 7 days and untagged
Do not automatically delete old files under ~/Downloads; produce a list first.
Finder tag check:
import os
def has_finder_tags(path: str) -> bool:
try:
return bool(os.getxattr(path, 'com.apple.metadata:_kMDItemUserTags'))
except OSError:
return False
Package Cache Cleaners
Run after targeted triage, not before the baseline:
uv cache prune --no-progress
npm cache clean --force
python3 -m pip cache purge
go clean -cache -testcache
brew cleanup --prune=7
Ignore unavailable tools. Record output in the manifest.
Manifest Requirements
Write JSON to:
~/.hermes/logs/disk-cleanup-YYYYMMDD-HHMMSS.json
Include:
- start and finish timestamp
- before and after
df
- every removed path and byte count
- every truncated log, old size, tail path, kept bytes
- every skipped path due to Finder tags
- every package-clean command exit code and output tail
- errors such as macOS Trash permission denial
Verification Checklist
Common Pitfalls
- Broadly applying "older than 7 days" to the whole home directory. This can delete books, screenshots, datasets, and project artifacts. Restrict to safe classes first.
- Deleting an open log file instead of truncating it. On Unix, deleting an open file may not reclaim space until the writer exits. Truncate the active inode after preserving a tail.
- Trusting source paths over live disk usage. Always use
du and lsof on the live machine.
- Treating all
.hermes state as disposable. Preserve sessions, auth, skills, plugins, cron jobs, and recent snapshots.
- Failing silently on macOS protected folders such as
.Trash. Record permission errors; do not force privileged deletion unless explicitly approved.
1---2name: host-disk-cleanup3description: Use when the local machine is out of disk space or the user asks to delete unused, untagged, old, cache, log, snapshot, Codex, or Hermes local state without touching important personal files.4license: MIT5---67# Host Disk Cleanup89## Overview1011Use this for emergency local disk cleanup on the user's machine. The core rule is: inspect first, reclaim obvious rebuildable or disposable data, preserve continuity, and never delete personal/project artifacts just because they are old.1213The concrete macOS pattern learned on this host: a single active Codex log (`~/.codex/log/codex-tui.log`) can grow past 150 GiB while many Codex processes keep it open. The right response is not broad deletion; preserve a tail, truncate the active log, then verify free space.1415## When to Use1617Use when the user says any of:18- 本地空间不足19- 磁盘满了20- 空间不够21- 清理空间22- 清理本地垃圾23- 把不用的删掉24- 删一周内不用的25- 删没标签的26- 清理未打标签文件27- Codex 日志太大28- Hermes state snapshots 太大29- macOS 缓存太大3031Do not use for:32- deciding which personal documents, books, screenshots, or Downloads to delete without a candidate list33- deleting repos, worktrees, session history, memories, skills, plugins, cron jobs, auth, or credentials34- destructive cleanup without a manifest and before/after verification3536## Safety Contract37381. Baseline first:39 - `df -h / /System/Volumes/Data 2>/dev/null || df -h /`40 - `du -xhd1 "$HOME" 2>/dev/null | sort -h | tail -30`412. Treat Finder tags as keep signals. Before deleting user-facing files, check `com.apple.metadata:_kMDItemUserTags`.423. Default safe deletion scope:43 - rebuildable caches: `~/.cache`, `~/Library/Caches`, package-manager caches44 - temp folders explicitly named temp/tmp45 - old Hermes pre-update snapshots or legacy checkpoints beyond retention46 - oversized logs, but truncate with tail preservation rather than blind delete474. Default protected scope:48 - `~/Downloads`, `~/Documents`, `~/Desktop`, repo roots, credentials, session transcripts, memories, skills, plugins, cron state495. For active logs opened by a running process, use `lsof` first and preserve a tail before truncation.506. Write a cleanup manifest under `~/.hermes/logs/` with removed paths, byte counts, skipped tagged paths, command outputs, and errors.517. Verify after cleanup with `df` and targeted `du`.5253## Triage Commands5455## Session References5657- `references/macos-disk-candidates-20260530.md` records observed Codex SQLite log behavior, Chrome model-cache targets, Hermes state caveats, and targeted macOS scan commands from a real cleanup run.5859## Triage Commands6061```bash62# Filesystem pressure63df -h / /System/Volumes/Data 2>/dev/null || df -h /6465# Largest top-level roots under home66du -xhd1 "$HOME" 2>/dev/null | sort -h | tail -306768# Common local-state roots69du -xhd1 "$HOME"/.codex "$HOME"/.hermes "$HOME"/.cache "$HOME"/Library 2>/dev/null | sort -h | tail -507071# Largest files in a suspect root72python3 - <<'PY'73import os, time, heapq74root=os.path.expanduser('~/.codex/log')75heap=[]76for dp, dns, fns in os.walk(root):77 for fn in fns:78 p=os.path.join(dp,fn)79 try: st=os.stat(p)80 except OSError: continue81 item=(st.st_size,p,st.st_mtime)82 if len(heap)<30: heapq.heappush(heap,item)83 else: heapq.heappushpop(heap,item)84for size,p,mt in sorted(heap, reverse=True):85 print(f'{size/1024/1024/1024:8.2f}G {((time.time()-mt)/86400):6.1f}d {p}')86PY8788# Who is writing an oversized log89lsof "$HOME/.codex/log/codex-tui.log" 2>/dev/null | head -2090```9192## Safe Active Log Truncation9394Use this pattern when a log is huge and active. It keeps the last bytes for evidence and truncates the same inode so open writers continue safely.9596```bash97python3 - <<'PY'98from pathlib import Path99import time100path = Path.home()/'.codex/log/codex-tui.log'101keep_bytes = 20 * 1024 * 1024102archive_dir = Path.home()/'.codex/archived_logs'103archive_dir.mkdir(parents=True, exist_ok=True)104stamp = time.strftime('%Y%m%d-%H%M%S')105tail_path = archive_dir / f'{path.name}.{stamp}.tail'106size = path.stat().st_size107with open(path, 'rb') as f:108 f.seek(max(0, size - keep_bytes))109 data = f.read()110with open(tail_path, 'wb') as out:111 out.write(data)112with open(path, 'r+b') as f:113 f.truncate(0)114print(f'truncated={path} old_bytes={size} kept_tail={tail_path} kept_bytes={len(data)}')115PY116```117118Also check Hermes MCP stderr when Hermes logs are large:119120```bash121lsof "$HOME/.hermes/logs/mcp-stderr.log" 2>/dev/null | head -20122```123124Apply the same preserve-tail-and-truncate pattern, with `keep_bytes = 5 * 1024 * 1024` and archive dir `~/.hermes/logs/archived`.125126## Older-than-7-Days Untagged Cleanup127128For this user's phrasing, "一周内不用" means candidates older than 7 days. Do not apply it to all of `$HOME`. Apply only to safe classes unless the user explicitly approves a candidate list for personal files.129130Safe classes:131- `~/.cache/*` older than 7 days and untagged132- `~/Library/Caches/*` older than 7 days and untagged133- `~/tmp/*` older than 7 days and untagged134- `~/.hermes/state-snapshots/YYYYMMDD-*-pre-update` older than 7 days and untagged135- `~/.hermes/checkpoints/legacy-*` older than 7 days and untagged136137Do not automatically delete old files under `~/Downloads`; produce a list first.138139Finder tag check:140141```python142import os143144def has_finder_tags(path: str) -> bool:145 try:146 return bool(os.getxattr(path, 'com.apple.metadata:_kMDItemUserTags'))147 except OSError:148 return False149```150151## Package Cache Cleaners152153Run after targeted triage, not before the baseline:154155```bash156uv cache prune --no-progress157npm cache clean --force158python3 -m pip cache purge159go clean -cache -testcache160brew cleanup --prune=7161```162163Ignore unavailable tools. Record output in the manifest.164165## Manifest Requirements166167Write JSON to:168169```text170~/.hermes/logs/disk-cleanup-YYYYMMDD-HHMMSS.json171```172173Include:174- start and finish timestamp175- before and after `df`176- every removed path and byte count177- every truncated log, old size, tail path, kept bytes178- every skipped path due to Finder tags179- every package-clean command exit code and output tail180- errors such as macOS Trash permission denial181182## Verification Checklist183184- [ ] `df` shows meaningful reclaimed space.185- [ ] Largest suspected log no longer dominates disk usage.186- [ ] Tail archive exists for truncated logs.187- [ ] Recent Hermes state snapshots remain if they are within retention.188- [ ] `Downloads`, repos, documents, skills, memories, sessions, auth, and cron state were not broadly deleted.189- [ ] Manifest path is reported to the user.190191## Common Pitfalls1921931. Broadly applying "older than 7 days" to the whole home directory. This can delete books, screenshots, datasets, and project artifacts. Restrict to safe classes first.1942. Deleting an open log file instead of truncating it. On Unix, deleting an open file may not reclaim space until the writer exits. Truncate the active inode after preserving a tail.1953. Trusting source paths over live disk usage. Always use `du` and `lsof` on the live machine.1964. Treating all `.hermes` state as disposable. Preserve sessions, auth, skills, plugins, cron jobs, and recent snapshots.1975. Failing silently on macOS protected folders such as `.Trash`. Record permission errors; do not force privileged deletion unless explicitly approved.