I came back to my desk, checked in on the boss, and it proudly told me that 22 of my Claude panes were stuck.
Not “I fixed them.” Not “I’m on it.” Just a tidy little status report: here are the 22 that hit their rate limit, standing by for further instructions.
Let me back up. I run a fleet of Claude Code sessions — the coding agent, one per pane, all living inside tmux, which is just a terminal that can hold dozens of side-by-side windows on one screen. On top of them sits a “boss” agent whose whole job is to watch the others and keep them alive. When one of the worker agents runs out of its usage budget for the hour (that’s the rate limit — think a monthly phone-data cap, but it resets in five hours), Claude Code pops up a little dialog and freezes. The boss is supposed to notice that dialog and restart the pane.
So when the boss came back to me holding a clipboard of 22 frozen agents like it had done its job, that was the bug. It treated “22 panes are rate-limited” as news to escalate instead of work to do.
Here’s the thing I hadn’t said out loud, even to myself: restarting a rate-limited pane is not a decision. There is no judgment call. You dismiss the dialog, you pick an account that still has headroom, and you resume the exact same session. A machine should do it and never mention it. But I’d never told the boss that, so it did the polite, cautious thing — it asked.
I rewrote its charter with one line that mattered: rate-limit recovery is mechanical. Do it silently. Never surface it as a question. And I gave it the tool to actually do the recovery — a launcher I call cl that rotates across my Claude accounts, checks which one still has budget, and resumes the frozen session by its UUID so no context is lost. If every account is capped, it falls back to DeepSeek instead of giving up.
The rescue loop: dismiss the dialog, rotate the account, resume by UUID give me the detail
The two parts that took real fiddling:
Dismissing the frozen dialog. Claude Code’s rate-limit prompt needs a specific key sequence to escape cleanly, not a single keypress:
tmux send-keys -t "$pane" Escape
tmux send-keys -t "$pane" C-c
tmux send-keys -t "$pane" C-c
tmux send-keys -t "$pane" Enter # lands on "Exit anyway"Relaunching without losing state. cl picks an account and resumes the same session:
account=$(balance --why | awk '/headroom/{print $1; exit}')
account=${account:-deepseek-fallback}
cl --account "$account" --resume "$session_uuid" "$brief"One trap worth naming: don’t feed the brief with raw send-keys into a live TUI. Characters interleave with the app’s own redraws and you get a garbled prompt. Pass the brief as a launch-time positional arg (as above) or via a paste buffer (tmux load-buffer + paste-buffer), so it arrives atomically.
Why this works is almost boring: deterministic housekeeping should never travel up to a human, because a human adds latency and zero judgment to a step that has neither ambiguity nor risk. Every second those 22 panes sat frozen waiting on me was pure waste.
So sort every recurring thing your agents do into two buckets. Mechanical recovery — retries, restarts, rotations, resumes — gets automated and stays silent. Genuine decisions — spending real money, deleting data, anything you’d want to be able to explain later — get escalated to you. The failure mode isn’t automating too much. It’s letting a robot ask permission for the one thing it never needed to ask about.