Repository navigation
Description
Summary
Move all routing, killswitch, menu, and pacing logic into common-auth, and give each auth plugin the same routing modes and the same routing behavior. The sidebar must show the shared behavior without more work in each plugin. Each shared part must be a template that a plugin can change for a provider quirk, not a rule that it cannot change.
Current state
The default branches at these commits: common-auth 343c381, anthropic-auth 937b27b, openai-auth 5da845f, antigravity-auth 4533e06.
| Part | common-auth | openai-auth | anthropic-auth | antigravity-auth |
|---|---|---|---|---|
Routing modes (./routing: ordered, sticky-balanced, placements) |
Yes | Uses it | Own code | Own code |
| Killswitch floors | An input to ./routing. Floors are in the Limits section of ./commands. |
Uses it | Own code | Own code |
Command menu (./commands) |
Yes | Uses it | Uses it | Uses it |
Auth login menu (./auth-menu) |
Yes | Uses it | No login menu | Own code |
| Pacing | No | Own code | Own code | Own code |
| Reserve for each window | reservePercent, for sticky-balanced only |
Uses it | Own code | Own code |
The library has most of the routing and menu parts at this time. Two plugins do not use the routing part, and pacing is in each plugin.
Requested
- Routing and killswitch: anthropic-auth and antigravity-auth use
./routingfor mode resolution, admission,orderedandsticky-balancedrouting, and killswitch verdicts. Each plugin keeps its provider policy in its adapter. The section "Native policy that stays in the adapter" indocs/adoption-inventory.mdgives the policy that stays. - The same routing functions: each plugin gives the same
routing.modevalues and the same behavior for each value. The sidebar reads the mode, the order, and the killswitch state from shared code. Then a change in the library shows in each sidebar. - Menus and options: in each plugin, the auth menus and the option sections (Accounts, Quota, Routing, Limits) come from
./auth-menuand./commands. Provider-specific sections and menu items stay in the plugin. - Pacing: one shared pacing function in common-auth, for example in
./quotaor in a new./pacing. It reads no clock. The time is a parameter. Each plugin and each sidebar uses it. - Flexibility: each shared part has options or hooks for provider quirks. Examples are a status classifier, the
requiredLabelslist for admission, provider-specific window groups, and more menu sections. The shared behavior is the default. A plugin can replace one part and keep the other parts.
Follow-up: reserve mode
This is a different request, for after the parity work. It uses the shared pacing function from item 4.
- The reserve works on pacing, not on a constant percent. For each window, the pace is the share of the window time that is complete. An account that uses its quota faster than its pace uses its reserve.
- Routing uses accounts that are at or below their pace first.
- When the account in use gets above its pace, the routing mode selects the next step:
- Continue on the same account, above its pace, down to the killswitch floor. Then move to the next account.
- Move to a different account that is at or below its pace. Use accounts that are above their pace only when no account is at or below its pace.
- A margin for each window is an option: the percent above the pace that does not count as reserve use. The plugin sets the default.
- Thus the reserve gets smaller near the end of the window. At the end of the window, the pace lets the account use almost all of the window, and only the killswitch floor stays.
- The sidebar shows when an account is above its pace and uses its reserve.
The reservePercent input of routeSticky is a constant percent. This request adds a reserve that follows the pace, as a replacement or as a second type.
Activity
iceteaSA commentedon Oct 29, 2026
The body changed: the reserve mode in the follow-up section works on pacing, not on a constant percent.
Thus the reserve mode uses the shared pacing function in item 4.
oaiauth-alfonso commentedon Nov 2, 2026
Thanks for laying this out so clearly. We're doing it.
The plan moves routing modes, admission and killswitch floors, the wait-or-switch decision after a limit, shared pacing and the menu sections into common-auth, for all four auth plugins (openai-auth, anthropic-auth, antigravity-auth and claustrum-auth). Provider quirks stay in each plugin through hooks, as you suggested. The first step is a shared table of expected routing decisions that each plugin's adoption must pass, so behaviour that differs today is decided once instead of drifting.
The pace-based reserve in your follow-up is part of the plan, built on the shared pacing function.
We'll link the work here as it lands.
iceteaSA commentedon Nov 3, 2026
Desktop GUI plugins in OpenCode 2: how the shared quota view and menus could reach the desktop app
OpenCode 2.2.0 added experimental desktop GUI plugins (docs). A plugin package adds a
./gui-experimentalexport beside.and./tui. The export is one prebuilt CommonJS file, built with the Vite preset from@opencode/plugin/gui/vite. The desktop app loads it for each plugin inopencode.json(c), with no separate install step. This could carry the shared pieces of this issue into the desktop app as well as the TUI.What the GUI API offers for an auth plugin
Slotatsession.header, aTitlebarItempill, and aComposerPillwhose rows open a menu. Each can show the serving account and the remaining window. A sidePaneltab can hold the full view, with the same sections asquota-sidebar.SettingsPage(its own page, or a section on the General page) can hold routing mode, account order, killswitch floors and pacing margins.Commandentries (palette, keybind, optional/command) can run actions such as "switch account" or "reorder accounts".ctx.client.rpc(...). So the GUI reads the state that the server part already computes, and the window needs no credential access of its own.A possible shape for common-auth
quota-sidebar(OpenTUI) and a new GUI renderer (Solid) are two thin views over one model, and the shared table of expected routing decisions stays the one source of behaviour.@cortexkit/common-auth/guiwith one helper that the plugin's GUIsetupcalls to add the status pill or slot, the panel tab and the settings page. The Vite preset bundles every dependency except the modules the app provides (effect,solid-js,@opencode/plugin/gui,@opencode/clientand a few more). So the shared GUI code must import those from the app and must not bring its own copy.Registry(for example<owner>.quota), the other plugins add their rows withctx.add, and the owner renders one panel. A GUI-only package without a server part is also a valid plugin (its id is the package name), if a neutral owner is better than one of the four.Limits to know
opencode plugin update).opencode.json(c), not fromcli.json.opencodenamespace are reserved.If it helps, I can prototype a small
./gui-experimentalfor one auth plugin (a status pill and a settings page over one RPC snapshot) to test this shape before it goes into common-auth.