Picked "via magpie" on a ChatGPT-signed Codex, a magpie model is set beside the sign-in: openai_base_url to the gateway, the magpie table, no model_provider. When Codex itself (its /model, or a Codex app still running on its old pick) then wrote one of its own models back (gpt-6.1-sol), Wired found nothing to say magpie had put it there, so the row read Not connected while its config still pointed at magpie's gateway. Set so, Codex keeps a codex.beside mark (gone when magpie becomes its provider, on a pick of its own through the picker, or on disconnect), and Agent.Beside makes Wired true on it; the model written back is still told as a change from outside (#750's drift stays). Connecting where Codex can't join (its ChatGPT allowance used up, or a model_provider of its own) went to the first of magpie's other models (Grok 4.7, "magpie doesn't serve the model it was on"), since Codex's field leaves out magpie's codex/* models: Agent.OwnVia now finds the model it is on as magpie serves it on the user's ChatGPT account (codex/gpt-6.1-sol), and Connect keeps it there. TestCodexOwnPickAfterMagpieModelStaysConnected and TestCodexConnectKeepsItsOwnModelThroughMagpie are new; with the change taken out the first reads the reported config (model gpt-6.1-sol, openai_base_url, [model_providers.magpie], no model_provider) as not connected and the second connects to fake/m1 "first". Tested in temp HOMEs only. go vet, go build (GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass (internal/proc TestUserPath timed out waiting on a login shell under load once, and passes on its own).
30d952cf (v0.1.976) forgetSideLogin no longer refuses the account a subscription uses first; magpie accounts forget goes through the same ForgetLogin, so a plugin's in-use account is forgotten and the remaining one becomes the one in use. Test-only; go vet and go test -tags nogui . ./internal/provider/... pass.
magpie gateway-key models <id> openai/gpt-5 anthropic/* (all takes it off); gateway-key list has a MODELS column. The app's menu, fitting neither below nor above its button, now goes on the roomier side and scrolls instead of running off the window. en/zh/ja/de. TestGatewayKeyModelsHoldAKey (lists, 403s by id, bare name and group, Anthropic shape, fallback skipped, magpie's own call, a free key) fails without the change; TestModelPatterns, TestKeyModelsKept, TestGatewayKeyModelsCLI, TestCallerKeyModelsRoutes pass; gateway-key-models.test.cjs (Chromium and WebKit, en and zh: no native select, menu inside a 420px window, picks sent on close, All models, no scroll, no left border, 560px fits) passes with gateway-connect-keys, gateway-key-limit, gateway-caller-keys and click-scroll. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass.
magpie gateway-key models <id> openai/gpt-5 anthropic/* (all takes it off); gateway-key list has a MODELS column. The app's menu, fitting neither below nor above its button, now goes on the roomier side and scrolls instead of running off the window. en/zh/ja/de. TestGatewayKeyModelsHoldAKey (lists, 403s by id, bare name and group, Anthropic shape, fallback skipped, magpie's own call, a free key) fails without the change; TestModelPatterns, TestKeyModelsKept, TestGatewayKeyModelsCLI, TestCallerKeyModelsRoutes pass; gateway-key-models.test.cjs (Chromium and WebKit, en and zh: no native select, menu inside a 420px window, picks sent on close, All models, no scroll, no left border, 560px fits) passes with gateway-connect-keys, gateway-key-limit, gateway-caller-keys and click-scroll. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass.
magpie group set <id> levels=low,medium,high,xhigh, levels= clears; TUI l; GUI group editor's Levels: its models' shared / named) is offered instead in /v1/models, Codex's catalog, Pi and the rest; only levels magpie knows are taken, stored lowest first; a group in a group that names its own offers them for its models; unset is as before. A member without the level asked is sent its nearest, as it already was. The GUI's group save also keeps a family set from the CLI. TestGroupLevelsOverride, TestGroupLevelsReachAgents, TestGroupLevelsNamed (passthrough and translated: medium→high, xhigh→max on the low/high/max member, as asked on the one with all), TestGroupSetLevels and routing-levels.test.cjs (Chromium, WebKit, en/zh) fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a known flake under load, passes alone); click-scroll, old-webkit, routing-effort(-row), routing-levels, settings-groups GUI tests pass.
magpie group pick <id> <model> (or group set <id> pick=<model>, a bare model id when it names one member) picks from the CLI; magpie groups and group show mark the pick, the TUI shows "manual → model". A renamed provider or model renames the pick. TestManualGroup, TestGroupPick and routing-manual.test.cjs (Chromium, WebKit, en/zh) fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; click-scroll, old-webkit, routing-levels, routing-steady, panel-routing, settings-groups pass.
magpie tray, autostart's argument, so the new version came up as a tray icon however the update was asked for; the Mac reopens its .app and was fine. The window's Update pill and Settings' "Restart to update" send the tab they're on, the new process starts as magpie gui <tab>; the tray menu's Restart to Update brings the window back if it was open and keeps to the tray if not; autostart stays tray. magpie gui <tab> / magpie app <tab> open the window on that tab, and hand it to a magpie already running. The MAGPIE_REPLACES handover is unchanged: the new process waits for the old one before its single-instance lock. Tested with TestRelaunchArgs and TestRelaunchBinaryArgs (a script in magpie's place is started with gui settings <pid> / tray <pid>); go vet, go build (GUI and -tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried: a real restart to update on Windows or Linux.
559ce021 (#203) had a custom name keep " · <provider>" after it like any other, so "Opus 5.5" read "Opus 5.5 · Claude Code" in every list Labels feeds (Codex's model_catalog_json and the gateway's Codex /models, Pi's, OpenCode's, ZCode's, OMP's, Muse's), while #92 had been promised the name as written. Both are kept: the setting is now Off / Not on names I set (自定义名称不带供应商) / On. On stays the default and keeps #203's behaviour, so nobody's list changes unasked; own leaves a name the user gave as it is and a vendor's name with its provider's; off is #335's plain names. Stored as plainOwnNames beside plainNames, so a settings.json of before reads as it did (plainNames: true is off). POST /api/settings/plain-names takes mode on|own|off (a body of on alone still works), magpie model suffix on|own|off, a Settings save keeps it, and /v1/models' magpie_label now follows the setting through Labels as the agents' lists do. The row's hint is one line that fits (en, zh), and its zh name says 供应商 as the rest of the app. Prompts and headers are unchanged. TestSuffixMode, TestSuffixModesReachAgentFiles (Codex model_catalog_json and Pi models.json), TestModelsListSuffixModes (/v1/models magpie_label) and model-suffix-own.test.cjs (Chromium and WebKit, en and zh) fail without the change; TestModelName and TestModelNameAndLevelsReachAgentFiles keep #203's assertions. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestConfiguredModelsAdvertiseImageInput load-flaky, passes alone); plain-names, click-scroll, old-webkit pass.
magpie omp auto sets omp's thinking to auto, and the panel's effort slider shows a level it doesn't list as it is (#339)
until codex exec …; do magpie quota wait codex || break; done) — it reads the vendors itself as magpie quota does, gateway running or not (provider.Allotted: the subscriptions' and plans' readings, no key balances; AskUsage has each look wait for a new reading, and only a wait for Claude runs Claude Code's /usage, through AskClaudeUsage, which now calls it). An account has allowance when routing's usedUp says so (no window that stops it, every model, at 100%; exported as provider.UsedUp), and BackAt is when the last of those windows starts again. While all are used up it sleeps to the soonest reset plus 30s, at least a minute and at most ten, saying on stderr what it waits for and until when; an allowance it can't read (an error, or only the last reading kept in its place) is asked again after 1, 2, 4, 8 then every 10 minutes. A provider's accounts switched off or signed out in magpie are left out, as the agent is never moved to them; an account is named by its user, or <provider>/<user> when two subscriptions share it. --timeout <duration> exits 1 when it passes first, --quiet says nothing, an unknown name or flag exits 2 (main now honours an exitError's code) and Ctrl+C 130. The loop takes its reading, clock and sleep as functions: quota_wait_test.go runs it on a fake clock (already available → no sleep; used up → 10m, 10m, then to just past the reset; one account named ignores another's room; a reset under a minute away is a minute; --timeout ends at the deadline after its last look; unreadable usage backs off and the wait goes on once read; an untold reset is looked at every 10 minutes; an off account is passed over; Ctrl+C), plus resolving names and the usage errors. Help in magpie quota's and magpie's usage, and the README. go vet, builds (darwin, GOOS=linux, GOOS=windows), the new tests and ./internal/provider pass; not run against real accounts.
until codex exec …; do magpie quota wait codex || break; done) — it reads the vendors itself as magpie quota does, gateway running or not (provider.Allotted: the subscriptions' and plans' readings, no key balances; AskUsage has each look wait for a new reading, and only a wait for Claude runs Claude Code's /usage, through AskClaudeUsage, which now calls it). An account has allowance when routing's usedUp says so (no window that stops it, every model, at 100%; exported as provider.UsedUp), and BackAt is when the last of those windows starts again. While all are used up it sleeps to the soonest reset plus 30s, at least a minute and at most ten, saying on stderr what it waits for and until when; an allowance it can't read (an error, or only the last reading kept in its place) is asked again after 1, 2, 4, 8 then every 10 minutes. A provider's accounts switched off or signed out in magpie are left out, as the agent is never moved to them; an account is named by its user, or <provider>/<user> when two subscriptions share it. --timeout <duration> exits 1 when it passes first, --quiet says nothing, an unknown name or flag exits 2 (main now honours an exitError's code) and Ctrl+C 130. The loop takes its reading, clock and sleep as functions: quota_wait_test.go runs it on a fake clock (already available → no sleep; used up → 10m, 10m, then to just past the reset; one account named ignores another's room; a reset under a minute away is a minute; --timeout ends at the deadline after its last look; unreadable usage backs off and the wait goes on once read; an untold reset is looked at every 10 minutes; an off account is passed over; Ctrl+C), plus resolving names and the usage errors. Help in magpie quota's and magpie's usage, and the README. go vet, builds (darwin, GOOS=linux, GOOS=windows), the new tests and ./internal/provider pass; not run against real accounts.
magpie
Every agent's model. One place.
Claude Code on Kimi, Codex on DeepSeek, Gemini CLI on GLM, OpenCode on your ChatGPT plan.
Switch them from the menu bar. One local gateway serves them all, and it moves to another account when a quota runs out.
Download · Docs · Reference · Discord · English · 简体中文
Why magpie
You probably use more than one coding agent. Each one keeps its model in its own file, in its own format, with its own keys and base URLs. Each one also has its own idea of which vendors it supports. A subscription you pay for works in one agent and nowhere else. When it runs out at 3 pm, you start editing config files.
magpie puts all of it in one place:
|
🎛 One screen for every agent |
🔌 One gateway for every API |
🔀 Routing that keeps going |
|
🔑 Subscriptions you can share |
🧩 Plugins |
📊 Usage and cost tracking |
Pick any model for any agent
Click a value and a filtered list opens. It holds every model of every provider you added, as provider/model. Pick one and the agent's config file is rewritten safely and atomically. Use Profiles to save the setup of every agent under one name ("Budget", "Focus") and switch them all at once.
magpie also lives in the menu bar. There is a tray panel on macOS, Windows and Linux, a full window, a TUI (magpie tui), a web UI (magpie web) and a plain CLI.
|
|
Add providers with one field
Pick a preset and paste a key. That's it. The model list comes from the vendor itself, with names and reasoning levels filled in from models.dev, so a model released this morning shows up on the next refresh. No model list is built into magpie.
Presets include Anthropic · OpenAI · Google Gemini · DeepSeek · Kimi · Zhipu GLM · MiniMax · StepFun · Qwen · Baidu Qianfan · Tencent Cloud · Huawei Cloud MaaS · Volcengine Ark · Mistral · Groq · xAI · OpenRouter · Together · Fireworks · SiliconFlow · NVIDIA NIM · ModelScope · Ollama · LM Studio … and any OpenAI-compatible or Anthropic-compatible URL.
Already set up somewhere else? Import reads the providers you set up in CC Switch, Claude Code, Codex and Alma. Add to magpie links let a provider's website hand its config to magpie in one click.
Routing that keeps going
A routing group is several models that an agent picks as one: group/daily-coding. The gateway spreads requests over every member's keys and accounts:
| Mode | What it does |
|---|---|
smart |
Of the subscriptions with quota left, use the one whose allowance renews soonest, so less is lost at the reset |
order |
Use the first model until it can't answer, then the next |
rotate |
Move to the next member on each turn |
usage |
Use the least-used member first |
pace |
Use the account with the most of its week left per hour until its reset |
Conversations stay with the account that answered them while the vendor's prompt cache is still worth keeping. Intent routing goes further: a small model you choose reads each new turn, so tests can go to the strong model and quick questions to the fast, cheap one. Groups can contain other groups. The Routing tab shows each decision live.
|
|
Sign in once, use it everywhere
An agent you're signed in to is a subscription with models behind it, so magpie offers it as a provider. Several accounts per subscription are supported, and magpie fails over between them.
- Claude: drives the real local
claudebinary and bridges your agent's tools over MCP - Codex / ChatGPT: your ChatGPT plan's models in every other agent
- GitHub Copilot, Gemini (Code Assist), Antigravity, Grok (SuperGrok), Devin, Cursor and others
- Any OpenCode auth plugin or pi package from npm:
magpie plugin add opencode-gemini-auth # an OpenCode plugin from npm
magpie plugin add pi-antigravity # a pi package, the same way
magpie plugin login google-plugin # its own sign-in flow, in magpie
magpie runs plugins on Bun, which it downloads the first time a plugin needs it. A plugin signs in, lists its models and makes each request. Agents use its models like any other provider's. Browse the community plugins at magpie-community/plugins, or write your own.
A plugin can also be gateway middleware: JavaScript run inside magpie's gateway on what every agent sends and gets back, whatever the provider. onRequest can rewrite a request or turn it away, onEvent sees each streamed event, and onResponse sees a whole reply. It runs in-process, so an event costs about a microsecond, and a hook that throws or runs too long leaves the request as it was.
// alias.middleware.js — magpie plugin add ./alias.middleware.js
export function onRequest(body, ctx) {
if (body.model === "fast") return { ...body, model: "deepseek/deepseek-chat" };
}
Ready-made middleware, most of it what New API does for its channels, with the same JSON, is under Plugins › Discover › Gateway middleware:
| Package | What it does |
|---|---|
param-override |
New API's param_override: set, delete, move or rewrite request fields, under conditions, or turn a request away |
model-map |
New API's model_mapping: send a model under another name; replies keep the name asked for |
system-prompt |
Your system prompt on every request, or some agents' or models' |
word-guard |
New API's sensitive-word filter: turn away or mask words in what users send, and in replies |
think-tags |
Take <think>…</think> out of replies, or put reasoning_content into them |
magpie plugin add @magpie-community/middleware-model-map
magpie plugin options model-map '{"mapping": {"fast": "deepseek/deepseek-chat"}}'
See Gateway middleware.
Usage and cost tracking
- Tokens, cache reads and writes, reasoning tokens and calls, with cost at list price. You can set your own prices for each model.
- Balances and quota windows for every key, plan and subscription account (
magpie quota). The reset reminder warns you before a window renews with much of it unused. - Usage by session: each agent conversation with its cost and title, and a command to resume it.
- Usage by account and by upstream key, so you can check a vendor's bill line by line.
- OTLP export to your own observability stack.
Share one magpie
- Share it on your network. Turn on Share on local network, then create a named gateway key for each client, each with its own daily, weekly or monthly token and cost limit.
- Remote magpie. A laptop can use the providers, accounts and routing groups of the magpie on your desktop, while still wiring its own agents.
- Docker. Run
ghcr.io/yetone/magpieon a server or a NAS, and manage it from the web UI. - Sync. Back up to a file, or keep machines in sync over WebDAV (Nutstore, Nextcloud…) or S3.
Library: instructions, MCP servers and skills
Write your instructions, MCP servers and skills once. magpie writes them into each agent's own files in that agent's own format. It removes only what it wrote, so everything else in those files stays as it was.
Supported agents
|
Claude Code · Claude Desktop · Codex · Gemini CLI · OpenCode · OpenChamber · MiMo Code · Pi · Aside · OmO · Goose · Cursor CLI · Zed · VS Code Chat · VS Code Insiders · JetBrains Air · Copilot CLI · Crush · DeepSeek Harness · Command Code · fx · oh-my-pi · Devin · Hermes Agent · Mister Morph · Kimi Code · Muse Code · Empryo · MiniMax Code · Droid · Cline · Qoder · Qoder CN · Grok Build · ZCode · WorkBuddy · T3 Code · OpenHanako · AtomCode · Alma |
magpie shows only the agents installed on your machine. Anything else that takes a base URL can use the gateway too:
export OPENAI_BASE_URL=http://127.0.0.1:3425/v1 OPENAI_API_KEY=magpie
export ANTHROPIC_BASE_URL=http://127.0.0.1:3425 ANTHROPIC_API_KEY=magpie
export GOOGLE_GEMINI_BASE_URL=http://127.0.0.1:3425 GEMINI_API_KEY=magpie
Zed-compatible Agent paths
Magpie can use a Zed-compatible fork or installation whose executable or configuration directory is different from the upstream defaults. Set these variables before starting Magpie:
export MAGPIE_ZED_BIN=/Applications/ZedG.app/Contents/MacOS/zedg
export MAGPIE_ZED_CONFIG_DIR="$HOME/.config/zed"
export MAGPIE_ZED_PROCESS_NAMES=zedg,ZedG
magpie serve
MAGPIE_ZED_BIN controls installation detection, MAGPIE_ZED_CONFIG_DIR
selects the directory containing settings.json, and
MAGPIE_ZED_PROCESS_NAMES supplies comma-separated process names used for
restart notices. The existing Zed configuration adapter is reused, so this is
intended for forks that keep Zed's settings.json and Agent model schema, such
as ZedG. These variables affect
the Magpie process in which they are set; put them in the service environment
when running Magpie under systemd or Docker. They configure a Zed-compatible
Agent on the same machine as Magpie; they do not discover or modify an Agent
running on another host. On macOS, if the configured binary does not resolve to
a .app bundle, Magpie falls back to the standard Zed application locations
when authorizing the gateway credential.
Quick start
1. Install. Download the app from usemagpie.ai, or run:
curl -fsSL https://usemagpie.ai/install.sh | sh
Mac builds are signed and notarised. Every build updates itself. Behind a firewall, use --proxy or --mirror. You can also use go install github.com/yetone/magpie@latest, or the Docker image.
2. Add a provider. Open magpie, then go to Providers → Add provider. Pick a preset, or sign in with a subscription.
3. Pick a model for each agent on the Agents page. Start a new agent session and it uses the new model.
Or do the same from the terminal:
magpie provider add deepseek sk-… # a preset needs only the key
magpie claude deepseek/deepseek-v4-pro # Claude Code on DeepSeek
magpie codex moonshot/kimi-k2.5 # Codex on Kimi
magpie group add "Opus anywhere" models=claude/claude-opus-5-5,copilot/claude-opus-5.5 routing=smart
magpie claude group/opus-anywhere # fails over between subscriptions
magpie save work && magpie use work # profiles
magpie quota # what's left on every plan
magpie tui # the whole thing, in a terminal
Documentation
- Get started: the guided tour
- Reference: every agent, provider option, gateway endpoint, CLI command and file
- Plugins: use plugins and write your own
- Intent routing: route each turn by what it asks for
- Import links: "Add to magpie" buttons for provider websites
Community
Questions, ideas or a model that won't show up? Join us on Discord or open an issue.
If magpie saves you from editing one more config file, a ⭐ helps others find it.