# Five Requests in Fifteen Seconds From One Status Bar Item

> Source: <https://dev.to/devshakib/five-requests-in-fifteen-seconds-from-one-status-bar-item-4kgh>
> Published: 2026-09-14 16:40:57+00:00

Claude Code knows how much of your usage limits you have left, but it shows you

in a panel you have to go and open. The number belongs where you are already

looking, so it went into the VS Code status bar:

```
Claude 5h 12% · 7d 39%
```

Hover for every limit and when each one resets; the item turns amber at 75% and

red at 90%. The first version worked. The second, released the same evening, had

the usage endpoint answering 429: five requests in fifteen seconds, and every one

of them extended the wait.

The mistake was thinking of the extension as one program. It isn't. Each VS Code

window runs its own copy, with its own timers and its own event handlers, and

nothing is shared between them unless you share it.

So the real schedule was never "one request every five minutes". It was:

Move between a few windows, click the item because the number looks stale, and

you get what happened here: five requests in fifteen seconds, each one making

the block longer.

VS Code gives every extension a global storage folder,

`context.globalStorageUri`, and it is the same folder in every window. That makes

it the simplest place to keep a result that all of them can read.

A window no longer asks the server just because it woke up. It reads the file

first, and only fetches if the numbers there are older than the refresh

interval:

``` js
// Fresh enough? Then this is just a render — no request.
const age = last ? Date.now() - last.at : Infinity;
if (age < (manual ? CLAIM_MS : s.minutes * 60_000)) {
  render();
  return;
}
```

Two windows can still find the same stale file at the same moment, so the one

that fetches writes a claim first, and any window that sees a claim younger than

30 seconds stays out of it:

```
// Another window is already fetching.
if (cache.fetchingAt && Date.now() - cache.fetchingAt < CLAIM_MS) return;
```

The timers also carry up to 20 seconds of random jitter, so windows opened

together don't wake together. Focusing a window now costs nothing: it re-renders

what is already in the file.

The worst part of the old version was the click. The item looked stuck, so it

got clicked, and each click was another request to a server that had just said

stop.

Now a 429 sets a block, written to the same shared file so every window obeys it.

Its length is whichever is longer: the server's own `retry-after`, or 5 minutes

doubling on each repeat up to 30.

``` js
function nextBlock(strikeCount, retryAfterMs) {
  const curve = Math.min(BLOCK_MAX, BLOCK_MIN * 2 ** Math.max(0, strikeCount - 1));
  return Math.max(curve, retryAfterMs || 0);
}
```

And a click cannot override it. That felt wrong to write, because a button that

does nothing looks broken. So the tooltip says when the next check is due, which

turns "why won't it refresh" into an answer.

The very first version had the opposite problem: it treated one failure as news.

The extension reads the login Claude Code already keeps: the macOS Keychain

entry `Claude Code-credentials`, or `~/.claude/.credentials.json` elsewhere.

Claude Code rewrites that entry whenever it renews its login, and a read that

lands in that moment comes back without a token. The status bar showed a warning

where the numbers should have been, until the next poll five minutes later.

Now a failure keeps the last numbers on screen, falls back to the token already

held, and retries after 20 seconds, then 60, then 120. The warning appears only

after three failures in a row, and the tooltip always names the last one. Nothing

is hidden; it just stops shouting.

Anything that reads a login should say plainly what it does with it:

`api.anthropic.com`, shared by every
window.
The endpoint deserves the same honesty. It is the one Claude Code's own usage

panel reads, not a published API, so a Claude Code update could change or remove

it. If that happens, the extension shows a warning instead of numbers.

ds_usage is free and MIT licensed, on the

[VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=devShakib.ds-usage),

with the source on [GitHub](https://github.com/devShakib015/ds_usage).

*Originally published at [devshakib.jumyn.com](https://devshakib.jumyn.com/blog/five-requests-in-fifteen-seconds-from-one-status-bar-item). I write about Flutter, Dart and the parts of shipping that are genuinely awkward — and publish the packages that came out of them at [pub.dev/publishers/jumyn.com](https://pub.dev/publishers/jumyn.com/packages).*
