Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ If a command is unavailable on your platform, state exactly what was not run in

Update documentation in the same pull request when behavior changes:

- `docs/wiki/` pages for user-visible behavior: `Feature-Guide.md`, `Command-Reference.md`, `Configuration.md`, `Updating.md`, `Troubleshooting.md`
- `docs/wiki/` pages for user-visible behavior: `Feature-Guide.md`, `Providers.md`, `Command-Reference.md`, `Configuration.md`, `Updating.md`, `Troubleshooting.md`
- `README.md` when the quick start or installation flow is affected
- `docs/wiki/Architecture-Overview.md` for module, storage, or data-flow changes
- `docs/wiki/Developer-Onboarding.md` for engineering workflow changes
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ codex-switch launch # start Codex with the best account
## What it does

- Saves, imports, renames, switches, and recoverably deletes Codex profiles.
- Saves custom API providers (OpenRouter and other Responses-compatible endpoints) and launches Codex with them without writing to `~/.codex`:

```bash
codex-switch provider add openrouter \
--base-url https://openrouter.ai/api/v1 \
--model openai/gpt-5.3-codex
codex-switch launch openrouter
```
- Displays the main and model-specific quota pools in CLI and TUI views.
- Selects an eligible account with adaptive, pace-aware scoring, and launches Codex with it.
- Supports reset cards, quota warmup, JSON output, proxies, and a Beta background daemon (LaunchAgent, systemd, or Windows Task Scheduler; tune `cache_refresh_interval_secs` and `auto_warmup`).
Expand All @@ -55,7 +63,7 @@ codex-switch launch # start Codex with the best account

## Documentation

