Skip to content

Throttle background Claude CLI usage spawns to a 15-minute floor - #2923

Merged
steipete merged 2 commits into
mainfrom
fix/2916-claude-cli-spawn-frequency
Aug 14, 2026
Merged

Throttle background Claude CLI usage spawns to a 15-minute floor#2923
steipete merged 2 commits into
mainfrom
fix/2916-claude-cli-spawn-frequency

Conversation

@steipete

Copy link
Copy Markdown
Owner

Fixes #2916

What actually spawns, and how often

The issue claims CodexBar spawns the ~272 MB Claude Code CLI on every 5-minute refresh. Verified against the code — this is accurate, but only for a specific configuration slice:

  • Who hits it: users whose Claude usage source is CLI, or Auto resolving to CLI (no OAuth credentials, no web session), and who have opted into background CLI execution (Keychain disabled, or prompt policy always, or a prior successful foreground CLI fetch establishing the background availability marker — the fix: gate CLI background usage fetch on confirmed-absent OAuth creds #2813 gate). OAuth- and web-sourced users never hit this path.
  • What each cycle costs: ClaudeStatusProbe.fetch() runs the interactive CLI through a PTY for /usage and again for /status (identity enrichment), so one refresh is typically 2 launches of the ~280 MB Node binary (~/.local/share/claude/versions/…), 3 on a startup-looking retry. At the 5-minute default that's ~576 process launches/day.
  • What was already bounded: claude --version probes were fixed by the 30-minute fingerprinted cache in ProviderVersionDetector (plus fix: refresh Claude CLI version after user-initiated usage fetch #2911's one-shot recovery); claude auth status only runs on the CLI-runtime path and Auto planning; the rate-limit gate only bounds the failure lane.

On real disk I/O the issue's arithmetic (~34 GB/day) overstates the steady-state cost: repeated reads of the same binary are served from the macOS unified page cache, so most cycles do not hit disk. What is real: the first read after eviction, the constant page-cache pressure of re-faulting a ~280 MB image every few minutes (which evicts other data and causes I/O elsewhere), and the CPU/energy cost of cold-starting Node+V8 ~576×/day. The PR body of the fix is honest about this: the win is process-spawn cost and cache pressure, with true disk-read savings dependent on memory pressure.

The fix

ClaudeCLIUsageSpawnThrottle caches the last successful CLI fetch result keyed by (binary path, identified account scope, web-extras flag, prepaid-balance flag) and serves it to background app refreshes within a 15-minute floor — the same floor the repo already uses for expensive local work (UsageStore.minimumTokenFetchTTL).

The cached result is bypassed/invalidated when it must be:

  • User-initiated refreshes always spawn (menu Refresh, settings probes) — manual freshness is untouched.
  • CLI-runtime invocations (codexbar usage) always spawn.
  • The owner-CLI recovery pass (claudeOwnerCLIRecoveryOnly) always spawns — it exists to get an authoritative read after an OAuth account mismatch.
  • A cached entry whose rate window crosses its reset boundary is dropped, so the reset-boundary refresh scheduler still publishes post-reset state promptly.
  • An account/profile swap changes the key (ClaudeAccountProfile.identifiedSessionScope), so stale-account data can never be served; unidentified profiles are never cached.
  • Failures are never cached — the failure gates and CLI rate-limit gate keep owning that lane.
  • The cached snapshot keeps its original updatedAt, so menu staleness display stays honest.

Tradeoff

Users on CLI source with a 1–5-minute refresh interval now get background CLI data at most every 15 minutes (manual refresh unaffected). Rationale: the CLI path is already the lowest-fidelity source (rendered percentages only, percentOnly confidence), the PTY probe itself takes 12–60 s per attempt, and the repo already applies exactly this 15-minute floor to token-cost scans for the same energy reason. Reset boundaries — the moment short-interval users actually care about — bypass the cache. OAuth/web users (the recommended sources) keep their configured cadence entirely.

Effect for affected users: ~576 CLI launches/day → ~96/day at default settings (~6× fewer), and proportionally less page-cache churn.

Proof

  • swift test --filter ClaudeCLIUsageSpawnThrottleTests — 8 new regression tests through the strategy seam (stubbed ClaudeStatusProbe.fetchOverride, spawn counting across simulated refresh cycles, clock override for the floor, profile-swap invalidation, reset-boundary invalidation).
  • make test — full sharded suite: 857 selections, 72/72 groups green, 0 retries.
  • make check — SwiftFormat + SwiftLint strict: clean.
  • Codex autoreview: clean, no accepted findings.

@clawsweeper

clawsweeper Bot commented Aug 14, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Aug 14, 2026
@clawsweeper

clawsweeper Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codex review: needs changes before merge. Reviewed August 14, 2026, 1:57 AM ET / 05:57 UTC.

ClawSweeper review

What this changes

The PR adds a 15-minute in-memory cache for successful background Claude CLI usage fetches so repeated app refreshes avoid relaunching the Claude CLI, while manual and recovery fetches remain immediate.

Merge readiness

⚠️ Ready for maintainer review - 5 items remain

Keep this owner-authored PR open: the current diff still has two concrete P2 blockers—its cache omits web-enrichment setting inputs, and it edits the release-owned changelog outside the release flow.

Priority: P2
Reviewed head: f7a837a10c687a6ed1699e20d80468999ccd7b71

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) The patch has substantial focused coverage but retains two concrete, bounded merge blockers.
Proof confidence 🌊 off-meta tidepool Not applicable: The contributor is the repository owner, so the external-contributor real-behavior-proof gate does not apply; the PR body nevertheless reports focused and full test runs.
Patch quality 🦐 gold shrimp (3/6) 2 actionable review findings remain.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: The contributor is the repository owner, so the external-contributor real-behavior-proof gate does not apply; the PR body nevertheless reports focused and full test runs.
Evidence reviewed 4 items Current cache key omits enrichment context: The current PR diff defines the throttle key with only binary path, account scope, web-extras enabled, and prepaid-balance enabled. The supplied review discussion identifies manual cookie and organization settings as further inputs to enriched results, so a settings change can return the prior enriched result during the 15-minute cache interval.
Release-owned changelog remains in the branch: The current PR file list still adds an unreleased Claude entry to CHANGELOG.md; repository policy says generated/root release artifacts should be avoided except during releases.
Prior review continuity: The supplied prior ClawSweeper review raised both findings, and the current PR metadata still lists the same CHANGELOG edit and four-field cache-key design.
Findings 2 actionable findings [P2] Fingerprint web-enrichment inputs in the cache key
[P2] Remove the release-owned changelog edit
Security None None.

How this fits together

CodexBar’s Claude provider selects a usage source and invokes the Claude CLI during refreshes. This throttle intercepts eligible background CLI refreshes, returns a recent successful usage result when safe, and otherwise proceeds to the normal probe and menu/provider display.

flowchart LR
A[Background app refresh] --> B[Claude usage strategy]
B --> C{Eligible cached result?}
C -->|Yes| D[Return prior usage snapshot]
C -->|No| E[Run Claude CLI probe]
E --> F[Build usage result]
F --> G[Cache successful result]
D --> H[Provider and menu display]
G --> H
Loading

Before merge

  • Fingerprint web-enrichment inputs in the cache key (P2) - The key includes only the binary, account scope, and two feature booleans, while enriched CLI results also depend on the cookie/session context and configured organization. Changing either setting can return the old enriched ProviderFetchResult during the 15-minute floor; add a non-sensitive fingerprint or invalidate these entries when those settings change.
  • Remove the release-owned changelog edit (P2) - This normal provider PR adds an unreleased entry to CHANGELOG.md, contrary to the repository policy reserving root release artifacts for releases. Keep user-facing release context in the PR description and leave the changelog to the release flow.
  • Resolve merge risk (P1) - Changing a manual cookie, browser-derived web session, or Claude organization can serve stale enriched usage or balance data for up to 15 minutes because those inputs are not represented in the cache identity.
  • Resolve merge risk (P1) - The branch modifies a release-owned changelog despite this being a normal provider change rather than a release operation.
  • Complete next step (P2) - Both remaining blockers have a narrow mechanical repair path in the new throttle, its regression tests, and the release-note file.

Findings

  • [P2] Fingerprint web-enrichment inputs in the cache key — Sources/CodexBarCore/Providers/Claude/ClaudeCLIUsageSpawnThrottle.swift:7-10
  • [P2] Remove the release-owned changelog edit — CHANGELOG.md:8
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Changed surface 4 files affected: production +153/-2, tests +326, release note +1 The implementation is focused, but the changed cache boundary and release-note edit both need resolution before merge.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #2916
Summary: This PR explicitly targets the repeated background Claude CLI spawning reported by the linked issue.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge-risk options

Maintainer options:

  1. Repair cache identity and release-note scope (recommended)
    Include non-sensitive fingerprints or explicit invalidation for enrichment settings, cover the transition in tests, and remove the unreleased changelog edit before merge.
  2. Accept temporary enriched-data staleness
    Merge with the current cache key only if maintainers explicitly accept up to 15 minutes of stale web-enriched Claude data after a relevant settings change.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Remove the CHANGELOG entry; add non-sensitive enrichment-context cache identity or invalidation with a regression test for changed cookie/organization settings.

Technical review

Best possible solution:

Fingerprint all non-sensitive web-enrichment inputs or invalidate enriched cache entries when those settings change, add regression coverage for that transition, and leave release-note ownership to the release flow.

Do we have a high-confidence way to reproduce the issue?

Yes, from the supplied current diff: cache lookup is keyed without the web-enrichment settings that feed enriched Claude results, so changing those settings within 15 minutes can reuse the old snapshot.

Is this the best way to solve the issue?

No: throttling is a focused approach, but the cache must account for every result-shaping enrichment input and should not include a normal PR edit to the release-owned changelog.

Full review comments:

  • [P2] Fingerprint web-enrichment inputs in the cache key — Sources/CodexBarCore/Providers/Claude/ClaudeCLIUsageSpawnThrottle.swift:7-10
    The key includes only the binary, account scope, and two feature booleans, while enriched CLI results also depend on the cookie/session context and configured organization. Changing either setting can return the old enriched ProviderFetchResult during the 15-minute floor; add a non-sensitive fingerprint or invalidate these entries when those settings change.
    Confidence: 0.94
  • [P2] Remove the release-owned changelog edit — CHANGELOG.md:8
    This normal provider PR adds an unreleased entry to CHANGELOG.md, contrary to the repository policy reserving root release artifacts for releases. Keep user-facing release context in the PR description and leave the changelog to the release flow.
    Confidence: 0.98

Overall correctness: patch is incorrect
Overall confidence: 0.94

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against a0a514fdaf30.

Labels

Label justifications:

  • P2: This is a bounded provider freshness and compatibility issue without evidence of an urgent outage.
  • merge-risk: 🚨 compatibility: The cache can temporarily return enriched data from a prior cookie or organization configuration after users change settings.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🌊 off-meta tidepool and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Not applicable: The contributor is the repository owner, so the external-contributor real-behavior-proof gate does not apply; the PR body nevertheless reports focused and full test runs.

Evidence

Acceptance criteria:

  • [P1] swift test --filter ClaudeCLIUsageSpawnThrottleTests.
  • [P1] make check.
  • [P1] make test.

What I checked:

  • Current cache key omits enrichment context: The current PR diff defines the throttle key with only binary path, account scope, web-extras enabled, and prepaid-balance enabled. The supplied review discussion identifies manual cookie and organization settings as further inputs to enriched results, so a settings change can return the prior enriched result during the 15-minute cache interval. (Sources/CodexBarCore/Providers/Claude/ClaudeCLIUsageSpawnThrottle.swift:7, f7a837a10c68)
  • Release-owned changelog remains in the branch: The current PR file list still adds an unreleased Claude entry to CHANGELOG.md; repository policy says generated/root release artifacts should be avoided except during releases. (CHANGELOG.md:8, f7a837a10c68)
  • Prior review continuity: The supplied prior ClawSweeper review raised both findings, and the current PR metadata still lists the same CHANGELOG edit and four-field cache-key design. (9aff91a40954)
  • Inspection limitation: The local read-only inspection command could not start because the sandbox failed with “bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted”; this review therefore relies on the supplied current PR diff, review discussion, and GitHub metadata.

Likely related people:

  • steipete: The supplied merged history identifies steipete as author of the recent Claude CLI version-recovery work, and this PR changes the same provider area. (role: recent Claude-provider contributor; confidence: high; commits: 7fa295caf045, f7a837a10c68; files: Sources/CodexBarCore/Providers/Claude/ClaudeProviderDescriptor.swift, Sources/CodexBarCore/Providers/Claude/ClaudeCLIUsageSpawnThrottle.swift)
  • axisrow: The supplied history shows axisrow authored the merged background Claude CLI availability gate that this throttle deliberately preserves. (role: adjacent feature contributor; confidence: medium; commits: 89ee92124fda; files: Sources/CodexBarCore/Providers/Claude/ClaudeProviderDescriptor.swift)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Add a regression test for changing the cookie/session or organization within the throttle interval.
  • Remove the CHANGELOG edit and retain release context in the PR body.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (2 earlier review cycles)
  • reviewed 2026-08-14T05:12:43.693Z sha c0ea74b :: found issues before merge. :: [P2] Remove the release-owned changelog edit
  • reviewed 2026-08-14T05:32:39.706Z sha 9aff91a :: found issues before merge. :: [P2] Fingerprint web enrichment inputs in the cache key | [P2] Remove the release-owned changelog edit

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c0ea74ba20

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1013 to +1017
ClaudeCLIUsageSpawnThrottle.key(
binary: $0,
environment: context.env,
useWebExtras: self.useWebExtras,
includePrepaidBalance: self.includePrepaidBalance && context.includeOptionalUsage)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include web enrichment inputs in the CLI cache key

When Claude CLI usage is enriched with web extras or prepaid balance, the fetcher below uses self.manualCookieHeader and context.settings?.claude?.organizationID, but this throttle key only varies by the two booleans. For the same CLI account, if the manual/auto web cookie or target org changes after a successful enriched fetch, background refreshes can return the previous enriched ProviderFetchResult for up to 15 minutes, so cost/extra-window data may come from the old web context instead of the current settings. Include a non-sensitive fingerprint of the web enrichment inputs in the key, or skip caching enriched results.

Useful? React with 👍 / 👎.

Background refresh ticks with a CLI-sourced Claude usage snapshot relaunched
the full ~280 MB Claude Code binary every cycle (~288 spawns/day at the
5-minute default), paging in over 100 MB per launch. Cache the last successful
CLI fetch result per binary/account-scope/options key and serve it to
background app refreshes within a 15-minute floor, matching the existing
minimumTokenFetchTTL precedent for expensive local work.

User-initiated refreshes, CLI-runtime invocations, and the owner-CLI recovery
pass always spawn; a crossed rate-window reset boundary or an account/profile
swap invalidates the cached entry, and failures are never cached.

Fixes #2916
@steipete
steipete force-pushed the fix/2916-claude-cli-spawn-frequency branch from c0ea74b to 9aff91a Compare August 14, 2026 05:28
@steipete
steipete merged commit 40723c8 into main Aug 14, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

the root cases of huge amount of disk read

1 participant