Repository navigation
[Feature]: Automatic account failover on rate limit for managed Claude/Codex subscription accounts #20512
Description
Problem or use case
I have several managed subscription accounts registered on one Orca host (2 Claude Max, 4 Codex). Long-running agent work still stops dead when the active account hits its 5-hour or weekly window, even though the other accounts have plenty of quota left. Recovering means noticing the stall, opening the account switcher, picking another account by hand, and restarting the work — and on a fleet of parallel agents that happens several times a day.
What makes this frustrating is that Orca already has every piece needed except the policy that connects them:
- Per-account isolated homes already exist:
claude-accounts/<id>/auth/andcodex-accounts/<id>/home/with its ownCODEX_HOMEper pane. - Usage and rate-limit tracking already exists, including reset times for the 5-hour, daily, and weekly windows, and an 80% warning chip in the status bar.
- The raw signal is already on disk and already parsed. Codex session logs carry, verbatim:
"rate_limits":{"limit_id":"codex","primary":{"used_percent":59.0,"window_minutes":10080,"resets_at":1789698647}}
So Orca knows which account is about to run out, knows when it resets, and knows which other accounts exist. It just never acts on that. Switching remains manual and UI-only.
Proposed solution
An opt-in auto-failover policy per provider (Claude, Codex), default off:
- Threshold setting — "Auto-switch account at N% of the tightest window" (suggested default 90%). Pre-emptive, so a turn in flight is not lost. Reacting only to a hard 429 is too late and loses work.
- Target selection — switch to the account with the most remaining quota in the relevant window. Skip accounts whose window has not reset yet; if every account is exhausted, surface the earliest
resets_atinstead of thrashing. - Reach running sessions — the switch must apply to sessions already in flight, not just newly spawned ones. This is the blocker today (see Claude account switch does not reach a running session; two panes in one worktree can run on two accounts #19900: a switch does not reach a running session, and two panes in one worktree can end up on two different accounts).
- Cooldown / circuit breaker — mark a switched-away account as cooling until its
resets_at, so failover cannot ping-pong between two nearly-exhausted accounts. - Headless and CLI parity — scripted runs, automations, and
orchestration worker-startneed the same behavior. At minimumorca account use <id|email>plus a policy flag; today no CLI command selects an account at all (related: [Feature]: Select the Claude account for headless/agent spawns via CLI (--account / orca account list) #8770). - Respect explicit pinning — a pane or worktree deliberately bound to one account opts out of failover (related: [Feature]: Per-worktree account pinning — run different Claude/Codex accounts concurrently #9496).
Alternatives or additional context
Existing issues cover only fragments of this. #8121 and #9565 both ask for "auto switch account when limit exceed" but are scoped to Grok and Kimi specifically. #15467 asks for a switch shortcut, #10688 for per-account usage in the Accounts pane, #8770 for CLI account selection, and #19900 documents that a switch does not reach a running session. This request is the generalized version for the two first-class providers with subscription OAuth accounts.
Community tools solve half of it and actively conflict with Orca's account management, which is why I think this belongs in Orca rather than beside it:
| Tool | What it does | Why it does not work under Orca |
|---|---|---|
| claude-swap (2.5k★) | Pre-emptive switch at 90% of the 5h/7d window | Writes ~/.claude and macOS Keychain directly, fighting Orca's managed auth. Compounded by #16016, where the active managed account is materialized into the default CLAUDE_CONFIG_DIR. |
| cc-switch (132k★) | Failover queue with a circuit breaker | Works through a local proxy over API-key providers (ANTHROPIC_BASE_URL → 127.0.0.1). Subscription OAuth accounts are read for quota display but are not failover-queue members. |
| coding_agent_account_manager | Cooldowns an account on a rate-limit error, re-runs on another | Per-command wrapper, reactive only, and unaware of Orca's per-account CODEX_HOME layout. |
None of them are safe to combine with Orca's managed account homes. Orca is the only component that already owns both the credentials and the usage data.
Environment
macOS, Orca 1.4.200, host runtime. 2 managed Claude accounts (Max), 4 managed Codex accounts.
Activity
JAEYOONSUNG commentedon Sep 15, 2026
Follow-up with a correction and a concrete implementation note, after prototyping this locally.
Do not source per-account quota from the session logs. My original post pointed at the
rate_limitspayload in Codex session files. That payload is real, but it is not attributable to an account by its path. Orca hardlinks session files across account homes — the same file appears under severalcodex-accounts/<id>/home/sessionstrees with the same inode:So a
rate_limitsentry found under account<id>may well belong to a different account. Three of my four accounts reported byte-identical "latest" numbers this way, which is how I noticed.The authoritative source is the app-server RPC.
account/rateLimits/readreturns the backend's ownaccountIdalongside the numbers, and honoursCODEX_HOME, so it isolates cleanly per managed account home:The response carries
ordinaryUsageAllowed,rateLimitsByLimitId, and per-windowusedPercent/resetsAt. Probing four account homes in parallel takes about 5 seconds.One scoring trap worth encoding in the feature. Accounts report more than one bucket. Only
codexgates ordinary work;codex_bengalfox(the Spark tier) sits at 0% even when the main bucket is fully spent. Scoring on the wrong bucket makes an exhausted account look like the best failover target. Two of my accounts right now:codexcodex_bengalfoxrate_limit_reachedA percentage alone is not enough —
ordinaryUsageAllowedandrateLimitReachedTypeare the real gate.On the CLI gap. As a stopgap I spawn the target account with
orca terminal create --command 'CODEX_HOME="…" codex'. Codex runs and the account binding is genuinely correct, but the tab is not tracked as an agent, since agent detection keys on the command's leading token — the same problem #8770 describes. A supported--accounton spawn, or anorca account use, would remove the need for the env-var prefix entirely and let auto-failover work headlessly.homofaber-tech commentedon Sep 18, 2026
Independent data point from the Claude side. We run an external failover tool (cron on a Windows Orca host with WSL, plus a second Orca running headless as
orca-ide servein a Linux container), two subscription accounts per agent. The RPC and bucket findings above match what we see; the gaps that actually broke us are on the CLI surface.1.
orca account list --jsonreturns one reading per agent, with no account identity.rateLimits.claude/rateLimits.codexcarryweekly/sessionusedPercent,resetsAt,statusandupdatedAt, but nothing says which account the numbers were measured for, and there is no entry for the inactive ones (inactiveClaudeAccountswas empty in every sample here). So an external policy cannot answer the two questions it needs: whose numbers are these, and does the other account have room?What that cost us: right after an account change, the reading still described the previous account. Our checker read 100% weekly, attributed it to the account that had just become live (which was nearly unused) and switched to the account that was genuinely exhausted. Hysteresis alone would have flip-flopped it every 30 minutes. We now discard any reading whose
updatedAtpredates the last account change, and cache the last reading per account so we never switch into one that is still over its limit. Both workarounds disappear if the payload carries anaccountId.2. A dead login is indistinguishable from a limit without matching English strings. When the live credential expires, the same field reports:
status: "error",error: "OAuth access token has expired. Re-authenticate to continue."status: "unavailable",error: "Codex not signed in"Our first version classified the codex wording as a limit and switched accounts, which did not help and left the other account marked invalid when its post-switch verification failed. A typed discriminator (
auth/limit/unknown) alongside the human-readable message would make this safe to automate.3. Readings go stale with no way to ask for a refresh.
updatedAtis routinely 10+ minutes old here, and stays put for 30+ minutes while the app is idle, so a 5-minute checker mostly re-reads the same numbers — and, with the attribution guard above, skips entirely. A--refreshflag onorca account list, or a smallorca account usagecommand, would let a headless checker poll on its own cadence.4. Applying a switch headlessly. Same conclusion as the comment above for codex. On the Claude side
claude.activeAccountIdsByRuntimeis null in our setup, so the system credential file is what actually runs and switching means swapping that file's contents. Orca's picker only reaches new terminals, so afterwards the UI label disagrees with the identity running inside existing ones. Anorca account use <agent> <id>that applies on the running host would remove that entire class of workaround.If maintainers want it, I'm happy to open a PR for (1) and (2) —
accountIdand a typed status on the CLI payload, with tests. Both are small, provider-neutral, and independent of whether the failover policy itself ever ships inside Orca.JAEYOONSUNG commentedon Sep 18, 2026
Thanks — this is a useful independent data point, and it sharpens what the CLI would need. A few observations from the Codex side that bear directly on your (1) and (2), because the app-server surface already has both properties the CLI lacks.
On (1), attribution.
codex app-server→account/rateLimits/readreturns the backend's ownaccountIdalongside the numbers, so the reading carries its identity. Run once per managed home (CODEX_HOME=<account>/home) and you get a per-account table with no inference. That is the mechanism I'd suggest the CLI payload borrow rather than a new field being invented — the value already exists on the wire. Your stale-after-switch failure is exactly what this prevents: the number and the identity arrive together, so nothing can be attributed to the wrong account.On (2), auth vs. limit. The same RPC already discriminates them. A home with no credential returns a JSON-RPC error (
-32600,"codex account authentication required to read rate limits") while an exhausted account returns a normal result withordinaryUsageAllowed: falseandrateLimitReachedTypeset. I verified this against a deliberately empty home this morning. So a typed status on the CLI could be derived mechanically: RPC error →auth,ordinaryUsageAllowed === false→limit, elseok. No English matching needed.Two things your comment made me check in my own external tool, for anyone building the same:
resetsAtand never select it as a target inside that window, whatever the next reading says. Combined with a minimum interval between switches, that closes the flip-flop you describe even if a reading is briefly misattributed.On (3), staleness. For Codex the app-server read is live, so there is nothing to refresh. For Claude,
claude -p "/usage" --output-format jsonis also live and free (total_cost_usd: 0,num_turns: 0), and it returns per-model weekly windows — on this machine the Fable window sits at 100% while "all models" is at ~65%. That distinction matters for policy: it is a reason to switch model, not account, and an account-level checker would burn a healthy account on it. Only the active account is readable this way, which is the gap that leaves your point (1) genuinely open on the Claude side.On (4), agreed — same conclusion as #19900. A switch reaches new terminals only; existing panes keep the identity they were given (for Codex that is per-pane
CODEX_HOME, which is actually the better model and is why Codex panes can already run different accounts side by side).I'd support the PR for (1) and (2). If it sources
accountIdand the typed status from the app-server response rather than the CLI's cached reading, both fall out for free and stay correct after a switch.ryofukutani commentedon Sep 19, 2026
Data point from a macOS host (Orca 1.4.205, nine managed Claude accounts), on the "applying a switch headlessly" gap raised above.
~/.claude/.credentials.json(and theClaude Code-credentialskeychain item) from outside does not stick here. Orca keeps the selection insettings.activeClaudeManagedAccountIdand rewrites the system credentials from the selected account on its periodic sync, so an external swap gets reverted and the status bar keeps showing the old account.accounts.selectClaudewith{"accountId": "<uuid>"}, on the same socketorca account listuses. Reading the source, it goes through the same serialized path as the picker (write-back of the outgoing account's refreshed token, the live-PTY guard around refresh,~/.claude.jsonoauthAccount). That is exactly the part an external failover tool should not reimplement.Request: expose it on the CLI, e.g.
orca account use <id|email> [--provider claude|codex] --json, returning the newactiveAccountId. It is a thin wrapper over an existing method, it keeps external failover tools away from credential files entirely, and it is useful whether or not the in-app failover policy ships.— Claude (Claude Code), posting for @ryofukutani (session: dev-project-42)
JAEYOONSUNG commentedon Sep 19, 2026
Confirming from a macOS host (1.4.205, four Codex + two Claude accounts) that
accounts.selectClaude/accounts.selectCodexover the runtime socket is what an external tool should call, and +1 toorca account use. Two additions.Why the RPC and not the files, stated once for anyone landing here. Your point about the periodic sync is the decisive one: the selection lives in Orca's settings, and the system credential is derived from it, so anything written to
~/.claude/.credentials.jsonfrom outside is not a switch, it is a race Orca wins on the next sync. The RPC is the switch. It also carries the parts nobody should reimplement — the outgoing account's refreshed-token write-back and the live-PTY guard around the refresh — which is what makes it safe to fire from a scheduled job while sessions are open. I have had it running on a 15-minute schedule for several days without a live session being disturbed.A per-pane Claude account already exists in the codebase — on WSL. Reading the bundle, the WSL runtime pins each Claude session to its managed account with
envPatch: {CLAUDE_CONFIG_DIR: <account auth dir>}, and there is even an invariant for it (claude sessions pin CLAUDE_CONFIG_DIR, not …). The host runtime instead does the auth-only swap inside the default config dir, which is the root of #14254 and #7782 (both closed) and of the "every session on the machine follows the switcher" complaint. The two runtimes could share the WSL model: hand each Claude pane aCLAUDE_CONFIG_DIRthe way Codex panes already get aCODEX_HOME. That would give concurrent Claude accounts per pane with no new mechanism, and the sync problem above disappears because nothing is swapped in place any more.For what it's worth, that is also the workaround that survives the sync today: a second
CLAUDE_CONFIG_DIRwith its own sign-in is invisible to Orca and does not get reverted, at the cost of Orca not recognising the pane as an agent (#8770).So the CLI ask would be two thin wrappers over things that already exist:
orca account use <id|email> --provider … --jsonoveraccounts.select*, and, for the host runtime, the per-paneCLAUDE_CONFIG_DIRpinning WSL already does.karoliang commentedon Sep 20, 2026
Strong agree on the framing, and the part I would underline is your own sentence: Orca already has every piece except the policy that connects them.
I have been building that policy layer outside Orca for a slightly wider case, and two things from doing it may be useful here.
The numbers differ in quality, and a failover policy has to carry that. Reading the three providers I use:
GET https://opencode.ai/zen/go/v1/usagewith rolling, weekly and monthly percentages and an ISO reset for each. Exact and live.rate_limits.primary.used_percentwithwindow_minutesandresets_atinto its newest session rollout JSONL. Exact, but only written when Codex runs, so between runs it is a lower bound on usage, never an upper one. That is the same behaviour as [Bug]: Codex quota refresh is not timely #11538.Failing over onto an account whose headroom is an estimate can strand a run just as badly as not failing over at all. What has worked for me is treating an estimated number as usable only for work that already justifies an escalation, and never as ordinary spare capacity.
Ordering matters more than availability. Once more than one account has room, the useful rule turned out to be: spend the bucket that expires first. A window resetting in three hours is capacity about to be thrown away; a monthly window is the scarce thing. Picking the account with the most headroom does the opposite of the right thing, because the monthly bucket usually looks the emptiest.
Also worth separating from failover proper: dropping a tier before the wall rather than at it. With two readings of the same bucket you have a burn rate, and if the projection crosses 100% before the reset you can stop handing that account expensive work while it still has room for cheap work.
I filed two adjacent issues that this one would compose with rather than duplicate: exposing the usage numbers over the CLI and RPC (#21746), and an optional agent-selection hook on
worker-start(#21747). The first is what any external policy needs and is the smaller half; this issue stays the in-app behaviour.Happy to share the standalone implementation once it is public if that is useful as a reference for the ordering rules.
karoliang commentedon Sep 20, 2026
Following up on the offer above: the standalone implementation is public now at https://github.com/karoliang/rightsize (MIT, Python standard library only, no dependencies).
Relevant to this issue rather than the whole tool:
rightsize.pyheadroom()andpick()hold the ordering rules, roughly forty lines between them. Candidates are filtered by a per-provider reserve, then sorted by which bucket resets soonest.GET https://opencode.ai/zen/go/v1/usage; Codex only leavesrate_limitsbehind in its session rollout, so it is a lower bound; Claude Code caches nothing.test_rightsize.pyruns the policy against synthetic quota states with no network, including the two cases that are easy to get wrong: an unknown headroom must not be treated as spare capacity, and an exhausted ladder must escalate rather than return nothing.None of it is an Orca plugin and it does not need to be. It reasons about host-level quota, which is exactly the limitation #21746 would remove, since Orca is the only thing that knows which managed account a given pane will use.
JAEYOONSUNG commentedon Sep 20, 2026
The ordering rule is the part I had backwards, so thank you for stating it plainly. My tool sorted candidates by most headroom and handed work to the account that looked emptiest — which, exactly as you say, is usually the one whose scarce long window is emptiest. It now sorts eligible candidates by soonest reset, with headroom only as a tie-break, and logs the reason it chose ("window resets 09-27 08:46 with 90 points usable, so spend it before it expires"). The burn-rate skip is in too: two readings of the same bucket, project to the reset, pass the account over while it still looks fine. Tests cover both, including the two you flagged as easy to get wrong.
Two of your three quality tiers are better than the probes suggest, and it changes the policy. This is the part worth checking before anyone builds on the estimate path.
Codex is exact and live, not a lower bound. The session-rollout
rate_limitspayload is the wrong source — and worse than stale, it is unattributable, because Orca hardlinks session files across account homes (same inode under severalcodex-accounts/<id>/home/sessionstrees), so a payload found under one account may belong to another. The right source iscodex app-server→account/rateLimits/read, which answers on demand whether or not Codex has run, and returns the backend's ownaccountIdalongside the numbers. Run it once perCODEX_HOMEand you get an exact per-account table with no inference and no attribution problem. I verified just now against a home that had not run Codex in days:usedPercent,resetsAt, andaccountIdall present.Claude Code is exact, live, and free.
claude -p "/usage" --output-format jsonreturns the same windows the TUI shows. Measured on this machine a moment ago:total_cost_usd: 0,num_turns: 0,duration_api_ms: 0. No transcript reconstruction, no estimate. The catch is different from the one you describe: only the ACTIVE account answers, because Orca swaps one credential in place rather than keeping one per account — which is precisely the gap #21746 would close.So on my machine the tiers are: Codex exact per-account, Claude exact but active-account-only. The "unknown is not spare capacity" rule still earns its place, but it now guards a much smaller set.
One dimension the model is missing: the binding bucket can be per-model. Claude reports a shared weekly window and a per-model weekly window. Here, right now, the Fable window sits at 100% while all-models reads 25%. Treating that as one number gives the wrong action either way: account-level failover burns a healthy account for what is a model problem, and ignoring it strands the run. The fix is to let the verdict name what to change — model or account — and my policy splits
model_exhaustedfromaccount_exhaustedfor that reason. Ifrightsizegrows a per-model bucket id, the existing ordering rules apply to it unchanged.Happy to send the per-provider probe notes as a PR to
rightsizeif the app-server approach is useful to you — it removes the lower-bound caveat for Codex entirely.karoliang commentedon Sep 20, 2026
I owe you a correction on that, because I have since found the rule I gave you is right for cheap work and wrong for expensive work, and you have now shipped the half I got wrong.
Soonest reset is right until the dispatch is expensive. The rule exists so capacity about to vanish is not wasted, and the way to waste it is to spend it on the priciest thing you run. A repo of mine hit exactly that: OpenCode's weekly at 77 per cent used with eight points left and nineteen hours to run, Codex at 0 per cent with a week of room, and a design-tier task banded onto the emptying bucket because its window closed sooner. The cheap work that bucket could have absorbed went elsewhere, and the expensive work would have been fine on the plan that was sitting idle.
So the ordering is now split by cost: cheap bands take the soonest reset, and the expensive rung takes the most headroom. A candidate whose bucket cannot cover the dispatch's estimated cost is passed over rather than merely ranked low.
The windows are nested, and pacing only the binding one misses it. This is the part I would most encourage you to copy, because it is invisible until you look for it. Same account, same moment:
The weekly looked nearly spent and was perfectly on pace. The binding bucket was the weekly, so a policy that paces only the bucket that binds sees a healthy account. The month those same tokens also came out of was on course to be gone in a week.
projected = percent / elapsed_fractionneeds no history, so it costs nothing to run on every window rather than one.Two different overruns, and only one may be relaxed. Whole-window pace is a forecast from an average; the two-reading burn rate you mention is a measurement. They disagree usefully: a month at 40 per cent with half its window gone is fine on average and on course for 115 per cent at the rate of the last two days. I now run both on every bucket. Where a policy lets a task ignore pacing rather than be stranded, it should ignore the average and never the measurement.
One trap worth naming since your burn-rate skip is in: a sample has to be worth extrapolating. Two minutes of a seven-day window projected to five thousand per cent and marked a just-reset bucket as overrunning. Mine now requires the sample to cover at least five per cent of the window.
On sourcing Codex, the thread was right and I was wrong. I had been reading
rate_limitsout of the newest rollout, with the staleness caveat. @JAEYOONSUNG's point about hardlinking is confirmed here even with a single account: one rollout under the Orca account home hasnlink=2, the same inode as the copy under~/.codex. With one account that is harmless; with several the block carries no identity to check.codex app-server→account/rateLimits/readis the answer, as suggested upthread, and it is better than I expected: 0.74 seconds, no interactive session needed, and it carries its ownaccountId.{"rateLimits":{"primary":{"usedPercent":7,"windowDurationMins":10080,"resetsAt":1790480193}, "planType":"pro"},"accountId":"e81eb3ba-..."}Live it reads 7 per cent; the newest rollout file reads 0. That endpoint is now the first source in my tool with the file kept only as a fallback, which removes the failure mode I described earlier in this thread, where a nineteen-hour-old reading of 93 per cent kept a provider out of every ladder after its quota had moved on.
All of the above is in https://github.com/karoliang/rightsize if it is useful to read rather than re-derive: the ordering lives in
pick(), the pacing inbucket_pace()andheadroom(), and each rule has a regression test written from the state that broke it. Twelve of those tests exist because I had agents attack the policy and they found two rules meeting to produce an answer nobody would defend.thinklanguages commentedon Oct 11, 2026
Windows data point (Orca 1.4.205, four managed Claude accounts), on external switchers.
I tried claude-swap to get proactive switching at a usage threshold. The switch does not survive on a host where Orca manages the accounts:
/loginto a second account, Orca copied the live credentials into that account'sclaude-accounts/<id>/auth/.credentials.json, and 4 ms later rewrote~/.claude/.credentials.jsonfrom the account insettings.activeClaudeManagedAccountId.So the revert @ryofukutani describes on macOS happens on Windows too, and there is no supported way today to get threshold-based switching next to Orca's account management.
+1 to items 1, 2 and 5 of the proposal: an opt-in "switch at N%" policy that picks the account with quota left, and
orca account use <id|email>so a script or the agent itself can apply a switch.orca account addandorca account listare the only account commands in the CLI today.adifsgaid commentedon Oct 12, 2026
I had a go at the Claude half of this in #28044.
It's opt-in. Once the selected account passes 90% of its 5-hour or weekly window, the next Claude you start goes to whichever managed account has the most room. There's a small margin and a cooldown so two accounts near the line don't ping-pong. No Codex yet, and running sessions keep their account, same as a manual switch today (#19900).
@JAEYOONSUNG @karoliang @ryofukutani your notes in this thread saved me a lot of digging, especially the point about never trusting usage you can't tie to an account. That ended up being the trickiest part to get right.
If any of you runs several Claude accounts and has time to try the branch, I'd really like to know whether it picks the account you would have picked.
bacaxnot commentedon Oct 14, 2026
+1. Another data point, from a setup where Orca drives a shared Linux box over SSH and rotation runs outside Orca.
On that box,
cswap auto(claude-swap) runs as a systemd service. Orca has no Claude account registered there and only reads the credentials, so the two never fight over them. It works, but it's a second system to keep alive. I'd much rather Orca owned this. #28044 looks like the right start, and these are the parts we rely on daily that it doesn't cover yet:Happy to test #28044 against an SSH-host setup once it's in a build.
hyeonjong-ai commentedon Oct 15, 2026
+1 from our team — this is a real pain point for us too.
We run several Claude accounts in Orca and keep 6–8 agent sessions going in parallel most of the day. When the active account hits its usage window, the session just stops until someone notices and switches accounts by hand. It would be great if Orca could automatically switch to another registered Claude account with remaining quota and keep the work going without interruption (ideally at a turn boundary, with a short notice of which account it switched to and why).
We'd really love to see this land soon. If there's anything we can do to help — testing a preview build, sharing usage patterns or logs, or giving feedback on the design — we're happy to help.
adifsgaid commentedon Oct 17, 2026
@hyeonjong-ai two open PRs cover what you describe:
claude --resumeon the new account. It happens at a turn boundary: a session mid-turn waits for the turn to end, and one with unsent text waits too.What it looked like with two real accounts last night: account A was at its weekly limit, so the turn ended with "You've hit your weekly limit". I opened the Claude menu, it said 1 session was still on the old account, I clicked Move Session, and a few seconds later the same session id was running on account B and answered from the earlier turn. With "Move idle sessions" on, a session sitting in a background tab moved by itself about a minute after the switch.
With 6 to 8 sessions, the idle ones in background tabs move on their own and the one you're looking at moves when you click. One gap for now: a turn that already died on the limit gets moved, but you still type "continue" yourself.
If you can try it with that many sessions, that would help a lot. Both are on my fork for now (
claude-auto-switchandfeat/claude-move-sessions-on-account-switch).adifsgaid commentedon Oct 17, 2026
@hyeonjong-ai small update to the above: a maintainer merged #29898 this morning, which does the running-session part on main, so I closed #29802. After a switch, Orca now offers to restart the Claude sessions still on the old account, or does it without asking if you pick Always restart in Settings › Accounts.
#28044 now hands its automatic switch to that same step. So with Always restart, the full flow is: the account runs low, Orca switches, and the running sessions resume on the new one. If you want to try it, the
claude-auto-switchbranch on my fork has all of it on top of current main.AmethystLiang commentedon Oct 19, 2026
We've improved the manual switching process in recent releases.
And will look into how to reliably do the automated switching. Thanks everyone for sending in all your research. Much appreciated!
adifsgaid commentedon Oct 19, 2026
@AmethystLiang thanks. For the automated part, #28044 is up to date with main and now goes through #29898's setting: once the selected account passes 90% of its 5-hour or weekly window, Orca switches to the account with the most room left, and running sessions get the same Ask / Always restart / Never restart treatment as a switch by hand. It's off by default. If you'd rather it work differently, I'm happy to rework it.
ng-technology-llc commentedon Oct 21, 2026
Please include Antigravity in this failover. On macOS every parallel Antigravity worker shares one machine-wide credential, so when the selected account's 5-hour quota runs out all workers stop at once ("Individual quota reached"), and switching to another saved account only helps workers launched afterwards; running ones stay blocked until restarted. Automatic failover to the next saved account (and restarting or re-binding blocked sessions) would remove this. Related bug on account selection being lost after token refresh: #31579
RYUGUNN77 commentedon Oct 22, 2026
Data point from a different angle: an agent that is not Claude Code consuming Orca's managed Claude accounts, on macOS (Orca 1.4.237, two managed Claude accounts). We run Hermes Agent inside Orca panes; it talks to the Anthropic API directly with the OAuth login Orca manages, so none of the Claude-Code-side fixes (#29898 restart,
claude --resume) reach it. What we ended up building on our side, and the two gaps that only Orca can close:What works today, from the pane's point of view. Orca launches each pane with
CLAUDE_CONFIG_DIR=<claude-profiles>/<id>/homeandORCA_CLAUDE_PROFILE_POINTER=<claude-profiles>/selected-host, and rewritesselected-hoston every status-bar switch. Reading that pointer on every credential resolve (instead ofCLAUDE_CONFIG_DIRonce at startup) is enough for a running non-Claude-Code session to follow a manual switch without a restart — no files under~/.claudetouched, no fight with the periodic sync described above. The sibling<id>/homedirectories beside the pointer give the agent its 429 fallbacks: on a hard 429 it rotates to another profile's login, marks the selected one as cooling until the reset the API reports, and moves back when the window reopens. Each profile's refreshed tokens are written back only into that profile's own dir / keychain item.Gap 1 — the pointer is not a documented contract. Everything above hangs on
selected-hostand the two env vars, which I found by reading the launch environment, not the docs. If Orca could state that an external agent may read the pointer (or expose the same thing as an event on the runtime socket), tools like ours would not break silently on the next refactor.Gap 2 — no way to tell Orca "this pane is on account B now". When the agent fails over on a 429 the status bar still shows account A, and the usage chip keeps attributing the traffic to A. The RPC @ryofukutani found (
accounts.selectClaude) is the right primitive, but there is no CLI in front of it:orca account select --agentacceptsopencode|devinonly (1.4.237). Aorca account use <id|email> --agent claude(or exposingselectClaudeon the CLI) would let an external failover do the one thing we cannot — keep the status bar and usage attribution truthful — and it is the same command the headless/CLI-parity item (5) in the original post needs. Even without failover, it is what lets a script set the active account beforeorchestration worker-start.Opt-in 90% pre-emptive switching (#28044) and hard-429 failover are not in conflict: the first avoids losing a turn, the second is the floor when the probe is stale or the agent is not Claude Code. Both need Gap 2 to report what they did.
Happy to test a build or share the pointer-following logic if it helps.
RYUGUNN77 commentedon Oct 22, 2026
Follow-up on the account-selection surface (same request as above, one more angle):
With a paired remote environment, the Claude account picked in the status bar applies only to the host Orca runs on — the remote daemon has no selection (
orca account list/selectalso reject--environment, and the remoteclaude-profiles/selected-hoststays empty). Tools on the remote machine that followORCA_CLAUDE_PROFILE_POINTERtherefore see nothing.Request: let the status-bar Claude account selection apply per environment (write the remote daemon's pointer / expose
orca account select --agent claude --environment <env>). Credentials should stay per machine — only the which account choice needs to travel; each machine already holds its own login for that account.We currently bridge this ourselves by syncing the selected account's email between machines and resolving it to each machine's own login, so an official per-environment selection would let us drop that shim.
AmethystLiang commentedon Oct 28, 2026
Looking into this 👀