Repository navigation
[Feature]: Generic OAuth account-pool failover with session affinity and quota-aware selection #695
Description
Area
Authentication / OAuth account pools / routing
Goal
Implement one generic OAuth account-pool selection and failover engine that provider integrations can reuse.
This issue owns the runtime policy for:
- session/account affinity;
- account-health classification used for routing;
- failover when the assigned account becomes unusable;
- quota-aware account ranking where trustworthy quota evidence exists;
- deterministic handling of unknown quota;
- cooldown and eventual re-entry of temporarily limited accounts;
- observable, bounded explanations for account-selection decisions.
Provider-specific account-management UI, import formats, and quota probes belong in their respective provider issues.
Current status
The routing policy has been defined and accepted.
The remaining work is implementation of the generic OAuth-pool runtime. Existing provider-specific pool implementations must not become the de facto generic contract by copy/paste.
Antigravity-specific work is now separated cleanly from this generic runtime:
- [Feature] Google Antigravity multi-account management, pool health and quota UX #1062 tracks the Antigravity-specific multi-account management, quota/health UX, and integration with the shared OAuth pool; it remains open.
- [Feature]: add per-account Gem/Cla quota display for Google Antigravity #1082 separately tracks the remaining per-account Antigravity Gem/Cla quota evidence.
- [Feature]: safely import Cockpit Tools Google Antigravity accounts #1076 separately tracks Cockpit Tools account import.
- [Feature] Let users define the priority order for automatic account failover in the Codex pool #821, user-defined account priority ordering for automatic failover, is completed.
This issue remains open because the generic OAuth failover/affinity engine itself is not complete.
Accepted routing policy
Hard failover
Break affinity when the currently assigned account is positively known to be unusable for the request.
Relevant signals include:
429
rate limit / quota exhaustion
401
credential no longer usable
403
only when provider-specific classification establishes that the account
is unusable; generic 403 must not automatically poison an account
Provider errors must be classified deliberately. An unrelated upstream failure must not incorrectly mark an account unhealthy.
Hard-error failover is the correctness path.
Session affinity
Healthy conversations stay on their assigned account.
Ordinary requests must not rotate across accounts merely for load balancing.
Conceptually:
new conversation
-> choose eligible account
-> bind affinity
later request
-> same healthy account
assigned account becomes unusable
-> break affinity
-> choose next eligible account
-> bind replacement
In-flight requests and concurrent sessions must not corrupt or accidentally overwrite affinity state.
Quota-aware selection
When fresh, account-scoped quota evidence is available, it may improve account selection.
The accepted policy permits deprioritizing an account at or above approximately 95% detected quota usage.
This is an optimization, not a correctness dependency.
A provider with no usable quota probe must still support hard-error failover.
Stale quota must not be treated as current quota.
Unknown quota
Unknown quota remains a first-class state.
Suggested ordering:
known healthy
>
healthy but quota-unverified
>
known depleted / cooling down / unusable
Unknown must not mean:
0% used
and must not mean:
fully healthy capacity
Account A's quota or failure state must never be projected onto account B.
Cooldown and re-entry
A temporary 429 or quota exhaustion must not permanently remove an account from the pool.
The generic runtime needs an explicit lifecycle such as:
eligible
-> temporarily limited
-> cooling down
-> eligible again after validated reset/re-probe evidence
Re-entry must be bounded and deterministic.
#822 and #823 remain separate reset-lifecycle features. Their background redemption/activation behavior must not be required for generic failover correctness.
No healthy alternative
If the assigned account becomes unusable and no eligible alternative exists:
- stop retrying after a bounded number of attempts;
- return the appropriate provider failure;
- do not loop through the pool indefinitely;
- do not silently revive an account still known to be unusable.
Priority relationship
#821 implemented user-defined priority ordering for the existing automatic account transition surface.
The generic OAuth-pool engine should be able to consume an explicit priority signal where applicable without making priority configuration mandatory.
Priority is an input to candidate selection, not a replacement for:
- health classification;
- affinity;
- cooldown;
- quota evidence;
- failover correctness.
Provider integration contract
Provider integrations should supply normalized evidence such as:
credential usable / requires reauth
quota known / unknown
quota utilization
reset known / unknown
temporarily limited
cooldown state
provider-specific account-unusable classification
The generic pool should own the selection policy.
Do not implement separate Antigravity, Anthropic, Kimi, or other provider-specific copies of the same routing state machine.
Observability and privacy
Operators should be able to determine why an account was:
selected
kept because of affinity
skipped
deprioritized
cooled down
failed over
re-entered
without exposing:
- access tokens;
- refresh tokens;
- API keys;
- OAuth authorization material;
- unsafe account identifiers;
- raw provider quota payloads;
- unbounded upstream error bodies.
Use safe opaque account references where attribution is required.
Related issues
- [Feature] Google Antigravity multi-account management, pool health and quota UX #1062 — Antigravity-specific multi-account management, health/quota UX, and shared-pool integration; remains open.
- [Feature]: add per-account Gem/Cla quota display for Google Antigravity #1082 — Antigravity per-account Gem/Cla quota evidence.
- [Feature]: safely import Cockpit Tools Google Antigravity accounts #1076 — Cockpit Tools Antigravity account import.
- [Feature] Let users define the priority order for automatic account failover in the Codex pool #821 — user-defined failover priority ordering; completed.
- [Feature]: opt-in crash-safe reset-credit auto-redemption before expiry #822 — automatic reset-credit redemption; separate lifecycle feature.
- [Research] Provider-specific post-reset activation to anchor quota windows #823 — optional post-reset activation; separate lifecycle feature.
- [Feature]: add proactive round-robin and broader quota failover to apiKeyPool #1267 — API-key-pool broader quota failover and proactive round-robin; separate credential class.
Acceptance criteria
- A reusable generic OAuth account-selection/failover engine exists.
- Healthy conversations preserve account affinity.
-
429/ recognized quota exhaustion can trigger bounded same-request failover. - Authentication failures trigger failover only when the account is actually unusable.
- Generic
403responses are not blindly classified as account exhaustion. - Unknown-quota accounts are represented and ranked explicitly.
- Fresh account-scoped quota can optionally influence selection without becoming required for correctness.
- Temporarily limited accounts have a deterministic cooldown and re-entry path.
- No-alternative behavior is bounded and tested.
- Concurrent requests cannot corrupt affinity or selection state.
- Provider integrations reuse the generic engine instead of duplicating routing policy.
- Completed priority-ordering work from [Feature] Let users define the priority order for automatic account failover in the Codex pool #821 can be consumed as an optional selection input.
- Account-selection decisions are observable without exposing credential material.
- Regression coverage includes healthy affinity, 429 failover, auth-failure failover, unknown quota, cooldown/re-entry, concurrency, and no healthy alternative.
- Accepted implementation is merged into
dev.
Activity
github-actions commentedon Jul 29, 2026
Automated translation bookkeeping — detected language: English.
Ingwannu commentedon Aug 1, 2026
Multiple Antigravity accounts can already be stored and selected manually, but "automatically" is not specific enough to define safe routing behavior.
Please clarify the trigger and invariants: quota percentage, upstream 429/402, authentication failure, or round-robin; whether an existing conversation must stay on its account; how unknown quota is handled; and whether the requested policy is Antigravity-only or should use the generic OAuth account pool. Automatic background use is out of scope unless explicitly designed. Keeping this open for those details rather than guessing at a policy.
lidge-jun commentedon Aug 2, 2026
Triage status: useful capability, but we need the policy defined before implementation. Could you spell out: (1) the exact trigger conditions for an automatic switch (which signals, which thresholds), (2) affinity rules while requests are in flight, (3) behavior when an account's quota state is unknown, and (4) whether this should be Antigravity-specific or a generic pool mechanism? Answers to those four determine the design.
luwei1990 commentedon Aug 6, 2026
Proposed Failover & Routing Policy
1. Trigger Signals & Thresholds
429(Rate Limit) or401/403(Auth invalid).2. Session Affinity
429/401) occurs, at which point fallback to a healthy account in the pool happens automatically.3. Unknown Quota Handling
4. Scope
lidge-jun commentedon Aug 6, 2026
Thanks — this answers all four questions, and it is the specification this needed.
Recording the policy as accepted design input:
429and401/403; optional pre-emptive switch at ≥95% detected quota.The scoping answer is the important one. Building this on the generic pool means the same failover logic serves other OAuth providers instead of creating a second, divergent mechanism next to the existing Codex pool — that is the right call and it is what makes this implementable.
Two things still need deciding before code, and they follow from your own rules rather than contradicting them:
429account is not permanently dead. The pool needs a cooldown and a re-probe path, otherwise a busy pool degrades to one survivor by the end of the day. Reset-window handling is being discussed in [Research] Provider-specific post-reset activation to anchor quota windows #823 and [Feature]: opt-in crash-safe reset-credit auto-redemption before expiry #822; this issue should consume whatever those settle on rather than inventing a third policy.429path is the real guarantee and the threshold is an optimization. Worth stating that way so the feature is not oversold.Keeping this open as the failover-policy issue. #1062 tracks the pooling and quota-statistics surface for Antigravity, and #821 tracks user-defined priority ordering on top of automatic selection — all three want the same underlying pool, so the runtime slice should land once and be shared.
No implementation timeline promised. This is now unblocked on design, which it was not before.
agentHits commentedon Aug 7, 2026
@Wibias @lidge-jun The most important task is to implement a feature for importing accounts from any subscription—specifically, subscriptions sourced from the Cockpit Tools application. This application stores subscription data, which we can export in the following format: [
{
"email": "jimguerrero@gmail.com",
"refresh_token": "1//0cEqtAXq6tRLmCgYIARAAGAwSNwF-D8IrR5oO9j05ZXkGS0FRW9FMEjOwLyae9aIj5nGwfo4-HcTP1LLim_3e2djmCAw_Rm3VzCU"
}
] — and this import capability needs to be integrated into OpenCodeX via the import function. This will allow us to easily manage accounts by simply adding them to the OpenCodeX system, making the process convenient for everyone.
[-][Feature]: Support switching antigravity accounts automatically[/-][+][Feature]: Generic OAuth account-pool failover with session affinity and quota-aware selection[/+]Wibias commentedon Aug 7, 2026
Goal
Implement a generic OAuth account-pool failover policy that can be shared by Antigravity and other OAuth-backed providers.
This issue tracks the runtime account-selection and failover policy.
Provider-specific account-management UI, quota presentation, and import formats belong in their respective provider issues.
Accepted routing policy
Hard failover
Switch away from the active account when the upstream returns an error indicating the account is currently unusable:
429— rate limit or quota exhaustion;401— authentication is no longer usable;403— authentication/account access is rejected in a way that makes the account unusable for the request.The implementation should classify errors carefully rather than treating every provider-side failure as an account-health failure.
Optional proactive selection
When reliable quota information is available, an account at or above 95% detected quota usage may be deprioritized before a hard failure occurs.
This is an optimization, not the correctness guarantee.
If quota information is missing, stale, or not available for a provider, hard-error failover remains the authoritative path.
Session affinity
A conversation should remain on its assigned account while that account remains healthy.
OpenCodex should not rotate accounts between ordinary requests simply for load balancing.
Affinity should be broken only when the assigned account becomes unusable according to the failover policy.
Unknown quota
An account whose quota state is unknown should be treated as:
Suggested ranking:
Unknown quota must not automatically mean either exhausted or fully healthy.
Cooldown and re-entry
An account that hits a temporary quota/rate limit must not be permanently removed from the pool.
The pool needs a cooldown and re-probe/re-entry path.
Reset-window and proactive reactivation behavior should reuse the lifecycle defined by #822 and #823 rather than introducing a separate third policy.
Scope
This should be implemented in the generic OAuth account-pool layer so provider integrations can reuse a single selection and failover engine.
This issue owns:
This issue does not own:
Related issues
Acceptance criteria
lidge-jun commentedon Aug 19, 2026
리뷰 · 우선순위 69 / 80
현재
dev에는 Anthropic 옵트인 계정 풀(src/oauth/anthropic-routing.ts)처럼 프로바이더별 스티키 어피니티와 429 페일오버가 있습니다. 이 이슈가 소유한 일반 OAuth 풀 런타임은 그 파일이 아닙니다. 이슈 본문도 기존 구현을 복사해 일반 계약으로 삼지 말라고 합니다. #821 사용자 우선순위는 끝났고, Antigravity UX는 #1062/#1082로 분리됐습니다.이슈가 원하는 것은 재사용 엔진입니다. 세션 어피니티, 라우팅용 건강 분류, 할당 계정이 못 쓰일 때의 페일오버, 신뢰할 수 있는 쿼터 증거로 순위, unknown 쿼터의 결정적 처리, 쿨다운 재진입, 유계 설명입니다. 수락된 하드 페일오버는 429와 사용 불가 401, 그리고 프로바이더가 사용 불가로 분류한 403입니다. 일반 403으로 계정을 독극물 처리하면 안 됩니다.
네이티브 신뢰성과 프로바이더 호환이 점수입니다. 건강한 대화는 계정에 붙고, 로드밸런싱으로 돌면 안 됩니다. unknown 쿼터는 건강하지만 미검증이며 0%나 죽은 계정이 아닙니다. 사전 95% 전환은 선택이며 하드 에러 경로와 같으면 안 됩니다. Windows/서비스에서 인플라이트 요청의 어피니티를 바꾸면 도구 턴이 계정을 갈아탑니다.
위생적으로 Cockpit import(#1076)와 이 런타임을 섞지 마십시오. 가져오기는 자격 증명을 넣고, 이 이슈는 고릅니다. 프로바이더 UI가 선택 이유를 보여 주려면 엔진이 먼저 관측 가능한 결정을 내야 합니다.
해결방안은 Anthropic 풀에서 정책을 일반화하되, 프로바이더 분류 훅만 남기고 계정 선택 코어를 한곳으로 모으는 것입니다. 하드 에러가 어피니티를 깨고, 쿼터 unknown은 후순위입니다. 패치는 추측하지 않으며, 현재 트리를 일반 OAuth 페일오버 완료로 보지 않습니다.
이 댓글은 grok-bot이 작성했습니다
nordz0r commentedon Aug 29, 2026
Adding concrete 2.35.0 evidence from a real 4-account Antigravity pool (Windows 10, npm @bitkyc08/opencodex 2.35.0) in support of implementing the accepted policy from this issue.
State today — the pool exists, but every proactive control is Codex/Anthropic-only:
ocx account list google-antigravity --quota— 4 OAuth accounts stored, but no quota probe and no priority data:Reactive 429 failover (
oauthAccountFailover, #2568) does work and is genuinely useful, but it is strictly reactive: the daily-driver account keeps getting hammered until a hard 429, in-flight conversations are disrupted, and only then does rotation kick in. With 4 accounts the pool never spreads load proactively — there is no threshold, no strategy (quota/round-robin/fill-first), no priority tiers, no sticky limit for generic OAuth providers.Also note the pre-emptive leg of the policy accepted in this thread ("optional pre-emptive switch at ≥95% detected quota") is currently unreachable for Antigravity because there is no quota probe at all —
QUOTAis-for every account (tracked separately in #1082). Until that lands, even the accepted policy can only operate on 429/401/403 signals.Happy to test the generic runtime against this 4-account pool once an implementation lands — good natural testbed (different plan types across the accounts).
Ingwannu commentedon Aug 29, 2026
Confirmed against current dev 8df7051: your four-account evidence matches the implementation boundary.
So this is not a configuration mistake and the issue should remain open. The safest implementation order is: first land the per-account Antigravity quota path tracked in #1082; then generalize the pool-settings API and CLI through a provider capability contract; finally let the generic OAuth selector consume that evidence for quota, round-robin, and fill-first behavior. That avoids creating a second Antigravity-only router and keeps unknown quota as unknown rather than treating it as zero capacity.
Your four-account pool is a useful acceptance environment. The eventual regression should prove that proactive selection spreads new sessions without breaking existing affinity, while 401/403/429 recovery still walks the eligible roster and never exposes account identity or quota data across rows.
docs(devlog): fold the A-phase audit blockers into the backlog plan
feat(oauth): generic pool-settings contract for OAuth providers (#695 …
lidge-jun commentedon Sep 1, 2026
Slice 1 landed on
devvia #3214 (squash356e495f5), following the order agreed above: per-account Antigravity quota went in with #3213, and this adds the pool-settings capability contract. Any generic OAuth provider (Antigravity, xAI, Cursor, Kimi, Copilot, Nous, …) now acceptsstrategyandautoSwitchThresholdthroughGET/PUT /api/oauth/accounts/pooland theocx account strategy/ocx account auto-switchverbs, persisted onproviders.<name>.oauthAccountFailover. Codex and Anthropic contracts are unchanged.What is deliberately still open here, for the next slice: the generic selector consuming those settings (quota / round-robin / fill-first, threshold-driven proactive switch), session affinity for generic pools, classified 401/403 hard failover, cooldown re-probe, and bounded selection reasons. Until that lands the stored settings are declared but inert, and the API says so (
"inert": true). Keeping the issue open for that runtime slice.lidge-jun commentedon Sep 3, 2026
Closing in favor of #3375, which carries the remaining scope forward.
Thank you @luwei1990 — this report on generic OAuth account-pool failover with session affinity and quota-aware selection was accurate, and part of it shipped.
What landed. The first tranche landed:
src/oauth/generic-account-failover.tsimplements 429 cooldown, rotation, and quota-ranked initial selection (816f3a1).What is still missing. reusable session affinity, 401 / provider-classified 403 failover, the full health lifecycle, and decision observability.
Rather than leave four issues open each describing one facet of the same unfinished lifecycle, the surviving scope is consolidated in #3375, which names this issue and credits you for the original analysis. Please follow and comment there; if you think the consolidation dropped something you asked for, say so on #3375 and it will be added.
feat(oauth): generic pool-settings contract for OAuth providers (lidg…
feat(oauth): generic pool-settings contract for OAuth providers (lidg…