Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
Markdown
Neo resource audit — 2026-06-11 #
Snapshot of what eats the 8 GB MacBook Neo's RAM/CPU during a normal
working morning, what was changed in response, and what's left as
operating practice. Companion to reports/js-tooling-audit.md.
Findings (mid-morning, 5 Claude sessions + netlify dev up) #
- Swap was 5.2 GB used of 6 GB with only 28% memory free — the machine sits one heavy job away from thrashing at all times.
netlify dev's esbuild service (zip-it-and-ship-it) holds ~420–510 MB resident permanently and bursts to 80% CPU while functions rebuild. Biggest single resident process tied to dev work.- Claude sessions: ~690 MB across 6 processes, and each session spawns its own MCP stack — at audit time 60 MCP processes / 309 MB (6× emacs-mcp, 6× mail-mcp, ~16 chrome-devtools-mcp instances each with a watchdog sidecar). None orphaned — all parented to live sessions — it's pure per-session multiplication.
- Chrome: 19 processes / ~450 MB (a single renderer hit 280 MB).
mu(mail indexer) spikes to ~380 MB / 30% CPU while indexing.- ffmpeg: 145 files under
pop/spawn it; only one passes-threads. Default = all 6 cores at normal priority, so a render competes head-on with the UI and every Claude session.
What changed #
- Slab menubar telemetry (
slab/menubar-swift):- New monospaced row under Status:
mem 28% free · swap 5.2/6G · load 4.2, orange when free < 15% or swap > 90% full. - Its submenu lists the top 6 processes by resident memory
(
MB / %CPU / name) + "Open Activity Monitor". - Each live
/poprender row now shows the driver process's RSS (viaproc_pid_rusage) next to its progress bar, so a running job is tied to what it costs. Children (ffmpeg/python) surface in the hogs list. - Sources:
StateSnapshot.swift(SystemStats,readSystemStats(),residentMB(of:)),MenuBuilder.swift(buildSystem), rebuild withslab/menubar-swift/install.sh.
- New monospaced row under Status:
- QoS shims (
toolchain/shims/ffmpeg,ffprobe): exec the real binary undertaskpolicy -c utility. Renders use all idle cores at full speed but yield to the UI under contention. Wired ahead of homebrew in~/.config/fish/config.fishon the Neo, so anything spawned from a shell (including node children resolvingffmpegvia PATH) inherits it. Scripts that hardcode/opt/homebrew/bin/ffmpegbypass the shim.
Round 2 (same day): MCP de-duplication for parallel sessions #
Claude Code spawns every stdio MCP server once per session, so N parallel sessions pay N copies. Fixes, in order of leverage:
- mail-mcp + emacs-mcp → shared HTTP daemons. Both servers grew a
--http [port]mode (stdio default untouched — codespaces keeps using.mcp.jsonas-is). On the Neo they run once under launchd (computer.aesthetic.mail-mcp:7765,computer.aesthetic.emacs-mcp:7766 —toolchain/mcp/install-daemons.sh), and local-scope http entries in~/.claude.jsonshadow the stdio ones. 12 processes across 6 sessions → 2 total, shared by any number of sessions. - chrome-devtools telemetry watchdogs killed. All three entries
(local/chicken/panda) now pass
--no-usage-statistics, which stops the ClearcutLogger from spawning a watchdog sidecar per instance (was ~16 extra processes). - npx wrapper dropped. Entries point at a pinned global install
(
npm i -g chrome-devtools-mcp, fnm default bin) instead ofnpx -y chrome-devtools-mcp@latest— no registry check and no npx process tree per session. Update deliberately manual now:npm i -g chrome-devtools-mcpto bump. - Local chrome-devtools is lazy.
toolchain/mcp/minis-mcp.mjsis group-based: the local server enables on browser/chrome/devtools/screenshot/lighthouse/webpage/headless mentions (stamp~/.claude/chrome-mcp-active), auto-disables after 12 h idle — same mechanism the chicken/panda pair already used. Sessions that never touch a browser no longer spawn it at all.
Existing sessions keep their old processes until restarted; the savings land as terminals close and reopen.
Deliberately not done #
- Global
NODE_OPTIONS=--max-old-space-size: on an 8 GB machine V8's default old-space cap is already ~2 GB, and the actual hogs (esbuild = Go, ffmpeg = C, Chrome) aren't V8 heap. A global cap changes nothing except adding a new crash mode for legit big renders. - Wrapping
npm run sitein taskpolicy: package.json scripts are shared with codespaces/linux; esbuild's CPU burn is bursty, not constant. Revisit only if it shows up pinned in the new hogs list.
Operating practice (the stuff config can't fix) #
- Don't leave
netlify devrunning when not doing site work — it's ~600 MB (node + esbuild service) of permanent residency. - Each Claude session costs ~100–150 MB plus ~60 MB of MCP servers; five idle sessions ≈ 1 GB. Close finished terminals. If the chicken/panda DevTools MCPs keep appearing in sessions that never use them, shorten the minis-mcp hook's 12 h idle expiry.
- Existing rules still apply: one Chromium, one ffmpeg, one whisper at
a time; vitest
--maxWorkers=1(see agent memory "8 GB RAM concurrency limits"). - Swap doesn't shrink once grown — after a heavy day the 5 GB swap file stays. A reboot is the only real reset.