Skip to content

FAQ

How is this different from just editing my CLI config files?

Hand-editing a config file switches an account once. AI Switch is about everything that happens after the switch.

Concretely:

  • One change, several CLIs. Codex, Claude Code, Gemini CLI, and Grok all use different config formats. AI Switch writes each one's native format from a single interface.
  • Writes are safe. Before every config write it takes a snapshot and records a hash, writes atomically, detects concurrent modification, and supports guarded rollback. Hand-editing has none of that.
  • Switching can be automatic. When an account hits a cooldown or exhausts its quota, requests fall through to the next account in the pool. You do not have to notice an error and go edit a file.
  • You can see what happened. Usage, token counts, pricing, failure reasons, and the raw upstream error body are all recorded.

If you have exactly one account and never switch, hand-editing really is enough. The difference shows up once you have several accounts, or once you want failover to happen without you. See quick start and accounts and the pool.

Which platforms are supported, and why are OpenCode, OpenClaw, and Hermes "partial"?

Seven platforms. All seven route API traffic and write config; the difference is the official-account half.

PlatformSupport
CodexNative: API routing, config writing, official account import and quota
Claude CodeNative: the same, with quota where the upstream account flow allows it
Gemini CLINative: API routing, config writing, import; official quota is not claimed
GrokNative: the same as Claude Code
OpenCodePartial: API routing and config writing; no official account
OpenClawPartial: the same
HermesPartial: the same

Those three are agent harnesses, not model vendors — they have no official sign-in of their own, so official account import, official account routing, deeplink, and quota lookup do not exist for them. That is the whole of what "partial" means. Config writing does work: AI Switch writes an ai-switch custom provider into ~/.config/opencode/opencode.json, ~/.openclaw/openclaw.json, and ~/.hermes/config.yaml. The one extra requirement is that creating an API credential for them requires an explicit base URL and API dialect, because these three platforms have no default dialect.

The full capability matrix (ten platform capabilities across seven platforms) is in the platform support matrix.

What is protocol bridging, and when do I need it?

Different CLIs speak different dialects, and so do different upstream services. Protocol bridging is the translation in between.

AI Switch supports four upstream protocols: openai, openai-responses, anthropic, and gemini. The local entry protocol is fixed — the Codex entry point speaks OpenAI Responses, the Claude entry point speaks Anthropic Messages. When the entry protocol and your chosen account's upstream protocol disagree, a bridge kicks in; there are seven bridge paths in total.

When you need it: you have an Anthropic-protocol account but want to use it from Codex CLI, or you have an OpenAI-compatible third-party endpoint and want Claude Code to reach it. In both cases you change nothing in the CLI — you just pick the account's upstream protocol in AI Switch.

When you can ignore it: the account protocol already matches the CLI (Claude Code with an Anthropic account, for instance). No bridge engages and the request is forwarded as-is.

How each path behaves is covered in protocol routing and bridging.

Why does port 19527 serve both the web UI and model APIs?

The default shared listener port is 19527. Paths split traffic into two classes:

