From 5a9bbbc2fbb5e03c60d252ba48417a1b93beef00 Mon Sep 17 00:00:00 2001 From: asdf8675309 <174058705+asdf8675309@users.noreply.github.com> Date: Tue, 4 Aug 2026 11:00:47 -0400 Subject: [PATCH] fix(installer): raise the shipped statusline refreshInterval from 1s to 30s deployStatusline() wires every new install with refreshInterval: 1, so Claude Code polls the statusline once per second. Nothing on the bar changes that fast. A warm render of LIFEOS_StatusLine.sh costs 0.28-0.29s. The usage figures it displays sit behind a 900s cache TTL (USAGE_CACHE_TTL), and the script renders no wall clock, so the fastest timer-driven value on the bar updates once every 15 minutes. A 1s poll re-renders it about 900 times per data change. The waste is not the only cost. Public PR #1767 reports that Claude Code terminates a statusline render which overruns its interval, and that the killed renders leaked 244,760 scratch directories on a headless box until the filesystem ran out of inodes. 30 is a conservative starting point, not a derived optimum. It is far inside the 900s TTL of the slowest-moving source while cutting the duty cycle from about 29 percent to about 1 percent. The principled value tracks how often the underlying data actually shifts, so this number should be revisited if the bar gains a faster-changing source. Everything on the bar that moves on events rather than on a timer, such as the model and the branch, still re-renders at turn boundaries regardless of this interval. --- LifeOS/Tools/DeployComponents.ts | 8 +++++++- LifeOS/install/skills/LifeOS/Tools/DeployComponents.ts | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/LifeOS/Tools/DeployComponents.ts b/LifeOS/Tools/DeployComponents.ts index f8ccdd3120..b08230459f 100755 --- a/LifeOS/Tools/DeployComponents.ts +++ b/LifeOS/Tools/DeployComponents.ts @@ -190,7 +190,13 @@ function deployStatusline(ctx: Ctx): ComponentResult { const alreadyWired = current?.command === command; if (!alreadyWired) { backup(settingsPath); - settings.statusLine = { type: "command", command, refreshInterval: 1 }; + // A warm render costs ~0.29s and the usage figures it shows sit behind a + // 900s TTL, so a 1s poll re-rendered ~900x per data change, and renders + // that overrun their interval get killed mid-flight (public PR #1767). + // 30 is a conservative starting point, NOT a derived optimum: the right + // interval tracks how fast the underlying data actually moves, so revise + // it if the bar gains a faster-changing source. + settings.statusLine = { type: "command", command, refreshInterval: 30 }; // Atomic — never leave a half-written settings.json (public PR #1643, @elhoim) atomicWriteText(settingsPath, JSON.stringify(settings, null, 2) + "\n"); } diff --git a/LifeOS/install/skills/LifeOS/Tools/DeployComponents.ts b/LifeOS/install/skills/LifeOS/Tools/DeployComponents.ts index f8ccdd3120..b08230459f 100755 --- a/LifeOS/install/skills/LifeOS/Tools/DeployComponents.ts +++ b/LifeOS/install/skills/LifeOS/Tools/DeployComponents.ts @@ -190,7 +190,13 @@ function deployStatusline(ctx: Ctx): ComponentResult { const alreadyWired = current?.command === command; if (!alreadyWired) { backup(settingsPath); - settings.statusLine = { type: "command", command, refreshInterval: 1 }; + // A warm render costs ~0.29s and the usage figures it shows sit behind a + // 900s TTL, so a 1s poll re-rendered ~900x per data change, and renders + // that overrun their interval get killed mid-flight (public PR #1767). + // 30 is a conservative starting point, NOT a derived optimum: the right + // interval tracks how fast the underlying data actually moves, so revise + // it if the bar gains a faster-changing source. + settings.statusLine = { type: "command", command, refreshInterval: 30 }; // Atomic — never leave a half-written settings.json (public PR #1643, @elhoim) atomicWriteText(settingsPath, JSON.stringify(settings, null, 2) + "\n"); }