🤖 Agent-filed: investigated and written by Claude Code on behalf of @nichenke. Every code citation below was verified against aa309c0, and the CPU numbers were measured on the reporter's machine.
git_delivery_watcher() is documented and coded to scan "every five minutes" but runs back-to-back, holding a sustained fraction of a CPU core indefinitely.
Mechanism
git_delivery_watcher() (token_meter/app.py:7081) waits with _git_delivery_wake.wait(GIT_DELIVERY_INTERVAL_S), where the interval is 5 * 60 (app.py:306).
publish_source_inventory() (app.py:3051) unconditionally calls _git_delivery_wake.set() (app.py:3075).
watcher() (app.py:9024) loops every 0.5s (time.sleep(0.5) at the loop tail, app.py:9160) and calls publish_source_inventory(sources) (app.py:9086) whenever refresh_known_source_activity() (app.py:7595) returns a new list object.
threading.Event.wait(timeout) returns immediately when the event is already set — verified on Python 3.9.6, where wait(300) on a set event returned in 0.0000s. So each scan is followed immediately by the next and the five-minute interval never applies.
Step 3 fires whenever the active session's transcript mtime has advanced, which is most 0.5s ticks while any agent session is streaming output. That frequency is inferred from the mtime comparison in refresh_known_source_activity; I did not instrument the per-tick rate.
The .set() call arrived with the Git activity feature (cc162d7, 2026-09-04). The 0.5s fast-path refresh predates it (27e4f76, 2026-08-14).
Impact
Continuous git rev-list --topo-order --reverse --max-count=2001 (services/git_delivery.py:484-485) plus --max-count=2001 reflog reads (:542), across up to MAX_REPOSITORIES = 50 repositories.
Measured: 137:01 of CPU time over 4:00:16 wall clock — 57% of one core — sustained, with git subprocesses spawning continuously and ~/.token-meter/git-delivery.sqlite3 rewritten every few seconds.
Removing the _git_delivery_wake.set() at app.py:3075 locally reduced sustained CPU from 57% to 32% of one core, and dropped git subprocess spawns from continuous to 2 per 40s.
Workload
Per-pass cost is bounded — eligible = candidate_rows[:MAX_REPOSITORIES] (git_delivery.py:625) caps a pass at 50 repositories and MAX_COMMITS_PER_SCAN caps it at 5,000 commits. The runaway is therefore frequency, not pass size. Concurrent session count is what drives frequency, because each session writing its transcript triggers another publish_source_inventory() and another .set().
The reporting machine runs:
| Factor |
Count |
Bears on |
| Concurrent agent sessions |
12 Claude Code CLI + 8 Codex app-servers |
Trigger frequency — the driver of this bug |
| Git repositories under scanned roots |
106 |
Every pass hits the 50-repo cap |
| Worktrees |
170, plus 26 under .claude/worktrees/ |
Each resolves to its own repo_key, so they count as candidates |
| Claude transcripts |
2,799 across 147 project directories, 1.3 GB |
Inventory size; bears on #3, not on this bug |
| Codex session files |
184 |
Same as above |
A single-session user with a handful of repositories would trigger the scan rarely, and each pass would finish well under the caps — which may be why this has not surfaced before.
Suggested fix
Enforce an interval floor rather than dropping the early-wake behaviour, so source changes can still trigger a prompt scan without allowing back-to-back passes:
last_scan = 0.0
while True:
...
remaining = GIT_DELIVERY_INTERVAL_S - (time.monotonic() - last_scan)
if remaining > 0:
_git_delivery_wake.wait(remaining)
_git_delivery_wake.clear()
continue
git_delivery_service().scan(candidates)
last_scan = time.monotonic()
Related
#3 (closed) covered the 0.5s watcher poll itself and estimated an intrinsic baseline near 34% of one core. This report is a separate mechanism: the Git delivery watcher's own interval being bypassed. The residual 32% remaining after the local workaround is consistent with #3's baseline estimate, but I did not profile it successfully (macOS sample output was unsymbolized), so I am not attributing it here.
Environment
- Revision
aa309c0, macOS 26.6.2 arm64, Python 3.9.6 (system Python, via the com.token-meter.server LaunchAgent)
🤖 Agent-filed: investigated and written by Claude Code on behalf of @nichenke. Every code citation below was verified against
aa309c0, and the CPU numbers were measured on the reporter's machine.git_delivery_watcher()is documented and coded to scan "every five minutes" but runs back-to-back, holding a sustained fraction of a CPU core indefinitely.Mechanism
git_delivery_watcher()(token_meter/app.py:7081) waits with_git_delivery_wake.wait(GIT_DELIVERY_INTERVAL_S), where the interval is5 * 60(app.py:306).publish_source_inventory()(app.py:3051) unconditionally calls_git_delivery_wake.set()(app.py:3075).watcher()(app.py:9024) loops every 0.5s (time.sleep(0.5)at the loop tail,app.py:9160) and callspublish_source_inventory(sources)(app.py:9086) wheneverrefresh_known_source_activity()(app.py:7595) returns a new list object.threading.Event.wait(timeout)returns immediately when the event is already set — verified on Python 3.9.6, wherewait(300)on a set event returned in 0.0000s. So each scan is followed immediately by the next and the five-minute interval never applies.Step 3 fires whenever the active session's transcript mtime has advanced, which is most 0.5s ticks while any agent session is streaming output. That frequency is inferred from the mtime comparison in
refresh_known_source_activity; I did not instrument the per-tick rate.The
.set()call arrived with the Git activity feature (cc162d7, 2026-09-04). The 0.5s fast-path refresh predates it (27e4f76, 2026-08-14).Impact
Continuous
git rev-list --topo-order --reverse --max-count=2001(services/git_delivery.py:484-485) plus--max-count=2001reflog reads (:542), across up toMAX_REPOSITORIES = 50repositories.Measured: 137:01 of CPU time over 4:00:16 wall clock — 57% of one core — sustained, with git subprocesses spawning continuously and
~/.token-meter/git-delivery.sqlite3rewritten every few seconds.Removing the
_git_delivery_wake.set()atapp.py:3075locally reduced sustained CPU from 57% to 32% of one core, and dropped git subprocess spawns from continuous to 2 per 40s.Workload
Per-pass cost is bounded —
eligible = candidate_rows[:MAX_REPOSITORIES](git_delivery.py:625) caps a pass at 50 repositories andMAX_COMMITS_PER_SCANcaps it at 5,000 commits. The runaway is therefore frequency, not pass size. Concurrent session count is what drives frequency, because each session writing its transcript triggers anotherpublish_source_inventory()and another.set().The reporting machine runs:
.claude/worktrees/repo_key, so they count as candidatesA single-session user with a handful of repositories would trigger the scan rarely, and each pass would finish well under the caps — which may be why this has not surfaced before.
Suggested fix
Enforce an interval floor rather than dropping the early-wake behaviour, so source changes can still trigger a prompt scan without allowing back-to-back passes:
Related
#3 (closed) covered the 0.5s watcher poll itself and estimated an intrinsic baseline near 34% of one core. This report is a separate mechanism: the Git delivery watcher's own interval being bypassed. The residual 32% remaining after the local workaround is consistent with #3's baseline estimate, but I did not profile it successfully (macOS
sampleoutput was unsymbolized), so I am not attributing it here.Environment
aa309c0, macOS 26.6.2 arm64, Python 3.9.6 (system Python, via thecom.token-meter.serverLaunchAgent)