* agent: Ante takes magpie as a provider in ~/.ante/catalog.json Ante (antigma.ai, AntigmaLabs/ante) is asked for in #1179. Its catalog is ~/.ante/catalog.json ($ANTE_HOME moves the folder), merged on top of the providers it ships: a providers map keyed by the id --provider takes, each with base_url, wire_style (AnthropicMessage, OpenAiCompatible, OpenAiResponse or Gemini), an optional auth, and preferred_models, the ids its model picker shows (docs.antigma.ai, reference/catalog-reference). magpie adds the entry "magpie" at the gateway's /v1 on OpenAiCompatible, which is the wire style Ante speaks Chat Completions with and what the gateway takes every model on, and lists magpie's models in its preferred_models. The user's own providers and the models section are left as they are, and magpie's entry goes again when magpie steps out; a file magpie made goes with it. No auth block is written. The gateway listens on loopback and lets any token in from this machine (gateway.Token's own comment, lan.go's identifyCaller: "Loopback takes any token"), and Ante counts a provider with no auth as authenticated. A bearer env_key would mean putting the gateway's key into Ante's environment, which the user would have to do themselves -- the same decision Empryo's entry makes, which sends no key of the user's either. A gateway shared on the local network is another matter, and the same one every agent magpie wires has. Two things are deliberately left off a model's entry. A routing group is not told what it reasons at: which member answers, and what that member takes, is the group's own to decide per turn, and magpieModels sets no APIs for a group for the same reason. And support_vision is never written: Ante takes a model as seeing images unless told otherwise, and what magpie knows is only as good as a provider's own list -- a relay's models are often not described at all, so writing false would have Ante drop the reader's images before the gateway, which describes them to a model that can't see them itself (provider.Described). No other agent magpie wires declares it either. Ante ships macOS and Linux builds alone and suggests WSL on Windows, so the Windows machine's Ante is usually the one in a distro: wslKinds gains it beside Empryo, which also means the gateway address Ante is pointed at is the one that distro reaches magpie on (place.base), and a distro not known to be in mirrored networking gets the notice it already gets for the others. TestAnte covers a user's own providers and models section kept as they are, magpie's entry added and taken away, Sync repointing it, and a file magpie made going again. TestAnteKeepsTheUsersFile covers a catalog magpie can't parse costing magpie's provider and not the user's. TestAnteGroupSaysNoCapab ilities covers a group declaring neither effort nor support_vision. TestAnteEfforts covers the ladder: Ante's has no "none" or "minimal", its two lowest, so both are its "min", and the rungs come out in Ante's order whatever order magpie lists them in. Tried with a real Ante 0.2.9 in WSL Ubuntu: magpie wrote the catalog, and `ante catalog` then read 16 providers with magpie's among them, 39 models, and Ante filled in support_vision: true for each itself. Ante then ran a real turn through the gateway — `ante --provider magpie --model group/auto-deepseek-v4-1-flash -p …` answered, and magpie's own usage log has the request (ep /v1/chat/completions, req the group's id, served by one of its members, out 10) — and so did a second model on another provider. The gateway was reached over the Windows host's address from the distro (172.17.128.1), this machine's own being on 127.0.0.1 alone, which is what notMirrored tells the user about. go vet, gofmt -l and go build (linux nogui, windows) pass. go test -tags nogui ./internal/agent: 12 failures here, the same 12 on unmodified main (the Windows ones AGENTS.md lists). ./internal/gui and ./internal/provider: TestGatewayFixQuitsOnlyAMagpie, TestPurposeAssetMatchesUsage, TestUpdateThatWontStart and TestLoginUsageClaudeAskedMeanwhile, all four on unmodified main here too. docs/reference.md's adapter table gains Ante. * agent: Ante keeps the user's own keys, reads ANTE_HOME, sends no effort it wasn't told to, and starts Ante on magpie (#1210) Seven points from the review, each with a test that fails without it. 1. ANTE_HOME was in the file's own comment and in docs/reference.md but never read: the path was fixed to $HOME/.ante, so a user who set it had magpie write a catalog Ante does not look at. anteDir reads it through place.getenv, the way MiniMax Code reads MINIMAX_DATA_DIR, so a distro's own ANTE_HOME - which magpie can't read - still means ~/.ante there. "ANTE_HOME" joins agentenv.Vars so a sandbox clears it. 2. providers.magpie was written whole, so every key of the user's that magpie doesn't write - the auth block a gateway shared on the LAN or reached from WSL needs to send a key, http_headers, extra_body, stream_idle_timeout_secs, thinking_display - went at the next sync, and an unchanged catalog was rewritten every round. It goes through theirsKept and syncJSON now, as #1103 did for the others: the user's keys in magpie's entry stay, preferred_models is magpie's list alone, and a file that says the same as it does is left as it is. 3. The two files were written in separate steps, so a change that failed halfway left Ante's catalog without magpie's entry and its settings still naming magpie. Each field's Set and its Sync are wrapped in atomic(), as empryo, minimax and kimi do. 4. The comment said Ante's "min" was the rung it sends no effort at, and folded both magpie's "none" and its "minimal" into it. Ante's reference says what min is: "OpenAI-compatible providers send the selected level as the same-named reasoning_effort (min is sent as minimal)" - so min is a sent level, and magpie's "none" has no rung of Ante's to fold into. Ante's "min" is magpie's "minimal"; a model magpie knows only "none" of comes out as the empty list, which is Ante's own way of saying it takes no effort setting at all. 5. The default was the highest rung the model takes, so every model magpie listed ran at Ante's slowest and dearest level. No effort is written: "Omit for models with no reasoning knob (Ante then sends no effort parameter and hides the effort slider)". 6. Having magpie in the catalog never meant Ante used it. What a session starts on is the provider and the model of ~/.ante/settings.json; with neither set Ante "uses the first authenticated provider in catalog order", and Ante's own presets come before magpie's entry - so while the user has any of those signed in, that is the one picked and magpie is not. (Measured: nothing named in settings, two keyless providers ordered aaa_other then magpie, and the request went to aaa_other's port; settings provider=magpie and it went to magpie's.) magpie sets that pair now and saves what it found there, so Disconnect hands it back; a provider the user picks in Ante's own /providers while magpie is wired is theirs and stands, and Check says so instead of keeping quiet. Ante's settings name the model apart from the provider, so magpie writes the catalog id it put in preferred_models, un-prefixed, and reads a bare id as magpie's only beside magpie's provider. Tests lean on the package's own testenv, not a real ~/.ante. TestAnteSyncKeepsTheUsersKeys is modelled on ad3b7fe5's TestAirProviderWritesKeepCustomFields and goes both ways - sync and pick - and wants an unchanged file to keep its mtime. Tried with a real Ante 0.2.9 in WSL Ubuntu on this machine (Ante ships macOS and Linux builds alone; there is no Windows Ante here). The strongest of these is the whole of it: magpie's own Go code - ante(home).Connect(), then the model field - wrote a catalog.json and settings.json into a temp folder, that folder was handed to the real Ante as ANTE_HOME, and Ante ran a turn through it with no --provider, no --model and nothing typed by hand. - `ante doctor` read `home ok /tmp/ante-e2e` and `16 providers (1 authed), 108 models` from ANTE_HOME, and magpie's entry came back with the base_url it was given: ANTE_HOME really moves the folder, and a base_url already ending in /v1 is not doubled (the request went to /v1/chat/completions). - What a session starts on is settings.json's provider, measured against two keyless providers each answering on its own port, so the logged port names the one Ante asked. Catalog ordered aaa_other then magpie, nothing named in settings: Ante asked 44331, aaa_other - the first authenticated in catalog order, exactly the review's "很可能选不到 magpie". settings provider=magpie: it asked 44220, magpie. settings provider=aaa_other: 44331 again, so a pick the user makes in Ante's own /providers overrules what magpie wrote, which is why stepping out leaves it rather than handing back the one magpie found. And with magpie the only authenticated provider, auto-detection does reach it - so the catalog entry is not useless, it is simply not enough while the user has any other provider signed in, which is every real install. - What Ante sends for effort, from the same files: no reasoning_effort at all for a model with no effort written (item 5, as its reference says omitting it sends none); `--effort min` on a model sent `reasoning_effort: "minimal"` - Ante's min is magpie's minimal, exactly item 4; and a model Ante was told `"supported_efforts": []` for sent no reasoning_effort even when asked `--effort low`, which is what a none-only model now gets instead of a level that refuses it. - The user's own keys inside magpie's entry are ones Ante reads, not decoration: `ante catalog` hands back the entry's auth, http_headers, extra_body, stream_idle_timeout_secs and thinking_display unchanged, and a bearer env_key there makes `ante doctor` count the provider as the one authed. That is item 2. - The no-auth decision holds on Ante's side, isolated by doctor's counts: Ante's own presets alone read `15 providers (0 authed)`; a magpie with no auth block reads `(1 authed)`; the same magpie given a bearer env_key that isn't set drops back to `(0 authed)`; with the key set, `(1 authed)`. So an entry with no auth is authenticated and one that asks for a key the user doesn't have is not - writing an env_key, which the first version's comment considered, would have made magpie the one provider Ante refuses to auto-detect. - Ante fills `support_vision: true` in for itself, as the PR's own note said, and a routing group declared with no capabilities at all still worked. Not covered by that run: the stand-in server answered inside the distro, so this proves Ante's config handling end to end, not a live magpie gateway relay (the first commit's message records a real turn through one). Every probe used ANTE_HOME into a temp folder; this machine's real ~/.ante gained no catalog.json or settings.json. What each fix failed without it, one test each: taking ANTE_HOME out -> TestAnteHome "$ANTE_HOME ignored"; theirsKept out -> "the user's auth lost or changed"; syncJSON out -> "an unchanged catalog was rewritten"; atomic out -> "settings.json kept half of a change that failed"; the old min mapping -> "anteEfforts([minimal high]) = [high], want [min high]"; a written default -> "deepseek/pro: effort written"; settings never pointed at magpie -> TestAnte; a model never written -> TestAnteModelField; Check left quiet -> "moved off magpie: \"\""; handing magpie back over a pick the user made while wired -> TestAnteKeepsWhatTheUserPickedWhileWired; never restoring the model -> TestAnteConnectDisconnect "not put back"; Connect picking the model field instead of magpie as provider -> "Connect left the user's model beside magpie's provider"; ANTE_HOME kept out of agentenv.Vars -> TestFolderVarsAreListed. Taking preferred_models out of the whole list is the one mutation no test turns red on: mergeTheirs cannot merge a JSON array (sync.go returns want for it), so the file behaves the same either way and the argument is there for intent and for the other keys, not for behaviour. go vet ./... and go build ./... pass, as do GOOS=linux go build -tags nogui ./... and GOOS=windows go build ./..., and gofmt is clean on LF content (this clone has core.autocrlf and no .gitattributes, so gofmt -l reports every file). go test -tags nogui ./internal/agent fails twelve tests, and an untouched worktree of origin/main run the same command on this machine fails the same twelve, test for test; ./internal/agentenv, ./internal/appdir and ./internal/edit pass, and every Ante test passes at -count=5. The whole ./... was run on both: the failing sets are alike, origin/main having one more, TestLoginUsageClaudeAskedMeanwhile, already filed as #1228. None of those twelve is this change's, and none is fixed here. * docs: agent-wiring records that Ante keeps the user's keys in magpie's entry and starts on settings.json's provider (#1210) The two rules the review asked for, written where the repo keeps them - the same linesad3b7fe5(#1239) added for Air and2d9db1b6(#1242) for malformed configs. The Verification block gains the package's own Ante run, as #1239 added Air's. --------- Co-authored-by: wizzy-yang <wizzy-yang@users.noreply.github.com>
Subsystem design references
These pages describe current responsibilities, runtime paths, state, and contracts. Start with the subsystem relevant to your task, then follow its source links to verify the implementation you change.
| Subsystem | Reference |
|---|---|
| Built-in subscriptions moving to plugins | Provider and plugin ownership |
| Plugins that run on the gateway's requests and replies | Gateway middleware |
| Claude subscription turns across Claude Code runs | Claude subscription bridge |
| How the gateway picks a provider, key or account, and falls back | Gateway routing and fallback |
| Connecting an agent's config to the gateway, drift, disconnect, WSL twins | Agent wiring |
| Providers, keys, subscription accounts, refresh and allowance | Providers and accounts |
| Instructions, MCP servers, skills and RTK written into agents | Library |
Tray, panel, window, magpie web and the page's JSON API |
GUI app shell |
A subsystem can span several packages or repositories. Its reference describes the behavior those parts provide together; it does not need to list every function.
Maintain a reference
Update the owning reference in the same PR when a change alters a documented responsibility, interface, state transition, runtime path, compatibility rule, or failure behavior. An internal refactor that preserves these contracts does not require a prose change.
Keep each fact in one reference and link to it from agent instructions or other pages. Link to source files and named symbols rather than copying implementation details that change frequently. Explain field meanings and constraints that signatures alone do not express.
For a new reference, include the responsibilities and boundaries, source of truth, main runtime paths, state transitions, important constraints, and existing verification commands. Include failure and compatibility behavior where relevant. Document current behavior separately from proposed changes; the proposal belongs in its issue or PR.
Describe a PR's semantic changes
For each affected subsystem, explain the observable change with its trigger and before/after behavior. Include changes to interfaces, state, compatibility, and failure behavior when relevant. Link the affected reference, implementation, and verification evidence. State when a refactor preserves the documented behavior.
For example, a change to plugin adoption should explain which migration state and account condition trigger it, which implementation handles requests before and after adoption, and which test exercises that transition.
This is an author-provided explanation that a reviewer verifies against the diff and surrounding code. It is not an automatically proven compatibility verdict.
Review a change
- Identify the affected subsystem and the actual runtime path, including plugin or built-in ownership.
- Compare the claimed before/after behavior with the base and head implementation. Trace relevant callers and state transitions beyond the changed lines.
- Check that changed contracts appear in the owning reference and that source links still resolve.
- Check that the cited tests or runtime evidence exercise the claimed behavior. Report checks that were not run.
A documentation update alone does not prove the implementation. Existing tests and runtime evidence remain necessary for behavior changes.