Three of my four Claude Code accounts hit their rate limits within a few minutes of each other — “walled,” out of their budget for the hour, like four phones on a shared plan where three have blown through the monthly data cap. That’s exactly the situation I built the rescue daemon for: a little background process whose whole job is to notice a walled seat and move the work onto a healthy one.
It sat there and did nothing.
The one account with headroom — plenty of budget left — was invisible to it. Not down. Not busy. Invisible. The daemon genuinely did not believe that account existed.
Here’s the embarrassing part. I run two things against this fleet of accounts. A load balancer that picks a live account to route new work to, and the rescue daemon that rescues stranded sessions off walled seats. Both of them need the same thing: the list of accounts I actually have. The balancer figured that list out by looking at the credential files on disk. The daemon had a list too — but it was a hardcoded array I’d typed by hand months earlier, back when there were three accounts.
A week before the incident I’d registered a fourth account. I dropped its credentials in, the balancer picked it up automatically, everything worked, I moved on. I never touched the daemon, because nothing told me to. The two lists silently disagreed from that moment on, and I had no idea until the exact worst time — the one moment the fourth account was the only thing that could have saved me.
I fixed it by deleting the hardcoded array entirely. Now both the balancer and the daemon learn the roster the same way: they scan the credentials directory and match credentials-*.json. Whatever files are there, that’s the fleet. Adding an account is dropping a file. No code edit, no second place to remember.
Discovery over enumeration give me the detail
The bug was two sources of truth for one fact. The balancer did discovery; the daemon did enumeration:
# rescue daemon, before — rots the moment the fleet grows
ACCOUNTS = ["acct-1", "acct-2", "acct-3"]
# both components, after — one derivation, filesystem is the source
from pathlib import Path
def roster(cred_dir="~/.claude-fleet"):
return sorted(Path(cred_dir).expanduser().glob("credentials-*.json"))The test that would’ve caught it: assert both components return the same roster. If you can’t write that assertion because one of them builds its list from a literal, that’s the smell.
assert balancer.roster() == daemon.roster()Why this beats being careful: being careful means remembering to update the second list every time, forever, correctly. A directory scan means the fleet is the files — there’s no second copy to forget, because there’s no second copy.
If two services act on the same set of things, don’t give each its own idea of what that set is. Derive it, both of them, from one place — a directory, a shared config, a table. And make “add a member” a data operation, not a code change. The copy you type by hand is fine the day you type it. It starts rotting the next day, and it fails you on the day you most need it to be right.