The **[GitHub Wiki](https://github.com/xjoker/codex-switch/wiki)** is the complete documentation — getting started, feature guide, command reference, configuration, updating and channels, troubleshooting, FAQ, and the contributor guides (architecture, onboarding). Its sources live in [`docs/wiki/`](docs/wiki) and are reviewed with the code.
The **[GitHub Wiki](https://github.com/xjoker/codex-switch/wiki)** is the complete documentation — getting started, feature guide, custom API providers, command reference, configuration, updating and channels, troubleshooting, FAQ, and the contributor guides (architecture, onboarding). Its sources live in [`docs/wiki/`](docs/wiki) and are reviewed with the code.

Maintainer documents: [release process](docs/RELEASE.md) · [changelog](docs/CHANGELOG.md) · [contributing](CONTRIBUTING.md).

Expand Down
10 changes: 9 additions & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ codex-switch launch # 用最佳账号启动 Codex
## 功能一览

- 保存、导入、重命名、切换和可恢复地删除 Codex 账号。
- 保存自定义 API 提供方(OpenRouter 等兼容 Responses 协议的接口),并通过 `launch` 启动 Codex,不写入 `~/.codex`:

```bash
codex-switch provider add openrouter \
--base-url https://openrouter.ai/api/v1 \
--model openai/gpt-5.3-codex
codex-switch launch openrouter
```
- CLI 与 TUI 展示主额度池和每个模型的独立额度池。
- 自适应配速感知评分自动选号,并可直接用它启动 Codex。
- 支持重置卡、配额预热、JSON 输出、代理,以及 Beta 后台守护进程(macOS LaunchAgent / Linux systemd / Windows 任务计划程序 Task Scheduler;可调 `cache_refresh_interval_secs` 与 `auto_warmup`)。
Expand All @@ -55,7 +63,7 @@ codex-switch launch # 用最佳账号启动 Codex

## 文档

**[GitHub Wiki](https://github.com/xjoker/codex-switch/wiki)** 是完整文档:开始使用、功能指南、命令参考、配置、更新与通道、故障排查、FAQ 以及贡献者指南。中文读者从 [中文指南](https://github.com/xjoker/codex-switch/wiki/Chinese-Guide) 开始;行为细节以英文页面为准。
**[GitHub Wiki](https://github.com/xjoker/codex-switch/wiki)** 是完整文档:开始使用、功能指南、自定义 API 提供方、命令参考、配置、更新与通道、故障排查、FAQ 以及贡献者指南。中文读者从 [中文指南](https://github.com/xjoker/codex-switch/wiki/Chinese-Guide) 开始;行为细节以英文页面为准。

维护者文档:[发布流程](docs/RELEASE.md) · [更新日志](docs/CHANGELOG.md) · [贡献指南](CONTRIBUTING.md)。

Expand Down
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased

- **Custom API providers** — Save an OpenRouter-style endpoint under `$CODEX_SWITCH_HOME/providers/` and start Codex with `codex-switch launch <alias>`. The API key is read from a hidden prompt or `--api-key-stdin`, stored mode `0600`, and injected into the child environment; it never appears on the command line, and `$CODEX_HOME` is not written. `use` and auto-select stay ChatGPT-only. The TUI adds a Providers tab (`Tab` to switch; `a` / `d` to add or remove). Codex currently speaks only `wire_api = "responses"`, so Chat Completions-only vendors (including DeepSeek's official API) must be reached through a Responses-capable gateway. See [Custom API providers](wiki/Providers.md).

## v20260811.3.0 — 2026-08-11

- **Reset Card details refresh without blocking the account table** — Main Usage results render immediately while card details refresh in a serialized background queue. The Cards column shows a cyan refresh marker during work and a yellow waiting marker during HTTP 429 cooldown, while preserving the last known unexpired cards.
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Reader-facing documentation lives in [`docs/wiki/`](wiki) and is published autom
|---|---|---|
| New user | [Getting started](wiki/Getting-Started.md) | [Feature guide](wiki/Feature-Guide.md) |
| Operator | [Configuration](wiki/Configuration.md) | [Troubleshooting](wiki/Troubleshooting.md) |
| Custom API / OpenRouter | [Custom API providers](wiki/Providers.md) | [Command reference](wiki/Command-Reference.md) |
| Contributor | [Contributing](../CONTRIBUTING.md) | [Developer onboarding](wiki/Developer-Onboarding.md) |
| Maintainer | [Architecture overview](wiki/Architecture-Overview.md) | [Release process](RELEASE.md) |
| Release reader | [Changelog](CHANGELOG.md) | [GitHub Releases](https://github.com/xjoker/codex-switch/releases) |
Expand Down
18 changes: 16 additions & 2 deletions docs/wiki/Architecture-Overview.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Architecture overview

`codex-switch` is a single Rust binary. It owns saved profile state under `CODEX_SWITCH_HOME` and coordinates access to the live Codex authentication file under `CODEX_HOME`.
`codex-switch` is a single Rust binary. It owns saved profile and custom-provider state under `CODEX_SWITCH_HOME` and coordinates access to the live Codex authentication file under `CODEX_HOME`.

## System boundaries

Expand All @@ -9,17 +9,21 @@ flowchart LR
User[CLI or TUI user] --> Dispatch[Command dispatch]
Service[Platform service manager] --> Daemon[Background daemon]
Dispatch --> Profiles[Profile and lock layer]
Dispatch --> Providers[Custom API providers]
Dispatch --> Usage[Usage, refresh, models, reset cards]
Dispatch --> Login[OAuth login]
Dispatch --> Update[Self-update]
Daemon --> Profiles
Daemon --> Usage
Profiles <--> CSHome[CODEX_SWITCH_HOME]
Providers --> CSHome
Providers --> CodexLaunch[Codex CLI -c overlay]
Profiles <--> CodexAuth[CODEX_HOME/auth.json]
Usage --> OpenAI[Authenticated OpenAI services]
Login --> OpenAI
Update --> Releases[GitHub Releases]
Codex[Codex CLI] --> CodexAuth
CodexLaunch --> Codex
```

The application treats local files, command-line input, environment variables, OAuth callbacks, HTTP responses, and release assets as trust boundaries. Internal module calls rely on Rust types and established invariants.
Expand All @@ -41,6 +45,14 @@ Configuration is loaded once from `config.toml`. An existing unreadable or inval

Profile identity prefers `account_id` and falls back to email when required for locally authenticated operations. Imports are intentionally create-only: Usage API access proves workspace membership, but a Team workspace ID can belong to several users and cannot authorize overwriting an existing profile. Tokens refreshed while a profile is active are written to both the saved profile and the live auth file under the same switching discipline. A rotated import that loses verifiable identity is written under `recovery/`, outside the selectable profile tree.

## Custom API providers

[`src/provider.rs`](https://github.com/xjoker/codex-switch/blob/dev/src/provider.rs) owns third-party API provider profiles (OpenRouter and other Responses-compatible endpoints). Each profile is a TOML file under `$CODEX_SWITCH_HOME/providers/<alias>/provider.toml` (directory `0700`, file `0600`). It carries a Codex `model_providers.<id>` definition plus a bearer key; it has no `auth.json`.

[`src/commands/launch.rs`](https://github.com/xjoker/codex-switch/blob/dev/src/commands/launch.rs) takes a separate path when the named alias is a provider: it does not stage `$CODEX_HOME/auth.json`. The profile is translated into `codex -c …` overrides that define and select the provider, and the key is injected into the child process environment under `env_key` — never onto the command line. Because `-c` layers on the user's base `$CODEX_HOME/config.toml`, MCP servers and other Codex settings survive. Auto-select (`launch` with no alias) and `use` stay ChatGPT-only.

The TUI isolates the two kinds of profile on separate tabs so quota/scoring bindings never mix with provider add/remove. See [Custom API providers](Providers).

## Usage, refresh, and selection

The [`src/usage/`](https://github.com/xjoker/codex-switch/tree/dev/src/usage) module is split by responsibility:
Expand All @@ -59,7 +71,7 @@ Selection has two phases. Eligibility excludes candidates with missing authorita

## TUI and output contracts

[`src/tui/`](https://github.com/xjoker/codex-switch/tree/dev/src/tui) separates application state, key bindings, menus, popups, and rendering. Network or filesystem actions suspend or update the terminal deliberately rather than running inside rendering functions.
[`src/tui/`](https://github.com/xjoker/codex-switch/tree/dev/src/tui) separates application state, key bindings, menus, popups, and rendering. Network or filesystem actions suspend or update the terminal deliberately rather than running inside rendering functions. Accounts and custom providers occupy separate tabs so quota/scoring keys never mix with provider add/remove.

[`src/output.rs`](https://github.com/xjoker/codex-switch/blob/dev/src/output.rs) owns JSON response types and human formatting. In JSON mode stdout must contain only structured output; human diagnostics and progress are routed to stderr. This separation is part of the automation contract and is covered by integration tests.

Expand All @@ -86,6 +98,7 @@ PID-file cleanup verifies lock ownership before removal. Removing a path while a
| `$CODEX_HOME/auth.json` | Live authentication read by Codex CLI |
| `$CODEX_HOME/config.toml` | Codex configuration, including file-store requirement |
| `$CODEX_SWITCH_HOME/profiles/<alias>/auth.json` | Saved account credentials |
| `$CODEX_SWITCH_HOME/providers/<alias>/provider.toml` | Custom API provider definition and key |
| `$CODEX_SWITCH_HOME/current` | Current alias marker |
| `$CODEX_SWITCH_HOME/deleted-profiles/` | Recoverable profile archives |
| `$CODEX_SWITCH_HOME/cache.json` | Usage, workspace metadata, and rejected-credential cache |
Expand All @@ -106,3 +119,4 @@ Release artifacts are built only by GitHub Actions for six platform/architecture

- Set up the repository with [Developer onboarding](Developer-Onboarding).
- Review test and pull-request requirements in [Contributing](Contributing).
- Custom API provider storage and launch overlay: [Custom API providers](Providers).
1 change: 1 addition & 0 deletions docs/wiki/Chinese-Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ codex-switch tui

- [开始使用](Getting-Started) — 安装、登录和首次启动
- [功能指南](Feature-Guide) — 主要工作流与安全边界
- [自定义 API 提供方](Providers) — OpenRouter 等第三方接口(英文页)
- [命令参考](Command-Reference) — 全部命令、全局选项和 TUI 快捷键
- [配置](Configuration) — 路径、代理、daemon 与 launch 设置
- [更新](Updating) — 更新方式、通道切换和旧版本迁移
Expand Down
40 changes: 36 additions & 4 deletions docs/wiki/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ The installed binary remains authoritative: use `codex-switch --help` and `codex
| `import <path> [alias]` | Validate and import one `auth.json`, or recursively scan a directory for JSON files. The alias applies to single-file imports only; directories auto-assign aliases. |
| `list [-f]` | Show profiles, usage, and availability; `-f` / `--force` bypasses the cache. |
| `use [alias] [--consume-card]` | Switch explicitly, or omit the alias to auto-select with the unified scoring algorithm. When the pool is exhausted, `--consume-card` consumes the earliest-expiring reset card to revive an account (auto-select only; ignored when an alias is given). |
| `launch [alias] [--consume-card] -- [args]` | Start Codex with the best (or specified) profile's auth. Everything after `--` is passed through to Codex. |
| `launch [alias] [--consume-card] -- [args]` | Start Codex with the best (or specified) ChatGPT profile's auth, or with a custom API provider when `alias` names one. Everything after `--` is passed through to Codex. Auto-select (no alias) is ChatGPT-only. |
| `provider add <alias> --base-url <URL> --model <id>` | Save a custom API provider. The API key is read from a hidden prompt, or from stdin with `--api-key-stdin` — never from argv. |
| `provider list` | List saved providers (no keys). |
| `provider show <alias>` | Show one provider; the key is redacted. |
| `provider remove <alias> [-y]` | Delete a provider and its stored key; `-y` / `--yes` skips the prompt. Non-interactive and `--json` runs require `--yes`. |
| `reset-card <alias> [-y]` | Consume the earliest-expiring reset card for a profile after confirmation; `-y` / `--yes` skips the prompt. |
| `warmup [alias]` | Send a minimal request to activate the quota-window countdown for one or all profiles. |
| `rename <old> <new>` | Rename a saved profile. |
Expand All @@ -28,7 +32,7 @@ The installed binary remains authoritative: use `codex-switch --help` and `codex

| Option | Environment variable | Behavior |
|---|---|---|
| `--json` | — | Compact structured output (supported by `list`, `use`, `reset-card`, `rename`, `delete`, `login`, `import`, `self-update`, `daemon status`). |
| `--json` | — | Compact structured output (supported by `list`, `use`, `reset-card`, `rename`, `delete`, `login`, `import`, `self-update`, `daemon status`, `provider add`, `provider list`, `provider show`, `provider remove`). |
| `--json-pretty` | — | Indented structured output. |
| `--proxy <URL>` | `CS_PROXY` | Override proxy configuration for this process; supports `http(s)://`, `socks4://`, `socks5://`, and `socks5h://` (remote DNS). |
| `--color <auto\|always\|never>` | `CS_COLOR` | Control terminal color. `NO_COLOR` disables color regardless of this option. |
Expand All @@ -39,8 +43,8 @@ The installed binary remains authoritative: use `codex-switch --help` and `codex

- Structured data is written to stdout; progress and diagnostics are written to stderr.
- JSON and other non-interactive execution never consumes a reset card or deletes a profile without an explicit opt-in flag.
- `launch` treats everything after `--` as Codex CLI arguments.
- A manual `use` affects the next Codex process. Restart an already-running Codex process to load the new `auth.json`.
- `launch` treats everything after `--` as Codex CLI arguments. When `alias` names a custom provider, Codex is started with `-c` overrides and the key in the child environment; `$CODEX_HOME/auth.json` is not swapped.
- A manual `use` affects the next Codex process and accepts ChatGPT profile aliases only. Restart an already-running Codex process to load the new `auth.json`.
- Update checks are manual except for the one check performed when the TUI starts.

Examples:
Expand All @@ -49,11 +53,25 @@ Examples:
codex-switch --json list
codex-switch --json use work
codex-switch launch work -- --model gpt-5.4
codex-switch provider add openrouter --base-url https://openrouter.ai/api/v1 --model openai/gpt-5.3-codex
codex-switch launch openrouter
codex-switch self-update --check
```

## Provider

`provider add` required flags are `--base-url` and `--model`. Optional `--name` defaults to the alias; `--env-key` defaults to `CODEX_SWITCH_<ALIAS>_KEY`; `--wire-api` defaults to `responses` (the only protocol current Codex accepts). `--api-key-stdin` is required when there is no interactive terminal.

The alias must not collide with a ChatGPT profile, another provider, or Codex's reserved ids `openai`, `ollama`, and `lmstudio`. Removal is immediate and is not archived under `deleted-profiles/`.

See [Custom API providers](Providers) for OpenRouter, DeepSeek-via-gateway, storage, and the no-argv key contract.

## TUI shortcuts

Two tabs: **Accounts** and **Providers**. `Tab` / `Shift+Tab` switches between them. `q` and `h` are global.

### Accounts tab

`Enter` opens the scrollable detail and action menu for the selected account; if accounts are marked, it opens the batch menu instead.

| Key | Action |
Expand All @@ -79,10 +97,24 @@ codex-switch self-update --check
| `Esc` | Clear filter/marks or close the current popup |
| `q` | Quit |

### Providers tab

| Key | Action |
|---|---|
| `j` / `k` or `↑` / `↓` | Navigate |
| `a` | Add a provider (alias → base URL → model → API key; the key is masked) |
| `d` | Remove the selected provider (confirmation required) |
| `Tab` | Switch to Accounts |
| `h` | Show help |
| `q` | Quit |

The Providers table never renders the stored key. Launching a provider is CLI-only (`codex-switch launch <alias>`).

Destructive or consumptive actions always require confirmation.

## Next steps

- See how these commands combine into workflows in the [Feature guide](Feature-Guide).
- Custom API endpoints, OpenRouter, and key handling: [Custom API providers](Providers).
- Adjust defaults, proxy, and daemon behavior in [Configuration](Configuration).
- Check update channels and flags in [Updating](Updating).
4 changes: 3 additions & 1 deletion docs/wiki/Configuration.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Configuration

`codex-switch` uses `~/.codex-switch` by default. Set `CODEX_SWITCH_HOME` to relocate its profiles, cache, locks, logs, and daemon state. This does not change Codex's own home; set `CODEX_HOME` for that.
`codex-switch` uses `~/.codex-switch` by default. Set `CODEX_SWITCH_HOME` to relocate its profiles, custom providers, cache, locks, logs, and daemon state. This does not change Codex's own home; set `CODEX_HOME` for that.

Configuration is optional: a missing `config.toml` means defaults. An existing but unreadable or invalid file fails fast with its path instead of being silently ignored.

Expand Down Expand Up @@ -30,6 +30,7 @@ Accounts are added by logging in with `codex-switch login` or by importing an ex
|---|---|
| `$CODEX_HOME/auth.json` | Live authentication read by Codex. |
| `$CODEX_SWITCH_HOME/profiles/<alias>/auth.json` | Saved profile authentication. |
| `$CODEX_SWITCH_HOME/providers/<alias>/provider.toml` | Custom API provider definition and key (directory `0700`, file `0600`). |
| `$CODEX_SWITCH_HOME/deleted-profiles/` | Recoverable deleted profiles. |
| `$CODEX_SWITCH_HOME/current` | Current alias marker. |
| `$CODEX_SWITCH_HOME/cache.json` | Per-profile usage cache. |
Expand Down Expand Up @@ -128,5 +129,6 @@ Every command writes diagnostic logs to `$CODEX_SWITCH_HOME/logs/`, one file per
## Next steps

- See what these settings control in the [Feature guide](Feature-Guide).
- Custom API provider storage and launch overlay: [Custom API providers](Providers).
- Look up the flags that override configuration in the [Command reference](Command-Reference).
- Diagnose configuration errors with [Troubleshooting](Troubleshooting).
Loading