Panel trafficModel API traffic
Paths/, /api/*, /ws/*, /health/models, /v1/*, /v1beta/*, /messages, /responses
Who connectsYour browser or phoneAI CLIs on your machine or remotely
What flowsThe AI Switch UI's own API calls and event streamModel inference requests, rewritten and forwarded upstream
AuthWeb access token (HTTP bearer)Route proxy key (AI Switch writes it into each CLI config)
When route access is offStill availableReturns route_proxy.access_disabled

One-line version: One port, separate permissions per traffic class.

Route access is an independent switch: turning it off does not stop the shared port, so Web pages and the health check remain available; turning it on starts the shared port when needed. Route proxy setup is in accounts and the pool; web service setup is in web service mode.

Where are my API keys stored, and is that safe?

Keys live in the SQLite database under your local data directory ~/.ai-switch — specifically in the secret_payload_json column of the route_credentials table.

To be clear about what that means: the current version does not encrypt that column at rest, and it does not use the operating system's keychain. Security is therefore equivalent to the security of your local filesystem. Treat the entire ~/.ai-switch directory as a credential directory:

  • Mind the permissions on the directory and the database file; other users on the same machine should not be able to read them.
  • Keep it out of public repositories, unencrypted sync folders, and shared directories.
  • Prefer a volume with full-disk encryption.
  • When you back the directory up, handle it as secret material (encrypted archive, offline storage).

The web service adds a separate layer: every /api/* and /ws/events request requires the access token. Direct desktop listeners on 127.0.0.1 or 0.0.0.0 open sensitive commands after startup, while loopback listeners exposed through Tailscale still follow the sidecar state. With plaintext 0.0.0.0, the token is the only protection. The standalone server still rejects non-loopback plaintext startup by default.

The data directory layout is described in desktop deployment.

What happens when an account runs out of quota? How does failover work?

Accounts are scheduled by a priority from 1 to 5, defaulting to 3, with lower numbers used first. Each account also has a concurrency limit, 5 by default for new accounts — once an account has that many requests in flight, the next one goes looking for the next account in the pool.

When an account fails or exhausts its quota, AI Switch:

  1. Records the failure kind, the failure message, and the raw error body the upstream returned
  2. Distinguishes transient failures (counted, with a backoff-scheduled retry) from quota exhaustion (cooled down until the quota window resets)
  3. Detects streaks of the same semantic failure, so requests stop being wasted on an account that is genuinely broken
  4. Hands the request to the next available account in the pool

Recovery is driven by a background scheduler that can re-enable accounts on a schedule or after a health-check probe. See reliability and auto recovery.

When should I lower the concurrency limit?

Official accounts and some third-party endpoints are sensitive to concurrency: parallel requests on a single account tend to trigger rate limiting, and sometimes get flagged as abnormal usage. For those upstreams, set the account's limit to 1 or 2 so AI Switch spreads concurrency across accounts — which is the whole point of a pool — rather than piling it onto one.

What does "insufficient permissions ... Missing scopes" mean?

The full error reads:

You have insufficient permissions for this operation. Missing scopes: api.responses.write. Check that you have the correct role in your organization (Reader, Writer, Owner) and project (Member, Owner), and if you're using a restricted API key, that it has the necessary scopes.

Check whether the account is an API key or an official (OAuth) account first — the cause is completely different.

API key accounts: the key lacks the permission

OpenAI's restricted API keys grant permissions item by item, and whatever follows Missing scopes: is the item this key does not have. api.responses.write covers /v1/responses; model.request covers the older chat/completions-style endpoints. The error's second half mentions organization and project roles, which sends most people auditing their team's permissions — but the problem is almost always the key itself.

Two ways out:

  • In the console that issued the key, set its permissions to All, or grant just the item the error names.
  • If the missing item is api.responses.write, switch the account's interface format to OpenAI Chat Completions. "Model capabilities" and "Responses" are separate permissions, so a key missing only the latter can usually still serve chat/completions.

Official accounts: before v0.8.5, AI Switch used the wrong host

An official Codex account holds a ChatGPT subscription seat, not Platform API credit, and the two live on different hosts: subscriptions are served by https://chatgpt.com/backend-api/codex, the Platform API by https://api.openai.com. The latter only accepts API keys and judges them by scope, so a subscription token sent there is always answered with this "missing api.responses.write" — a verdict on a key the account does not have.

Before v0.8.5, an official Codex account whose Config JSON had no base_url (the import examples and most auth files carry none) was sent to api.openai.com, so a perfectly healthy subscription reported this error forever while the same login worked in every other tool. Since v0.8.5 the default is ChatGPT's backend.

On an older version you can work around it by hand: edit the account and add to its Config JSON

json
"base_url": "https://chatgpt.com/backend-api/codex"

Relay-hosted OAuth accounts are unaffected — their config already names the relay's own base_url, and an explicit value still wins.

How AI Switch handles the error

The account is marked abnormal on the first occurrence, rather than waiting for a streak, because a missing permission holds for every model on that credential — rotating accounts, switching models, and waiting out a cooldown all change nothing. The upstream sentence is kept in the account list's failure hint and in the real-generation test panel, alongside a hint in the UI language. To tell which case you are in, run the real-generation test, expand "view input/output", and check which host target_url points at.

Can I use it from my phone?

Yes. Enable the web service, open it in your phone's browser, and enter the access token. Desktop and browser run the same UI — there is no stripped-down mobile version.

Things to know:

  • The default bind is 127.0.0.1:19527, which only the host machine can reach. A phone requires either changing the bind address or going through Tailscale.
  • Desktop Settings can select 0.0.0.0 for LAN access without TLS. Every Web command is then served over plaintext HTTP and the access token is the only protection, so use it only on a trusted network. The standalone server's non-loopback plaintext restriction is unchanged.
  • The better option is Tailscale: install the client on your phone, join the same tailnet, and you get access without exposing a public port or sourcing certificates yourself.

Setup steps are in web service mode and remote access and HTTPS.

If I go through Tailscale, do I still need a token?

Yes. This is deliberate, not an oversight.

Tailscale solves network reachability; it does not replace application-level auth. Whether a request comes from the local machine, from another device inside the tailnet, or from the public internet via Tailscale Funnel, the token check on /api/* and /ws/events is never skipped.

The reasoning is simple: any device on your tailnet — including one shared with you, or one that has been compromised — can reach your node. Dropping the token would mean exposing your account management interface to the entire tailnet.

Tailscale login is also manual; the app never logs in automatically at startup.

Where is my data, and how do I back it up?

Everything lives under ~/.ai-switch/ in your home directory:

text
~/.ai-switch/
├── ai-switch.db              # main database (dev builds use ai-switch-dev.db)
├── settings.json             # app settings
├── web-service.json          # web service config
├── route-proxy-https.json    # route proxy HTTPS config
├── backups/
│   └── config-snapshots/     # a snapshot before every CLI config write
├── certs/route-proxy/        # route proxy self-signed certificates
├── imports/
├── logs/
└── tailscale/

Backing up the whole directory is enough — accounts, settings, and keys are all in there (the keys inside the database). Which also means the backup is itself a credential: store it encrypted, and keep it out of public repos and unencrypted sync folders.

The location is not configurable. AI_SWITCH_DATA_DIR, which appears in the README, is not implemented in the current code and setting it has no effect — the app always uses .ai-switch under the running user's home directory. To relocate the data, control the service account's home directory or mount a container volume there.

If the actual goal is moving accounts to another device, the built-in credential export/import is a better tool than copying directories, since it records provenance information.

My account list is empty after upgrading to 0.7.3 — is the data gone?

No. Nothing was deleted. The database was moved into ~/.ai-switch/backups/ under a name like ai-switch.db.migration-conflict-<timestamp>.

The cause: 0.7.3 changed the line endings of two database migration scripts from CRLF to LF. Not a single SQL statement changed, but migration checksums are computed over the file's raw bytes, so every existing install decided at startup that a migration had been modified — which triggered the fallback of the day: move the whole database into backups/ and create a fresh, empty one.

From 0.8.0 on:

  • a checksum mismatch caused only by line endings is repaired in place, with no quarantine;
  • if the live database is empty and a quarantined one exists in backups/, it is restored automatically at startup (validated on a copy first, and never over accounts you created after the quarantine);
  • when a migration's contents genuinely changed and the database holds data, the app refuses to start instead of replacing it.

So opening the app after upgrading to 0.8.0 should bring your accounts back. If it does not, quit the app and copy the newest migration-conflict file from backups/ back to ~/.ai-switch/ai-switch.db, then start it again.

Which operating systems are supported?

Windows, macOS, and Linux. Every release is built by CI on all three:

OSInstaller format
WindowsNSIS installer (.exe)
macOS.dmg and .app
Linux.deb and .AppImage

The desktop app supports auto-updates, with minisign-signed update packages that the client verifies before installing. The standalone server and Tailscale sidecar also ship as per-platform binary archives.

Download and install instructions are in installation.

Is AI Switch open source? What is the license?

Yes. It is MIT licensed, Copyright (c) 2026 xyito.

Repository: https://github.com/ijry/ai-switch

MIT means you can use, modify, and redistribute it freely, including commercially, as long as you keep the copyright and license notice. Third-party dependency licenses are listed in the repository's LICENSES/ directory and THIRD_PARTY_NOTICES.md.

What is the relationship with cc-switch?

AI Switch is compatible with cc-switch's import protocol, for exactly one reason: so cc-switch users can migrate their configuration over easily. The add-account dialog's "导入其他客户端" tab also reads config files under ~/.cc-switch on this machine directly (opened read-only, never modifying their data) and imports the API accounts you tick. The desktop app can additionally enable ccswitch:// deep-link compatibility (off by default), so import links originally aimed at cc-switch are accepted by AI Switch too.

Beyond that there is no relationship. AI Switch is an independent, from-scratch implementation: this project only studies public behavior, public documentation, and public file formats; it does not reuse their code. The "Clean-Room Boundary" section of the repository README states this boundary explicitly.

Put another way: compatibility means "can read the same config and import formats", not "shares an implementation".

Does the desktop app update itself?

Yes. The updater points at the latest.json manifest on the repository's releases, and the client verifies each package's minisign signature against a built-in public key. Verification failure means no install.

The release pipeline includes a dedicated check that the signing key and the configured public key are the same pair, so a key rotation cannot silently break the update path. Details are in release process.

Which clients do MCP and skills management cover?

MCP management writes to the configuration of eleven clients: Claude Code, Codex, Gemini, Grok, OpenCode, OpenClaw, Hermes, Cursor, Cline, CodeBuddy, and Kimi Code. You install an MCP server once and tick which clients should receive it.

For skills, two packages ship built in with 27 skills total: ai-switch.core (14, engineering workflow) and ai-switch.science (13, research methodology).

See MCP servers and skills management.

Released under the MIT License.