Area
Authentication and account pool
What are you trying to accomplish?
I run a Codex account pool built from several paid ChatGPT accounts. When one subscription lapses and the account is downgraded to Free, I want pool selection to stop handing it production traffic, instead of discovering the downgrade from failed or degraded requests.
Reported on X by @LjranceLi on 2026-09-10: one of their accounts expired without being renewed, was downgraded to Free, and they asked for "an option to only select non-free accounts" for GPT subscribers (https://x.com/LjranceLi/status/2097934784895058054).
What prevents this today?
Pool eligibility never looks at the plan tier. In src/codex/account-usability.ts at dev 6d3ad12e3 (2.51.0), isCodexAccountUsable() decides selection from an optional modelEligibleAccountIds set for account-gated models, the main-account hard lock / native-main traffic block / legacy pool sentinel, isAccountNeedsReauth(), pool membership, a stored credential, deletedAt, and codexValidationPending. The plan is not an input to any branch.
The tier is already known locally:
src/codex/plan-from-token.ts persists the JWT chatgpt_plan_type onto codexAccounts[].plan when it contradicts the stored value.
src/codex/plan.ts classifies plan keys and already treats go and free specially (isThirtyDayOnlyCodexPlan).
src/codex/main-account.ts documents the main-account plan label (plus, go, free, team).
The only exclusion mechanism is manual and untyped: src/codex/account-pause.ts writes pausedCodexAccountIds, which an operator has to set by hand after they have already diagnosed the failure.
What should OpenCodex do?
- Let an operator declare a plan policy for pool selection, so a Free (or otherwise below-threshold) account is skipped for ordinary routing.
- When a refresh observes that an account's plan dropped below the policy, stop selecting it and record a reason that names the plan change, instead of leaving it in rotation to fail per request.
- Show that reason where the operator already looks: the account card in the dashboard and the account line in CLI status output, with the plan label visible.
- Keep an explicit, operator-chosen route to that account working. This is a selection policy, not a hard block.
Example usage or interface
# opt in: never auto-select a downgraded account
ocx config set codexPool.excludedPlans '["free"]'
# or, expressed as a floor
ocx config set codexPool.minimumPlan plus
Dashboard, Providers -> Codex account card:
account: work@example.com plan: free state: not selected (plan below codexPool.minimumPlan=plus)
Alternatives or workarounds
- Manually pause the account (
pausedCodexAccountIds). That works only after the operator has already diagnosed which account regressed.
- Delete and re-add the account after renewal. Same diagnosis cost, and it discards affinity and quota history.
Additional context
Checks
Area
Authentication and account pool
What are you trying to accomplish?
I run a Codex account pool built from several paid ChatGPT accounts. When one subscription lapses and the account is downgraded to Free, I want pool selection to stop handing it production traffic, instead of discovering the downgrade from failed or degraded requests.
Reported on X by @LjranceLi on 2026-09-10: one of their accounts expired without being renewed, was downgraded to Free, and they asked for "an option to only select non-free accounts" for GPT subscribers (https://x.com/LjranceLi/status/2097934784895058054).
What prevents this today?
Pool eligibility never looks at the plan tier. In
src/codex/account-usability.tsatdev6d3ad12e3(2.51.0),isCodexAccountUsable()decides selection from an optionalmodelEligibleAccountIdsset for account-gated models, the main-account hard lock / native-main traffic block / legacy pool sentinel,isAccountNeedsReauth(), pool membership, a stored credential,deletedAt, andcodexValidationPending. The plan is not an input to any branch.The tier is already known locally:
src/codex/plan-from-token.tspersists the JWTchatgpt_plan_typeontocodexAccounts[].planwhen it contradicts the stored value.src/codex/plan.tsclassifies plan keys and already treatsgoandfreespecially (isThirtyDayOnlyCodexPlan).src/codex/main-account.tsdocuments the main-account plan label (plus,go,free,team).The only exclusion mechanism is manual and untyped:
src/codex/account-pause.tswritespausedCodexAccountIds, which an operator has to set by hand after they have already diagnosed the failure.What should OpenCodex do?
Example usage or interface
Dashboard, Providers -> Codex account card:
Alternatives or workarounds
pausedCodexAccountIds). That works only after the operator has already diagnosed which account regressed.Additional context
Checks