Traced live on the mini, 70+ sessions Verified against api.anthropic.com rate-limit headers · 2026-08-27
Why does Claude keep asking you to log in?
Two kinds of token, two separate stores, four places a credential hides — and why the meter said 99% when the account was at 84%.
ANSWER · LOGGING IN IS WHAT LOGS EVERYONE ELSE OUT
docs.propflowai.coCLAUDE AUTH MODEL
02 /VERDICT
The short version, before the mechanism
One session refreshing its token silently logs out every other session on that account.
Claude Code stores a login in a file with no lock on it. Refreshing rotates the token server-side, so every other copy becomes invalid the instant one session uses it.
UPSTREAM BUGS
7
open GitHub issues, same root cause
ROTATIONS · 08-26
6
each one invalidating 28–113 panes
RE-LOGINS THAT DAY
~hourly
all day, by hand
AFTER THE FIX
0
bearer tokens cannot be revoked this way
The fix is not "log in less". It is to stop using the kind of credential that can be revoked out from under a running session.
A session token is borrowed. A bearer token is issued.
WHAT /login GIVES YOU
The session token
Lives in ~/.claude/.credentials.json. Short-lived — about 8 hours — and kept alive by a refresh token. Using that refresh token rotates it, and every other copy of it dies at that moment. The file has no lock, so two sessions racing is normal, not exotic.
WHAT claude setup-token GIVES YOU
The bearer token
A one-year sk-ant-oat01-… string, scope user:inference. It never refreshes, so it never rotates, so nothing another session does can revoke it. Handed to a process as an environment variable at launch.
Both authenticate the same account and spend the same quota. The difference is only who can invalidate them.
The refresh is the destructive act — and every session does it automatically.
session A's token nears expiry
→
A refreshes it
→
server rotates the token
→
B, C, D… hold a dead copy
WHAT SESSIONS B–D SEE
401
OAuth access token has been revoked — on their very next prompt, mid-work.
WHAT FIXES IT FOR THEM
/login
…which rotates the token again, and kills whoever refreshed last. The cure is the disease.
This is why it felt random. You were not doing anything wrong — you were in a loop with no exit.
measured on the mini · 6 rotations, 28–113 panes each · 2026-08-2604
05 /STORES
The part that makes the dashboards confusing
There are two completely separate collections of credentials.
THE KEYCHAIN POOL
8 accounts, macOS Keychain
What ccswitch list shows and what ccswitch auto rotates. Session-token based, so it carries the revocation problem. It is also the thing most of our reporting still reads.
THE BEARER BANK
8 tokens, ~/.claude/.tokens/
Plain files, one per account, selected by the ~/.zprofile-token symlink. This is what every session actually runs on since 2026-08-26.
We migrated the fleet to the bank and left the reporting pointed at the pool. Every confusing number in the last two days comes from that one gap.
The statusline was showing a different account's usage.
WHAT THE METER SAID
99%
The keychain pool's active account — one this session was not using and could not affect.
WHAT THIS SESSION WAS AT
84%
Bearer account6, read live from the API's own rate-limit headers.
The code took max(live, cached) of two numbers that used to describe the same account. Since the bearer migration they routinely describe different ones — so the worse of two unrelated figures won.
ccswitch cmd_statusline · fixed in ccswitch#12 · 2026-08-2707
08 /THE 99%
Which number to trust, and when
Three meters, and only one of them is about you.
The 5-hour window
The one that stops a turn mid-flight. Refills continuously. This is the number to watch when you are actively working.
The 7-day window
The weekly budget. Resets on a rolling date per account, not on a calendar week — two accounts can be 5 days apart.
The Fable quota
A separate cap from the general one. An account can be healthy at 84% overall and completely out of Fable.
Ground truth
ccswitch doctor reads the account this session is really on, by inspecting the process rather than the shell.
A 429 is not a dead token. It means the credential is good and the account is capped — calling it dead sends you to re-mint something that works.
anthropic-ratelimit-unified-{5h,7d}-utilization08
09 /LIMITS
The constraint everything else bends around
Switching accounts changes what the next session gets. Never this one.
Why
A process's environment is fixed at exec. Repointing the symlink cannot reach inside a program that is already running.
What that means
A session keeps its token until it is re-executed — tmux respawn-pane -k with --resume. The conversation survives; the process does not.
The trap
echo $CLAUDE_CODE_OAUTH_TOKENlies. Every shell re-reads the symlink, so it shows what a restart would get — not what the session is spending.
The honest read
ps eww -o command= -p <pid> — the process's own environment, as captured at launch.
This bit us directly: a diagnostic reported the switch as already applied while the session was still billing the old account. It was reading the shell, not the session.
The auto-switch was steering a wheel that was no longer connected.
every turn boundary
→
ccswitch auto runs
→
checks the keychain pool
→
bearer bank untouched
Nothing was broken. Nothing was ever wired. The bearer bank had no rotation at all, so an active account reached 99% of its weekly cap with every session still pointed at it — while ccswitch list reported the pool as healthy.
Now fixed:auto evaluates the bank too, bounded to one probe per 15 minutes, with the full sweep only at an actual rotation event.
ccswitch#10 · rotate the bearer bank · merged 2026-08-2710
11 /LIMITS
Two operations that sound alike and are opposites
Rotating a bearer is free. Refreshing a login is destructive.
ROTATE THE BEARER
Repoint a symlink
Changes which token new sessions get. Touches no server state, invalidates nothing, and cannot affect a running session. Safe to do at any time, for any reason.
REFRESH A LOGIN
Rotate server-side
Mints a new token and invalidates every other copy. This is why a guard now refuses to refresh a token any live session is still holding — not refreshing costs a usage reading; refreshing costs someone their login.
The guard reports such an account as "in use by a running session — not refreshed". That is an honest unknown, not a failure.
ccswitch held_mark / held_recently · ccswitch#711
12 /PLAYBOOK
The one case where a login is still the answer
Do it where no live session can be hurt.
01 · WHERE
On the Mac, never the mini
Each machine has its own credentials.json, so a Mac login physically cannot revoke a mini session.
02 · WHY
Only to mint, not to work
Log in, then immediately claude setup-token and bank the bearer. The login is a means to a token, not a way to run.
03 · WHO
An adrift account needs its owner
"No fresh token in 17 days" means that machine stopped publishing — re-minting it elsewhere steals ownership rather than fixing it.
Day to day the answer is: don't. A bearer session that is out of quota needs a rotation and a respawn, not a login.