Skip to content

Repository files navigation

cleanup-chromes

Deletes the browser binaries your coding agents leave behind — and kills the ones still burning CPU after their agent died.

cleanup-chromes is a skill for AI agents that reclaims disk space on macOS from throwaway test-browser caches and macOS code_sign_clone leftovers — often 10–60+ GB — and terminates orphaned automation-browser process trees that heat up your Mac while you do nothing. It deletes only hardcoded, regenerable targets and kills only process trees that pass every orphan gate. Real browser profiles, /Applications, and live sessions are hard-refused.

💾 The cause

AI coding agents (Claude Code, Codex, Cursor, …) drive real browsers. To do that, Playwright, Puppeteer, Cypress, Selenium, and chrome-devtools-mcp each download their own Chromium builds, and macOS creates extra code-sign copies of Chrome, Brave, Edge, and OpenAI apps on top. None of these tools clean up after themselves. The leftovers pile up in known locations:

  • ~/Library/Caches/ms-playwright, ~/.cache/puppeteer, ~/Library/Caches/Cypress — downloaded browser builds, several GB each
  • /private/var/folders/.../X/com.google.Chrome.code_sign_clone — macOS code-sign clones; Disk Utility and du will show these at 38+ GB, but that is the apparent size (APFS shares blocks with the app itself) — the real gain is smaller and is measured only after deletion

If DaisyDisk, du, or Storage settings ("System Data") show gigabytes in places like these, this skill is the fix: it deletes exactly these agent-created leftovers — and nothing else. Every tool re-downloads what it needs on next use.

🔥 Or: why your Mac is hot while you're doing nothing

When a coding agent's session crashes or gets killed, the browser it was driving doesn't die with it. A headless Chrome and its Playwright daemon keep running for hours — spinning at 40–60% CPU on work nothing will ever collect — and on a fanless MacBook Air that alone makes the chassis hot. Busy CPU proves nothing: the orphan's debugging pipe is dead, so it can never be driven again. kill-orphans finds these trees and shuts them down, but only after every gate agrees they are truly abandoned (see 🧟 Orphaned browser processes).

📦 Install

Codex

/skill-installer cleanup-chromes from Rayan-and-beyond/cleanup-chromes

Restart Codex if it asks you to.

Manual install — copy the skill folder to ~/.agents/skills/:

git clone https://github.com/Rayan-and-beyond/cleanup-chromes.git /tmp/cc && cp -r /tmp/cc/skills/cleanup-chromes ~/.agents/skills/ && rm -rf /tmp/cc

Claude Code

npx skills add Rayan-and-beyond/cleanup-chromes -a claude-code -g

Or Claude Code's native plugin flow:

/plugin marketplace add Rayan-and-beyond/cleanup-chromes
/plugin install cleanup-chromes@cleanup-chromes

Installs to ~/.claude/skills/cleanup-chromes.

Any agent CLI

npx skills add Rayan-and-beyond/cleanup-chromes

GitHub CLI:

gh skill install Rayan-and-beyond/cleanup-chromes

Other agents

Anything that reads the open Agent Skills standard works — copy this folder into that agent's skills directory.

▶️ Use

Codex

$cleanup-chromes — run a scan of agent browser leftovers

Claude Code

/cleanup-chromes run a scan of agent browser leftovers

Or just ask: "my disk is almost full, run a cleanup-chromes scan" — or "my Mac is hot and nothing is running, check for orphaned agent browsers". Your agent shows you the scan first and asks before deleting or killing anything.

Terminal (no agent)

git clone https://github.com/Rayan-and-beyond/cleanup-chromes.git && cd cleanup-chromes
./skills/cleanup-chromes/cleanup-chromes.sh scan           # read-only, shows what's reclaimable
./skills/cleanup-chromes/cleanup-chromes.sh delete         # removes only what passed every check
./skills/cleanup-chromes/cleanup-chromes.sh kill-orphans   # reports orphaned browser trees (dry-run)

📊 What you get

The scan reports every target with a size and a verdict: SAFE, IN USE, or REFUSED (with the reason). Clone sizes are marked apparent — APFS shares their blocks with the app bundle, so only the delete summary's df-measured freed_mb is the true gain. Deletion ends with a machine-readable line:

SUMMARY mode=<scan|delete> freed_mb=<n> deleted=<n> skipped=<n> failed=<n>

Exit codes: 0 success · 1 one or more deletions failed · 2 invalid argument. Deletion results are appended to cleanup.log.

🧟 Orphaned browser processes (kill-orphans)

The second half of the skill. If your Mac runs hot with nothing open, an abandoned agent session is a likely culprit — check with:

./skills/cleanup-chromes/cleanup-chromes.sh kill-orphans             # dry-run report
./skills/cleanup-chromes/cleanup-chromes.sh kill-orphans --do-it     # terminate confirmed orphans

A process tree is confirmed orphaned only when all four gates pass (default-deny):

