Preflight Checklist
What's Wrong?
after 2 minutes:

another minute:

just keeps ramping up.
What Should Happen?
tokensave serve leaks memory unbounded (~1.7 MB/s per process) and pins a CPU core at 99% — grows to tens of GB, exhausts swap, drives sustained thermal load on Apple Silicon
Version: tokensave 7.0.2
Install path: ~/.local/bin/tokensave (155 MB binary, dated Jun 24)
Transport: stdio MCP server, launched by Claude Code / Claude Desktop
OS: macOS 15.7 Sequoia (build 24G222), Darwin 24.6.0, arm64
Hardware: MacBook Air, Apple M4 (10 cores), 16 GB RAM, 256 GB SSD
Summary
Every tokensave serve process started by Claude Code enters an unbounded growth state shortly after launch: resident memory climbs linearly and without plateau while CPU sits pinned at ~99% of one core, indefinitely. The process never stabilizes, never releases, and never self-terminates. It has to be killed manually from Activity Monitor or by quitting Claude entirely.
This is not a slow drift. It is a steady, measurable leak, and because Claude Code spawns one tokensave serve per session, the rate multiplies by the number of open sessions.
On a 16 GB fanless MacBook Air this is not a cosmetic issue. It fills physical RAM, saturates the 4 GB swap file, forces the memory compressor to run continuously, and — because the leak is paired with a permanently spinning CPU core — produces sustained heat on a machine with no active cooling. I have observed idle-state package temperatures reaching 105 °C with nothing else running. That is a hardware-stress condition caused by a background MCP server the user never explicitly invoked.
Measured evidence
Two tokensave serve processes were running (two open Claude sessions). Sampled with ps -o pid,pcpu,rss,etime every 10 seconds:
06:12:14 pid 4175 93.3% CPU 280432 KB RSS elapsed 02:26
pid 4340 96.0% CPU 249104 KB RSS elapsed 02:15
06:12:24 pid 4175 91.7% CPU 297360 KB RSS elapsed 02:36
pid 4340 95.1% CPU 266320 KB RSS elapsed 02:25
06:12:34 pid 4175 99.2% CPU 314688 KB RSS elapsed 02:46
pid 4340 98.1% CPU 283632 KB RSS elapsed 02:35
06:12:44 pid 4175 95.1% CPU 332128 KB RSS elapsed 02:56
pid 4340 98.7% CPU 300704 KB RSS elapsed 02:45
06:12:54 pid 4175 99.0% CPU 343984 KB RSS elapsed 03:03
pid 4340 99.6% CPU 312544 KB RSS elapsed 02:52
Growth rate: ~17.3 MB per 10 s, per process → ≈1.73 MB/s each, ≈3.5 MB/s combined.
Extrapolated: ≈208 MB/min → ≈12.5 GB/hour with two sessions open. The curve is dead linear across the whole sample window — there is no GC, no cap, no backoff.
Virtual size: VSZ reads 411,485,488 KB (~392 GB) per process. Activity Monitor reports the figure it derives from this plus compressed pages, which is why the user-visible "Memory" column climbs from under 1 MB to tens of GB within minutes — matching the ~30 GB readings I see before I intervene.
CPU: both processes hold 91–99% continuously. 13 threads each. Neither drops to idle at any point, including while Claude itself is idle and awaiting user input.
System impact at time of capture:
vm.swapusage: total = 4096.00M used = 3071.44M free = 1024.56M
Pages free: 21122 (≈330 MB free of 16 GB)
Pages active: 401973
Pages inactive: 399775
Swap is 75% consumed. On a 256 GB SSD, hours of this per day is also a meaningful write-amplification concern for NAND endurance.
Probable root cause: unbounded recursive filesystem walk escaping the session working directory
This is the part that I think matters most, and it is reproducible in the lsof output.
pid 4340 was launched with its working directory set to an empty, freshly created scratch workspace:
cwd DIR .../scratch-workspaces/68e613fe-.../scratch-2026-09-21-1f0e92
That directory contained zero files. Despite that, the same process held open directory handles four levels deep inside an unrelated node_modules tree on the Desktop:
15r DIR /Users/main/Desktop/.../wallet-widget copy/node_modules/react-native/ReactCommon/react/utils
16r DIR /Users/main/Desktop/.../node_modules/react-native/ReactCommon/react/utils/platform
17r DIR /Users/main/Desktop/.../node_modules/react-native/ReactCommon/react
18r DIR /Users/main/Desktop/.../node_modules/react-native/ReactCommon/react/utils/platform/android
A subsequent sample of the same PID showed it had moved on to a completely different tree — a Data/Cache/effect/... cache hierarchy — and pid 4175 (cwd /Users/main/Downloads/Shade) was simultaneously walking its own Data/Cache/effect/... path.
So: the indexer is not scoped to the project root. It walks outside the session's working directory, descends into node_modules and into application cache directories, and does so with no apparent ignore-list, no depth limit, and no size ceiling. On a developer machine, that search space is effectively infinite — every node_modules in every stale project copy, every browser/app cache, every .git object store. Each walked entry appears to be retained rather than streamed, which is consistent with both the linear RSS growth and the pinned CPU.
Config in use (~/.tokensave/config.toml) is stock, with watcher_debounce = "2s" and extraction_timeout_secs = 60. The 60 s extraction timeout does not appear to bound the walk itself, and the on-disk databases stay small (tokensave.db 385 KB, global.db 57 KB, total ~/.tokensave = 508 KB) while RSS goes to gigabytes — the memory is being held in-process, not flushed to the store. That asymmetry is the strongest single indicator of a leak rather than legitimate indexing work.
Steps to reproduce
- macOS machine with a normal developer home directory (several projects containing
node_modules, app caches under ~/Library).
tokensave 7.0.2 installed at ~/.local/bin/tokensave, registered as a stdio MCP server:
{ "type": "stdio", "command": "/Users/<user>/.local/bin/tokensave", "args": ["serve"], "env": {} }
- Open a Claude Code session — any session, including one whose working directory is an empty folder.
- Watch the process:
while true; do ps -o pid,pcpu,rss,etime,command -c -p $(pgrep -d, -f "tokensave serve"); sleep 10; done
- Observe RSS climbing ~1.7 MB/s per process with CPU at ~99%, never plateauing.
lsof -p <pid> | awk '$5=="DIR"' — confirm open directory handles outside the session cwd.
Expected: indexing scoped to the project root, bounded memory, CPU returning to idle once the initial index completes.
Actual: unbounded RSS growth, permanent 99% CPU, directory traversal outside the project root, no termination condition.
Impact
- Memory exhaustion: 16 GB RAM + 4 GB swap consumed within minutes to tens of minutes depending on session count. System becomes unresponsive; other applications are compressed/swapped out.
- Thermal: one fully pinned core per session on a fanless M4 Air. Observed idle-state temperature of 105 °C. Sustained operation at that level drives aggressive throttling and, over time, is a legitimate concern for component longevity on a passively cooled chassis.
- SSD wear: continuous swap churn on a 256 GB drive.
- Forced manual intervention: the only remedies are killing the process in Activity Monitor or restarting Claude — several times per working day.
- Silent onset: nothing in the Claude UI indicates the MCP server has gone runaway. The user only finds it by opening Activity Monitor and noticing the machine is hot.
Suggested fixes
- Scope the walk to the session's working directory. A process whose cwd is an empty scratch folder should never open handles under
~/Desktop/.../node_modules or ~/Library/.../Cache.
- Ship a default ignore-list —
node_modules, .git, target, dist, build, vendor, Pods, .venv, ~/Library, and anything marked with the macOS "do not backup"/cache attributes.
- Hard-cap resident memory with a configurable ceiling; abort or spill the index when it is hit rather than growing without limit.
- Stream to the store instead of accumulating in RAM. The 508 KB on-disk footprint against multi-GB RSS suggests everything is being buffered in memory first.
- Bound the traversal — max depth, max entry count, max wall-clock, and honor
extraction_timeout_secs for the walk phase too.
- Yield the CPU. A background indexer should not hold 99% of a core indefinitely; add throttling/nice-ing and idle down when there is no work.
- Deduplicate across sessions. N Claude sessions currently means N full independent crawls of overlapping trees. A single shared daemon or a cross-process lock (a
sync.lock file already exists in ~/.tokensave/) would cut this by the session multiplier.
Environment dump
tokensave 7.0.2
macOS 15.7 (24G222) — Darwin 24.6.0 arm64
Apple M4, 10 cores, 17179869184 bytes RAM (16 GB), 256 GB SSD
Binary: /Users/main/.local/bin/tokensave (155060928 bytes, Jun 24 18:11)
Data dir: ~/.tokensave — tokensave.db 385 KB, global.db 57 KB, total 508 KB
Config: upload_enabled = true, watcher_debounce = "2s", extraction_timeout_secs = 60
Host: Claude Code (stdio MCP)
I am happy to collect a heap profile, sample/spindump output, or run an instrumented build if that would help narrow it down.
Error Messages/Logs
Steps to Reproduce
Steps to reproduce
macOS machine with a normal developer home directory (several projects containing node_modules, app caches under ~/Library).
tokensave 7.0.2 installed at ~/.local/bin/tokensave, registered as a stdio MCP server:
{ "type": "stdio", "command": "/Users//.local/bin/tokensave", "args": ["serve"], "env": {} }
Open a Claude Code session — any session, including one whose working directory is an empty folder.
Watch the process:
while true; do ps -o pid,pcpu,rss,etime,command -c -p $(pgrep -d, -f "tokensave serve"); sleep 10; done
Observe RSS climbing ~1.7 MB/s per process with CPU at ~99%, never plateauing.
lsof -p | awk '$5=="DIR"' — confirm open directory handles outside the session cwd.
Expected: indexing scoped to the project root, bounded memory, CPU returning to idle once the initial index completes. Actual: unbounded RSS growth, permanent 99% CPU, directory traversal outside the project root, no termination condition.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
No response
Claude Code Version
latest
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
No response
Preflight Checklist
What's Wrong?
after 2 minutes:

