oc-codex-multi-auth 6.21.0 → 6.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +168 -10
  2. package/config/README.md +53 -33
  3. package/config/opencode-legacy.json +129 -279
  4. package/config/opencode-modern.json +43 -132
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +293 -57
  7. package/dist/index.js.map +1 -1
  8. package/dist/lib/account-display.d.ts +46 -0
  9. package/dist/lib/account-display.d.ts.map +1 -1
  10. package/dist/lib/account-display.js +260 -0
  11. package/dist/lib/account-display.js.map +1 -1
  12. package/dist/lib/accounts/warm-request.d.ts.map +1 -1
  13. package/dist/lib/accounts/warm-request.js +9 -11
  14. package/dist/lib/accounts/warm-request.js.map +1 -1
  15. package/dist/lib/accounts.d.ts +4 -0
  16. package/dist/lib/accounts.d.ts.map +1 -1
  17. package/dist/lib/accounts.js +20 -15
  18. package/dist/lib/accounts.js.map +1 -1
  19. package/dist/lib/auth/login-runner.d.ts.map +1 -1
  20. package/dist/lib/auth/login-runner.js +79 -2
  21. package/dist/lib/auth/login-runner.js.map +1 -1
  22. package/dist/lib/auto-update-checker.d.ts +17 -1
  23. package/dist/lib/auto-update-checker.d.ts.map +1 -1
  24. package/dist/lib/auto-update-checker.js +49 -3
  25. package/dist/lib/auto-update-checker.js.map +1 -1
  26. package/dist/lib/cli.d.ts +1 -0
  27. package/dist/lib/cli.d.ts.map +1 -1
  28. package/dist/lib/cli.js +9 -3
  29. package/dist/lib/cli.js.map +1 -1
  30. package/dist/lib/codex-usage.d.ts +4 -3
  31. package/dist/lib/codex-usage.d.ts.map +1 -1
  32. package/dist/lib/codex-usage.js +13 -11
  33. package/dist/lib/codex-usage.js.map +1 -1
  34. package/dist/lib/config.d.ts +75 -0
  35. package/dist/lib/config.d.ts.map +1 -1
  36. package/dist/lib/config.js +152 -1
  37. package/dist/lib/config.js.map +1 -1
  38. package/dist/lib/constants.d.ts +13 -0
  39. package/dist/lib/constants.d.ts.map +1 -1
  40. package/dist/lib/constants.js +13 -0
  41. package/dist/lib/constants.js.map +1 -1
  42. package/dist/lib/plan-allotment.d.ts +72 -0
  43. package/dist/lib/plan-allotment.d.ts.map +1 -0
  44. package/dist/lib/plan-allotment.js +142 -0
  45. package/dist/lib/plan-allotment.js.map +1 -0
  46. package/dist/lib/plugin-origin.d.ts +77 -0
  47. package/dist/lib/plugin-origin.d.ts.map +1 -0
  48. package/dist/lib/plugin-origin.js +301 -0
  49. package/dist/lib/plugin-origin.js.map +1 -0
  50. package/dist/lib/prompts/codex.d.ts +12 -2
  51. package/dist/lib/prompts/codex.d.ts.map +1 -1
  52. package/dist/lib/prompts/codex.js +47 -16
  53. package/dist/lib/prompts/codex.js.map +1 -1
  54. package/dist/lib/quota-display.d.ts +40 -0
  55. package/dist/lib/quota-display.d.ts.map +1 -0
  56. package/dist/lib/quota-display.js +45 -0
  57. package/dist/lib/quota-display.js.map +1 -0
  58. package/dist/lib/quota-notifications.d.ts +2 -1
  59. package/dist/lib/quota-notifications.d.ts.map +1 -1
  60. package/dist/lib/quota-notifications.js +34 -14
  61. package/dist/lib/quota-notifications.js.map +1 -1
  62. package/dist/lib/quota-overview.d.ts +253 -0
  63. package/dist/lib/quota-overview.d.ts.map +1 -0
  64. package/dist/lib/quota-overview.js +707 -0
  65. package/dist/lib/quota-overview.js.map +1 -0
  66. package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
  67. package/dist/lib/request/fetch-helpers.js +84 -50
  68. package/dist/lib/request/fetch-helpers.js.map +1 -1
  69. package/dist/lib/request/helpers/model-map.d.ts +10 -0
  70. package/dist/lib/request/helpers/model-map.d.ts.map +1 -1
  71. package/dist/lib/request/helpers/model-map.js +39 -11
  72. package/dist/lib/request/helpers/model-map.js.map +1 -1
  73. package/dist/lib/request/helpers/responses-lite.d.ts.map +1 -1
  74. package/dist/lib/request/helpers/responses-lite.js +4 -1
  75. package/dist/lib/request/helpers/responses-lite.js.map +1 -1
  76. package/dist/lib/request/request-transformer.d.ts.map +1 -1
  77. package/dist/lib/request/request-transformer.js +37 -15
  78. package/dist/lib/request/request-transformer.js.map +1 -1
  79. package/dist/lib/request/retry-budget.d.ts +26 -0
  80. package/dist/lib/request/retry-budget.d.ts.map +1 -1
  81. package/dist/lib/request/retry-budget.js +43 -0
  82. package/dist/lib/request/retry-budget.js.map +1 -1
  83. package/dist/lib/schemas.d.ts +73 -0
  84. package/dist/lib/schemas.d.ts.map +1 -1
  85. package/dist/lib/schemas.js +53 -0
  86. package/dist/lib/schemas.js.map +1 -1
  87. package/dist/lib/storage/backup.d.ts +33 -0
  88. package/dist/lib/storage/backup.d.ts.map +1 -1
  89. package/dist/lib/storage/backup.js +43 -7
  90. package/dist/lib/storage/backup.js.map +1 -1
  91. package/dist/lib/storage/credential-snapshots.d.ts +78 -0
  92. package/dist/lib/storage/credential-snapshots.d.ts.map +1 -0
  93. package/dist/lib/storage/credential-snapshots.js +302 -0
  94. package/dist/lib/storage/credential-snapshots.js.map +1 -0
  95. package/dist/lib/storage/export-import.d.ts.map +1 -1
  96. package/dist/lib/storage/export-import.js +7 -0
  97. package/dist/lib/storage/export-import.js.map +1 -1
  98. package/dist/lib/storage/flagged.d.ts.map +1 -1
  99. package/dist/lib/storage/flagged.js +23 -1
  100. package/dist/lib/storage/flagged.js.map +1 -1
  101. package/dist/lib/storage/load-save.d.ts +4 -0
  102. package/dist/lib/storage/load-save.d.ts.map +1 -1
  103. package/dist/lib/storage/load-save.js +50 -0
  104. package/dist/lib/storage/load-save.js.map +1 -1
  105. package/dist/lib/storage/paths.d.ts +1 -0
  106. package/dist/lib/storage/paths.d.ts.map +1 -1
  107. package/dist/lib/storage/paths.js +1 -1
  108. package/dist/lib/storage/paths.js.map +1 -1
  109. package/dist/lib/storage/test-home-guard.d.ts +35 -0
  110. package/dist/lib/storage/test-home-guard.d.ts.map +1 -0
  111. package/dist/lib/storage/test-home-guard.js +59 -0
  112. package/dist/lib/storage/test-home-guard.js.map +1 -0
  113. package/dist/lib/tools/codex-dashboard.d.ts.map +1 -1
  114. package/dist/lib/tools/codex-dashboard.js +3 -2
  115. package/dist/lib/tools/codex-dashboard.js.map +1 -1
  116. package/dist/lib/tools/codex-doctor.d.ts.map +1 -1
  117. package/dist/lib/tools/codex-doctor.js +16 -0
  118. package/dist/lib/tools/codex-doctor.js.map +1 -1
  119. package/dist/lib/tools/codex-health.d.ts.map +1 -1
  120. package/dist/lib/tools/codex-health.js +10 -2
  121. package/dist/lib/tools/codex-health.js.map +1 -1
  122. package/dist/lib/tools/codex-label.d.ts.map +1 -1
  123. package/dist/lib/tools/codex-label.js +1 -0
  124. package/dist/lib/tools/codex-label.js.map +1 -1
  125. package/dist/lib/tools/codex-limits.d.ts.map +1 -1
  126. package/dist/lib/tools/codex-limits.js +13 -9
  127. package/dist/lib/tools/codex-limits.js.map +1 -1
  128. package/dist/lib/tools/codex-list.d.ts.map +1 -1
  129. package/dist/lib/tools/codex-list.js +28 -3
  130. package/dist/lib/tools/codex-list.js.map +1 -1
  131. package/dist/lib/tools/codex-note.d.ts.map +1 -1
  132. package/dist/lib/tools/codex-note.js +4 -1
  133. package/dist/lib/tools/codex-note.js.map +1 -1
  134. package/dist/lib/tools/codex-pool.d.ts.map +1 -1
  135. package/dist/lib/tools/codex-pool.js +6 -2
  136. package/dist/lib/tools/codex-pool.js.map +1 -1
  137. package/dist/lib/tools/codex-refresh.d.ts.map +1 -1
  138. package/dist/lib/tools/codex-refresh.js +4 -1
  139. package/dist/lib/tools/codex-refresh.js.map +1 -1
  140. package/dist/lib/tools/codex-remove.d.ts.map +1 -1
  141. package/dist/lib/tools/codex-remove.js +1 -0
  142. package/dist/lib/tools/codex-remove.js.map +1 -1
  143. package/dist/lib/tools/codex-reset.d.ts.map +1 -1
  144. package/dist/lib/tools/codex-reset.js +13 -7
  145. package/dist/lib/tools/codex-reset.js.map +1 -1
  146. package/dist/lib/tools/codex-status.d.ts.map +1 -1
  147. package/dist/lib/tools/codex-status.js +25 -2
  148. package/dist/lib/tools/codex-status.js.map +1 -1
  149. package/dist/lib/tools/codex-switch.d.ts.map +1 -1
  150. package/dist/lib/tools/codex-switch.js +1 -0
  151. package/dist/lib/tools/codex-switch.js.map +1 -1
  152. package/dist/lib/tools/codex-tag.d.ts.map +1 -1
  153. package/dist/lib/tools/codex-tag.js +4 -1
  154. package/dist/lib/tools/codex-tag.js.map +1 -1
  155. package/dist/lib/tools/codex-warm.d.ts.map +1 -1
  156. package/dist/lib/tools/codex-warm.js +1 -0
  157. package/dist/lib/tools/codex-warm.js.map +1 -1
  158. package/dist/lib/tools/index.d.ts +9 -0
  159. package/dist/lib/tools/index.d.ts.map +1 -1
  160. package/dist/lib/tools/index.js.map +1 -1
  161. package/dist/lib/tui-quota-cache.d.ts +35 -0
  162. package/dist/lib/tui-quota-cache.d.ts.map +1 -1
  163. package/dist/lib/tui-quota-cache.js +76 -11
  164. package/dist/lib/tui-quota-cache.js.map +1 -1
  165. package/dist/lib/tui-quota-overview.d.ts +55 -0
  166. package/dist/lib/tui-quota-overview.d.ts.map +1 -0
  167. package/dist/lib/tui-quota-overview.js +209 -0
  168. package/dist/lib/tui-quota-overview.js.map +1 -0
  169. package/dist/lib/tui-status.d.ts +55 -0
  170. package/dist/lib/tui-status.d.ts.map +1 -1
  171. package/dist/lib/tui-status.js +155 -14
  172. package/dist/lib/tui-status.js.map +1 -1
  173. package/dist/lib/ui/auth-menu.d.ts +2 -0
  174. package/dist/lib/ui/auth-menu.d.ts.map +1 -1
  175. package/dist/lib/ui/auth-menu.js +10 -6
  176. package/dist/lib/ui/auth-menu.js.map +1 -1
  177. package/dist/tui.d.ts +55 -0
  178. package/dist/tui.d.ts.map +1 -1
  179. package/dist/tui.js +511 -29
  180. package/dist/tui.js.map +1 -1
  181. package/package.json +1 -1
  182. package/scripts/install-oc-codex-multi-auth-core.js +583 -66
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![CI](https://github.com/ndycode/oc-codex-multi-auth/actions/workflows/ci.yml/badge.svg)](https://github.com/ndycode/oc-codex-multi-auth/actions/workflows/ci.yml)
6
6
  [![MIT license](https://img.shields.io/npm/l/oc-codex-multi-auth.svg)](LICENSE)
7
7
 
8
- `oc-codex-multi-auth` is an OpenCode plugin for ChatGPT Plus/Pro OAuth, Codex and GPT-5/GPT-6 model routing (including GPT-6 Astra, the Daybreak cyber tiers, and GPT-5.6 Sol/Terra/Luna), multi-account rotation, account switching, health checks, quota visibility, diagnostics, and recovery tools. It installs the OpenCode provider/TUI configuration, registers a 24-tool `codex-*` command toolkit, and routes OpenCode OpenAI SDK requests through the ChatGPT-backed Codex flow with local account state.
8
+ `oc-codex-multi-auth` is an OpenCode plugin for ChatGPT Plus/Pro OAuth, Codex and GPT-5/GPT-6 model routing (including GPT-6 Astra/Sol/Luna, the Daybreak cyber tiers, and GPT-5.6 Sol/Terra/Luna), multi-account rotation, account switching, health checks, quota visibility, diagnostics, and recovery tools. It installs the OpenCode provider/TUI configuration, registers a 24-tool `codex-*` command toolkit, and routes OpenCode OpenAI SDK requests through the ChatGPT-backed Codex flow with local account state.
9
9
 
10
10
  Use it when you want OpenCode to run Codex-style coding workflows from your own ChatGPT subscription while keeping accounts visible, switchable, health-checked, and recoverable from the terminal.
11
11
 
@@ -20,9 +20,9 @@ Use it when you want OpenCode to run Codex-style coding workflows from your own
20
20
  ## What You Get
21
21
 
22
22
  - OpenCode plugin support for ChatGPT Plus/Pro OAuth and Codex/GPT-5 coding workflows
23
- - GPT-6 Astra, GPT-5.6 Sol/Terra/Luna, and the Daybreak Blue/Red cyber tiers on the responses-lite request path, plus GPT-5.5, GPT-5.5 Fast, GPT-5.4 Mini, GPT-5.4 Nano, GPT-5.1, and Codex model templates
23
+ - GPT-6 Astra, GPT-6 Sol/Luna, GPT-5.6 Sol/Terra/Luna, and the Daybreak Blue/Red cyber tiers on the responses-lite request path, plus GPT-5.5, GPT-5.5 Fast, GPT-5.4 Nano, and GPT-5.1 templates
24
24
  - Routing for the Daybreak-gated cyber tiers (`gpt-daybreak-blue-latest`, `gpt-daybreak-red-latest`, `gpt-5.6-cyber`), deliberately kept out of the shipped templates since they need program approval
25
- - Compact modern OpenCode config with 13 base families and 59 variant presets; explicit legacy selector IDs when needed
25
+ - Compact modern OpenCode config with 10 base families and 53 variant presets; explicit legacy selector IDs when needed
26
26
  - Stateless Codex-compatible request handling with `store: false` and `reasoning.encrypted_content`
27
27
  - Multi-account rotation with hybrid health scoring, cooldowns, automatic token refresh, and failover
28
28
  - Explicit saved-account listing, account switching, labeling, tagging, notes, health checks, and diagnostics
@@ -90,8 +90,8 @@ Installer flags:
90
90
  | Flag | Effect |
91
91
  | --- | --- |
92
92
  | (default) / `--plugin-only` | Register the plugin and TUI integration without changing `provider.openai` |
93
- | `--modern` | Install compact modern catalog: 13 bases, 59 variants |
94
- | `--full` | Compact bases plus 59 explicit selector IDs |
93
+ | `--modern` | Install compact modern catalog: 10 bases, 53 variants |
94
+ | `--full` | Compact bases plus 53 explicit selector IDs |
95
95
  | `--legacy` | Explicit-only catalog for older OpenCode |
96
96
  | `--dry-run` | Show changed config paths without values or writes |
97
97
  | `--no-cache-clear` | Skip clearing the OpenCode plugin cache |
@@ -128,7 +128,28 @@ opencode debug config
128
128
  opencode auth login
129
129
  ```
130
130
 
131
- The default installer only normalizes the plugin entry in `~/.config/opencode/opencode.json`, enables the TUI status plugin in `~/.config/opencode/tui.json`, and clears the cached plugin copy. Catalog modes also merge their selected `provider.openai` definitions. Changed config files are backed up before writing.
131
+ The default installer only registers the plugin entry in `~/.config/opencode/opencode.json`, enables the TUI status plugin in `~/.config/opencode/tui.json`, and clears the cached plugin copy. Catalog modes also merge their selected `provider.openai` definitions. Changed config files are backed up before writing.
132
+
133
+ ### Running from a local checkout
134
+
135
+ You can point OpenCode at a clone of this repository instead of the published
136
+ package, which is how the project is developed:
137
+
138
+ ```json
139
+ { "plugin": ["file:///path/to/oc-codex-multi-auth"] }
140
+ ```
141
+
142
+ The installer leaves that entry exactly as written. It identifies an entry by
143
+ the package it resolves to rather than by how the path is spelled, so a clone
144
+ is recognized under any directory name, whether it is referenced as a path, a
145
+ `file://` URL, or its build output. `oc-codex-multi-auth` is appended only when
146
+ no entry in the config resolves to this plugin, so the installer never replaces
147
+ a checkout with the published package or registers both at once.
148
+
149
+ Stale references the installer itself produced are still retired: the bare
150
+ package name repeated, version-pinned entries, the former
151
+ `oc-chatgpt-multi-auth` name, and paths into `node_modules` or the OpenCode
152
+ package cache.
132
153
 
133
154
  ### Standalone CLI (no agent / no token cost)
134
155
 
@@ -197,7 +218,7 @@ opencode run "Plan the refactor" --model=openai/gpt-6-astra --variant=high
197
218
  Use Codex-focused routing:
198
219
 
199
220
  ```bash
200
- opencode run "Refactor the retry logic and update the tests" --model=openai/gpt-5-codex --variant=high
221
+ opencode run "Refactor the retry logic and update the tests" --model=openai/gpt-6-sol --variant=high
201
222
  ```
202
223
 
203
224
  If browser launch is blocked, use the alternate login paths in [docs/getting-started.md](docs/getting-started.md#remote-or-headless-login).
@@ -256,7 +277,7 @@ Most of these also run as a **direct CLI** with no agent or model involvement, s
256
277
 
257
278
  - stateless request handling forces `store: false`
258
279
  - `reasoning.encrypted_content` is preserved for multi-turn continuity
259
- - GPT-6 Astra, the Daybreak tiers and the GPT-5.6 tiers use the responses-lite request shape and default client identity `opencode`; other models default to `codex_cli_rs`
280
+ - GPT-6 Astra/Sol/Luna, the Daybreak tiers and the GPT-5.6 tiers use the responses-lite request shape and default client identity `opencode`; other models default to `codex_cli_rs`
260
281
  - account rotation is health-aware (`rotationStrategy` default `hybrid`) and avoids repeatedly selecting cooling accounts
261
282
  - The quota guard checks each enabled account at a bounded interval (30 minutes by default). When it finds a fully spent 5-hour or weekly subscription quota, rotation skips that account until its reported reset instead of drawing from paid Credits. `codex-limits` applies the same guard immediately when run manually. After running standalone `limits`, restart an already-running OpenCode instance or wait for its next quota poll to reload the updated account state.
262
283
  - same-host OpenCode processes sharing an account file serialize refresh-token exchange and commit so one current single-use token is exchanged once
@@ -265,7 +286,7 @@ Most of these also run as a **direct CLI** with no agent or model involvement, s
265
286
  - unsupported-model handling is strict by default, with opt-in fallback controls
266
287
  - TUI quota status follows the account/workspace used by the latest request
267
288
  - Business workspace memberships and Personal accounts keep separate usage and quota windows. Business members sharing one workspace are distinguished by their member/seat identity, so their usage is not collapsed into one row.
268
- - An account identifies itself by its own ChatGPT email and the last 6 characters of its account id, with the email masked when `maskEmail` is on. The OAuth id_token also lists the API-platform organizations the login belongs to; those are not ChatGPT workspaces and are never used to name an account, so logging in clears a label left behind by one. A label you set with `codex-label` is always kept.
289
+ - An account identifies itself by its own ChatGPT email and the last 6 characters of its account id, with the email masked when `maskEmail` is on. An account id names a ChatGPT workspace and every member of a Business workspace shares it, so a record that also carries a member/seat id prints a short excerpt of that as `seat:`. The excerpt is a 6-character tail where that is enough to tell the listed accounts apart. Where it is not, it widens, moves to where those ids first differ, or joins two short excerpts with `..` - real member ids are long, share a leading prefix, and differ in more than one place, so a tail alone often cannot separate them. Where no excerpt that short can separate them, `seat:` is instead an **opaque hash prefix** such as `719f78b5`: it identifies the seat and stays stable, but it is not part of the member id and cannot be matched against anything ChatGPT shows you. Whichever form it takes, two distinct seats never render the same `seat:` and a `seat:` is never longer than 32 characters. A record with no member id renders exactly as before. The OAuth id_token also lists the API-platform organizations the login belongs to; those are not ChatGPT workspaces and are never used to name an account, so logging in clears a label left behind by one. A label you set with `codex-label` is always kept.
269
290
  - The ChatGPT plan (`Free`, `Plus`, `Pro`, `Business`, `Business Premium`, `Enterprise`) is read from the access token, refreshed on every token refresh, and shown by `codex-list` and `codex-status`. `codex-limits` and the TUI read the plan live from the usage endpoint and name it the same way. An unrecognized plan is reported verbatim rather than renamed.
270
291
 
271
292
  ---
@@ -284,6 +305,7 @@ Most of these also run as a **direct CLI** with no agent or model involvement, s
284
305
  | Backups | `~/.opencode/backups/` or `~/.opencode/projects/<project-key>/backups/` |
285
306
  | Logs | `~/.opencode/logs/codex-plugin/` |
286
307
  | TUI quota cache | OpenCode state dir plus `oc-codex-multi-auth-tui-quota.json`, else `$OPENCODE_STATE_DIR/oc-codex-multi-auth-tui-quota.json` or `~/.local/state/opencode/oc-codex-multi-auth-tui-quota.json` |
308
+ | TUI pool quota cache | `oc-codex-multi-auth-tui-quota-overview.json`, in the same directory, written only when `quotaStatus.mode` is `overview` |
287
309
 
288
310
  Per-project storage is enabled by default. The plugin walks up from the current directory to find a project root, then stores account pools under the project-specific key. If no project root is found, it falls back to global storage.
289
311
 
@@ -297,6 +319,132 @@ Primary config files:
297
319
  - `~/.config/opencode/tui.json`
298
320
  - `~/.opencode/openai-codex-auth-config.json`
299
321
 
322
+ ### Quota percentage display
323
+
324
+ Every quota percentage a person reads is worded as the headroom still left,
325
+ which is how Codex itself reports a quota:
326
+
327
+ ```text
328
+ 5h limit: 88% left # codex-limits, quota details dialog
329
+ 5h 88% # TUI prompt status line
330
+ ```
331
+
332
+ Set `quotaDisplay` to `"used"` to report consumption instead:
333
+
334
+ ```json
335
+ {
336
+ "quotaDisplay": "used"
337
+ }
338
+ ```
339
+
340
+ ```text
341
+ 5h limit: 12% used
342
+ 5h 12%
343
+ ```
344
+
345
+ Add it to `~/.opencode/openai-codex-auth-config.json`, or set
346
+ `CODEX_AUTH_QUOTA_DISPLAY=used`, then quit and restart OpenCode. The setting
347
+ covers the TUI prompt status line and quota details dialog, `codex-limits`,
348
+ the standalone `limits` CLI, the interactive account check, and the macOS
349
+ quota notifications below.
350
+
351
+ It changes wording only. Quota exhaustion, rotation blocks, notification
352
+ thresholds, and the status line's warning/danger colouring all stay keyed on
353
+ the percentage remaining, so a nearly spent account still colours red while
354
+ reading `95%`. The `usedPercent` and `leftPercent` fields in `--json` /
355
+ `format="json"` output are unaffected.
356
+
357
+ ### Pool-wide quota status
358
+
359
+ The prompt status line describes the account that served the last request. On
360
+ a pool of several accounts that account changes as rotation moves, so the line
361
+ changes identity under you and no single glance shows where the pool stands.
362
+
363
+ Set `quotaStatus.mode` to `"overview"` to describe the whole pool on one
364
+ constant line instead, which only changes when a quota does:
365
+
366
+ ```json
367
+ {
368
+ "quotaStatus": {
369
+ "mode": "overview",
370
+ "layout": "accounts",
371
+ "accountNames": "number",
372
+ "order": "number",
373
+ "multipliers": false,
374
+ "allotment": false,
375
+ "resetTimes": "low",
376
+ "resetCredits": false,
377
+ "recovery": false,
378
+ "rows": 1,
379
+ "showFor": "always"
380
+ }
381
+ }
382
+ ```
383
+
384
+ ```text
385
+ 24%: #1 13%, #2 0% 3d, #3 12% # defaults
386
+ 24%: 3 accounts # "layout": "count"
387
+ 24%: #1 5x 13%, #2 20x 0% 3d, #3 1x 12% # "multipliers": true
388
+ 24%: #1 5x 13%, #2 20x 0% 3d 1r, #3 1x 12% # + "resetCredits": true
389
+ 24%: 3 accounts, +12% in 3d # "layout": "count", "recovery": true
390
+ 24% of 26x: #1 13%, #2 0% 3d, #3 12% # "allotment": true
391
+ 24%: #1 13% 2d, #2 0% 3d, #3 12% 5d # "resetTimes": "always"
392
+ 24%: 13%, 0% 3d, 12% # "accountNames": "none"
393
+ 24%: damian 13%, work 0% 3d, spare 12% # "accountNames": "label"
394
+ 24%: #2 0% 3d, #1 13%, #3 12% # "order": "most-used"
395
+ 24%: 13% 2d, 0% 3d 4d 5d # "layout": "aggregate"
396
+ ```
397
+
398
+ Each switch is independent, so any combination works. `#N` is the account
399
+ number `codex-list` and `codex-switch` use. An account is shown by whichever
400
+ of its windows has the least headroom, since that is the one that stops a
401
+ request; a reset time (`3d`) is added for an account at or below 25% by
402
+ default, for every account under `"resetTimes": "always"`, and for none under
403
+ `"never"`. `1r` counts banked rate-limit resets that account can redeem now.
404
+
405
+ `order` takes `number`, `most-used`, `least-used`, `renewing-earliest`, or
406
+ `renewing-latest`. `layout: "aggregate"` prints a shared percentage once and
407
+ keeps only what differs after it, which matters most on a pool where several
408
+ accounts are spent.
409
+
410
+ The leading figure is the pool total, and it is a **weighted** mean: a Pro seat
411
+ spent to 50% has given up twenty times the capacity a Business Standard seat
412
+ does at 50%, so an unweighted average would describe a pool nobody has. The
413
+ per-plan ratios are listed in [docs/plan-allotments.md](docs/plan-allotments.md),
414
+ and `"allotment": true` shows what they add up to.
415
+
416
+ `mode` also accepts a list, and the line then alternates between those screens
417
+ every `rotateMs` (default 5000). The third screen, `resets`, appears only once
418
+ every account is spent and lists the banked reset credits worth redeeming,
419
+ latest reset first - redeeming one on an account that renews by itself tomorrow
420
+ throws it away:
421
+
422
+ ```json
423
+ {
424
+ "quotaStatus": { "mode": ["overview", "resets"] }
425
+ }
426
+ ```
427
+
428
+ ```text
429
+ Free resets: 6d 1r damian@nowaker.net, 4d 2r work@example.com
430
+ ```
431
+
432
+ `"rows"` (1-4, default 1) is a ceiling rather than a height: a rendering that
433
+ fits on one row still takes one, so `"rows": 2` costs nothing on a wide terminal
434
+ and buys the whole line back on a narrow one, where the agent/model label beside
435
+ it has already wrapped to two rows anyway. `"showFor": "codex-models"` hides the
436
+ line unless the session is running a model this plugin routes.
437
+
438
+ Percentages follow `quotaDisplay`, so the first line above reads
439
+ `76%: #1 87%, #2 100% 3d, #3 88%` under `"used"`. The whole setting is
440
+ presentation only: rotation, quota blocks and the line's warning/danger
441
+ colouring stay keyed on the headroom remaining.
442
+
443
+ Add the object to `~/.opencode/openai-codex-auth-config.json`. It is read from
444
+ that file only - a display preference belongs to a person, not to a shell - and
445
+ the status line re-reads it while sessions are open, so an edit takes effect
446
+ within a couple of seconds without a restart.
447
+
300
448
  ### Desktop quota notifications
301
449
 
302
450
  Quota notifications are an optional macOS-only feature. Separately, the quota
@@ -318,6 +466,10 @@ Account identities are omitted for readability and lock-screen privacy:
318
466
  Weekly: 72% | resets 22:30 on Aug 30
319
467
  ```
320
468
 
469
+ The percentage follows `quotaDisplay`, so the same two lines read `90%` and
470
+ `28%` under `"used"`. `thresholds` are always remaining-percent values
471
+ regardless.
472
+
321
473
  ```json
322
474
  {
323
475
  "quotaNotifications": {
@@ -420,7 +572,11 @@ Selected runtime/environment overrides:
420
572
  | `CODEX_TUI_GLYPHS=ascii\|unicode\|auto` | Force terminal glyph style |
421
573
  | `CODEX_TUI_MASK_EMAIL=0/1` | Mask account emails across account-display surfaces (list/status/limits/health/dashboard/menus + TUI quota status) |
422
574
  | `CODEX_TUI_MASK_EMAIL_DETAILS=0/1` | Also hide account email in quota details when prompt masking is enabled |
575
+ | `CODEX_AUTH_QUOTA_DISPLAY=free\|used` | Word quota percentages as headroom left (default, matching Codex) or as consumption |
576
+
423
577
  | `CODEX_AUTH_PER_PROJECT_ACCOUNTS=0/1` | Disable/enable per-project account pools |
578
+ | `CODEX_AUTH_CREDENTIAL_SNAPSHOTS=0/1` | Disable/enable pre-write snapshots of the credential store (default on) |
579
+ | `CODEX_AUTH_CREDENTIAL_SNAPSHOTS_MAX_COUNT=<n>` | How many credential snapshots to keep (`0` keeps all of them) |
424
580
  | `CODEX_AUTH_AUTO_UPDATE=0/1` | Disable/enable daily npm update check and cache refresh |
425
581
  | `CODEX_AUTH_ROTATION_STRATEGY=hybrid\|sticky\|round-robin` | Account selection strategy |
426
582
  | `CODEX_AUTH_UNSUPPORTED_MODEL_POLICY=strict\|fallback` | Control unsupported-model retry behavior |
@@ -456,6 +612,8 @@ By default, account pools are stored locally as V3 JSON files. File permissions
456
612
 
457
613
  Use JSON storage when you want predictable, inspectable local files and easy backup/export behavior.
458
614
 
615
+ Before the store is changed in a way that matters, the plugin copies the previous version of the file into `backups/` as `codex-credential-snapshot-*.json`, mode `0600` in a `0700` directory. The snapshot holds the state being replaced, not the state replacing it, which is what makes it useful if the file is ever overwritten wholesale. Token refreshes count as significant, which bounds how stale a restore can be. Refresh tokens are single-use, so a snapshot taken just before a refresh holds the consumed token for the one account that refresh rotated - that account needs a fresh `opencode auth login` - while every other account in the pool comes back with the token that was live at that moment. A snapshot old enough to predate many refreshes restores a pool where most or all accounts can no longer authenticate, which is the failure this bounding exists to avoid. Rotation bookkeeping - `lastUsed`, rate-limit and cooldown state, quota stamps, and the rotation cursor - never triggers one on its own, so the kept snapshots are not churned away by ordinary traffic. The plugin keeps the 10 most recent and prunes strictly by that filename prefix, so nothing else in `backups/` is touched. Set `credentialSnapshots: false` to turn it off, or `credentialSnapshotsMaxCount` to keep a different number (`0` keeps all of them).
616
+
459
617
  </details>
460
618
 
461
619
  <details>
@@ -504,7 +662,7 @@ opencode auth login
504
662
  <summary><b>Common symptoms</b></summary>
505
663
 
506
664
  - Plugin does not load: rerun `npx -y oc-codex-multi-auth@latest`, then restart OpenCode
507
- - Config looks wrong: run `opencode debug config` and confirm `"plugin": ["oc-codex-multi-auth"]`
665
+ - Config looks wrong: run `opencode debug config` and confirm `"plugin": ["oc-codex-multi-auth"]`, or the path to your checkout when running one
508
666
  - OAuth callback fails: free port `1455`, then rerun `opencode auth login`
509
667
  - Browser launch is blocked: use the remote/headless login path from [docs/getting-started.md](docs/getting-started.md#remote-or-headless-login)
510
668
  - Wrong account is selected: run `codex-list`, then `codex-switch`
package/config/README.md CHANGED
@@ -6,17 +6,17 @@ This directory contains the official OpenCode config templates for `oc-codex-mul
6
6
 
7
7
  | File | OpenCode version | Description |
8
8
  |------|------------------|-------------|
9
- | [`opencode-modern.json`](./opencode-modern.json) | **v1.0.210+** | Variant-based config: **13 base models**, **59 variants** total |
10
- | [`opencode-legacy.json`](./opencode-legacy.json) | **v1.0.209 and below** | Legacy explicit entries: **59** individual model definitions |
9
+ | [`opencode-modern.json`](./opencode-modern.json) | **v1.0.210+** | Variant-based config: **10 base models**, **53 variants** total |
10
+ | [`opencode-legacy.json`](./opencode-legacy.json) | **v1.0.209 and below** | Legacy explicit entries: **53** individual model definitions |
11
11
 
12
12
  ## Install modes
13
13
 
14
14
  | Installer flag | What gets written |
15
15
  |----------------|-------------------|
16
16
  | default / `--plugin-only` | Register plugin entries; preserve `provider.openai` |
17
- | `--modern` | Compact modern: 13 base OAuth families + variant picker |
17
+ | `--modern` | Compact modern: 10 base OAuth families + variant picker |
18
18
  | `--full` | Modern bases **plus** explicit legacy selector IDs |
19
- | `--legacy` | Explicit-only catalog (59 preset model entries) |
19
+ | `--legacy` | Explicit-only catalog (53 preset model entries) |
20
20
 
21
21
  ```bash
22
22
  npx -y oc-codex-multi-auth@latest # plugin entries only
@@ -53,30 +53,29 @@ OpenCode v1.0.210+ added model `variants`, so one model entry can expose multipl
53
53
 
54
54
  Both templates include:
55
55
 
56
- ### Base model families (13)
56
+ ### Base model families (10)
57
57
 
58
58
  | Base | Variants (modern) |
59
59
  |------|-------------------|
60
60
  | `gpt-6-astra` | low, medium, high, xhigh, max, ultra |
61
+ | `gpt-6-sol` | low, medium, high, xhigh, max, ultra |
62
+ | `gpt-6-luna` | low, medium, high, xhigh, max |
61
63
  | `gpt-5.6-sol` | low, medium, high, xhigh, max, ultra |
62
64
  | `gpt-5.6-terra` | low, medium, high, xhigh, max, ultra |
63
65
  | `gpt-5.6-luna` | low, medium, high, xhigh, max |
64
66
  | `gpt-5.5` | none, low, medium, high, xhigh |
65
67
  | `gpt-5.5-fast` | none, low, medium, high, xhigh |
66
- | `gpt-5.4-mini` | none, low, medium, high, xhigh (retired from Codex 2026-08-31; auto-upgrades to `gpt-5.6-luna`) |
67
68
  | `gpt-5.4-nano` | none, low, medium, high, xhigh |
68
- | `gpt-5.1-codex-max` | low, medium, high, xhigh |
69
- | `gpt-5.1-codex` | low, medium, high |
70
- | `gpt-5.1-codex-mini` | medium, high |
71
69
  | `gpt-5.1` | none, low, medium, high |
72
- | `gpt-5-codex` | low, medium, high |
70
+
71
+ `gpt-5.4-mini`, `gpt-5-codex`, `gpt-5.1-codex`, `gpt-5.1-codex-max`, and `gpt-5.1-codex-mini` were removed from both templates: `gpt-5.4-mini` retired from Codex with ChatGPT sign-in on 2026-08-31 (replacement `gpt-6-luna`), and `gpt-5-codex`/`gpt-5.1-codex`/`gpt-5.1-codex-max`/`gpt-5.1-codex-mini` were shut down from the OpenAI API on 2026-07-23 (replacement `gpt-5.6-sol`, or `gpt-5.6-terra` for `gpt-5.1-codex-mini`). They are no longer shipped, but routing is unchanged: a user who still types one of these ids by hand is still routed and rescued by the default fallback chains below.
73
72
 
74
73
  Shared template requirements:
75
74
 
76
75
  - `store: false` and `include: ["reasoning.encrypted_content"]`
77
76
  - Context metadata:
78
- - `gpt-6-astra` / `gpt-5.6-sol` / `gpt-5.6-terra` / `gpt-5.6-luna` / `gpt-5.5` / `gpt-5.5-fast`: context **1,050,000**, output **128,000**
79
- - `gpt-5.4-mini` / `gpt-5.4-nano` / Codex models (`gpt-5-codex`, `gpt-5.1-codex*`, …): context **400,000**, output **128,000**
77
+ - `gpt-6-astra` / `gpt-6-sol` / `gpt-6-luna` / `gpt-5.6-sol` / `gpt-5.6-terra` / `gpt-5.6-luna` / `gpt-5.5` / `gpt-5.5-fast`: context **1,050,000**, output **128,000**
78
+ - `gpt-5.4-nano`: context **400,000**, output **128,000**
80
79
  - `gpt-5.1`: context **272,000**, output **128,000**
81
80
 
82
81
  Use `opencode debug config` to verify that these template entries were merged into your effective config. A `--modern` install shows base OAuth entries such as `gpt-5.5` / `gpt-5.6-sol`; the separate OpenCode variant picker exposes the reasoning presets. The default install writes no catalog, so these entries appear only if OpenCode supplies them itself.
@@ -87,10 +86,22 @@ If your OpenCode runtime supports global compaction tuning, you can also set val
87
86
 
88
87
  - Served over the **responses-lite** path. Astra's catalog entry landed in openai/codex commit `ed391d4d` (2026-09-03) and reads `use_responses_lite: true`, `tool_mode: "code_mode_only"`, `multi_agent_version: "v2"`, so the shape is read rather than inferred. The `CODEX_AUTH_ASTRA_RESPONSES_LITE` switch that 6.17.0 carried while this was unverifiable has been removed.
89
88
  - Rollout gate: Astra reached a limited set of organizations first, so accounts outside it auto-fallback
90
- `gpt-6-astra → gpt-5.6-sol → gpt-5.6-terra → gpt-5.6-luna → gpt-5.5 → gpt-5.2`
89
+ `gpt-6-astra → gpt-6-sol → gpt-5.6-sol → gpt-5.6-terra → gpt-5.5 → gpt-6-luna → gpt-5.6-luna`
91
90
  (disable with `CODEX_AUTH_DISABLE_GPT6_AUTO_FALLBACK=1`).
92
91
  - Efforts are low through `ultra`, per OpenAI's Codex model list. `ultra` is sent as `max` on the wire, as with 5.6.
93
- - Bare `gpt-6` is a plugin-side alias. `gpt-6-astra-pro` is not a Codex-routable id and collapses onto `gpt-6-astra`.
92
+ - Bare `gpt-6` is a plugin-side alias for `gpt-6-astra`, unchanged by the Sol/Luna additions. `gpt-6-astra-pro` is not a Codex-routable id and collapses onto `gpt-6-astra`.
93
+
94
+ ## GPT-6 Sol / Luna notes
95
+
96
+ - `gpt-6-sol` ("GPT 6 Sol") and `gpt-6-luna` ("GPT 6 Luna") were added to the Codex model catalog on 2026-09-22 (openai/codex commit `49e95cc7`). Sol is the workhorse model for coding and everyday work; Luna is the fast, affordable model for easier tasks.
97
+ - Both ship in the modern and legacy templates. Sol supports low/medium/high/xhigh/max/ultra; Luna supports low/medium/high/xhigh/max (no `ultra`). Neither accepts `none` or `minimal`; both clamp to `low`.
98
+ - Served over the **responses-lite** path with default client identity `opencode`, same as Astra.
99
+ - `ultra` is sent as `max` on the wire, as with Astra and 5.6.
100
+ - Covered by the same `CODEX_AUTH_DISABLE_GPT6_AUTO_FALLBACK` opt-out as Astra.
101
+
102
+ ## GPT-5.5 notes
103
+
104
+ - Still shipped and live. OpenAI's Codex models page lists GPT-5.5 as retiring from Codex with ChatGPT sign-in on 2026-10-14, with `gpt-6-sol` as the replacement on Plus/Pro/Business/Enterprise/Edu and `gpt-6-luna` on Free/Go.
94
105
 
95
106
  ## Cyber tier notes (Daybreak-gated)
96
107
 
@@ -102,9 +113,9 @@ If your OpenCode runtime supports global compaction tuning, you can also set val
102
113
 
103
114
  - Served over the **responses-lite** path (`use_responses_lite`).
104
115
  - Preview entitlement: accounts without access auto-fallback
105
- `gpt-5.6-sol → gpt-5.6-terra → gpt-5.6-luna → gpt-5.5 → gpt-5.2`
116
+ `gpt-5.6-sol → gpt-5.6-terra → gpt-5.5 → gpt-6-luna → gpt-5.6-luna`
106
117
  (disable with `CODEX_AUTH_DISABLE_GPT56_AUTO_FALLBACK=1`).
107
- - Default client identity for every responses-lite model (5.6, GPT-6 Astra, Daybreak) is host/opencode (`originator: opencode`); other families default to Codex CLI identity.
118
+ - Default client identity for every responses-lite model (5.6, GPT-6 Astra/Sol/Luna, Daybreak) is host/opencode (`originator: opencode`); other families default to Codex CLI identity.
108
119
  - `ultra` is accepted as a client-side alias and sent as `max` on the wire (no subagent orchestration in this plugin).
109
120
 
110
121
  ## Spark model note
@@ -121,8 +132,9 @@ Recommended compact UI selectors:
121
132
  opencode run "task" --model=openai/gpt-5.5 --variant=medium
122
133
  opencode run "task" --model=openai/gpt-5.5-fast --variant=medium
123
134
  opencode run "task" --model=openai/gpt-6-astra --variant=medium
135
+ opencode run "task" --model=openai/gpt-6-sol --variant=medium
136
+ opencode run "task" --model=openai/gpt-6-luna --variant=medium
124
137
  opencode run "task" --model=openai/gpt-5.6-sol --variant=medium
125
- opencode run "task" --model=openai/gpt-5-codex --variant=high
126
138
  ```
127
139
 
128
140
  If you need direct explicit selector IDs for scripts, install with:
@@ -139,31 +151,39 @@ A barebones debug template is available at [`minimal-opencode.json`](./minimal-o
139
151
 
140
152
  Current defaults are strict entitlement handling except for common default-selector entitlement gates:
141
153
 
142
- - **GPT-6 Astra** auto-fallback: `gpt-6-astra → gpt-5.6-sol → gpt-5.6-terra → gpt-5.6-luna → gpt-5.5`
154
+ - **GPT-6 Astra** auto-fallback: `gpt-6-astra → gpt-6-sol → gpt-5.6-sol → gpt-5.6-terra → gpt-5.5 → gpt-6-luna → gpt-5.6-luna`
143
155
  - **Daybreak** cyber tiers: no fallback chain, deliberately
144
- - **GPT-5.6** auto-fallback: `gpt-5.6-sol → gpt-5.6-terra → gpt-5.6-luna → gpt-5.5`
145
- - **`gpt-5.5`** and canonical **`gpt-5-codex`** can auto-fallback through `gpt-5.6-terra`, `gpt-5.6-luna`, then `gpt-5.2` when the backend reports the selected model is not supported
156
+ - **GPT-5.6** auto-fallback: `gpt-5.6-sol → gpt-5.6-terra → gpt-5.5 → gpt-6-luna → gpt-5.6-luna`
157
+ - **`gpt-5.5`** can auto-fallback through `gpt-6-sol`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-luna`, then `gpt-5.6-luna`; canonical **`gpt-5-codex`** can auto-fallback through `gpt-5.6-terra`, then `gpt-5.6-luna` when the backend reports the selected model is not supported
146
158
  - `unsupportedCodexPolicy: "strict"` returns other entitlement errors directly
147
159
  - set `unsupportedCodexPolicy: "fallback"` (or `CODEX_AUTH_UNSUPPORTED_MODEL_POLICY=fallback`) to enable the full fallback chain for manual/legacy selectors
148
160
  - `fallbackToGpt52OnUnsupportedGpt53: true` keeps the legacy `gpt-5.3-codex -> gpt-5.2-codex` edge inside fallback mode
149
161
  - user-typed `gpt-5.5-pro*` is canonicalized to `gpt-5.5` before fallback because GPT-5.5 Pro is ChatGPT-only, not a Codex-routable model; `gpt-6-astra-pro*` is canonicalized to `gpt-6-astra` for the same reason
150
- - legacy Codex selector `gpt-5.1-codex` normalizes to canonical `gpt-5-codex`, while `gpt-5.2-codex` and `gpt-5.3-codex` route as distinct backend model IDs; if canonical Codex or a gated model fails entitlement, default auto-fallback can retry through `gpt-5.6-terra`, `gpt-5.5`, then `gpt-5.2`
151
- - set `CODEX_AUTH_DISABLE_GPT6_AUTO_FALLBACK=1` to disable GPT-6 Astra auto-fallback
162
+ - legacy Codex selector `gpt-5.1-codex` normalizes to canonical `gpt-5-codex`, while `gpt-5.2-codex` and `gpt-5.3-codex` route as distinct backend model IDs; if canonical Codex or a gated model fails entitlement, default auto-fallback can retry through `gpt-5.6-terra`, then `gpt-5.6-luna`
163
+ - set `CODEX_AUTH_DISABLE_GPT6_AUTO_FALLBACK=1` to disable GPT-6 Astra/Sol/Luna auto-fallback
152
164
  - set `CODEX_AUTH_DISABLE_GPT56_AUTO_FALLBACK=1` to disable GPT-5.6 auto-fallback
153
165
  - set `CODEX_AUTH_DISABLE_GPT55_AUTO_FALLBACK=1` to disable GPT-5.5 auto-fallback
154
166
  - set `CODEX_AUTH_DISABLE_CODEX_AUTO_FALLBACK=1` to disable canonical Codex/GPT-5.4-family auto-fallback
155
- - `gpt-5.4-pro -> gpt-5.6-terra -> gpt-5.5 -> gpt-5.2` applies when you manually select `gpt-5.4-pro`
167
+ - `gpt-5.4-pro -> gpt-6-sol -> gpt-5.6-terra -> gpt-5.6-luna` applies when you manually select `gpt-5.4-pro`
156
168
  - `unsupportedCodexFallbackChain` lets you override fallback order per model
157
-
158
- Default chains when generic fallback policy is enabled (and empty override map):
159
-
160
- - `gpt-6-astra → gpt-5.6-sol → gpt-5.6-terra → gpt-5.6-luna → gpt-5.5` (also auto under default strict for rollout gates)
161
- - `gpt-5.6-sol → gpt-5.6-terra → gpt-5.6-luna → gpt-5.5` (also auto under default strict for preview gates)
162
- - `gpt-5.5 → gpt-5.6-terra → gpt-5.6-luna → gpt-5.2`
163
- - `gpt-5-codex → gpt-5.6-terra → gpt-5.5 → gpt-5.2`
164
-
165
- > GPT-5.4 and GPT-5.4 Mini were retired from Codex on 2026-08-31; the catalog marks both `visibility: "hide"` and names their replacements (`gpt-5.4` -> `gpt-5.6-terra`, `gpt-5.4-mini` -> `gpt-5.6-luna`), and `gpt-5.4-nano` has no catalog entry. The default chains therefore end at live models rather than leading with retired ones.
166
- - `gpt-5.4-pro → gpt-5.6-terra → gpt-5.5 → gpt-5.2` (if you manually select `gpt-5.4-pro`)
169
+ - a single request hops across at most 6 quota-exhausted models (`MAX_QUOTA_FALLBACK_SWITCHES`, was 3)
170
+
171
+ Default chains when generic fallback policy is enabled (and empty override map). The general rows follow one order, most capable first (`gpt-6-astra > gpt-6-sol > gpt-5.6-sol > gpt-5.6-terra > gpt-5.5 > gpt-6-luna > gpt-5.6-luna`), and each row is that order's tail after its own model:
172
+
173
+ - `gpt-6-astra → gpt-6-sol → gpt-5.6-sol → gpt-5.6-terra → gpt-5.5 → gpt-6-luna → gpt-5.6-luna` (also auto under default strict for rollout gates)
174
+ - `gpt-6-sol → gpt-5.6-sol → gpt-5.6-terra → gpt-5.5 → gpt-6-luna → gpt-5.6-luna`
175
+ - `gpt-5.6-sol → gpt-5.6-terra → gpt-5.5 → gpt-6-luna → gpt-5.6-luna` (also auto under default strict for preview gates)
176
+ - `gpt-5.6-terra → gpt-5.5 → gpt-6-luna → gpt-5.6-luna`
177
+ - `gpt-5.5 → gpt-6-sol → gpt-5.6-sol → gpt-5.6-terra → gpt-6-luna → gpt-5.6-luna`
178
+ - `gpt-6-luna → gpt-5.6-luna → gpt-6-sol → gpt-5.6-sol → gpt-5.6-terra → gpt-5.5`
179
+ - `gpt-5.6-luna → gpt-6-luna → gpt-6-sol → gpt-5.6-sol → gpt-5.6-terra → gpt-5.5`
180
+ - `gpt-5-codex → gpt-5.6-terra → gpt-5.6-luna`
181
+
182
+ > The terminal is `gpt-5.6-luna`, not `gpt-5.5`: OpenAI's Codex model docs say GPT-5.5 retires from Codex with ChatGPT sign-in on 2026-10-14, while 5.6 Luna is listed for every plan with no retirement date. `gpt-5.2`, the terminal before that, left the catalog in openai/codex #44250 (2026-09-09). GPT-5.4 and GPT-5.4 Mini were retired from Codex on 2026-08-31; the catalog marks both `visibility: "hide"` and names their replacements (`gpt-5.4` -> `gpt-6-sol`, `gpt-5.4-mini` -> `gpt-6-luna`), and `gpt-5.4-nano` has no catalog entry. The default chains therefore end at live models rather than leading with retired ones.
183
+ - `gpt-5.4 → gpt-6-sol → gpt-5.6-terra → gpt-5.6-luna`
184
+ - `gpt-5.4-mini → gpt-6-luna → gpt-5.6-luna`
185
+ - `gpt-5.4-nano → gpt-6-luna → gpt-5.6-luna`
186
+ - `gpt-5.4-pro → gpt-6-sol → gpt-5.6-terra → gpt-5.6-luna` (if you manually select `gpt-5.4-pro`)
167
187
  - `gpt-5.3-codex → gpt-5-codex → gpt-5.2-codex`
168
188
  - `gpt-5.3-codex-spark → gpt-5-codex → gpt-5.3-codex → gpt-5.2-codex` (only if Spark IDs are added manually)
169
189
  - `gpt-5.2-codex → gpt-5-codex`