Back to Cc Switch

CC Switch v3.20.1

docs/release-notes/v3.20.1-en.md

3.20.131.3 KB
Original Source

CC Switch v3.20.1

This release settles two hard debts on the Codex side: compatibility with Codex CLI 0.149 — the definitive fix for third-party switches failing with 401 "Missing API key": switching is now config-only, the key travels in the provider's own table and never enters auth.json, and a family of legacy config shapes that made 0.149 refuse to start is repaired automatically on every switch; and ChatGPT accounts in the same Team workspace no longer overwrite each other — existing managed accounts need one re-login each (see Upgrade Notes). Three data-reliability fixes land alongside: provider edits always reach the live config, the Codex edit dialog no longer shows another card's key, and restores no longer wipe hand-written prompt files. On the usage side there is a new "Auto-Scan Session Logs" switch, and scanning large session files drops from seconds to milliseconds. This release includes a database migration (v17 → v18) — a backup is created automatically before migrating, and downgrading requires restoring it.

中文版 → | 日本語版 →


Highlights: What You Can Do Now

  • Switch third-party providers normally on Codex CLI ≥ 0.149 (#6744): since 0.149, custom providers no longer inherit ambient credentials from auth.json, so third-party switches made the old default way (key written only to auth.json) all failed with 401. Switching is now config-only across the board — the key goes into the provider's own [model_providers.*] table (experimental_bearer_token, honored since Codex 0.48), and auth.json returns to being purely the official ChatGPT login file.
  • Let multiple ChatGPT accounts from one Team workspace coexist safely (#6780, fixes #2245): accounts used to be keyed by the workspace ID, so two members of one Team collapsed onto a single record, with the later login silently overwriting the earlier one's tokens. Same-workspace logins now coexist as separate account rows, and requests routed through takeover are validated against the bound account — a bill can never land on another member.
  • Trust "saved successfully" (#6779): a takeover backup row left behind by a crash could make edits of the active provider update only the database while the real config file stayed untouched. Ownership is now decided by a rebuilt predicate; edits always reach the live config.
  • See the card's own key in the edit dialog (#6534, fixes #6414): the shared auth.json has no provider identity, so editing the active Codex provider could display — and on save persist — a key left behind by a different card, making keys converge across cards sharing a base URL ("model not found"). The form now rebuilds the key from the card's own bearer token in config.toml.
  • Restore backups with confidence (#6810, fixes #6778): when a cloud snapshot has no enabled prompt for an app, a WebDAV/S3 download or backup import no longer truncates your hand-written CLAUDE.md / AGENTS.md / GEMINI.md / SOUL.md to empty.
  • Turn off background session scanning: the usage page gains an "Auto-Scan Session Logs" switch; off means manual mode — local session logs are scanned only when you click "Sync Now". Proxy-takeover request accounting records in real time, never reads session files, and keeps working either way.
  • See your OpenCode Go subscription quota: the usage-script Token Plan query now recognizes OpenCode Go, with 5-hour / weekly / monthly usage percentages and reset times in the usage card and tray.
  • Set Otty as your terminal on macOS (#6620): available for session resume, provider terminals and tool commands.
  • Scan large session files in milliseconds instead of seconds: Claude session logs move to incremental byte-cursor scanning — a 12 MB active session file drops from a 6.04 s full parse to a 9.3 ms incremental read.

Usage Guides

  • Adding Providers: provider management after the Codex config-only switch.
  • Usage Statistics: how the session-scan switch and the Token Plan quota query are counted.

[!WARNING]

Only Official Channels (Please Read)

CC Switch is a fully free and open-source desktop app, and we do not charge users any fees. Please only obtain the software through the official channels listed below:

ChannelOnly Official
Websiteccswitch.io
Sourcegithub.com/farion1231/cc-switch
DownloadsGitHub Releases
Author@farion1231
Report an ImposterGitHub Issues

Any "CC Switch" website or client that asks you for payment, top-ups, or login credentials is fake. If you have been tricked into paying, stop the transaction immediately and file a report through GitHub Issues.


Overview

This release's main line runs through Codex, starting from an upstream compatibility break: Codex CLI 0.149 tightened credential inheritance — custom providers no longer read ambient credentials from auth.json, so every third-party switch written the old default way failed with 401. CC Switch's answer is not a patch but a redesign: third-party switching is now config-only — the key travels in the provider's own config table, and auth.json returns to being purely the official ChatGPT login file. Alongside it, a family of legacy config shapes 0.149 refuses to load (stale tables squatting on reserved ids, tables missing name, legacy top-level openai_base_url reroutes) is repaired automatically on every switch and takeover projection, and a new preflight refuses combinations 0.149 cannot load by name — instead of reporting a "successful" switch Codex cannot start from.

The second line is account and data safety: members of one ChatGPT Team workspace no longer overwrite each other in the Auth Center (existing managed accounts need one re-login); provider edits are guaranteed to reach the live config; the Codex edit dialog no longer bleeds another card's key; restores no longer wipe hand-written prompt files. On the usage side, session scanning gains an auto/manual switch and an incremental byte-cursor scanner (6.04 s → 9.3 ms), with three Claude session-accounting correctness fixes along the way — the origin of this release's only database migration (v17 → v18).

Release date: 2026-08-28

Change size: 26 commits | 66 files changed | +7,474 / -1,000 lines


Added

Session-Log Scanning: Auto/Manual Mode

The usage page gains an "Auto-Scan Session Logs" card with a switch (on by default, so behavior is unchanged after upgrading). Turning it off stops all background session scanning — including the startup pass — and a "Sync Now" button appears as the manual entry point, reporting imported entries, files scanned and an error count when done. Proxy-takeover request accounting records in real time and never reads session files, so it keeps recording regardless of the switch; the startup cost backfill (which only patches existing database rows) still runs in manual mode.

OpenCode Go Subscription Usage

The usage-script Token Plan query now recognizes OpenCode Go, showing 5-hour / weekly / monthly usage percentages with reset times in the usage card and tray, reusing the existing quota-tier display. The endpoint is Bearer-auth only (the exact opposite of the inference side, which only accepts x-api-key); a valid key without a Go subscription reports a distinct message (HTTP 403) instead of a generic auth failure, a zero-usage window drops the upstream's placeholder reset time, and an unrecognized response shape reports an error instead of an empty card. Newly added OpenCode Go providers in Claude Code, Claude Desktop, Codex, OpenCode and Pi enable the query automatically; OpenCode Zen pay-as-you-go is deliberately not covered — that plan has no usage API upstream.

Otty Terminal Support (macOS)

"Otty" joins the macOS terminal picker, covering session resume, provider terminals and tool commands. Launching first attempts a new tab in the existing Otty window via the Otty CLI, then a new Otty window; provider terminals and tool commands additionally fall back to Terminal.app on failure, while a failed session resume reports the error — with an explicit install hint when the Otty CLI is missing — and copies the command to the clipboard. CLI discovery probes the app bundle (system and per-user), Homebrew paths and PATH. The user manual's macOS terminal tables were corrected along the way — Kaku and Warp were already supported but missing from the lists. (#6620)


Changed

Codex Third-Party Switching Is Config-Only

Switching to a third-party Codex provider now writes the API key into the provider's own [model_providers.*] table (the experimental_bearer_token field, honored since Codex 0.48) and never writes it into auth.json — which returns to being purely the official ChatGPT login file. The background: Codex 0.149 stopped letting custom providers inherit ambient credentials from auth.json, so third-party switches made the old default way (key written only to auth.json) started failing with 401.

The "Keep official login for direct switches" toggle now has exactly one meaning: ON leaves the official ChatGPT login completely untouched across third-party switches; OFF deletes auth.json instead of overwriting it with the API key (a failed deletion surfaces a warning that the official login is still on disk in the Codex config directory). Two safety gates now run on every third-party switch, not just in preservation mode: a key with no provider table to hold it, and a keyless config that would fall back to the official login (requires_openai_auth = true without its own credentials, or a bare top-level openai_base_url reroute), are both refused by name — including third-party cards with an empty config, which previously rode silently in auth.json. requires_openai_auth on the active keyed third-party table is re-stamped on each direct switch to match the preservation toggle, so Codex's login screen agrees with what is actually on disk. (#6744, #6746)

TeamoRouter Presets Move to teamorouter.cn

All eight app presets now point at api.teamorouter.cn, with the old .com endpoint registered as a selectable, speed-testable fallback candidate for Claude Code, Claude Desktop, Codex and Grok Build. Existing saved TeamoRouter providers keep whatever base URL they were saved with.


Fixed

Same-Workspace ChatGPT Accounts No Longer Merge in the Auth Center

Managed Codex OAuth accounts were keyed by chatgpt_account_id — which identifies a ChatGPT workspace, not a person: two members of one Team workspace collapsed onto a single record, the later login silently overwrote the earlier one's tokens, and provider bindings followed whoever logged in last. Accounts are now keyed locally, with the OIDC subject kept as proof of user identity, so same-workspace logins coexist as separate rows. Requests routed through takeover are additionally validated against the bound account's live token: a Codex session still holding another member's login gets an explicit "restart Codex" error instead of being forwarded under the wrong identity, and the outgoing workspace header always comes from the account binding rather than the client's own claim. Adopting a CLI-rotated refresh token, and deleting auth.json on account removal, both require provable ownership now — CC Switch can no longer adopt or delete another workspace member's login. Every account row offers in-place "Re-login" (bindings preserved); cancelling or superseding a device login drops the pending flow inside CC Switch — an abandoned browser authorization can no longer be committed minutes later to silently overwrite an account. An id_token that is not a well-formed JWT yields no identity at all — a malformed or truncated token can never stand in for a user. (#6780, #6831, fixes #2245)

Codex 0.149 Compatibility Repairs: Existing Configs No Longer Keep Codex From Starting

A family of config shapes that made Codex 0.149 refuse to load — seen by users as "CC Switch says switched, Codex won't start" — is now repaired automatically on every provider switch and takeover projection. Specifically: leftover [model_providers.openai] / .ollama / .lmstudio tables (written by older takeover projections; overriding a reserved id fails validation) are renamed losslessly to a CC-Switch-owned id and normalized into a loadable shape; provider tables missing name are backfilled (0.149 rejects the whole config over any nameless table — Bedrock tables are deliberately left nameless, since naming them breaks their built-in merge); legacy top-level openai_base_url reroutes carrying a usable key are migrated into a proper custom provider table (a keyless reroute is refused by the switch-time safety gate instead); and a new preflight rejects field combinations 0.149 cannot load, naming the offending table, instead of writing them out as a "successful" switch. Takeover of a card routed at the built-in openai provider now uses the officially supported top-level knob instead of creating a reserved table, and takeover of ollama/lmstudio-routed cards fails with an explicit error. The reserved-id list now matches upstream exactly (case-sensitive; amazon-bedrock-runtime added, legacy oss/ollama-chat treated as ordinary custom providers — their keys finally reach their own tables), and inline model_providers tables receive the injected token instead of being left with a dead top-level field.

A Refused Switch No Longer Corrupts the Refused Card

Live-write validation now runs as a preflight, before the current-provider pointer moves. Previously a write-layer refusal landed after current had already been committed — the next switch would backfill the old live config into the refused provider's saved settings.

Provider Edits Always Reach the Live Config File

A takeover backup row left behind by a crash or failed restore made saves of the active provider (Claude Desktop excepted) take the takeover path — updating only the database and the backup row while the real config file silently kept the old endpoint and key, indefinitely. Ownership is now decided by a single predicate requiring actual evidence of takeover (a placeholder in the live file, or the proxy enabled and running with a backup row, or an in-flight switch holding the per-app lock alongside a backup row); stale backup rows are refreshed to match the edited provider instead of hijacking the write. Universal provider saves now also re-project each generated child into the live config of any app where it is the active provider, and report per-app failures by name instead of claiming success. (#6779)

Codex Edit Dialog No Longer Shows Another Provider's Key

With official-login preservation enabled, auth.json is a shared slot with no provider identity, and the edit dialog used to prefer it when seeding the form — so editing the active Codex provider could display, and on save persist, a key left behind by a different card, making keys converge across cards sharing a base URL ("model not found" errors). The dialog now rebuilds the key from the provider's own bearer token in config.toml; official-category and OAuth-only providers are untouched, and a card whose config.toml carries no bearer token of its own — an older or hand-maintained shape, now that every third-party switch writes one — keeps the previous behavior of reading the live auth.json, manual edits included. (#6534, fixes #6414)

Restores No Longer Wipe Unmanaged Prompt Files

A WebDAV/S3 download or backup import whose snapshot had no enabled prompt for an app truncated that app's live prompt file (CLAUDE.md / AGENTS.md / GEMINI.md / SOUL.md) to empty — destroying hand-written local content that was never part of the sync payload. Such a restore now leaves the file entirely untouched; disabling the last prompt from the Prompts panel still clears it as before. (#6810, fixes #6778)

Recovery-Screen Exit Buttons Actually Quit the App

The process:allow-exit capability was missing, so on v3.20.0 the Quit button on the "database version too new" recovery screen, and the exit call after a config-load failure, were both silently rejected by the IPC layer: the Quit button did nothing (closing the window still quit the app), and after a config-load failure the app carried on into the normal UI instead of exiting as intended. This was independently discovered and fixed first by @SaladDay in #6567.

Three Claude Session-Accounting Correctness Fixes

Three data-accuracy fixes land with the incremental scanner, all on the Claude session-log path. A log line caught mid-write used to be permanently skipped by the old line-number cursor (the unfinished tail advanced the cursor, so the completed message was never imported) — the byte cursor only commits past complete lines, so the message is picked up next round. An externally truncated or rewritten session file is never replayed: re-importing entries whose detail rows the 30-day rollup has already pruned would permanently inflate totals, so the cursor is pinned at the new end of file and the skipped range is reported in the sync result's error list instead of silently dropped (truncation is caught by the cursor overrunning the file; same-size rewrites by a fingerprint of the bytes before the cursor). Mid-file read errors now keep committed progress, resume from the same spot next round and are reported, instead of returning a clean success; a failed cursor prefetch aborts the round instead of behaving like a first-ever scan and double-importing history.


Performance

Claude Session Logs: Incremental Byte-Cursor Scanning

Each scan round now seeks straight to the last committed byte offset and reads only what was appended, instead of re-reading a changed file end to end — per the change's own benchmark, a 12 MB active session file drops from a 6.04 s full parse to a 9.3 ms incremental read. Per-file cursors for Claude, Gemini, OpenCode, Grok Build and Pi are prefetched with one table read per importer per round instead of one lookup per file; on the Claude path, each file's imports and its cursor advance commit in a single transaction. A frozen-snapshot replay over 1,017 session files (409 MB) produced aggregates identical to the old scanner. Requires a schema migration (v17 → v18) adding two nullable columns — the byte cursor and a tail fingerprint; existing line-number cursors are converted in place on the first scan without re-importing anything.

Pi Session Dedup Uses the Identity Indexes

The combined dedup query (an OR across two identity columns) could only constrain the data-source prefix, scanning the entire Pi portion of the ledger for every parsed record — Pi imports got slower as usage history grew. It is now split into indexed point lookups with identical results, so import time no longer degrades with history size. (#6667)


Upgrade Notes

This Release Includes a Database Migration; Downgrading Requires Restoring the Backup

The schema migrates from v17 to v18 (a byte-cursor and a tail-fingerprint column on the session-scan cursor table), with a backup created automatically before migrating. Once this release has run, older CC Switch builds refuse to open the database — downgrading requires restoring that backup. Usage entries the old half-line bug had already skipped are not retroactively recovered — replaying them cannot be distinguished from re-importing already-rolled-up history.

Existing Codex OAuth Accounts Need One Re-Login

Every managed ChatGPT (Codex OAuth) account added before this release is quarantined until you click "Re-login" on its row in the Auth Center — older records used the ChatGPT workspace ID as the account key and carry no separately recorded per-user identity, so an ordinary token refresh cannot prove which user an old record belongs to. Provider bindings are preserved; re-login updates the account in place. Be sure to use the row's "Re-login" button: signing in again through "Add account" only creates a second row (logins no longer merge by workspace) and leaves the old row — and any provider bound to it — still quarantined. (#6780)

Codex Releases Older Than 0.48 Lose Third-Party Authentication

The provider-table token field that config-only switching writes is never read by pre-0.48 Codex. Upgrade Codex if you are still on an older build.

With the Preservation Toggle Off, Switching to a Third Party Deletes auth.json

With the "Keep official login for direct switches" toggle OFF (the default), switching to a third-party Codex provider now deletes auth.json rather than overwriting it with the API key. To get the ChatGPT login back: switch to an official provider bound to an Auth Center account (the login is written back in full from the stored account); an unbound official card that follows the Codex CLI's own login needs a codex login run. Turn the toggle ON to keep the official login across third-party switches.

Some Previously "Working" Codex Cards Are Now Refused at Switch Time

Third-party cards with an empty config (no table to hold the key), and keyless cards relying on requires_openai_auth = true or a bare openai_base_url reroute to borrow the official login, are now refused by name. Add a proper [model_providers.<id>] entry or an API key to such cards.

Existing Codex Configs Are Rewritten on the Next Live Write Where 0.149 Requires It

Legacy openai_base_url reroutes with a usable key become a [model_providers.cc-switch] table, stale reserved tables are renamed to a CC-Switch id, missing name fields are filled in, and requires_openai_auth on the active keyed third-party table is overridden on each switch to match the preservation toggle — a hand-set value on that table does not survive a switch.

Truncated or Externally Rewritten Claude Session Logs Are Skipped, Permanently and by Design

The rewritten range is not replayed (replaying would double-count against already-pruned rollups), and the skip is reported in the sync result's error list.

Keys Already Cross-Contaminated Before the #6534 Fix Are Not Repaired Automatically

If Codex providers sharing a base URL have already converged on one key, re-enter the correct key on each affected card once.

Restore Behavior Change (#6810)

Restoring a snapshot in which an app has no enabled prompt now preserves that app's live prompt file — the client keeps loading its old content even though the Prompts panel shows everything disabled. Enable and then disable a prompt from the panel (or edit the file yourself) if you want it cleared.

Universal Provider Saves Can Now Fail Loudly

If a live config file cannot be written for an app whose active provider is the generated child, the save reports an error naming that app; the database record is still saved — retry the sync or switch that app's provider once.

Existing TeamoRouter Providers Keep api.teamorouter.com

Re-add from the preset, or edit the base URL, to move to .cn.

OpenCode Go Usage Auto-Enables Only for Providers Added After This Release

For an existing card, open its usage-script settings and pick the Token Plan template → OpenCode Go once.


Risk Notice

Carried-Over Notices

xAI Grok OAuth sign-in: reuses the public OAuth client identity of the official Grok CLI; using it could lead to account restriction or suspension — see the v3.18.0 release notes for details.

Codex OAuth reverse proxy: using a ChatGPT subscription's Codex OAuth through a reverse proxy may violate OpenAI's terms of service. See the v3.13.0 release notes for details.

SuperGrok quota queries: the quota display on provider cards depends on a non-public billing endpoint at grok.com and may stop working once xAI changes the interface — see the v3.19.0 release notes for details.

Third-party provider routing: when the CC Switch local proxy converts and forwards Codex, Claude Desktop, or Grok Build requests to a third-party provider, each provider has different constraints on billing, compliance, and data retention. Please read the target provider's terms of service before use.

By enabling these features, users accept the associated risks. CC Switch is not responsible for any account restriction, warning, or service suspension resulting from their use.


Thanks

Eight of this release's 26 commits come from 5 outside contributors.

Code Contributions

  • Thanks to @SaladDay: the entire workspace account-isolation line (#6780), the JWT identity-parsing alignment (#6831) and the Pi session-dedup indexes (#6667); the missing exit-button capability was also independently discovered and fixed first by them in #6567.
  • Thanks to @YUZHEthefool: provider edits always reaching the live config (#6779, in collaboration with @BingZi-233) and the Codex edit-dialog key cross-contamination fix (#6534) — the two hard data-correctness entries in "Fixed" are this work.
  • Thanks to @SailingLoong: restores keeping unmanaged prompt files intact (#6810).
  • Thanks to @yovinchen: Otty terminal support (#6620).
  • Thanks to @ISuuuu: the WSL2 contract tests running from prebuilt binaries (#6472).

Issue Reports

  • Thanks to @hlwhl for the precise report on Codex 0.149's credential-inheritance change in #6744 — it framed this release's biggest line directly, and they were also first to propose a fix (#6746).
  • Thanks to the reporters of the Team-workspace account-overwrite problem: @cp7553479 (#2245), @Smilenize (#5885), @yingjiezhao0820 (#6688) and @buqi759 (#6738).
  • Thanks to the key cross-contamination family: @Joaging (#6414), @KawaiiSh1zuku (#6594) and @Michael-py001 (#6827).
  • Thanks to @gyzerocc for reporting the WebDAV restore wiping AGENTS.md (#6778) — with the trigger condition pinpointed exactly.

Download & Install

Visit Releases and download the build for your system, or get it from the official site ccswitch.io (downloads are distributed through Cloudflare edge nodes and do not depend on GitHub being reachable).

System Requirements

SystemMinimum VersionArchitecture
WindowsWindows 10 and laterx64 / ARM64
macOSmacOS 12 (Monterey)+Intel (x64) / Apple Silicon (arm64)
LinuxSee table belowx64 / ARM64

Windows

FileDescription
CC-Switch-v3.20.1-Windows.msiRecommended - MSI installer with auto-update
CC-Switch-v3.20.1-Windows-Portable.zipPortable build, unzip and run

Windows ARM64 devices should pick the artifact whose file name carries the arm64 tag.

macOS

FileDescription
CC-Switch-v3.20.1-macOS.dmgRecommended - DMG installer, drag to Applications
CC-Switch-v3.20.1-macOS.zipUnzip and drag to Applications, Universal Binary
CC-Switch-v3.20.1-macOS.tar.gzFor Homebrew install and auto-update

Homebrew install:

bash
brew install --cask cc-switch

Upgrade:

bash
brew upgrade --cask cc-switch

Linux

Linux assets are available for both x86_64 and ARM64 (aarch64). Choose the file whose architecture tag matches your machine's uname -m output:

  • CC-Switch-v3.20.1-Linux-x86_64.AppImage / .deb / .rpm
  • CC-Switch-v3.20.1-Linux-arm64.AppImage / .deb / .rpm
DistributionRecommended FormatInstall Command
Ubuntu / Debian / Linux Mint / Pop!_OS.debsudo dpkg -i CC-Switch-*.deb or sudo apt install ./CC-Switch-*.deb
Fedora / RHEL / CentOS / Rocky Linux.rpmsudo rpm -i CC-Switch-*.rpm or sudo dnf install ./CC-Switch-*.rpm
openSUSE.rpmsudo zypper install ./CC-Switch-*.rpm
Arch Linux / Manjaro.AppImageMake executable and run directly, or use AUR
Other distributions / unsure.AppImagechmod +x CC-Switch-*.AppImage && ./CC-Switch-*.AppImage