another minute:

just keeps ramping up.
What Should Happen?
tokensave serveleaks memory unbounded (~1.7 MB/s per process) and pins a CPU core at 99% — grows to tens of GB, exhausts swap, drives sustained thermal load on Apple SiliconVersion:
tokensave 7.0.2Install path:
~/.local/bin/tokensave(155 MB binary, dated Jun 24)Transport: stdio MCP server, launched by Claude Code / Claude Desktop
OS: macOS 15.7 Sequoia (build 24G222), Darwin 24.6.0, arm64
Hardware: MacBook Air, Apple M4 (10 cores), 16 GB RAM, 256 GB SSD
Summary
Every
tokensave serveprocess started by Claude Code enters an unbounded growth state shortly after launch: resident memory climbs linearly and without plateau while CPU sits pinned at ~99% of one core, indefinitely. The process never stabilizes, never releases, and never self-terminates. It has to be killed manually from Activity Monitor or by quitting Claude entirely.This is not a slow drift. It is a steady, measurable leak, and because Claude Code spawns one
tokensave serveper session, the rate multiplies by the number of open sessions.On a 16 GB fanless MacBook Air this is not a cosmetic issue. It fills physical RAM, saturates the 4 GB swap file, forces the memory compressor to run continuously, and — because the leak is paired with a permanently spinning CPU core — produces sustained heat on a machine with no active cooling. I have observed idle-state package temperatures reaching 105 °C with nothing else running. That is a hardware-stress condition caused by a background MCP server the user never explicitly invoked.
Measured evidence
Two
tokensave serveprocesses were running (two open Claude sessions). Sampled withps -o pid,pcpu,rss,etimeevery 10 seconds:Growth rate: ~17.3 MB per 10 s, per process → ≈1.73 MB/s each, ≈3.5 MB/s combined.
Extrapolated: ≈208 MB/min → ≈12.5 GB/hour with two sessions open. The curve is dead linear across the whole sample window — there is no GC, no cap, no backoff.
Virtual size:
VSZreads 411,485,488 KB (~392 GB) per process. Activity Monitor reports the figure it derives from this plus compressed pages, which is why the user-visible "Memory" column climbs from under 1 MB to tens of GB within minutes — matching the ~30 GB readings I see before I intervene.CPU: both processes hold 91–99% continuously. 13 threads each. Neither drops to idle at any point, including while Claude itself is idle and awaiting user input.
System impact at time of capture:
Swap is 75% consumed. On a 256 GB SSD, hours of this per day is also a meaningful write-amplification concern for NAND endurance.
Probable root cause: unbounded recursive filesystem walk escaping the session working directory
This is the part that I think matters most, and it is reproducible in the
lsofoutput.pid 4340was launched with its working directory set to an empty, freshly created scratch workspace:That directory contained zero files. Despite that, the same process held open directory handles four levels deep inside an unrelated
node_modulestree on the Desktop:A subsequent sample of the same PID showed it had moved on to a completely different tree — a
Data/Cache/effect/...cache hierarchy — andpid 4175(cwd/Users/main/Downloads/Shade) was simultaneously walking its ownData/Cache/effect/...path.So: the indexer is not scoped to the project root. It walks outside the session's working directory, descends into
node_modulesand into application cache directories, and does so with no apparent ignore-list, no depth limit, and no size ceiling. On a developer machine, that search space is effectively infinite — everynode_modulesin every stale project copy, every browser/app cache, every.gitobject store. Each walked entry appears to be retained rather than streamed, which is consistent with both the linear RSS growth and the pinned CPU.Config in use (
~/.tokensave/config.toml) is stock, withwatcher_debounce = "2s"andextraction_timeout_secs = 60. The 60 s extraction timeout does not appear to bound the walk itself, and the on-disk databases stay small (tokensave.db385 KB,global.db57 KB, total~/.tokensave= 508 KB) while RSS goes to gigabytes — the memory is being held in-process, not flushed to the store. That asymmetry is the strongest single indicator of a leak rather than legitimate indexing work.Steps to reproduce
node_modules, app caches under~/Library).tokensave 7.0.2installed at~/.local/bin/tokensave, registered as a stdio MCP server:{ "type": "stdio", "command": "/Users/<user>/.local/bin/tokensave", "args": ["serve"], "env": {} }lsof -p <pid> | awk '$5=="DIR"'— confirm open directory handles outside the session cwd.Expected: indexing scoped to the project root, bounded memory, CPU returning to idle once the initial index completes.
Actual: unbounded RSS growth, permanent 99% CPU, directory traversal outside the project root, no termination condition.
Impact
Suggested fixes
~/Desktop/.../node_modulesor~/Library/.../Cache.node_modules,.git,target,dist,build,vendor,Pods,.venv,~/Library, and anything marked with the macOS "do not backup"/cache attributes.extraction_timeout_secsfor the walk phase too.sync.lockfile already exists in~/.tokensave/) would cut this by the session multiplier.Environment dump
I am happy to collect a heap profile,
sample/spindumpoutput, or run an instrumented build if that would help narrow it down.Error Messages/Logs
Steps to Reproduce
Steps to reproduce
macOS machine with a normal developer home directory (several projects containing node_modules, app caches under ~/Library).
tokensave 7.0.2 installed at ~/.local/bin/tokensave, registered as a stdio MCP server:
{ "type": "stdio", "command": "/Users//.local/bin/tokensave", "args": ["serve"], "env": {} }
Open a Claude Code session — any session, including one whose working directory is an empty folder.
Watch the process:
while true; do ps -o pid,pcpu,rss,etime,command -c -p $(pgrep -d, -f "tokensave serve"); sleep 10; done
Observe RSS climbing ~1.7 MB/s per process with CPU at ~99%, never plateauing.
lsof -p | awk '$5=="DIR"' — confirm open directory handles outside the session cwd.
Expected: indexing scoped to the project root, bounded memory, CPU returning to idle once the initial index completes. Actual: unbounded RSS growth, permanent 99% CPU, directory traversal outside the project root, no termination condition.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
No response
Claude Code Version
latest
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
No response