fix(codex-cli): pin the official CLI credential store to file on disk (#641) - #642
Conversation
Repeated macOS login-keychain prompts (#641) come from the official Codex CLI, not from this project's own storage, which is plaintext JSON and never touches the keychain. The wrapper forwards `-c cli_auth_credentials_store="file"` on every command it launches, but that only covers processes it spawns. Third-party front-ends such as CodexBar exec the official binary directly and read ~/.codex/config.toml instead, so a config left on "keychain" keeps prompting no matter how many times the user clicks "Always Allow". Persisting the value used to be lazy: it happened only inside setCodexCliActiveSelection, i.e. on switch/login/health-check/repair. A user who never switched accounts through the manager could stay on the keychain store indefinitely. Reconcile it proactively instead, at first-run setup and again as an idempotent guard on wrapper startup, and give `doctor --fix` a real remediation rather than a bare warning. Also scope both the read and the write to top-level assignments. A `cli_auth_credentials_store` under `[profiles.*]` was previously rewritten in place, which mangled the scoped setting while leaving the top-level default on the keychain -- so the prompts survived the "fix". Doctor had the mirror bug and would report a profile-scoped value as healthy. The keychain itself is never read or written: `security find-generic-password` would raise the very prompt this change removes. Stale entries from an earlier official `codex login` simply stop being read, and doctor says so on darwin. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
📝 WalkthroughWalkthroughthe cli auth store is now reconciled to top-level Changescli auth-store enforcement
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Frontend as third-party frontend
participant Wrapper as codex-multi-auth wrapper
participant Writer as codex cli writer
participant Config as ~/.codex/config.toml
participant Codex as official Codex cli
Frontend->>Wrapper: invoke command
Wrapper->>Writer: reconcile persisted auth store
Writer->>Config: write top-level cli_auth_credentials_store = "file"
Wrapper->>Codex: forward command with per-invocation file override
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
📋 Issue PlannerBuilt with CodeRabbit's Coding Plans for faster development and fewer bugs. View plan used: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/codex-cli/writer.ts (1)
303-339: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winretry transient temporary-file writes on windows.
the new reconciliation path at
lib/codex-cli/writer.ts:339relies onatomicWriteText, butlib/codex-cli/writer.ts:216performs the temporarywriteFileonce; onlyrenameretriesEPERM/EBUSY. retry transient write failures too, otherwise a locked/virus-scanned temp path leaves persistence unenforced.based on learnings: “use atomic writes and retry
EPERM/EBUSYfailures for Windows configuration writes.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/codex-cli/writer.ts` around lines 303 - 339, Update atomicWriteText to retry transient EPERM and EBUSY failures from the temporary writeFile operation, using the same retry behavior already applied to rename. Ensure retries cover Windows temporary-file locking or scanning failures before propagating the error, while preserving the existing atomic write flow used by ensureCodexCliFileAuthStore.Sources: Coding guidelines, Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/codex-cli/writer.ts`:
- Around line 272-276: Update readTopLevelCodexCliAuthStoreMode to parse
cli_auth_credentials_store values enclosed in either TOML double or single
quotes, preserving trimming and null behavior. Add a regression test in the
codex CLI writer test suite covering a single-quoted literal value such as
'file'.
In `@lib/codex-manager/repair-commands.ts`:
- Around line 1806-1813: The auth-store remediation must be reported
independently of managed accounts. In
lib/codex-manager/repair-commands.ts:1806-1813, track the auth-store fix as
planned in dry-run and applied otherwise, and include that state in the fix
metadata so fix.changed is true even with no accounts; preserve the existing
supplemental auth-store action. In test/repair-commands.test.ts:1063-1133, add
no-account and dry-run assertions covering fix.changed and the auth-store
action.
In `@lib/runtime/first-run.ts`:
- Around line 29-30: Update the first-run marker handling around
existsSync(markerPath) to exclusively claim and migrate v1 markers to
FIRST_RUN_MARKER_VERSION 2 before returning setup complete. During this
migration, invoke only defaultEnforceAuthStore to persistently reconcile the
top-level cli_auth_credentials_store value to "file"; do not rerun app bind or
launcher setup. Add a regression test covering an existing v1 marker and the
resulting auth-store setting.
In `@test/codex-bin-wrapper.test.ts`:
- Around line 3079-3091: Extend the missing compiled auth-store coverage around
the existing test and runWrapper helper by launching multiple wrapper processes
concurrently with the compiled module absent. Await all results and assert every
invocation exits successfully and forwards the expected exec status arguments,
covering the lazy-load/missing-dist startup path.
---
Outside diff comments:
In `@lib/codex-cli/writer.ts`:
- Around line 303-339: Update atomicWriteText to retry transient EPERM and EBUSY
failures from the temporary writeFile operation, using the same retry behavior
already applied to rename. Ensure retries cover Windows temporary-file locking
or scanning failures before propagating the error, while preserving the existing
atomic write flow used by ensureCodexCliFileAuthStore.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a06c1735-89d1-45cd-8037-8fb5d60cec41
📒 Files selected for processing (13)
docs/configuration.mddocs/development/CONFIG_FIELDS.mddocs/reference/storage-paths.mddocs/troubleshooting.mdlib/codex-cli/writer.tslib/codex-manager/repair-commands.tslib/runtime/first-run.tsscripts/codex.jstest/codex-bin-wrapper.test.tstest/codex-cli-writer.test.tstest/first-run.test.tstest/helpers/cli-test-fixtures.tstest/repair-commands.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (27)
**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Use ESM only ("type": "module"), Node >= 18.17
Files:
test/helpers/cli-test-fixtures.tstest/codex-cli-writer.test.tsscripts/codex.jstest/codex-bin-wrapper.test.tstest/repair-commands.test.tslib/codex-manager/repair-commands.tslib/codex-cli/writer.tstest/first-run.test.tslib/runtime/first-run.ts
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not use
as any,@ts-ignore, or@ts-expect-errorin TypeScript files
Files:
test/helpers/cli-test-fixtures.tstest/codex-cli-writer.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.tslib/codex-manager/repair-commands.tslib/codex-cli/writer.tstest/first-run.test.tslib/runtime/first-run.ts
{scripts/**/*.js,test/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use bare recursive delete logic in Windows-sensitive scripts/tests without retry handling
Files:
test/helpers/cli-test-fixtures.tstest/codex-cli-writer.test.tsscripts/codex.jstest/codex-bin-wrapper.test.tstest/repair-commands.test.tstest/first-run.test.ts
**/*.{js,ts,mjs,cjs}
📄 CodeRabbit inference engine (README.md)
**/*.{js,ts,mjs,cjs}: Keep npm installation scripts side-effect-free; postinstall may print a short notice but must not modify runtime state or perform setup, especially in CI or non-interactive installs.
Never run npm install or update commands automatically; only display a manual upgrade notice when appropriate.
Do not publish or take ownership of a globalcodexbinary; preserve the official OpenAI installation as the owner of thecodexcommand.
Keep runtime rotation and local bridge services loopback-only, and protect local bridge access with hashed client tokens.
Keep OAuth credentials and account state local; do not send them to external services as part of normal account management.
Treat Responses background mode as opt-in: requests withbackground: truemust use statefulstore=true, while default stateless routing usesstore=false.
Use bounded outbound request budgets, avoid whole-pool replay when every account is rate-limited, and enter cooldown after repeated cross-account 5xx bursts.
Make experimental synchronization and backup flows non-destructive by default: preview before applying sync, preserve destination-only accounts, and fail safely on backup filename collisions.
Files:
test/helpers/cli-test-fixtures.tstest/codex-cli-writer.test.tsscripts/codex.jstest/codex-bin-wrapper.test.tstest/repair-commands.test.tslib/codex-manager/repair-commands.tslib/codex-cli/writer.tstest/first-run.test.tslib/runtime/first-run.ts
test/**
⚙️ CodeRabbit configuration file
tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.
Files:
test/helpers/cli-test-fixtures.tstest/codex-cli-writer.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.tstest/first-run.test.ts
docs/**/*.md
📄 CodeRabbit inference engine (docs/STYLE_GUIDE.md)
docs/**/*.md: User-facing documentation should follow the page template: Title and one-line lead, Quick path commands, Core operational workflow, Troubleshooting or failure handling, and Related links
Use short sections and scan-friendly tables in documentation where they improve clarity
Prefer direct, actionable language in documentation
Use runnable command examples in documentation
Explain expected outcomes after critical commands in documentation
Keep terminology consistent with runtime names in documentation
Avoid speculative language when behavior is deterministic in documentation
Put the user problem in the first paragraph before implementation detail
Use descriptive page titles such ascodex-multi-auth Featuresinstead of generic titles on public docs
Do not repeat keyword lists in every section; search terms should appear only where they help a developer understand the page
Canonical command family iscodex-multi-auth ...
Canonical runtime root is~/.codex/multi-auth
Runtime rotation must be described as default-on unless the release policy changes
Legacy command/path references belong only in migration contexts in documentation
Compatibility aliases (codex multi auth,codex multi-auth,codex multiauth) belong only in command reference, troubleshooting, or migration contexts
Keep command flags aligned with runtime usage text in documentation
Avoid non-runnable command snippets in documentation
Avoid conflicting path guidance across documentation
Avoid legacy-first onboarding language in documentationOrganize repository documentation according to the defined layers: product entry, user operations, reference, and development.
docs/**/*.md: Do not describecodex-multi-authas replacing@openai/codexor publishing the globalcodexbinary; preserve the official CLI's ownership ofcodex.
Usecodex-multi-authfor account management, and reservecodex-multi-auth-codexormcodexfor intentionally forwarding official Codex commands th...
Files:
docs/reference/storage-paths.mddocs/development/CONFIG_FIELDS.mddocs/troubleshooting.mddocs/configuration.md
docs/reference/**/*.md
📄 CodeRabbit inference engine (docs/STYLE_GUIDE.md)
New flags/settings/paths must be reflected in
docs/reference/*
docs/reference/**/*.md: Keep command, API, error-contract, settings, and storage-path details in the canonical reference documentation.
Document compatibility aliases (codex multi auth,codex multi-auth, andcodex multiauth) only in command-reference, troubleshooting, or migration sections.
Files:
docs/reference/storage-paths.md
docs/**/*
📄 CodeRabbit inference engine (docs/features.md)
docs/**/*: Keep all governance, account, usage, budget, routing, and runtime state local under~/.codex/multi-auth; do not implement this as a hosted multi-user service.
Store only redacted usage ledger data; never store prompts or tokens in usage records.
Store only hashes and prefixes for local bridge client tokens; plaincma_local_*secrets must not be persisted or re-exposed.
Enforce account pause and drain policies at runtime on the rotation path.
ApplyevaluateRuntimePolicybefore runtime account selection, including pause/drain, budgets, routing profiles, and capability checks.
Rotate accounts before streaming response bytes when quota, authentication refresh, network, or server failures occur.
An invocation-level account force-pin is ephemeral, fails hard when unavailable, and must never modify the persistedswitchpin.
Keep temporary provider configuration isolated from normal official Codex state by using a shadowCODEX_HOMEfor wrapper-launched sessions.
Use the canonical local data root~/.codex/multi-authand support Storage V3 migrations from older layouts.
Support project-scoped account pools and share account identity across linked worktrees of the same repository.
Persist quota cache data and selected-account synchronization so forecast/dashboard state survives runs and the active account can be written to official~/.codexauth files.
Provide browser-first OAuth with device-auth and manual callback fallbacks, including--device-auth,--manual,--no-browser, andCODEX_AUTH_NO_BROWSER=1.
Provide an optional loopback-only local bridge for/health,/v1/models, and/v1/responses, with token lifecycle operations and deterministic integration snippets.
Ensurecodex-multi-auth featuresprints the built-in numbered checklist through feature ID 54 and treat it as distinct from the complete product feature map.
Keep the runtime rotation proxy local-only and default-on, with status telemetry covering settings, app binding, waits...
Files:
docs/reference/storage-paths.mddocs/development/CONFIG_FIELDS.mddocs/troubleshooting.mddocs/configuration.md
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (docs/upgrade.md)
Document the canonical command names, runtime paths, configuration precedence, storage migration behavior, and upgrade procedures consistently across the referenced documentation.
Files:
docs/reference/storage-paths.mddocs/development/CONFIG_FIELDS.mddocs/troubleshooting.mddocs/configuration.md
docs/**
⚙️ CodeRabbit configuration file
keep README, SECURITY, and docs consistent with actual CLI flags and workflows. whenever behavior changes, require updated upgrade notes and mention new npm scripts.
Files:
docs/reference/storage-paths.mddocs/development/CONFIG_FIELDS.mddocs/troubleshooting.mddocs/configuration.md
docs/development/CONFIG_FIELDS.md
📄 CodeRabbit inference engine (docs/development/RUNBOOK_ADD_CONFIG_FIELD.md)
Update
docs/development/CONFIG_FIELDS.mdwith field inventory details when adding new configuration fieldsMaintain full field inventory in
docs/development/CONFIG_FIELDS.md
Files:
docs/development/CONFIG_FIELDS.md
docs/development/**/*.md
📄 CodeRabbit inference engine (docs/DOCUMENTATION.md)
Keep internal architecture, configuration flow, repository ownership, testing, parity, metadata, and audit guidance in development documentation.
Files:
docs/development/CONFIG_FIELDS.md
docs/development/**/*
📄 CodeRabbit inference engine (docs/development/CONFIG_FLOW.md)
docs/development/**/*: Resolve the runtime root directory in this order:CODEX_MULTI_AUTH_DIR; explicit non-defaultCODEX_HOME/multi-auth; existing account-storage roots underCODEX_HOMEor~/.codex; canonical~/.codex/multi-auth; and legacy paths only when storage signals exist.
ReaddashboardDisplaySettingsandpluginConfigfromsettings.json, while preserving legacy compatibility loading and migration.
ResolvepluginConfigvalues using this precedence: existingCODEX_MULTI_AUTH_CONFIG_PATHfile, valid unifiedsettings.jsonconfiguration, legacy compatibility configuration, thenDEFAULT_PLUGIN_CONFIG; apply environment-variable overrides afterward.
Ignore a configured but nonexistentCODEX_MULTI_AUTH_CONFIG_PATHduring loading, but create it on the first save while the variable remains set.
Resolve dashboard display values from persisteddashboardDisplaySettings, followed by normalization and fallback defaults.
Resolve account storage by selecting the root directory, using the global accounts file by default, using a project-namespaced path when project-scoped mode is active, and attempting applicable legacy project-file migration.
Normalize standalonecodex-multi-authbare subcommands toauth ...before dispatch; normalize wrapper aliases; run auth-manager commands locally; forward out-of-scope wrapper commands to the official Codex CLI.
For forwarded request-bearing commands, honor runtime rotation: resolveCODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY, thenpluginConfig.codexRuntimeRotationProxy, which defaults to enabled.
When rotation is enabled for a requesting command, use a per-process-token loopback Responses proxy, a temporary shadowCODEX_HOME, and a rewrittenconfig.toml; synchronize refreshed official Codex state on exit and remove the shadow home.
The runtime proxy must select or refresh managed accounts and rotate on rate-limit, authentication, network, or server failures before streaming begins.
The plugin host m...
Files:
docs/development/CONFIG_FIELDS.md
docs/development/**/*.{md,mdx}
📄 CodeRabbit inference engine (docs/development/TESTING.md)
When documentation changes, verify every command snippet is runnable, path references match runtime modules, cross-links are valid, and the feature matrix matches implemented features.
Files:
docs/development/CONFIG_FIELDS.md
docs/{index.md,getting-started.md,faq.md,architecture.md,features.md,configuration.md,troubleshooting.md,privacy.md,upgrade.md}
📄 CodeRabbit inference engine (docs/DOCUMENTATION.md)
Keep the listed public documentation pages as the canonical sources for operator onboarding, FAQ, architecture, features, configuration, troubleshooting, privacy, and upgrades.
Files:
docs/troubleshooting.mddocs/configuration.md
test/**/*.test.ts
📄 CodeRabbit inference engine (test/AGENTS.md)
test/**/*.test.ts: Write Vitest test suites with globals enabled (describe, it, expect)
Maintain 80%+ coverage threshold across statements, branches, functions, and lines
Use removeWithRetry() for Windows filesystem cleanup instead of bare fs.rm to handle EBUSY, EPERM, and ENOTEMPTY errors
Do not rely on dist/ in tests; use source files instead
Do not skip tests without justification
Relax lint rules for test files as configured in eslint.config.js
Files:
test/codex-cli-writer.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.tstest/first-run.test.ts
scripts/codex*.js
📄 CodeRabbit inference engine (AGENTS.md)
Do not bypass the official Codex CLI by reimplementing general Codex commands in the wrapper
Files:
scripts/codex.js
{scripts/*.js,lib/codex-manager/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Canonical package name is
codex-multi-auth; canonical command family iscodex-multi-auth ...
Files:
scripts/codex.jslib/codex-manager/repair-commands.ts
{lib,scripts}/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Windows filesystem safety: retry transient
EBUSY/EPERM/ENOTEMPTYcleanup and write failures where tests cover Windows locks
Files:
scripts/codex.jslib/codex-manager/repair-commands.tslib/codex-cli/writer.tslib/runtime/first-run.ts
test/**/codex-bin-wrapper.test.ts
📄 CodeRabbit inference engine (test/AGENTS.md)
Test bin wrapper lazy-load and missing dist handling with concurrent invocations in codex-bin-wrapper.test.ts
Files:
test/codex-bin-wrapper.test.ts
lib/**/*.ts
📄 CodeRabbit inference engine (lib/AGENTS.md)
lib/**/*.ts: Route all public exports throughlib/index.tsor documented package subpaths.
Keep module dependencies acyclic and preserve the layeringtypes/constants → storage → accounts → runtime → manager/CLI; lower layers must not import higher layers.
Preserve runtime rotation pass-through semantics except for intentionally changed auth or provider headers.
Deduplicate emails usingnormalizeEmailKey(), which trims and lowercases the email.
Use classes for state requiring multiple independent instances or dependency injection, includingAccountManager,CircuitBreaker,SessionAffinityStore, and theCodexErrorhierarchy. Reserve module-level state for genuinely process-global concerns and provide a test reset helper for such state.
Never import fromdist/in source tests or library code.
Never suppress type errors.
Never patch official Codex application binaries for desktop routing.
Never use bare recursive cleanup in Windows-sensitive paths without retry handling.
Files:
lib/codex-manager/repair-commands.tslib/codex-cli/writer.tslib/runtime/first-run.ts
lib/**
⚙️ CodeRabbit configuration file
focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.
Files:
lib/codex-manager/repair-commands.tslib/codex-cli/writer.tslib/runtime/first-run.ts
lib/{request,codex-cli}/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
ChatGPT-backed Codex request compatibility requires stateless defaults (
store: false) unless explicit background-mode compatibility is enabled
Files:
lib/codex-cli/writer.ts
lib/runtime/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not expose account emails or tokens in runtime proxy client response headers or logs
Files:
lib/runtime/first-run.ts
{lib/runtime/**/*.ts,lib/policy/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Runtime rotation is default-on through
codexRuntimeRotationProxy; users can opt out withcodex-multi-auth rotation disableorCODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY=0
Files:
lib/runtime/first-run.ts
lib/{storage,runtime}/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Local project-owned state defaults to ~/.codex/multi-auth; official Codex state remains under ~/.codex
Files:
lib/runtime/first-run.ts
lib/{runtime-rotation-proxy.ts,runtime/**/*.ts}
📄 CodeRabbit inference engine (lib/AGENTS.md)
Runtime rotation must fail open to normal official Codex forwarding when startup helpers are unavailable.
Files:
lib/runtime/first-run.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:03.936Z
Learning: Use `~/.codex/multi-auth/settings.json` as the canonical settings file, with top-level `version`, `dashboardDisplaySettings`, and `pluginConfig` fields.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Use `~/.codex/multi-auth` as the default plugin-owned storage root, overridable with `CODEX_MULTI_AUTH_DIR`; when `CODEX_HOME` is set to a non-default directory, resolve storage strictly to `$CODEX_HOME/multi-auth` without scanning the default root.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Keep official Codex CLI files (`~/.codex/accounts.json`, `~/.codex/auth.json`, and `~/.codex/config.toml`) separate from plugin-owned multi-auth files.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Preserve the official CLI file-backed authentication layout; wrapper-forwarded non-auth commands must use `cli_auth_credentials_store="file"` unless explicitly configured otherwise.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Never read or write the keychain or the `security` CLI.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Persistently reconcile the top-level `cli_auth_credentials_store` value to `"file"` during first-run setup, wrapper startup, and `doctor --fix`, while leaving values inside `[profiles.*]` tables unchanged.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Honor `CODEX_MULTI_AUTH_FORCE_FILE_AUTH_STORE=0` by disabling both wrapper-injected overrides and startup config reconciliation; honor `CODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE=0` by disabling config rewrites while retaining per-invocation overrides.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: First-run setup must use an exclusive-create marker so concurrent first invocations run setup at most once; setup failures must be debug-logged and must not block the user command.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Use atomic writes and retry `EPERM`/`EBUSY` failures for Windows configuration writes; if reconciliation still fails because the file is locked or read-only, swallow the failure and continue forwarding.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Use `settings.json.bak` only when `settings.json` exists but is unreadable; suppress flagged-account backup recovery while its reset-intent marker remains present.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Exclude cache-like artifacts and `.reset-intent` markers from recovery candidates; report deterministic canonical and discovered manual backup lists through `getBackupMetadata()`.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Named backup exports must be stored under the plugin-owned `backups` namespace, append `.json` when omitted, allow only letters, numbers, `_`, and `-`, reject path traversal and reserved `.rotate.`, `.tmp`, and `.wal` names, and avoid overwriting existing files unless an explicit force path is used.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: The local bridge must remain loopback-only, expose only `/health`, `/v1/models`, and `/v1/responses`, and persist token hashes rather than plaintext tokens; plaintext tokens may be shown only during token creation or rotation.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Enforce account policy pause and drain entries at selection time through `evaluateRuntimePolicy`, excluding blocked accounts from hybrid rotation.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Write app-bind provider configuration only after backing up the real `~/.codex/config.toml`; rotation disable and app unbind must restore the backup and remove the router startup entry.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:13.447Z
Learning: Validate storage and migration behavior with `npm run build` and the specified storage tests before shipping backup or restore changes.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Use `codex-multi-auth` as the canonical account-manager command family; do not assume the package publishes a global `codex` binary. `codex-multi-auth-codex` is an optional forwarding wrapper.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Only one Windows/WSL environment should run browser-based OAuth login at a time because the callback URI is fixed to `http://localhost:1455/auth/callback`; use device auth when coordination is impractical.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Treat Windows and WSL account state as separate; accounts must be authenticated independently in each environment.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Do not store project accounts in shared storage when repositories must remain isolated; use project-scoped storage according to the storage-path rules.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Keep `minRotationIntervalMs` at least `60000` milliseconds by default to reduce rapid account rotation and OAuth anti-abuse invalidation.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: The runtime proxy must remain loopback-only and route Responses traffic only for forwarded, request-bearing official Codex sessions and supported app launches.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Keep `pidOffsetEnabled` enabled for multi-process parallel workloads unless identical account scoring across processes is intentional.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Configure bounded `retryAllAccountsMaxRetries` and `retryAllAccountsMaxWaitMs` when enabling `retryAllAccountsRateLimited`; avoid waits that can exceed the host client's response-header timeout.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Distinguish the plugin's `fetchTimeoutMs` and `streamStallTimeoutMs` from the host client's provider-header timeout; change the host setting for host timeout errors.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: The project's own account state is stored as plain JSON under `~/.codex/multi-auth`; it must not read or delete macOS keychain items. Set the official CLI credential store to `file` unless keychain storage is deliberately retained.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Soft reset operations must remove only the account pool and settings; they must preserve usage ledgers, budgets, account policies, routing profiles, bridge tokens, quota cache, and observability files.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Complete uninstall must run `codex-multi-auth uninstall` before removing the npm package, because npm 7+ does not reliably run the required preuninstall cleanup.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: The uninstall cleanup must preserve the shared `bun.lock` when other Codex plugins remain installed and delete it only when this package is the sole plugin or `Codex.json` is absent.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:06:23.769Z
Learning: Use `--clear-accounts` only when permanently leaving the package because it irreversibly deletes stored credentials.
📚 Learning: 2026-06-04T06:14:18.093Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/scheduling-strategy-config.test.ts:1-1
Timestamp: 2026-06-04T06:14:18.093Z
Learning: In ndycode/codex-multi-auth, do not flag explicit imports from "vitest" (e.g., describe, it, expect, beforeEach/afterEach, etc.) in test files as issues—even if the Vitest config sets `globals: true`. The repo’s established convention is to keep these imports for consistency with neighboring tests; removing them would make files outliers.
Applied to files:
test/codex-cli-writer.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.tstest/first-run.test.ts
📚 Learning: 2026-06-04T06:14:24.975Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/runtime-rotation-proxy.test.ts:2478-2491
Timestamp: 2026-06-04T06:14:24.975Z
Learning: In ndycode/codex-multi-auth test files (e.g. `test/*.test.ts`), when creating V3 storage fixtures for accounts, it’s an intentional convention to use `as never` for deliberately minimal stored-account objects that only include `refreshToken`, `addedAt`, and `lastUsed`. Do not treat `as never` here as a type-safety problem: optional/other fields are expected to be populated by the runtime during execution, and the cast is used solely to keep the fixture minimal and consistent across existing tests.
Applied to files:
test/codex-cli-writer.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.tstest/first-run.test.ts
🪛 ast-grep (0.44.1)
test/codex-bin-wrapper.test.ts
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
lib/codex-manager/repair-commands.ts
[warning] 1789-1789: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFile(codexConfigPath, "utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
lib/codex-cli/writer.ts
[warning] 308-308: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFile(configPath, "utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
Four findings from review, all real: - config.toml values could be TOML literal strings. `cli_auth_credentials_store = 'file'` read as unset, so doctor warned about a healthy config and the wrapper rewrote it to `"file"` on every startup. Both quote forms are now recognized, and an already-correct value is left alone whatever its quoting. - doctor's fix metadata under-reported the remediation. `fix.changed` was computed only when managed accounts existed, so a machine with no accounts -- exactly the state a user hitting keychain prompts tends to be in -- got `changed: false` alongside a non-empty `actions` array. `--fix --dry-run` also planned nothing, unlike every other doctor fix; it now emits a prepared action. - the marker version bump was decorative. ensureFirstRunSetup short-circuits on marker existence, so already-installed users would never have run the new step. v1 markers are now migrated in place, replaying only the auth-store step; app bind and launcher install are deliberately not rerun so shortcuts the user removed stay removed. No exclusive claim is taken because both the config rewrite and the marker write are idempotent and atomic. An unreadable marker is treated as pre-v2 rather than re-triggering full setup. - test/AGENTS.md requires the bin wrapper's lazy-load and missing-dist paths to be covered under concurrent invocations; the missing-dist test was single-process. Added concurrent coverage both with and without the compiled module, and switched the call recorder to per-pid files so the fixture itself cannot race. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed all four review findings in 56a0c85. All were real; notes on each: 1. TOML literal strings ( 2. Fix metadata under-reporting ( 3. Marker migration ( On the "add an exclusively claimed migration" part, I went a different way deliberately: no claim is taken. Both operations are idempotent and atomic ( 4. Concurrent missing-dist coverage ( Verification: |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/codex-manager/repair-commands.ts (1)
1839-1844: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
--fixthat silently no-ops leaves the user with a bare warning.
lib/codex-manager/repair-commands.ts:1842gates the remediation hint on!options.fix, so when the user does rundoctor --fixandensureCodexCliFileAuthStorereturnsfalse— the documentedCODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE=0opt-out short-circuits atlib/codex-cli/writer.ts:314— the check stayswarnwith nothing butmode=keychain. no error, no action, no reason. the#641persona then has no idea why the fix they were told to run did nothing.💡 proposed fix: explain the no-op
if (codexAuthStoreMode !== "file" && !options.fix) { authStoreDetails.push("run `codex-multi-auth doctor --fix` to pin it to file"); } + if (codexAuthStoreMode !== "file" && options.fix && !authStoreFixChanged) { + authStoreDetails.push( + "--fix did not rewrite config.toml; check CODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE", + ); + }worth a companion case in
test/repair-commands.test.tsalongside the existing EBUSY test.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/codex-manager/repair-commands.ts` around lines 1839 - 1844, Update the repair flow around ensureCodexCliFileAuthStore and authStoreDetails so a --fix attempt that returns false adds a warning detail explaining that remediation was skipped, including the enforce-file-auth-store opt-out and the required action. Preserve the existing non-fix remediation hint, and add a companion test in repair-commands.test.ts covering the no-op case.docs/reference/storage-paths.md (1)
80-83: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winthe two opt-out bullets disagree about which sites they cover.
line 80 names three reconcile points (first-run, wrapper startup,
doctor --fix), but line 83's parenthetical forCODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORElists "first-run, account switch/login sync, anddoctor --fix" — it drops wrapper startup and adds a fourth site that line 80 never mentions. sincelib/codex-cli/writer.ts:314short-circuits everyensureCodexCliFileAuthStorecall including the wrapper's, the prose "everyconfig.tomlrewrite" is correct but the list contradicts it, and a reader comparing lines 82 and 83 will conclude the wrapper reconcile is only controllable viaCODEX_MULTI_AUTH_FORCE_FILE_AUTH_STORE.📝 proposed wording
-- Set `CODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE=0` to opt out of every `config.toml` rewrite (first-run, account switch/login sync, and `doctor --fix`) while leaving the per-invocation `-c` override in place. +- Set `CODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE=0` to opt out of every persisted `config.toml` rewrite (first-run, wrapper startup, account switch/login sync, and `doctor --fix`) while leaving the per-invocation `-c` override in place.also worth aligning line 80's "three points" with the switch/login-sync site if that one really does rewrite the persisted value.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/reference/storage-paths.md` around lines 80 - 83, Align the two opt-out bullets so they describe the same persisted config rewrite sites. Update the “three points” list and the CODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE description to include wrapper startup and account switch/login sync only if both are actual ensureCodexCliFileAuthStore paths, while preserving the distinction that FORCE controls wrapper startup reconciliation and ENFORCE disables every config.toml rewrite.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/runtime/first-run.ts`:
- Around line 456-491: Update migrateFirstRunMarker in lib/runtime/first-run.ts
(lines 456-491) to preserve marker.version ?? 1 when authStore is "failed", and
use FIRST_RUN_MARKER_VERSION only for completed or skipped outcomes. Update
test/first-run.test.ts (lines 438-462) to expect the pre-v2 marker after
enforceAuthStore throws, then add a second ensureFirstRunSetup call verifying
the migration retries and converges to v2.
---
Outside diff comments:
In `@docs/reference/storage-paths.md`:
- Around line 80-83: Align the two opt-out bullets so they describe the same
persisted config rewrite sites. Update the “three points” list and the
CODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE description to include wrapper
startup and account switch/login sync only if both are actual
ensureCodexCliFileAuthStore paths, while preserving the distinction that FORCE
controls wrapper startup reconciliation and ENFORCE disables every config.toml
rewrite.
In `@lib/codex-manager/repair-commands.ts`:
- Around line 1839-1844: Update the repair flow around
ensureCodexCliFileAuthStore and authStoreDetails so a --fix attempt that returns
false adds a warning detail explaining that remediation was skipped, including
the enforce-file-auth-store opt-out and the required action. Preserve the
existing non-fix remediation hint, and add a companion test in
repair-commands.test.ts covering the no-op case.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 740702b2-649f-4c1f-b72e-38b9e5b9ada9
📒 Files selected for processing (9)
docs/configuration.mddocs/reference/storage-paths.mdlib/codex-cli/writer.tslib/codex-manager/repair-commands.tslib/runtime/first-run.tstest/codex-bin-wrapper.test.tstest/codex-cli-writer.test.tstest/first-run.test.tstest/repair-commands.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (22)
test/**/*.test.ts
📄 CodeRabbit inference engine (test/AGENTS.md)
test/**/*.test.ts: Write Vitest test suites with globals enabled (describe, it, expect)
Maintain 80%+ coverage threshold across statements, branches, functions, and lines
Use removeWithRetry() for Windows filesystem cleanup instead of bare fs.rm to handle EBUSY, EPERM, and ENOTEMPTY errors
Do not rely on dist/ in tests; use source files instead
Do not skip tests without justification
Relax lint rules for test files as configured in eslint.config.js
Files:
test/codex-cli-writer.test.tstest/first-run.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.ts
**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Use ESM only ("type": "module"), Node >= 18.17
Files:
test/codex-cli-writer.test.tslib/codex-cli/writer.tslib/codex-manager/repair-commands.tstest/first-run.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.tslib/runtime/first-run.ts
**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not use
as any,@ts-ignore, or@ts-expect-errorin TypeScript files
Files:
test/codex-cli-writer.test.tslib/codex-cli/writer.tslib/codex-manager/repair-commands.tstest/first-run.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.tslib/runtime/first-run.ts
{scripts/**/*.js,test/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use bare recursive delete logic in Windows-sensitive scripts/tests without retry handling
Files:
test/codex-cli-writer.test.tstest/first-run.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.ts
**/*.{js,ts,mjs,cjs}
📄 CodeRabbit inference engine (README.md)
**/*.{js,ts,mjs,cjs}: Keep npm installation scripts side-effect-free; postinstall may print a short notice but must not modify runtime state or perform setup, especially in CI or non-interactive installs.
Never run npm install or update commands automatically; only display a manual upgrade notice when appropriate.
Do not publish or take ownership of a globalcodexbinary; preserve the official OpenAI installation as the owner of thecodexcommand.
Keep runtime rotation and local bridge services loopback-only, and protect local bridge access with hashed client tokens.
Keep OAuth credentials and account state local; do not send them to external services as part of normal account management.
Treat Responses background mode as opt-in: requests withbackground: truemust use statefulstore=true, while default stateless routing usesstore=false.
Use bounded outbound request budgets, avoid whole-pool replay when every account is rate-limited, and enter cooldown after repeated cross-account 5xx bursts.
Make experimental synchronization and backup flows non-destructive by default: preview before applying sync, preserve destination-only accounts, and fail safely on backup filename collisions.
Files:
test/codex-cli-writer.test.tslib/codex-cli/writer.tslib/codex-manager/repair-commands.tstest/first-run.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.tslib/runtime/first-run.ts
test/**
⚙️ CodeRabbit configuration file
tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.
Files:
test/codex-cli-writer.test.tstest/first-run.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.ts
docs/**/*.md
📄 CodeRabbit inference engine (docs/STYLE_GUIDE.md)
docs/**/*.md: User-facing documentation should follow the page template: Title and one-line lead, Quick path commands, Core operational workflow, Troubleshooting or failure handling, and Related links
Use short sections and scan-friendly tables in documentation where they improve clarity
Prefer direct, actionable language in documentation
Use runnable command examples in documentation
Explain expected outcomes after critical commands in documentation
Keep terminology consistent with runtime names in documentation
Avoid speculative language when behavior is deterministic in documentation
Put the user problem in the first paragraph before implementation detail
Use descriptive page titles such ascodex-multi-auth Featuresinstead of generic titles on public docs
Do not repeat keyword lists in every section; search terms should appear only where they help a developer understand the page
Canonical command family iscodex-multi-auth ...
Canonical runtime root is~/.codex/multi-auth
Runtime rotation must be described as default-on unless the release policy changes
Legacy command/path references belong only in migration contexts in documentation
Compatibility aliases (codex multi auth,codex multi-auth,codex multiauth) belong only in command reference, troubleshooting, or migration contexts
Keep command flags aligned with runtime usage text in documentation
Avoid non-runnable command snippets in documentation
Avoid conflicting path guidance across documentation
Avoid legacy-first onboarding language in documentationOrganize repository documentation according to the defined layers: product entry, user operations, reference, and development.
docs/**/*.md: Do not describecodex-multi-authas replacing@openai/codexor publishing the globalcodexbinary; preserve the official CLI's ownership ofcodex.
Usecodex-multi-authfor account management, and reservecodex-multi-auth-codexormcodexfor intentionally forwarding official Codex commands th...
Files:
docs/reference/storage-paths.mddocs/configuration.md
docs/reference/**/*.md
📄 CodeRabbit inference engine (docs/STYLE_GUIDE.md)
New flags/settings/paths must be reflected in
docs/reference/*
docs/reference/**/*.md: Keep command, API, error-contract, settings, and storage-path details in the canonical reference documentation.
Document compatibility aliases (codex multi auth,codex multi-auth, andcodex multiauth) only in command-reference, troubleshooting, or migration sections.
Files:
docs/reference/storage-paths.md
docs/**/*
📄 CodeRabbit inference engine (docs/features.md)
docs/**/*: Keep all governance, account, usage, budget, routing, and runtime state local under~/.codex/multi-auth; do not implement this as a hosted multi-user service.
Store only redacted usage ledger data; never store prompts or tokens in usage records.
Store only hashes and prefixes for local bridge client tokens; plaincma_local_*secrets must not be persisted or re-exposed.
Enforce account pause and drain policies at runtime on the rotation path.
ApplyevaluateRuntimePolicybefore runtime account selection, including pause/drain, budgets, routing profiles, and capability checks.
Rotate accounts before streaming response bytes when quota, authentication refresh, network, or server failures occur.
An invocation-level account force-pin is ephemeral, fails hard when unavailable, and must never modify the persistedswitchpin.
Keep temporary provider configuration isolated from normal official Codex state by using a shadowCODEX_HOMEfor wrapper-launched sessions.
Use the canonical local data root~/.codex/multi-authand support Storage V3 migrations from older layouts.
Support project-scoped account pools and share account identity across linked worktrees of the same repository.
Persist quota cache data and selected-account synchronization so forecast/dashboard state survives runs and the active account can be written to official~/.codexauth files.
Provide browser-first OAuth with device-auth and manual callback fallbacks, including--device-auth,--manual,--no-browser, andCODEX_AUTH_NO_BROWSER=1.
Provide an optional loopback-only local bridge for/health,/v1/models, and/v1/responses, with token lifecycle operations and deterministic integration snippets.
Ensurecodex-multi-auth featuresprints the built-in numbered checklist through feature ID 54 and treat it as distinct from the complete product feature map.
Keep the runtime rotation proxy local-only and default-on, with status telemetry covering settings, app binding, waits...
Files:
docs/reference/storage-paths.mddocs/configuration.md
docs/**/*.{md,mdx}
📄 CodeRabbit inference engine (docs/upgrade.md)
Document the canonical command names, runtime paths, configuration precedence, storage migration behavior, and upgrade procedures consistently across the referenced documentation.
Files:
docs/reference/storage-paths.mddocs/configuration.md
docs/**
⚙️ CodeRabbit configuration file
keep README, SECURITY, and docs consistent with actual CLI flags and workflows. whenever behavior changes, require updated upgrade notes and mention new npm scripts.
Files:
docs/reference/storage-paths.mddocs/configuration.md
{lib,scripts}/**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
Windows filesystem safety: retry transient
EBUSY/EPERM/ENOTEMPTYcleanup and write failures where tests cover Windows locks
Files:
lib/codex-cli/writer.tslib/codex-manager/repair-commands.tslib/runtime/first-run.ts
lib/{request,codex-cli}/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
ChatGPT-backed Codex request compatibility requires stateless defaults (
store: false) unless explicit background-mode compatibility is enabled
Files:
lib/codex-cli/writer.ts
lib/**/*.ts
📄 CodeRabbit inference engine (lib/AGENTS.md)
lib/**/*.ts: Route all public exports throughlib/index.tsor documented package subpaths.
Keep module dependencies acyclic and preserve the layeringtypes/constants → storage → accounts → runtime → manager/CLI; lower layers must not import higher layers.
Preserve runtime rotation pass-through semantics except for intentionally changed auth or provider headers.
Deduplicate emails usingnormalizeEmailKey(), which trims and lowercases the email.
Use classes for state requiring multiple independent instances or dependency injection, includingAccountManager,CircuitBreaker,SessionAffinityStore, and theCodexErrorhierarchy. Reserve module-level state for genuinely process-global concerns and provide a test reset helper for such state.
Never import fromdist/in source tests or library code.
Never suppress type errors.
Never patch official Codex application binaries for desktop routing.
Never use bare recursive cleanup in Windows-sensitive paths without retry handling.
Files:
lib/codex-cli/writer.tslib/codex-manager/repair-commands.tslib/runtime/first-run.ts
lib/**
⚙️ CodeRabbit configuration file
focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.
Files:
lib/codex-cli/writer.tslib/codex-manager/repair-commands.tslib/runtime/first-run.ts
docs/{index.md,getting-started.md,faq.md,architecture.md,features.md,configuration.md,troubleshooting.md,privacy.md,upgrade.md}
📄 CodeRabbit inference engine (docs/DOCUMENTATION.md)
Keep the listed public documentation pages as the canonical sources for operator onboarding, FAQ, architecture, features, configuration, troubleshooting, privacy, and upgrades.
Files:
docs/configuration.md
{scripts/*.js,lib/codex-manager/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Canonical package name is
codex-multi-auth; canonical command family iscodex-multi-auth ...
Files:
lib/codex-manager/repair-commands.ts
test/**/codex-bin-wrapper.test.ts
📄 CodeRabbit inference engine (test/AGENTS.md)
Test bin wrapper lazy-load and missing dist handling with concurrent invocations in codex-bin-wrapper.test.ts
Files:
test/codex-bin-wrapper.test.ts
lib/runtime/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Do not expose account emails or tokens in runtime proxy client response headers or logs
Files:
lib/runtime/first-run.ts
{lib/runtime/**/*.ts,lib/policy/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Runtime rotation is default-on through
codexRuntimeRotationProxy; users can opt out withcodex-multi-auth rotation disableorCODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY=0
Files:
lib/runtime/first-run.ts
lib/{storage,runtime}/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Local project-owned state defaults to ~/.codex/multi-auth; official Codex state remains under ~/.codex
Files:
lib/runtime/first-run.ts
lib/{runtime-rotation-proxy.ts,runtime/**/*.ts}
📄 CodeRabbit inference engine (lib/AGENTS.md)
Runtime rotation must fail open to normal official Codex forwarding when startup helpers are unavailable.
Files:
lib/runtime/first-run.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: Resolve runtime configuration sources in this order: existing CODEX_MULTI_AUTH_CONFIG_PATH file, valid unified settings.json pluginConfig, legacy compatibility files, then DEFAULT_PLUGIN_CONFIG; apply environment-variable overrides after source selection.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: Treat a set-but-missing CODEX_MULTI_AUTH_CONFIG_PATH as ignored during loading, while still using it as the save target.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: When CODEX_HOME is non-default, resolve multi-auth strictly under $CODEX_HOME/multi-auth without scanning other roots; CODEX_MULTI_AUTH_DIR may re-home multi-auth-owned files.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: Treat deprecated selectors such as gpt-5-codex and gpt-5.1-codex* as compatibility aliases, retrying with the current documented Codex model only after an actual unsupported-model response; fall back to gpt-5.4 only after a real unsupported-model response.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: The runtime rotation proxy must preserve request bodies and streaming responses, replace outbound authorization with the selected managed account, remove hop-by-hop/private metadata headers and stale decoded content-encoding, and return a structured pool-exhaustion error when no account is available.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: Token revocation responses must be returned directly instead of rotating accounts; revoked accounts receive the configured token-invalidation cooldown, and rotation must honor minRotationIntervalMs unless disabled.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: In sequential scheduling, keep using the active account until exhaustion, reclaim recovered accounts when scanning wraps, and never override a manual switch pin; sequential mode intentionally ignores per-session affinity.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: For parallel agents, pidOffsetEnabled should provide deterministic per-process account bias; retry-all-accounts waits must remain bounded by configured retry and wait budgets; routingMutex only serializes selection within one process.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: Package install scripts must remain side-effect-free; postinstall may print only a short notice and must not perform setup or updates.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: First-run desktop self-healing must run only on durable global installs, use the first-run marker, and avoid consuming or replaying setup for npx/project-local installs except the documented migration behavior.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: The wrapper must never automatically run npm install or update commands; version checks may only print a manual upgrade notice on a TTY or with CODEX_MULTI_AUTH_DEBUG=1.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:40:40.334Z
Learning: Persistent app binding must back up and restore the real Codex config, use a localhost router and user startup entry, and never patch official app files.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Use device authentication for remote, SSH, container, or headless environments, and use manual login only when device authentication is unavailable.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Only one Windows/WSL installation should run browser OAuth login at a time because the callback port is fixed at `localhost:1455`.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Treat account state as environment-specific: Windows and WSL installations maintain separate state directories and require independent sign-in.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Re-login accounts after `missing field id_token`, `refresh_token_reused`, or `token_expired` authentication failures.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Do not rapidly rotate accounts through the proxy; keep `minRotationIntervalMs` at least `60000` and re-login accounts whose tokens were invalidated.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Keep runtime rotation disabled or enabled consistently with the stored setting and environment override, and use the forwarding wrapper for routed official Codex sessions.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: For high parallelism, add accounts, keep `pidOffsetEnabled` enabled, use bounded `retryAllAccountsMaxRetries` and `retryAllAccountsMaxWaitMs`, and understand that `routingMutex` coordinates only within one process.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Keep plugin request and stream-stall timeouts bounded and distinguish them from the host client's provider-header timeout.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Use project-scoped storage when repositories should not share accounts, and migrate worktree state by running `codex-multi-auth list` in the worktree.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Soft reset must remove only the account pool and settings; it must preserve usage ledgers, budgets, policies, routing profiles, bridge tokens, quota cache, and observability files.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Run `codex-multi-auth uninstall` before `npm uninstall -g codex-multi-auth` to remove residual plugin, launcher, cache, and app-bind artifacts; use `--clear-accounts` only for an intentional irreversible credential wipe.
Learnt from: CR
Repo: ndycode/codex-multi-auth
Timestamp: 2026-07-28T11:41:11.581Z
Learning: Bug reports should include the report and doctor JSON output, Codex and package versions, global npm package status, and the failing command's complete terminal output.
📚 Learning: 2026-06-04T06:14:18.093Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/scheduling-strategy-config.test.ts:1-1
Timestamp: 2026-06-04T06:14:18.093Z
Learning: In ndycode/codex-multi-auth, do not flag explicit imports from "vitest" (e.g., describe, it, expect, beforeEach/afterEach, etc.) in test files as issues—even if the Vitest config sets `globals: true`. The repo’s established convention is to keep these imports for consistency with neighboring tests; removing them would make files outliers.
Applied to files:
test/codex-cli-writer.test.tstest/first-run.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.ts
📚 Learning: 2026-06-04T06:14:24.975Z
Learnt from: ndycode
Repo: ndycode/codex-multi-auth PR: 510
File: test/runtime-rotation-proxy.test.ts:2478-2491
Timestamp: 2026-06-04T06:14:24.975Z
Learning: In ndycode/codex-multi-auth test files (e.g. `test/*.test.ts`), when creating V3 storage fixtures for accounts, it’s an intentional convention to use `as never` for deliberately minimal stored-account objects that only include `refreshToken`, `addedAt`, and `lastUsed`. Do not treat `as never` here as a type-safety problem: optional/other fields are expected to be populated by the runtime during execution, and the cast is used solely to keep the fixture minimal and consistent across existing tests.
Applied to files:
test/codex-cli-writer.test.tstest/first-run.test.tstest/codex-bin-wrapper.test.tstest/repair-commands.test.ts
🪛 ast-grep (0.44.1)
test/codex-bin-wrapper.test.ts
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
🔇 Additional comments (12)
lib/codex-cli/writer.ts (2)
269-287: LGTM!
311-355: LGTM!test/codex-cli-writer.test.ts (1)
586-607: LGTM!Also applies to: 661-667
lib/runtime/first-run.ts (2)
54-91: LGTM!
513-593: LGTM!test/first-run.test.ts (1)
337-436: LGTM!Also applies to: 464-490
test/codex-bin-wrapper.test.ts (2)
104-140: LGTM!
3033-3143: LGTM!lib/codex-manager/repair-commands.ts (1)
2259-2274: LGTM!test/repair-commands.test.ts (1)
1038-1059: LGTM!Also applies to: 1098-1118, 1171-1180
docs/configuration.md (1)
181-184: LGTM!docs/reference/storage-paths.md (1)
62-70: LGTM!Also applies to: 93-93, 155-155
…lure A failed auth-store step was recorded with the current marker version, and ensureFirstRunSetup short-circuits on version alone. One transient Windows EPERM/EBUSY on a locked config.toml therefore left the CLI on keychain mode permanently -- manufacturing the exact symptom this branch exists to remove. markerVersionFor keeps the marker pre-v2 when the step fails, so the next invocation replays it. The step is idempotent, so the retry costs one extra marker read and self-heals as soon as the write succeeds. Applied to initial setup as well, not just the migration path: a first-run auth-store failure recorded the current version and never retried either. It now records the older version, and the next run replays only that step -- never app bind or launcher install. "skipped" still advances the version. It is the normal outcome for a config already pinned to "file", so treating it as unfinished would keep the marker below the current version forever on healthy installs. It also covers an explicit CODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE=0 opt-out, which is a user choice; if that opt-out is later removed, the wrapper-startup guard and `doctor --fix` both still reconcile the config. The previous test asserted the buggy behavior -- that a failed step still recorded the current version -- which is why the suite stayed green. Replaced with fail -> stays pre-v2 -> retries -> converges, for both the migration and initial-setup paths. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three defects found while auditing this branch, two of them introduced or amplified by it. Line endings were not preserved. Splitting on /\r?\n/ and rejoining with "\n" rewrote an entire CRLF config.toml as LF -- an edit nobody asked for, and one this branch made far more likely by running the reconcile on every wrapper startup rather than only on account switch. lib/runtime/config-toml.ts already had the right pattern; this now follows it. The top-level table scoping used /^\s*\[/, which also matches a continuation line of a multi-line array such as `[1, 2],`. That cut the scan short, so a real top-level assignment below it was missed and a second one appended. Duplicate keys are invalid TOML and would stop the official CLI from starting at all. Replaced with the complete-header shape used by readTomlTableName, extended to tolerate a trailing comment. `doctor --fix --dry-run` planned a rewrite that CODEX_MULTI_AUTH_ENFORCE_CLI_ FILE_AUTH_STORE=0 would have suppressed. shouldEnforceCodexCliFileAuthStore is now exported so the plan and the apply agree. Also reset the auth-store writer mocks per test: vi.clearAllMocks() keeps implementations, so one case's mockReturnValue leaked into the next. That bled a false expectation between the new doctor tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Two more rounds since the last update — one fixing a bug both reviewers caught, one from a self-audit of the whole branch.
|
Two fixes that change where the official Codex CLI keeps its state, plus a diagnostic that can now repair the first instead of only reporting it. Minor rather than patch: behaviour changes, it is not purely corrective. The wrapper now writes cli_auth_credentials_store into ~/.codex/config.toml at first run and on wrapper startup, where before it only did so on switch or login. 2.7.1 was explicitly "no new features and no configuration changes"; this one does change configuration behaviour, and documents a previously undocumented opt-out. Closes ndycode#641. Landed as ndycode#642, ndycode#639, and ndycode#643.
Summary
~/.codex/multi-authand never touches the keychain. The prompts come from the official Codex CLI whencli_auth_credentials_storein~/.codex/config.tomlis left on"keychain".-c cli_auth_credentials_store="file", but that only covers processes it spawns. A third-party front-end readsconfig.tomlinstead — so the persisted value is what actually decides whether the keychain gets opened.setCodexCliActiveSelection(switch / login / health check / repair). A user who never switched accounts through the manager could sit on the keychain store forever.What Changed
Proactive enforcement (
lib/codex-cli/writer.ts,lib/runtime/first-run.ts,scripts/codex.js)ensureCodexCliFileAuthStoreis now exported and defaults to the resolvedconfig.tomlpath.authStorestep (marker payload bumped to v2). Deliberately not gated onisCodexCliSyncEnabled()— turning account mirroring off is not a request to re-enable keychain prompts.codex login). It is idempotent, so no write amplification on the common path.Top-level scoping (the part that made the old behavior actively wrong)
[table]header. Previously acli_auth_credentials_storeunder[profiles.work]was rewritten in place — mangling a deliberate scoped setting while leaving the top-level default on the keychain, so the prompts survived the "fix".doctorhad the mirror bug and reported that profile-scoped value as healthy.Doctor (
lib/codex-manager/repair-commands.ts)codex-auth-storegains a real--fixremediation instead of an unactionable warning, and re-reports asokafterwards. Respects--dry-run; a failed rewrite degrades to acodex-auth-store-fixwarning rather than aborting doctor.--fix, the warning now names the command to run. On darwin, once pinned, it notes that credentials from an earlier officialcodex loginmay still sit in the login keychain, are no longer read, and can be cleared manually.Deliberately not done: nothing reads or deletes keychain items.
security delete-generic-passwordwould itself raise the exact prompt this PR removes, and it would add a macOS-only subprocess surface where none exists today. Prevention via config is deterministic and cross-platform.Toggles
CODEX_MULTI_AUTH_FORCE_FILE_AUTH_STORE=0-coverride and the wrapper-startup reconcile (kept coherent)CODEX_MULTI_AUTH_ENFORCE_CLI_FILE_AUTH_STORE=0config.tomlrewrite (first-run, sync,doctor --fix) — previously undocumented, now indocs/configuration.mdanddocs/development/CONFIG_FIELDS.mdValidation
npm run lintnpm run typechecknpm test— 334 files, 5247 passed / 6 skipped, 0 failednpm test -- test/documentation.test.tsnpm run buildNew coverage: top-level vs
[profiles.*]scoping, keychain→file rewrite, already-fileno-op, missing-file creation, enforcement opt-out, first-run enforcement + failure isolation, wrapper reconcile / opt-out / absent-dist / non-fatal write failure, and doctor fix / dry-run / already-ok / rewrite-failure paths.Docs and Governance Checklist
docs/getting-started.mdupdated — not neededdocs/features.mdupdated — not neededdocs/reference/*pages updated —docs/reference/storage-paths.md, plusdocs/configuration.md,docs/development/CONFIG_FIELDS.md, and a newdocs/troubleshooting.mdentry for the symptomdocs/upgrade.mdupdated — not needed, no migrationSECURITY.mdandCONTRIBUTING.mdreviewed for alignmentRisk and Rollback
~/.codex/config.tomlon more paths than before, so it touches a user-owned file at wrapper startup. Mitigations: idempotent (no write when already"file"), atomic rename with the existingEPERM/EBUSYretry, non-fatal on failure (forwarding proceeds), and fully opt-out-able. Top-level scoping means an existing[profiles.*]setting is no longer clobbered — a strict improvement overmain.config.tomlis swallowed and forwarding continues; explicitly covered by a test.authStorefield in the first-run marker (existence-gated, never parsed for behavior).Additional Notes
Users already hitting this can fix it immediately with
codex-multi-auth doctor --fixonce this ships; existing installs whose first-run marker is already claimed are covered by the wrapper-startup guard.🤖 Generated with Claude Code
note: greptile review for oc-chatgpt-multi-auth. cite files like
lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.Greptile Summary
this revision improves persisted codex cli file-store enforcement and its diagnostics.
Confidence Score: 3/5
this pr is not yet safe to merge because an incomplete first-run marker can permanently suppress auth-store retries, and concurrent config.toml replacements can still discard provider or auth-store updates.
the ordinary failed-migration path now remains pre-v2 and retries, but the initial claim itself is still version 2; if windows filesystem retries or another marker finalization failure are exhausted, the next invocation incorrectly treats that incomplete claim as finished. config.toml reconciliation also remains an unlocked read-modify-rename that can race app bind or unbind and lose either writer’s changes.
Files Needing Attention: lib/runtime/first-run.ts, lib/codex-cli/writer.ts, lib/runtime/app-bind.ts, scripts/codex.js
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[manager first run] --> B[enforce file auth store] C[wrapper startup] --> B D[doctor --fix] --> B B --> E[rewrite top-level config.toml assignment] E --> F[official codex uses file credentials]Reviews (4): Last reviewed commit: "fix(codex-cli): preserve config.toml for..." | Re-trigger Greptile
Context used (3)