Gate Meaning
1. Browser + profile command has --headless and its --user-data-dir lives in a temp dir (/var/folders, /tmp) — killing a temp profile can never lose personal browser data
2. Dead launcher every process above the browser is launchd-adopted (PPID=1) or itself an orphaned automation daemon — a live parent anchors the tree to an active session and rejects it
3. No driver --remote-debugging-pipe (far end was the dead parent → provably unusable) or --remote-debugging-port with no ESTABLISHED connection in lsof
4. Known fingerprint some command in the tree matches a known automation stack (Playwright, Puppeteer, Selenium, Cypress, chrome-devtools, rebrowser) — anything else is reported UNRECOGNIZED and never killed

Kills are graceful (SIGTERM, 5s grace, then SIGKILL), ordered orchestrators-first so nothing respawns mid-cleanup, guarded against PID recycling, and logged to cleanup.log. The summary line:

SUMMARY mode=kill-orphans confirmed=<n> killed=<n> grace_killed=<n> unrecognized=<n> deleted=n/a skipped=0 failed=0

scan/delete never kill processes; kill-orphans never deletes files.

🗑️ What it deletes

Location Usually left by
~/Library/Caches/ms-playwright Playwright
~/Library/Caches/ms-playwright-go Playwright Go
~/.cache/ms-playwright Playwright
~/.cache/puppeteer Puppeteer / Chrome for Testing
~/Library/Caches/Cypress Cypress
~/.cache/rebrowser-puppeteer rebrowser-puppeteer
~/.cache/selenium Selenium
~/.cache/chrome-devtools-mcp chrome-devtools-mcp
~/Library/Caches/chromium Chromium-based test tooling
/private/var/folders/*/*/X/*.code_sign_clone transient macOS code-sign clones

Clone allowlist

macOS names each clone root after the owning app's bundle identifier, so the script allowlists exact bundle IDs and maps them to an exact process-name check (pgrep -x — a command that merely mentions e.g. "Codex" in its arguments does not count as Codex running):

Bundle ID Owner Process guard
com.google.Chrome Google Chrome Google Chrome
com.openai.codex Codex Codex
com.openai.chat ChatGPT ChatGPT
com.brave.Browser Brave Browser Brave Browser
com.microsoft.edgemac Microsoft Edge Microsoft Edge

Any clone root with an unknown bundle ID is refused and reported — never deleted automatically.

🛡️ How it stays safe

Before anything is deleted, the script:

  • considers only the hardcoded throwaway locations above
  • hard-refuses real Chrome, Brave, and Edge profiles plus everything in /Applications
  • refuses unknown clone owners by default (default-deny)
  • checks open files with lsof and running owner apps with exact process-name matching
  • re-runs all checks immediately before each individual deletion

Before anything is killed, kill-orphans:

  • requires all four orphan gates above to pass (default-deny — unmatched trees are reported, never signalled)
  • protects PID 1, the script itself, and its parents
  • re-verifies each pid's live command immediately before signalling (a recycled pid is skipped)
  • logs every --do-it run with the root pid and full kill list

The default mode is scan, so running the script with no argument is non-destructive. kill-orphans is likewise a dry-run until you pass --do-it.

⚠️ Limits

cleanup-chromes is not a general disk cleaner and not a general task manager. It touches only the hardcoded targets above and kills only trees that pass every orphan gate.

Note

If your disk is full for a different reason (Photos, Mail, Xcode, …), or your Mac runs hot for a different reason (a runaway app of your own, malware, …), this skill will not help — and will not touch anything related.

Deleted caches re-download the next time the relevant tool runs. du overstates clone sizes on APFS (copy-on-write shares blocks) — trust the script's measured freed_mb. A tiny check-then-delete race remains theoretically possible if a process starts at exactly the wrong instant; the script minimizes this by refreshing its checks immediately before each removal (and before each kill signal).

Requirements

  • macOS
  • Bash (stock /bin/bash 3.2 is fully supported; the test suite targets it specifically)
  • standard macOS utilities including lsof, du, df, and pgrep

🧪 Development

Run the test suite with stock macOS bash (newer Homebrew bash will not reproduce the Bash 3.2 empty-array bugs):

/bin/bash tests/run_tests.sh

Scan-mode and kill-orphans tests are read-only — fixtures inject fake process tables via the CLEANUP_CHROMES_PS_HOOK and CLEANUP_CHROMES_LSOF_HOOK isolation overrides, so the suite never inspects or signals real processes. Delete-mode tests self-block unless the script-under-test supports the CLEANUP_CHROMES_CLONE_GLOB isolation override, so running the suite against an un-hooked older revision can never touch real data.

New cleanup targets must be regenerable caches or verified clone owners — a real bundle ID plus its exact process name, proven with pgrep -x "<name>" while the app is running.


MIT License

About

Reclaim GBs of disk space on macOS from Playwright/Puppeteer/Cypress/Selenium test-browser caches and macOS code_sign_clone leaks.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages