Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8b5926c
refactor(doctor): share account repair workflow
WarGloom Sep 8, 2026
2eafa8e
fix(cli): apply standalone doctor repairs
WarGloom Sep 8, 2026
ab6e401
fix(cli): preserve default keychain routing
WarGloom Sep 8, 2026
a3c9ea4
docs(cli): document standalone doctor repairs
WarGloom Sep 8, 2026
420dfcc
fix(cli): load default doctor storage backend
WarGloom Sep 8, 2026
10544c2
fix(cli): allow empty doctor account pools
WarGloom Sep 8, 2026
73e5fe0
feat(accounts): add account-wide quota-exhaustion state
WarGloom Sep 10, 2026
fbbc5c4
fix(usage): record spent subscription quota once, not per family
WarGloom Sep 10, 2026
079436f
fix(rotation): report quota exhaustion apart from rate limits
WarGloom Sep 10, 2026
d2657d3
fix(storage): merge quota exhaustion monotonically across processes
WarGloom Sep 10, 2026
a0152f1
fix(doctor): clear stale quota exhaustion on verified accounts
WarGloom Sep 10, 2026
da0d31b
fix(tui): label quota exhaustion instead of calling it a rate limit
WarGloom Sep 10, 2026
b3dbd22
refactor(request): share one fallback chain-walk policy
WarGloom Sep 11, 2026
4ec0eaa
feat(rotation): fall back model when every account is blocked
WarGloom Sep 11, 2026
db596e2
docs(config): note auto-fallback covers exhausted quota
WarGloom Sep 11, 2026
02ce44c
fix(tui): stop badging every account as rate-limited
WarGloom Sep 11, 2026
a9a2bf7
fix(rotation): record header quota exhaustion account-wide and gate f…
WarGloom Sep 11, 2026
d276daf
docs(config): describe fallback precedence and pool rules
WarGloom Sep 11, 2026
85395c1
fix(cli): fail doctor --fix on a corrupt default storage file
ndycode Sep 13, 2026
5acf01b
fix(health): report quota exhaustion apart from stale state
ndycode Sep 13, 2026
39074ad
docs(rotation): note the request-path hybrid last-resort override
ndycode Sep 13, 2026
7b8c983
refactor(tools): drop the unused getQuotaExhaustedUntil context surface
ndycode Sep 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ The sample above intentionally sets `"retryAllAccountsMaxRetries": 3` as a bound
| `unsupportedCodexPolicy` | `strict` | unsupported-model behavior: `strict` (return entitlement error) or `fallback` (retry with configured fallback chain) |
| `fallbackOnUnsupportedCodexModel` | `false` | legacy fallback toggle mapped to `unsupportedCodexPolicy` (prefer using `unsupportedCodexPolicy`) |
| `fallbackToGpt52OnUnsupportedGpt53` | `true` | legacy compatibility toggle for the `gpt-5.3-codex -> gpt-5.2-codex` edge when generic fallback is enabled |
| `unsupportedCodexFallbackChain` | `{}` | optional per-model fallback-chain override (map of `model -> [fallback1, fallback2, ...]`; default includes `gpt-6-astra` and the 5.6 tiers down to `gpt-5.5`, and `gpt-5.5`/`gpt-5-codex` down to `gpt-5.2`). The 5.6 tier, `gpt-5.5`, and canonical Codex auto-fallbacks are on by default for common entitlement gates; set `CODEX_AUTH_DISABLE_GPT6_AUTO_FALLBACK=1`, `CODEX_AUTH_DISABLE_GPT56_AUTO_FALLBACK=1`, `CODEX_AUTH_DISABLE_GPT55_AUTO_FALLBACK=1`, or `CODEX_AUTH_DISABLE_CODEX_AUTO_FALLBACK=1` to opt out. GPT-5.5 Pro and GPT-6 Astra Pro are not mapped: neither is a Codex-routable id. The Daybreak cyber tiers are deliberately chainless, so an unentitled account fails loudly rather than being answered by a general model. |
| `unsupportedCodexFallbackChain` | `{}` | optional per-model fallback-chain override (map of `model -> [fallback1, fallback2, ...]`; default includes `gpt-6-astra` and the 5.6 tiers down to `gpt-5.5`, and `gpt-5.5`/`gpt-5-codex` down to `gpt-5.2`). These entry IDs auto-fallback by default, even when selected directly, both for common entitlement gates and when every enabled account has an active upstream rate/quota block for the requested model; set `CODEX_AUTH_DISABLE_GPT6_AUTO_FALLBACK=1`, `CODEX_AUTH_DISABLE_GPT56_AUTO_FALLBACK=1`, `CODEX_AUTH_DISABLE_GPT55_AUTO_FALLBACK=1`, or `CODEX_AUTH_DISABLE_CODEX_AUTO_FALLBACK=1` to opt out. Directly selected non-entry IDs stay strict under this auto gate. GPT-5.5 Pro and GPT-6 Astra Pro are not mapped: neither is a Codex-routable id. The Daybreak cyber tiers are deliberately chainless, so an unentitled account fails loudly rather than being answered by a general model. |
| `sessionRecovery` | `true` | auto-recover from common api errors |
| `autoResume` | `true` | auto-resume after thinking block recovery |
| `tokenRefreshSkewMs` | `60000` | refresh tokens this many ms before expiry |
Expand All @@ -295,6 +295,15 @@ The sample above intentionally sets `"retryAllAccountsMaxRetries": 3` as a bound
| `streamStallTimeoutMs` | `45000` | max time to wait for next SSE chunk before aborting |
| `quotaNotifications` | disabled | optional macOS Notification Center alerts for aggregate 5-hour and weekly pool quotas. `autoProtectCredits` defaults to `true` and polls the same endpoint to exclude fully spent subscription quotas from rotation; `intervalMs` defaults to 30 minutes with a 30-second minimum, `notifyEveryCheck` defaults to `false`, and `thresholds` defaults to `[25, 10, 0]` |

For upstream rate/quota blocks, automatic model fallback runs **before** configured
waiting (`retryAllAccountsRateLimited` and its wait/retry limits). It only moves to
a model with an eligible account under that target's pool policy: unavailable
strict pools are skipped, while preferred pools may use general accounts. An
unavailable strict pool for the current model remains a strict-pool error. Local
token-bucket depletion or authentication cooldown alone does not trigger model
fallback. Shared subscription exhaustion blocks the account across all models;
changing models cannot bypass it.

The quota guard queries each distinct enabled account with bounded concurrency
every `intervalMs` (30 minutes by default), even when notifications are off.
When the backend reports a fully spent 5-hour or weekly subscription window,
Expand Down
5 changes: 4 additions & 1 deletion docs/tools-and-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Choose only one of `--plugin-only`, `--modern`, `--full`, or `--legacy`. Use `up
| `--json` | Machine-readable JSON output |
| `--include-sensitive` | Include sensitive identity fields in JSON where applicable |
| `--deep` | Deeper diagnostics (used with `doctor`; implied by `diag`) |
| `--fix` | Request fix application where supported (may be a no-op for some safe CLI paths) |
| `--fix` | With `doctor`, refresh enabled accounts and clear stale cooldown, rate-limit, and quota-exhaustion markers only after successful verification. A cleared quota stamp re-establishes itself on the next quota 429 or usage poll. Exit nonzero if any repair fails, or if the storage file cannot be parsed. |
| `--tag <tag>` | Filter accounts by tag when listing |
| `--config-path <path>` | Point at a specific accounts storage path |
| `--help` / `-h` | Print usage |
Expand All @@ -192,9 +192,12 @@ oc-codex-multi-auth status --json
oc-codex-multi-auth list --tag work
oc-codex-multi-auth warm --json
oc-codex-multi-auth doctor --deep
oc-codex-multi-auth doctor --fix --config-path ./accounts.json
npx -y oc-codex-multi-auth@latest warm
```

For `doctor --fix`, an explicit `--config-path` repairs only the selected JSON pool and bypasses keychain routing. Without `--config-path`, repair preserves enabled keychain routing, and a corrupt default storage file fails with a parse error instead of reporting an empty pool.

---

## Related runtime concepts
Expand Down
Loading