Skip to content

[Bug]: server.getUsageSummary scans an unbounded project tree and blocks macOS for 50+ seconds #7088

Description

@SeoFood

Summary

On macOS, opening the Usage page can block on server.getUsageSummary for roughly one minute. The slowdown is caused by the local transcript scan, not by the Mac hardware or by Claude actively running.

The issue is especially reproducible when Claude has not been used for months and ~/.claude/projects does not exist: the current resolver falls back to ~/projects, then recursively walks that entire tree looking for .jsonl files.

Reproduction

  1. Use T3 Code on macOS with no ~/.claude/projects directory (for example, Claude Code has not been used for months).
  2. Have a normal Codex history under ~/.codex/sessions and a non-trivial ~/Projects tree containing build artifacts and unrelated .jsonl files.
  3. Open the Usage page, or request server.getUsageSummary.
  4. Observe that the request remains pending for 50+ seconds.

Expected behavior

  • A missing default Claude transcript directory should be reported as missing and skipped.
  • The usage scanner should only walk explicitly configured transcript roots, not an entire home-level project directory as an implicit fallback.
  • Usage should load within a bounded, predictable time and expose per-provider scan progress/duration if a large cold scan is unavoidable.

Actual behavior

In the installed nightly bundle, UsageService.resolveTranscriptDirs resolves the default Claude home to the user's home directory, checks <home>/.claude/projects, and returns <home>/projects when that directory does not exist. listTranscriptFiles then recursively calls readdir on every directory and stats every .jsonl file without excluding build directories or other unrelated trees.

This means an inactive/missing Claude installation can make the Usage request scan the complete local project tree.

The same request also scans Codex rollouts. On this machine:

  • ~/.codex/sessions: 1,249 JSONL files, about 5.33 GiB total.
  • Cached 90-day scan: 910 Codex files, about 4.14 GiB.
  • The persisted usage cache is already present and only about 6.4 MB, so cache serialization is not the bottleneck.
  • The cache contains 75 stale/ unrelated files classified as Claude transcripts under ~/projects, including simulator logarchive and ASR benchmark JSONL files.

Trace evidence

Environment: b5a216d4-8818-4c48-9585-cd810786edc2

T3 Code Nightly: 0.0.34-nightly.20260815.1101 (cf7bfd1c9397)

Platform: macOS 27.0, Apple Silicon

Trace ID: 1440c415efea5a815352529ecdbefd64

Observed spans from ~/.t3/userdata/logs/server.trace.ndjson:

  • ws.rpc.server.getUsageSummary: 54,137.8 ms
  • UsageService.readSummary: 54,137.6 ms
  • A second consecutive call: 56,908.5 ms
  • UsageService.ensureRates: 10.3 ms
  • UsageService.resolveTranscriptDirs: 1.7 ms
  • UsageService.persistScanCache: 20.8 ms

The uninstrumented gap is therefore inside the directory walk and transcript parsing loop, not rate lookup or cache persistence.

Suggested fix

  • Do not fall back from a missing default ~/.claude/projects to ~/projects. Treat the default Claude root as missing unless a custom Claude home was explicitly configured.
  • Resolve all enabled provider instances' transcript roots explicitly and deduplicate them.
  • Skip known non-transcript directories and/or maintain a directory/file index instead of recursively walking broad roots on every request.
  • Add spans/counters around directory walking, file reads, and per-provider scan totals so future slow scans identify the exact root and phase.
  • Consider serving the last cached summary immediately and refreshing a cold scan in the background.

Related, but distinct, Usage issues: #5798 and #5805.

Activity

  1. maslinedwin commented on Aug 16, 2026

    @maslinedwin
    Contributor

    Fix is in #7177. A missing default ~/.claude/projects is now treated as missing instead of falling back to ~/projects.

  2. krutftw commented on Aug 19, 2026

    @krutftw
    Contributor

    A related but distinct datapoint from Windows, since #7177 only removes the ~/projects fallback: the scan is also unbounded with respect to the size of a perfectly ordinary ~/.codex/sessions.

    Machine: Windows 11 Pro 10.0.26100, T3 Code (Nightly) 0.0.34-nightly.20260819.1132. ~/.claude/projects exists (so the ~/projects fallback is not involved). ~/.codex/sessions holds 370 rollout .jsonl files totalling 62 GB — several individual rollouts are 1.2 GB each (heavy Codex use, nothing exotic).

    server.trace.ndjson spans for ws.rpc.server.getUsageSummary / UsageService.readSummary on this machine:

    call duration exit
    cold 440,223 ms (7.3 min) Success
    warm 20,169 ms Success
    warm 58,906 ms Success

    usage-scan-cache.json is 10.9 MB here; readFileRecords only reuses a cached entry when size/mtime/provider all match, so every new or still-growing large rollout costs a full re-read, and there is no setting to bound or disable the scan. The Usage page therefore takes minutes to load cold and tens of seconds warm.

    Suggestion on top of #7177: bound the scan (skip/stream files over N MB, cap total bytes per run, or move it off the request path with per-provider progress), so a large Codex corpus does not make getUsageSummary a multi-minute call.

    Authorship disclosure: investigated and written by Claude (Fable 5) in Claude Code on the reporter's machine, at the reporter's request.

  3. juliusmarminge commented on Oct 3, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Closing as resolved by #15149 (perf(usage): cut warm usage scans from seconds to milliseconds on large histories).

    That merge speeds warm getUsageSummary scans on large transcript histories (window-filtered retained entries, cheaper aggregation/dedupe, incremental cache writes, parallel stat/reads) — the same class of slowdown this issue and the follow-up Codex datapoint described (tens of seconds warm on a large ~/.codex/sessions). The old missing-~/.claude/projects → ~/projects fallback path is also no longer how resolveTranscriptDirs works on current main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions