Repository navigation
Conversation
Two per-render file reads did work that the output does not need: - getSkillsMetrics() existsSync+read+parsed the per-session skills log on every render even with no `skills` widget configured. It is now gated on a skills widget being present, like the other widget-specific inputs (speed, compaction, session-name). Saving is noise-level in practice (the skills hook is removed together with the widget, so the file is usually absent), but the read is pure waste. - The claude-account-email widget read and JSON.parsed the whole .claude.json on every render. That file also holds Claude Code's per-project history and grows to megabytes. The extracted email (or its absence) is now cached in ~/.cache/ccstatusline/claude-account-email.json (mode 0600) keyed on path + size + mtimeMs, so a hit costs one stat and a ~150-byte read. Stat precedes the read, so a concurrent rewrite can only cause an extra re-read, never a stale value; parse failures are not cached. Behaviour is unchanged (output byte-identical for present, missing, non-string, empty, corrupt and absent cases, miss and hit). Measured (bench of fork/exec renders, 30 interleaved passes, host load ~50 on 6 cores; CPU user+sys median / p90, ms), config = default + email widget, no transcript: .claude.json 1.1 MB: 1304 / 1443 -> 1163 / 1284 (-10.8%) .claude.json 5.6 MB: 1414 / 1538 -> 1109 / 1336 (-21.6%) In-process: 1 MB read+parse 15.0 ms -> 1.3 ms on a hit; 5.6 MB 76.7 ms -> 1.2 ms; a miss costs the same as before plus a small cache write. At ~100 KB the difference is within noise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
BLUF
~/.claude.json— 10–22% at 1–5 MB; noise at a typical ~100 KB.)claude-account-emailwidget used to read andJSON.parseall of.claude.jsonon every render. That file also stores Claude Code's per-project history, so it can grow to megabytes. The widget now caches the extracted email in~/.cache/ccstatusline/claude-account-email.json, keyed on the file's path + size + mtime. A cache hit costs onestatplus a read of about 150 bytes..claude.json: render CPU -10.8%..claude.json: render CPU -21.6%..claude.json.getSkillsMetrics()read the per-session skills log on every render even when noskillswidget was configured. It now only runs when a skills widget is configured, the same way the speed, compaction and session-name inputs already work. The saving is at noise level, because the skills hook is removed together with the widget, but the read had no purpose.mainin every case tested.Details
src/ccstatusline.ts: addshasSkillsWidget.skillsMetricsstaysnullwhen no skills widget is configured. OnlySkills.tsxreadscontext.skillsMetrics.src/utils/claude-account-email.ts(new, dependency-injectable liketerminal-width-cache.ts):getClaudeAccountEmail()does the following:.claude.jsonand returnsnullif the stat fails. The old code also returnednullwhen the file was missing.mtimeMs), returns the cached email. A cached "no email" (null) also counts as a hit.null.CLAUDE_CONFIG_DIRvalues that render alternately will evict each other. That is still correct because the path is part of the key; the worst case is the old cost plus a small cache write.src/widgets/ClaudeAccountEmail.ts: now calls the helper. The widget test now setsHOMEto its temp dir, so the cache is never written to the real~/.cache.getRemoteControlStatus()(readdir + parse + zod oversessions/*.json). With 14 session files and no match (the worst case), the most a cache could save end to end is +42 ms / 2.7%, which is within noise. In-process it costs 0.5 ms warm and 4.8 ms on the first call; with 50 files, 2.0 ms and 11.5 ms. Claude Code writes one file per live process, so a cache is not worth adding.includeSubagents: trueonly takes effect together with the already-gated speed metrics, so it was left alone.src/ccstatusline.ts, as do [medium] perf(render): skip the transcript scan when no widget reads it #634, [medium] perf(custom-command): run custom commands concurrently in-process before the render #630 and [medium] perf(startup): enable Node's module compile cache via a tiny bootstrap entry #637 (small, adjacent edits in the widget-gating block of the render path). It does not touchclaude-settings.ts.Measurements
Each render is a fork/exec of
node dist/ccstatusline.js. Baselinemainand the patched build ran interleaved round-robin in one run, with anode -e 0control arm. CPU is user+sys including reaped children, in ms. The host was heavily loaded, so compare the ratios within a run rather than the absolute values.Run A: payload with no transcript,
defaultconfig +claude-account-email, 30 passes, load1 median 50 (min 41, max 61) on 6 cores.node -e 0.claude.json.claude.jsonRun B: 5 MB transcript payload (so the render itself is heavier), 20 passes, load1 median 60 (min 50, max 68).
node -e 0In-process (bun, median of 15 runs, email extraction only):
.claude.jsonA synthetic
.claude.jsonof 411 / 1999 projects was used, with the usual per-project fields and prompt history.Checks
bun run lint: clean. This coverstsc --noEmitand eslint with--max-warnings=0.bun run build: OK.bun test: 2312 pass / 56 fail. Unmodifiedmainon the same host gave 2298 pass / 60 fail. The failures are the same flaky families on both: thefetchUsageData5 s timeouts, the TUI menu snapshot tests, and custom-command capture timing, all under load 50-60. None are in files this PR touches. The newclaude-account-emailtests pass (10/10), and so do theClaudeAccountEmailwidget and skills tests.mainand this PR for these cases:.claude.jsonwith the email present, missing, non-string,null, corrupt, or absent, in both labelled and raw mode, on both the cache-miss and cache-hit render.skills,defaultandheavyconfigs with 1 MB and 5 MB transcripts.🤖 Generated with Claude Code