@cortexkit/opencode-anthropic-auth 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +35 -845
  2. package/dist/cli-failure.d.ts +6 -5
  3. package/dist/cli.js +57 -103
  4. package/dist/custody-mode.d.ts +1 -0
  5. package/dist/{index-52r2e1h9.js → index-5hyennzm.js} +1 -1
  6. package/dist/{index-p4wvcwhh.js → index-fncp6r0j.js} +1 -1
  7. package/dist/index-jmjevtm1.js +2 -0
  8. package/dist/index-kd89hcr3.js +2 -0
  9. package/dist/index-mdpyfkv3.js +464 -0
  10. package/dist/index-nfcp0m1t.js +42 -0
  11. package/dist/index-qttfa42y.js +2 -0
  12. package/dist/{index-3xqv3rw3.js → index-rftced5v.js} +1 -1
  13. package/dist/{index-zdgceztz.js → index-vjehtqnb.js} +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/quota-preflight.d.ts +1 -0
  16. package/dist/rpc/port-file.js +1 -1
  17. package/dist/rpc/protocol.js +1 -1
  18. package/dist/rpc/rpc-client.js +1 -1
  19. package/dist/rpc/rpc-dir.js +1 -1
  20. package/dist/setup/command.d.ts +5 -14
  21. package/dist/setup/native-activation.d.ts +14 -6
  22. package/dist/setup/native-enrollment.d.ts +15 -0
  23. package/dist/setup/native-local.d.ts +31 -1
  24. package/dist/setup/process-fence.d.ts +0 -6
  25. package/dist/setup/types.d.ts +9 -0
  26. package/dist/sidebar-state.d.ts +20 -2
  27. package/dist/sidebar-state.js +1 -1
  28. package/dist/transform.d.ts +17 -2
  29. package/dist/tui-preferences.js +1 -1
  30. package/dist/tui.d.ts +0 -2
  31. package/dist/v2/activation.d.ts +2 -0
  32. package/dist/v2/adapter.d.ts +8 -2
  33. package/dist/v2/cachekeep.d.ts +19 -0
  34. package/dist/v2/menu.d.ts +2 -1
  35. package/dist/v2/server.js +4 -4
  36. package/dist/v2/setup.d.ts +2 -0
  37. package/dist/v2/source.d.ts +1 -0
  38. package/dist/v2/tui.js +1 -1
  39. package/package.json +5 -5
  40. package/src/sidebar-state.ts +165 -29
  41. package/src/tui-compiled/sidebar-state.ts +165 -29
  42. package/src/tui-compiled/tui.tsx +363 -239
  43. package/src/tui.tsx +149 -48
  44. package/dist/index-04syas8a.js +0 -2
  45. package/dist/index-b3mxpp4w.js +0 -2
  46. package/dist/index-ynq181e8.js +0 -42
  47. package/dist/index-yxtdke11.js +0 -449
  48. package/dist/setup/activation.d.ts +0 -7
  49. package/dist/setup/command.test.d.ts +0 -1
  50. package/dist/setup/detect.d.ts +0 -8
  51. package/dist/setup/host-executable.d.ts +0 -3
  52. package/dist/setup/jsonc.d.ts +0 -9
  53. package/dist/setup/opencode-config.d.ts +0 -18
  54. package/dist/setup/pi.d.ts +0 -18
package/README.md CHANGED
@@ -1,864 +1,54 @@
1
- # CortexKit Anthropic Auth for OpenCode and Pi
1
+ # @cortexkit/opencode-anthropic-auth
2
2
 
3
- Claude Pro/Max OAuth support for both [OpenCode](https://opencode.ai) and [Pi](https://pi.dev), maintained by CortexKit.
3
+ Use Claude Pro/Max subscriptions in [OpenCode](https://opencode.ai) 1 and 2 with `@cortexkit/opencode-anthropic-auth`. The companion `@cortexkit/pi-anthropic-auth` package supports [Pi](https://pi.dev); both integrations use the shared `@cortexkit/anthropic-auth-core` package.
4
4
 
5
- This repo is a Bun workspace monorepo with two user-facing integrations and one shared core package. The OpenCode package is a CortexKit-maintained fork of the original `@ex-machina/opencode-anthropic-auth` plugin. The Pi package is a native Pi extension that replaces the implementation of Pi's built-in Anthropic provider while keeping its `anthropic` provider ID and model IDs. Both integrations share the same Anthropic OAuth, account-pool, quota, prompt-cache, relay, dump, and request-signing logic through `@cortexkit/anthropic-auth-core`.
5
+ ## Why use it
6
6
 
7
- > [!IMPORTANT]
8
- > These instructions describe the upcoming native release, which is not yet published.
7
+ - Multiple Claude accounts with ordered fallbacks, quota-aware routing and per-session account affinity.
8
+ - Prompt-cache controls and optional cache keepalive for active sessions.
9
+ - Optional Claustrum integration: Claustrum is a local credential-vault service that supplies Claude accounts instead of each application's local account pool.
10
+ - An optional user-owned Cloudflare relay to reduce repeated request uploads.
9
11
 
10
- ## Packages
12
+ ## Disclaimer
11
13
 
12
- | Package | Agent | Purpose |
13
- | --- | --- | --- |
14
- | `@cortexkit/opencode-anthropic-auth` | OpenCode | OpenCode plugin and CLI for Claude OAuth, request rewriting, fallback accounts, quotas, cache controls, dumps, and relay setup. |
15
- | `@cortexkit/pi-anthropic-auth` | Pi | Pi extension that replaces the implementation of Pi's built-in Anthropic provider, keeping the `anthropic` provider ID and model IDs. |
16
- | `@cortexkit/anthropic-auth-core` | Shared | Reusable OAuth, account, quota, cache, relay, dump, SSE, and request-signing logic used by both integrations. |
17
-
18
- ## Support matrix
19
-
20
- | Capability | OpenCode | Pi |
21
- | --- | --- | --- |
22
- | Claude Pro/Max OAuth (local) | Local account pool, filled by `setup` migration, `setup --login`, or `/connect anthropic` | Local account pool, filled by `setup` migration, `setup --login`, or the `/claude` menu |
23
- | Claude accounts from the Claustrum vault | Optional, enrolled separately through `setup` | Optional, enrolled separately through `setup` |
24
- | Provider integration point | OpenCode plugin fetch/request transform (OpenCode 1 and OpenCode 2) | Pi `registerProvider("anthropic")`, replacing the built-in implementation |
25
- | Local account pool | `~/.config/opencode/anthropic-auth-pool.json` | `~/.pi/agent/anthropic-auth-pool.json` |
26
- | Old sidecar (migration source only) | `~/.config/opencode/anthropic-auth.json` | `~/.pi/agent/anthropic-auth.json` |
27
- | Slash command | `/claude` menu | `/claude` menu |
28
- | Menu actions not available in Pi | — | Refresh quota, killswitch, Prime on/off, lane start |
29
- | Quota sidebar widget | OpenCode TUI plugin via `tui.json` | Not available |
30
- | Fallback accounts, quota routing, relay, dumps, fast mode | Supported | Supported through the same shared core |
31
-
32
- ## What CortexKit adds over the original plugin
33
-
34
- - **Fallback Claude accounts**: keep a main Claude account and route to ordered fallback OAuth accounts or API-key routes on auth/quota/rate-limit failures.
35
- - **Routing modes**: choose **Routing mode** → `sticky-balanced` in the `/claude` menu to spread new sessions across OAuth accounts by current quota headroom while keeping each session on one account, or choose `main-first` / `fallback-first` ordering.
36
- - **Quota-aware routing**: skip main or fallback accounts when their 5-hour or 7-day Claude quota falls below your configured minimum.
37
- - **Persistent Claude cache controls**: manage Anthropic 1-hour prompt caching from the `/claude` menu's Cache group with explicit, automatic, or hybrid modes.
38
- - **Cache keepalive**: use **Keep cache warm always** or **Cache keep window** to pre-warm hybrid cache anchors for active sessions before the 1-hour TTL expires.
39
- - **Quota window priming**: opt in with **Enable Prime** to start each 5-hour quota window about one minute after it resets instead of waiting for the next normal prompt.
40
- - **Lane start (OpenCode only)**: use **Fire lane start** to send one synthetic, one-token turn through the current session's normal model, agent, variant, quota, routing, cache, and request pipeline.
41
- - **Fast mode toggle**: use **Enable fast mode** / **Disable fast mode** to request Anthropic fast mode for supported Opus models (`claude-opus-4-8`, `claude-opus-5`, and `claude-opus-5-5`).
42
- - **Adaptive reasoning visibility**: request summarized adaptive thinking for Claude Fable 5/5.1, Mythos 5/5.1, Opus 5/5.5, and Sonnet 5.5. OpenCode exposes native `low`, `medium`, `high`, `xhigh`, and `max` effort variants for Fable 5.1, Opus 5/5.5, and Sonnet 5.5. On Opus 5.5, thinking is always on (adaptive summarized) per the model specification. OAuth Fable 5.1 sessions can change effort between turns without rewriting the cached prefix.
43
- - **Claude Haiku 5.5**: `claude-haiku-5-5` supports a 1M context, 128K output and native `low` through `max` adaptive effort. Forced tool choice remains supported. Configured `error` or `drop_block` behavior handles replayed thinking after earlier conversation content changes. Explicit disabled thinking is preserved, with incompatible `xhigh`/`max` effort capped to `high`; manual budgets and sampling parameters are removed. Standard input/output rates are $0.10/$0.50 per million tokens, with fivefold request-wide rates above 100K total input including cache. OAuth model costs are zeroed by default. Opt-in quota-window priming uses Haiku 4.5 to start a new quota window.
44
- - **Fable/Opus 5 and 5.5 safety fallback (OpenCode)**: eligible OAuth requests try Anthropic's server-side safety fallback first. The plugin preserves Anthropic's fallback conversation boundary across OpenCode history and automatically starts its deterministic 10-response Opus 4.8 recovery if the response still ends in refusal. The TUI sidebar and OpenCode Desktop report the active target model and restoration. Set `OPENCODE_ANTHROPIC_AUTH_FALLBACK_MODE=legacy` to bypass the server policy and use client-side recovery exclusively.
45
- - **Live quota visibility**: the `/claude` menu's Quota group shows main and fallback quota state, reset times, and refresh errors.
46
- - **Host-local quota feed (OpenCode)**: optionally publish sanitized response-header quota observations so another local CortexKit process can reuse fresh account state without polling Anthropic's rate-limited usage endpoint.
47
- - **Quota sidebar widget**: register the OpenCode TUI plugin in `tui.json` to render a live sidebar with per-account quota, routing, cache, and health state.
48
- - **Killswitch (OpenCode menu)**: per-account hard-block thresholds that stop requests before hitting Anthropic's rate limits, with synthetic 429 retry-after when all accounts are exhausted.
49
- - **User-owned Cloudflare relay**: optionally provision your own Worker relay to reduce repeated client upload bytes for large OpenCode or Pi requests.
50
- - **Optional Claustrum vault custody**: enroll OpenCode or Pi with setup so it serves Claude accounts from the vault instead of its local account pool.
51
- - **Claude-compatible request hardening**: Claude Code 2.1.280 identity and final-body billing signing, user-turn prompt and request lineage across OpenCode tool loops, live-session-stable billing suffixes, Fable 5.1 thinking-prefix recovery, safer token refresh persistence, replay-safe fallback retries, and subagent cache isolation.
52
-
53
- ## What these integrations do
54
-
55
- - Let OpenCode and Pi use Claude Pro/Max OAuth credentials instead of an Anthropic API key.
56
- - In OpenCode, intercept the final Anthropic request and rewrite it into the Claude-compatible shape expected by Anthropic OAuth access.
57
- - In Pi, replace the implementation of Pi's built-in Anthropic provider, keeping its provider and model IDs, with one that uses the same Claude-compatible request path.
58
- - Add Claude billing headers with stable `cc_version`, OpenCode user-turn `cc_prompt_id`/`cc_prev_req` lineage, and body-derived `cch` signing.
59
- - Keep Claude OAuth accounts and API-key routes in a per-host local account pool, or serve accounts from an enrolled Claustrum vault.
60
- - Keep local OAuth tokens fresh in the background.
61
- - Apply quota thresholds before routing to main or fallback accounts.
62
- - Add one `/claude` menu for accounts, quota, routing, limits, cache, diagnostics, fast mode, Prime, and lane start.
63
- - Optionally relay large requests through a Cloudflare Worker owned by the user.
64
-
65
- ## Quick setup (recommended)
66
-
67
- In this guide, a *host* is OpenCode or Pi. Setup is an *offline* step: every OpenCode, LiteCode, and Pi process must be closed while it runs. Offline does not mean without network; setup still uses the network, for example to install packages and to sign in to Claude. Quit those processes, then run:
68
-
69
- ```bash
70
- bunx @cortexkit/opencode-anthropic-auth setup
71
- ```
72
-
73
- What setup does:
74
-
75
- - detects OpenCode, Pi, `ck`, and a running Claustrum daemon (Claustrum is a local credential-vault service; `ck` is its command-line tool), and lets you select which hosts to configure;
76
- - adds `@cortexkit/opencode-anthropic-auth` to `opencode.jsonc` (or `opencode.json`) and `tui.jsonc` (or `tui.json`), and installs `@cortexkit/pi-anthropic-auth` with `pi install`;
77
- - migrates each selected host to its local account pool, unless you choose Claustrum vault custody;
78
- - enrolls each selected host in the vault when you choose vault custody (it asks, and defaults to no).
79
-
80
- Setup refuses to change anything while an OpenCode, LiteCode, or Pi process is running.
81
-
82
- | Flag | Effect |
83
- | --- | --- |
84
- | `--yes`, `-y` | Do not prompt. Selects every detected host and keeps local custody unless `--claustrum` is also given. |
85
- | `--dry-run` | Print the planned actions and change nothing. |
86
- | `--login` | Sign in to Claude during setup and store that account as the main account in the local pool. |
87
- | `--claustrum` | Choose vault custody. Takes effect only when the Claustrum daemon is running and `ck` is installed; otherwise setup keeps local custody. Cannot be combined with `--login`. |
88
- | `--no-claustrum` | Keep local custody without asking. |
89
- | `--remove-pi-auth` | With `--yes`, consent to moving a stored Pi Anthropic login (see [Pi stored logins](#pi-stored-logins)). Plain `--yes` is not consent. |
90
-
91
- ---
14
+ This project is not affiliated with or endorsed by Anthropic. Using Claude subscriptions outside Anthropic's official clients may violate Anthropic's terms and can lead to account restrictions or suspension. Use it at your own risk.
92
15
 
93
16
  ## Install
94
17
 
95
- ### OpenCode
96
-
97
- Add the OpenCode plugin to your OpenCode configuration:
98
-
99
- ```json
100
- {
101
- "plugin": ["@cortexkit/opencode-anthropic-auth"]
102
- }
103
- ```
104
-
105
- Pinning is strongly recommended for any OpenCode plugin. Replace `VERSION` with the release you install:
106
-
107
- ```json
108
- {
109
- "plugin": ["@cortexkit/opencode-anthropic-auth@VERSION"]
110
- }
111
- ```
112
-
113
- OpenCode 1 and OpenCode 2 load the same package. After changing plugin config, restart OpenCode.
114
-
115
- > [!TIP]
116
- > If OpenCode keeps using an old build, clear OpenCode's plugin cache with `rm -rf ~/.cache/opencode` and restart.
117
-
118
- ### Pi
119
-
120
- Install the Pi package with Pi's package manager:
121
-
122
- ```bash
123
- pi install npm:@cortexkit/pi-anthropic-auth
124
- ```
125
-
126
- To pin a release, replace `VERSION` with its version number and keep the quotes: `pi install "npm:@cortexkit/pi-anthropic-auth@VERSION"`.
127
-
128
- To try it for one run without adding it to Pi settings:
129
-
130
- ```bash
131
- pi -e npm:@cortexkit/pi-anthropic-auth
132
- ```
133
-
134
- The Pi package replaces the implementation of Pi's built-in Anthropic provider; the `anthropic` provider ID and model IDs stay the same. It authenticates from the local account pool or the vault, not from Pi's `/login anthropic` credential. Run [setup](#quick-setup-recommended) before starting Pi.
135
-
136
- Pi's files live in `~/.pi/agent/` by default. `PI_CODING_AGENT_DIR` or `PI_AGENT_DIR` changes that directory, and `PI_ANTHROPIC_AUTH_FILE` changes the old sidecar path from which the pool's location is derived.
137
-
138
- ## Accounts and credential custody
139
-
140
- OpenCode and Pi each take Claude credentials from exactly one source:
141
-
142
- - **Local custody** (default): the host's local account pool.
143
- - **Vault custody**: the Claustrum vault, after the host is enrolled through setup.
144
-
145
- The host's Claustrum enrollment record decides which credential source requests use; settings files do not. An approved enrollment keeps the host on the vault even if its token file is missing, so the host refuses rather than falling back to local accounts. If the enrollment record cannot be read, requests the plugin would serve refuse until it is repaired or disconnected; ordinary API-key authentication is unaffected. See [the custody contract](https://github.com/cortexkit/anthropic-auth/blob/main/docs/custody-state-machine.md) for the full contract.
146
-
147
- ### Local account pool
148
-
149
- The pool holds the host's Claude OAuth accounts and Anthropic-compatible API-key fallback routes, plus plugin settings. One OAuth account is the main account, tried first by default; the others are fallbacks, tried in order when the main account is unusable. The pool's location follows the host's old sidecar path: its files are created in the same directory, so `OPENCODE_ANTHROPIC_AUTH_FILE` and `PI_ANTHROPIC_AUTH_FILE` move the pool too.
150
-
151
- | Host | Pool | Old sidecar (migration source) |
152
- | --- | --- | --- |
153
- | OpenCode | `~/.config/opencode/anthropic-auth-pool.json` | `~/.config/opencode/anthropic-auth.json` |
154
- | Pi | `~/.pi/agent/anthropic-auth-pool.json` | `~/.pi/agent/anthropic-auth.json` |
155
-
156
- Private credential state is kept beside the pool in `anthropic-auth-pool-state.json`. Every process of a host shares that host's pool. OpenCode and Pi keep separate pools.
157
-
158
- Setup migrates each host once, while OpenCode, LiteCode, and Pi are closed:
159
-
160
- - Fallback accounts, API-key routes, and settings from the old sidecar files are imported into the pool. The old sidecar files are not read afterwards.
161
- - OpenCode's stored Claude OAuth login becomes the main account in OpenCode's pool. OpenCode keeps only an inert placeholder: a fixed, non-secret marker that is not a usable credential and only tells OpenCode to route Claude requests through the plugin. A stored OpenCode API key is left unchanged.
162
- - Pi's stored Anthropic OAuth login is moved into the pool only with your consent.
163
-
164
- Requests refuse until migration has completed; they never fall back to credentials still stored in OpenCode's or Pi's own auth file. Before importing a stored main OAuth login, migration checks the Claude account UUID in the legacy main profile. That profile's recorded access-token fingerprint must match the host login; migration does not query Anthropic for identity. If it cannot, it changes nothing and tells you to run:
165
-
166
- ```bash
167
- bunx @cortexkit/opencode-anthropic-auth setup --login --no-claustrum
168
- ```
169
-
170
- `--login` opens a Claude sign-in during setup and stores the account as the main account.
171
-
172
- ### Signing in
173
-
174
- In local custody, after running setup (see [Local account pool](#local-account-pool)), add the main account in any of these ways:
175
-
176
- - **OpenCode 1**: run `/connect anthropic` and choose **Claude Pro/Max**. The account is saved in the local pool; OpenCode stores only the inert placeholder.
177
- - **OpenCode 2**: connect Anthropic and choose **Claude Pro / Max (native account pool)**.
178
- - **Pi**: after setup completes, open `/claude`, then use **Start OAuth sign-in** and **Finish OAuth sign-in**. The first account becomes the main account; later accounts are fallbacks, tried when the main account cannot serve.
179
- - **Any host**: `setup --login`, while the host is stopped.
180
-
181
- OpenCode's stock API-key options (**Create an API Key** and **Manually enter API Key** in OpenCode 1) remain ordinary OpenCode API-key authentication. The plugin passes those requests through unchanged.
182
-
183
- Local sign-in refuses while the host is enrolled in the vault (see [Claustrum vault custody](#claustrum-vault-custody)), with `Disconnect from the vault first.`
184
-
185
- ### Claustrum vault custody
186
-
187
- Vault custody is optional and chosen per host. Quit every OpenCode, LiteCode, and Pi process, make sure the Claustrum daemon is running and `ck` is installed, then run:
188
-
189
- ```bash
190
- bunx @cortexkit/opencode-anthropic-auth setup --claustrum
191
- ```
192
-
193
- For each selected host, setup proposes the `anthropic-auth-opencode` or `anthropic-auth-pi` enrollment, approves it with `ck auth enroll approve`, and grants that enrollment read access to the `anthropic-native` credential category (`ck auth grant --principal enrolled:anthropic-auth-<host> --selector-kind category --selector anthropic-native --operation read`). It then refreshes the vault inventory and requires its default Anthropic credential (`oauth:anthropic`) to have a vault-reported account identity; otherwise it stops with `The vault has no verified default Claude account. Sign in through the vault and rerun setup.`
194
-
195
- Vault setup writes the selected host's enrollment and, for Pi with your consent, Pi's auth file (see [Pi stored logins](#pi-stored-logins)). It does not read, import, change, or delete the local pool, migration journal, local runtime metadata, or routing assignments, it never imports local OAuth accounts into the vault, and it does not write OpenCode's auth file. If the vault reports that an earlier enrollment request was replaced by a newer one, already used, or no longer exists, setup clears that request and stops; run setup again.
196
-
197
- After setup, select the vault in the host:
198
-
199
- - **OpenCode 1**: run `/connect anthropic` and choose **Claude via credential vault**. This option appears only while OpenCode holds a vault enrollment, and it checks OpenCode's Anthropic login slot without changing it. If OpenCode already holds an Anthropic login, or the slot cannot be read, it refuses: remove that login with OpenCode's own tools, then choose the vault login, or disconnect from the vault. An OpenCode OAuth login other than the vault placeholder is never used while enrolled; requests refuse with `This host uses the credential vault, but OpenCode holds a separate Anthropic login. Remove it and choose the vault login, or disconnect from the vault.`
200
- - **OpenCode 2**: connect Anthropic and choose **Claude vault accounts**. It refuses unless OpenCode is enrolled.
201
- - **Pi**: no extra step; see [Pi stored logins](#pi-stored-logins).
202
-
203
- API keys stored in OpenCode are never changed and keep working as stock OpenCode authentication in every custody state, including an unreadable enrollment. OpenCode 2 serves a request only when it carries the plugin's placeholder; API keys from OpenCode's login, configuration, or environment, and any other connection, pass through unchanged.
204
-
205
- While a host is enrolled:
206
-
207
- - Claude accounts come only from the vault's scoped inventory. The vault's default account is the main account. Accounts added with `ck auth login --provider anthropic` are discovered without a restart and receive an initial quota check.
208
- - Every model request, quota or profile query, quota-window priming request, and cache keepalive request obtains fresh vault authorization. A vault refusal never falls back to a local credential.
209
- - Local pool accounts, including API-key routes, are not used, refreshed, quota-polled, kept warm, or shown. They stay unchanged and return after disconnect.
210
- - If the vault's default account changes to a different Claude account, sessions pinned to the old default are assigned afresh; other session pins are kept.
211
- - If the vault has no usable Claude account, requests refuse. Add accounts with `ck auth login --provider anthropic`, or disconnect from the vault.
212
- - The `/claude` menu still enables and disables vault accounts and resets recorded retry waits, but hides local sign-in, API-key additions, account removal and reordering, and enrollment reset.
213
-
214
- ### Pi stored logins
215
-
216
- Pi prefers its stored login over the extension's credentials. Setup asks before moving or stashing that login; with `--yes`, pass `--remove-pi-auth` to consent.
217
-
218
- - **Local custody**: setup moves Pi's stored Anthropic OAuth login into the local pool and removes Pi's copy. Until that happens, Pi refuses to serve with `Pi still has a host Anthropic OAuth credential. Run offline setup to migrate it and approve its removal before using the native pool.`
219
- - **Vault custody**: setup moves Pi's stored Anthropic login (OAuth or API key) into a private stash and leaves a fixed, non-secret API-key marker in Pi's auth file so Pi does not refresh the stashed OAuth login. Disconnecting restores the original login byte-for-byte before the enrollment is removed.
220
-
221
- ### Disconnecting from the vault
222
-
223
- Open `/claude` and choose **Disconnect from the vault** in the Accounts group. The action is offered while the host is enrolled, and also when the enrollment record cannot be read, so a damaged record can always be cleared. It asks for confirmation:
224
-
225
- ```text
226
- Disconnect this host from the vault and return to local accounts? The vault keeps this host's enrollment approved until an operator revokes it there.
227
- ```
228
-
229
- Disconnect never reads or changes OpenCode's stored sign-ins. For Pi, it restores the stashed login first. If Pi's auth file already holds a different login, disconnect stops, keeps both logins and the enrollment, and asks you to resolve them with setup. After a successful disconnect, the host returns to its local pool. If that pool has never been migrated, stop the hosts and run `setup --no-claustrum`; disconnect does not perform migration.
230
-
231
- Only the setup command creates or polls enrollment requests. In local custody, **Reset host enrollment** clears a denied or blocked enrollment request without proposing a new one; run setup afterwards. It never resets a pending request or an approved enrollment.
232
-
233
- ## Settings
234
-
235
- Plugin settings live in the host's local account pool (and, while the host is enrolled in the vault, in a separate `anthropic-auth-vault-settings.json`). Change the settings that have a `/claude` menu action from the menu; see [The /claude menu](#the-claude-menu).
236
-
237
- During migration, setup imports these settings from the old sidecar file (`~/.config/opencode/anthropic-auth.json` or `~/.pi/agent/anthropic-auth.json`, or the paths set by `OPENCODE_ANTHROPIC_AUTH_FILE` and `PI_ANTHROPIC_AUTH_FILE`). The old file is not read after migration. The imported shape is:
238
-
239
- ```json
240
- {
241
- "version": 1,
242
- "main": { "type": "opencode", "provider": "anthropic" },
243
- "fallbackOn": [401, 403, 429],
244
- "routing": {
245
- "mode": "main-first"
246
- },
247
- "refresh": {
248
- "enabled": true,
249
- "intervalMinutes": 10,
250
- "refreshBeforeExpiryMinutes": 240
251
- },
252
- "quota": {
253
- "enabled": true,
254
- "checkIntervalMinutes": 5,
255
- "minimumRemaining": {
256
- "five_hour": 10,
257
- "seven_day": 20
258
- },
259
- "failClosedOnUnknownQuota": true,
260
- "showToasts": false
261
- },
262
- "quotaHeaderFeed": {
263
- "enabled": false
264
- },
265
- "killswitch": {
266
- "enabled": false,
267
- "main": { "five_hour": 5, "seven_day": 10, "scoped": 0 },
268
- "accounts": {}
269
- },
270
- "claudeCache": {
271
- "enabled": false,
272
- "mode": "explicit"
273
- },
274
- "cacheKeep": {
275
- "enabled": false,
276
- "always": false,
277
- "startHour": 9,
278
- "endHour": 23
279
- },
280
- "dump": {
281
- "enabled": false
282
- },
283
- "claudeFast": {
284
- "enabled": false
285
- },
286
- "thinkingBinding": {
287
- "prefixMismatchBehavior": "account-default"
288
- },
289
- "costZeroing": {
290
- "enabled": true
291
- },
292
- "relay": {
293
- "enabled": false,
294
- "url": "https://opencode-anthropic-relay.example.workers.dev",
295
- "token": "relay-shared-secret",
296
- "transport": "http",
297
- "fallbackToDirect": true
298
- },
299
- "accounts": []
300
- }
301
- ```
302
-
303
- The `routing` block holds the routing mode, `claudeCache` the cache mode, `cacheKeep` the cache keepalive schedule, and `claudeFast` the fast-mode switch; the `/claude` menu changes all of them. Killswitch `scoped` thresholds apply to model-specific quota windows, such as a separate weekly limit for Claude Fable models (`claude-fable-*`). OpenCode zeroes Anthropic OAuth model costs by default because OAuth usage is quota-based; set `costZeroing.enabled` to `false` only if you want OpenCode to display the provider's model pricing instead. Set `quota.showToasts` to `true` to opt into OpenCode quota toast notifications after quota refreshes.
304
-
305
- `thinkingBinding.prefixMismatchBehavior` controls replayed signed/redacted thinking on OAuth Fable 5.1 requests. `account-default` (the default) sends no explicit prefix-mismatch override. Use `error` to make prefix changes fail deterministically during compaction testing, or `drop_block` to ask Anthropic to discard mismatched thinking blocks. The beta header is added only when an explicit behavior is configured and replayable thinking is present.
306
-
307
- `quotaHeaderFeed.enabled` is an OpenCode-only, restart-required opt-in. It publishes only allowlisted quota-window values, an opaque account reference, an observation timestamp, and the configured OAuth-account count; it never publishes tokens, raw headers, request bodies, model IDs, or refresh errors. Per-process lease files use owner-only permissions under `$TMPDIR/opencode-anthropic-auth/quota-header-feed`, expire after three minutes, and can be redirected with `OPENCODE_ANTHROPIC_AUTH_QUOTA_FEED_DIR`.
308
-
309
- Private runtime data (OAuth tokens, API-route keys, token refresh backoff, quota snapshots, and quota API backoff) is kept in `anthropic-auth-pool-state.json`, separate from settings. `sticky-balanced` session assignments use `anthropic-auth-pool-routing-state.json` in local custody and `anthropic-auth-vault-routing-state.json` in vault custody; session IDs are SHA-256 hashed in both.
310
-
311
- ## Fallback accounts
312
-
313
- Fallback accounts are separate Claude OAuth accounts or Anthropic-compatible API-key routes in the local pool, or additional accounts in the vault while the host is enrolled. By default, the main account is tried first unless quota policy says it is currently unusable. Fallbacks are then tried in account order when the primary request returns a configured fallback status.
314
-
315
- In the `/claude` menu, choose **Routing mode** → `fallback-first` to prefer usable fallback accounts before the main account, `main-first` to restore the default, or `sticky-balanced` to allocate each new session to an OAuth account according to its remaining quota above your configured minimums in the 5-hour, 7-day, and any model-specific window. The choice persists and takes effect on the next request without restarting. **Reset routing session** clears only the current session's assignment so its next request is allocated again.
316
-
317
- `sticky-balanced` normalizes quota headroom by time until reset and accounts for prompt bytes assigned since the last quota refresh, so new sessions do not crowd the same account before fresh quota arrives. Assignments are persisted by hashed session ID in `anthropic-auth-pool-routing-state.json` (`anthropic-auth-vault-routing-state.json` while enrolled in the vault), shared safely across OpenCode plugin instances and restarts. Sessions whose 1-hour prompt cache is already kept warm by background requests keep their current route when the mode is first enabled, avoiding a cache-losing account switch. Changing the user-selected model discards the old assignment and its model-specific CacheKeep preference before quota-based reselection; transparent safety-recovery model changes retain the original account.
318
-
319
- Session affinity, keeping a session on the same account, survives network/relay failures, 5xx responses, unconfirmed 429s, quota-probe failures, and relative quota changes. Confirmed 7-day or matching model-scoped exhaustion migrates a session. Confirmed 5-hour exhaustion migrates only when more than 15 minutes remain; otherwise the plugin retains the route and returns `Retry-After`. When a Claude Fable model returns a content-filter refusal and OpenCode temporarily switches the session to Opus 4.8 (see [Safety fallback](#safety-fallback)), the Fable request, the Opus 4.8 turns, and the cache prewarm sent before returning to Fable stay on the same assigned account. Direct Opus sessions first prefer an otherwise usable account whose Fable quota is exhausted.
320
-
321
- Default fallback statuses:
322
-
323
- ```json
324
- [401, 403, 429]
325
- ```
326
-
327
- Add and inspect OpenCode fallback accounts with the CLI (local custody only, after running setup for OpenCode):
328
-
329
18
  ```bash
330
- bunx @cortexkit/opencode-anthropic-auth login personal-alt
331
- bunx @cortexkit/opencode-anthropic-auth api add kie-opus
332
- bunx @cortexkit/opencode-anthropic-auth list
333
- ```
334
-
335
- Prefer npm? Use `npx -y @cortexkit/opencode-anthropic-auth ...` with the same subcommands. `login` and `api add` save to OpenCode's local pool and never change OpenCode's auth file; both refuse with `Disconnect from the vault first.` while OpenCode is enrolled in the vault, because vault accounts then replace the local pool. `api add` reads `OPENCODE_ANTHROPIC_AUTH_API_BASE_URL`, `OPENCODE_ANTHROPIC_AUTH_API_KEY`, and `OPENCODE_ANTHROPIC_AUTH_API_AUTH_HEADER` instead of prompting when they are set.
336
-
337
- In both hosts, the `/claude` menu's Accounts group offers the same local changes: **Start OAuth sign-in** / **Finish OAuth sign-in**, **Add API-key fallback**, **Enable account**, **Disable account**, **Remove account**, **Move account up**, and **Move account down**. Account actions ask for the complete account ID shown in the account status.
338
-
339
- API fallback routes use `Authorization: Bearer <key>` by default and rewrite requests to the configured Anthropic-compatible base URL. For Kie, use `https://api.kie.ai/claude` as the base URL; the plugin appends `/v1/messages` automatically. API-key routes are only eligible after direct evidence that the main OAuth quota is exhausted: a fresh quota reading for the current Claude account showing 0% remaining, or an actual main OAuth model response with HTTP 429 / streaming rate-limit error followed by a live quota check that confirms 0% remaining. Low-but-nonzero quota, stale cached quota, unconfirmed 429s, 401, or 403 do not trigger API-key routes. API-route keys are stored with the pool's private state, separate from public route settings. **Add API-key fallback** selects either `authorization-bearer` or `x-api-key` for the authentication header.
340
-
341
- OpenCode cost accounting stays simple: when the native Anthropic auth entry is OAuth, OpenCode sees zero-cost Claude OAuth models by default. If a request falls through to an API-key route, token accounting is still recorded, but OpenCode's built-in dollar cost is not route-aware. To retain Anthropic model pricing for OAuth sessions during migration, set `costZeroing.enabled` to `false` in the old `anthropic-auth.json` before the first local setup. Setup imports that setting; the menu does not expose it.
342
-
343
- The CLI manages only OpenCode's locally stored Claude accounts and API-key fallbacks. Add Pi fallback accounts from Pi's `/claude` menu.
344
-
345
- Fallback retries are only attempted when the request body is safely replayable. If the original body is non-replayable or already consumed, the plugin returns the primary response unchanged.
346
-
347
- ### Token refresh
348
-
349
- Local OAuth tokens refresh in the background so idle accounts do not expire before they are needed. Refresh token rotation is persisted immediately. The plugin also re-reads the latest stored account before refreshing, which avoids using stale refresh-token snapshots when multiple background paths run close together. Persisted refresh backoffs are bound to the refresh token that produced them, so replacing a rejected credential immediately clears the backoff left by the old refresh token. In vault custody, the vault alone refreshes credentials.
350
-
351
- If Anthropic reports `invalid_grant`, that account must be signed in again. **Reset account backoff** in the `/claude` menu's Accounts group manually clears the main account's refresh backoff and its matching quota backoff.
352
-
353
- ## Quota-aware routing
354
-
355
- When `quota.enabled` is true, the plugin checks Anthropic's OAuth usage endpoint and applies the configured remaining-quota thresholds to both main and fallback accounts.
356
-
357
- Example:
358
-
359
- ```json
360
- "minimumRemaining": {
361
- "five_hour": 10,
362
- "seven_day": 20
363
- }
364
- ```
365
-
366
- With this config, an account is skipped when it has less than 10% remaining in the 5-hour window or less than 20% remaining in the 7-day window. The aliases `5h` and `1w` are also accepted.
367
-
368
- Main-account quota is cached. If the main account is known to be exhausted, the plugin skips it until the relevant reset time. If the cached main quota is stale but usable, the request proceeds and quota refresh happens in the background.
369
-
370
- Open `/claude` to see current quota state in the Quota group (**Quota summary**). It covers the main account and every fallback from the local pool, or from the vault while enrolled. In OpenCode, **Refresh quota** requests fresh quota; Pi shows the summary without that action.
371
-
372
- Reset times are rendered as relative durations, such as `resets in 10m` or `resets in 1h 15m`.
373
-
374
- ### Quota header feed
375
-
376
- The optional quota header feed writes one lease file per process under `${TMPDIR:-/tmp}/opencode-anthropic-auth/quota-header-feed/`. Set `OPENCODE_ANTHROPIC_AUTH_QUOTA_FEED_DIR` to override the directory. Each file contains only quota headers observed by the process that wrote it. Each file records `lease_horizon_ms` (default 180000, three minutes). Consumers must discard entries whose `observed_at_ms` is in the future or at least that old, then combine fresh entries from every file and deduplicate by account. "Newest file wins" drops accounts seen by other processes.
377
-
378
- For each account, use the entry with the greatest `observed_at_ms` for quota values. Resolve `anthropic_account_uuid` from any entry in that account's group that carries it. During an upgrade, an older plugin process that is still running can write the newest entry without that field while an updated process writes entries that have it.
379
-
380
- Each entry always includes `anthropic_account_uuid`; an absent key identifies an older producer. Its value is provider-derived or `null`, never a local substitute. A consumer that sees `null` must count a gap, not fall back to `account_ref`: that field is a row ID local to one account store, not a global account identifier, so it must never be used to match accounts across stores.
381
-
382
- ## Safety fallback
383
-
384
- Eligible Fable 5/5.1 and Opus 5 OAuth requests try Anthropic's server-side safety fallback first. The plugin sends `fallbacks: "default"` with Anthropic's server-side fallback beta, preserves fallback conversation boundaries in OpenCode history, and reports model handoffs and restoration in the TUI sidebar or OpenCode Desktop. Follow-up requests may remain on Anthropic's selected fallback model for approximately one hour.
385
-
386
- If an eligible OAuth response still ends in refusal, CortexKit automatically starts its deterministic 10-successful-response Opus 4.8 recovery, prewarms the selected source model without the server-fallback opt-in, and then restores that model. If the refused response already completed a tool call, the plugin preserves that call and continues with its existing tool result instead of replaying the tool.
387
-
388
- Custom API-key routes do not receive the server-side fallback beta or request field.
389
-
390
- To bypass Anthropic's server policy and use deterministic client recovery from the first refusal, start OpenCode with:
391
-
392
- ```bash
393
- OPENCODE_ANTHROPIC_AUTH_FALLBACK_MODE=legacy opencode
394
- ```
395
-
396
- Legacy mode routes a refused Fable 5/5.1 or Opus 5 session through Opus 4.8 for 10 successful responses, prewarms the selected source model's cache, and then restores that model without first opting into Anthropic's server policy. Unset the variable and restart OpenCode to return to the default server-first policy with the same client recovery as a backstop.
397
-
398
- ## Killswitch
399
-
400
- The killswitch is a per-account hard-block that stops requests when remaining quota drops below configured thresholds, even if Anthropic's API would still accept them. Unlike `minimumRemaining` (which routes to fallback accounts), the killswitch removes accounts from the routing pool entirely.
401
-
402
- Killswitch settings have this shape; setup imports an existing `killswitch` block from the old sidecar file (`anthropic-auth.json`):
403
-
404
- ```json
405
- "killswitch": {
406
- "enabled": true,
407
- "main": {
408
- "five_hour": 5,
409
- "seven_day": 10,
410
- "scoped": 0
411
- },
412
- "accounts": {
413
- "work-alt": {
414
- "five_hour": 10,
415
- "seven_day": 20,
416
- "scoped": 0
417
- }
418
- }
419
- }
420
- ```
421
-
422
- Thresholds are remaining-percent values. With `five_hour: 5`, the account is killed when less than 5% of the 5-hour quota window remains. The optional `scoped` threshold applies to model-specific quota windows (for example a separate weekly limit for Claude Fable models, `claude-fable-*`) and blocks when the scoped remaining percent is at or below the threshold. Accounts without an entry in `accounts` fall back to the `main` thresholds. The aliases `5h` and `1w` are also accepted.
423
-
424
- Missing quota readings:
425
-
426
- - A positive 5-hour or 7-day floor requires a finite quota reading for that window. If the reading is missing or not a number, the account is blocked, whatever `quota.failClosedOnUnknownQuota` says.
427
- - With no positive floor, missing readings follow `quota.failClosedOnUnknownQuota`.
428
- - An explicit positive `scoped` floor requires scoped-window information for the account. If that information is missing, the account is blocked. A reported empty list of scoped windows shows the model has no separate window, so the scoped floor does not apply.
429
-
430
- Behavior:
431
-
432
- - When an account is killed, it is skipped during routing. Surviving accounts are tried instead.
433
- - When all accounts (main and all enabled fallbacks) are killed, the plugin returns a synthetic 429 response with a `retry-after` header set to the earliest quota reset time across all accounts.
434
- - On the first request after restart, the plugin eagerly fetches main quota so the killswitch evaluates immediately.
435
- - **Killswitch status** in the `/claude` menu's Limits group shows killswitch status and per-account killed/active state.
436
-
437
- Manage the killswitch from the `/claude` menu's Limits group: **Enable killswitch**, **Disable killswitch**, and **Set killswitch thresholds**. Enter thresholds as a JSON array of objects with `account` (the account ID shown in account status, or `main`), `fh` (5-hour), `sd` (7-day), and optional `scoped` values, for example:
438
-
439
- ```json
440
- [{"account":"main","fh":3,"sd":8,"scoped":0},{"account":"<account-id>","fh":5,"sd":10,"scoped":0}]
441
- ```
442
-
443
- Killswitch changes are persisted with the host's other plugin settings. Pi does not offer killswitch enable, disable, or threshold editing.
444
-
445
- ## The /claude menu
446
-
447
- Both hosts register one slash command, `/claude`. It opens a menu grouped by area; each action collects its own parameters, so typed arguments are not used (Pi rejects them and points you to the menu). Earlier separate `/claude-*` commands are no longer registered.
448
-
449
- | Group | Status shown | Actions | Pi |
450
- | --- | --- | --- | --- |
451
- | Accounts | Account status and usage | Enable account, Disable account, Remove account, Move account up, Move account down, Reset account backoff, Reset host enrollment, Add API-key fallback, Start OAuth sign-in, Finish OAuth sign-in, Custody setup guidance, Disconnect from the vault | All |
452
- | Quota | Quota summary | Refresh quota | Summary only |
453
- | Routing | Routing status | Routing mode (`main-first`, `fallback-first`, `sticky-balanced`), Reset routing session | All |
454
- | Limits | Killswitch status | Enable killswitch, Disable killswitch, Set killswitch thresholds | Not available |
455
- | Cache | Cache status, Cache keep status | Enable cache, Disable cache, Cache mode (`explicit`, `automatic`, `hybrid`), Keep cache warm always, Disable cache keep, Cache keep window, Cache keep for subagents (`on`/`off`) | All |
456
- | Diagnostics | Dump status, Logging status | Enable request dumps, Disable request dumps, Logging level (`error`, `warn`, `info`, `debug`, `trace`) | All |
457
- | Extras | Fast mode status, Prime quota window status | Enable fast mode, Disable fast mode, Enable Prime, Disable Prime, Fire lane start | Fast mode actions; Prime status without on/off |
458
-
459
- The Accounts actions shown depend on custody:
460
-
461
- - **Local custody**: every Accounts action except **Disconnect from the vault**.
462
- - **Vault custody**: the Accounts group shows `Accounts are managed in the vault. Disconnect from the vault to use local accounts.` Enable, disable, **Reset account backoff**, and **Disconnect from the vault** remain. Local sign-in, API-key additions, removal, reordering, **Reset host enrollment**, and **Custody setup guidance** are hidden and refused.
463
- - **Unreadable enrollment**: the Accounts group shows the same actions as vault custody, so **Disconnect from the vault** stays available.
464
-
465
- **Custody setup guidance** changes nothing; it explains that custody changes require stopping every OpenCode, LiteCode, and Pi process and running [setup](#quick-setup-recommended). **Remove account**, **Reset host enrollment**, and **Disconnect from the vault** ask for confirmation. Sign-in, API-key, guidance, and disconnect actions need an interactive session.
466
-
467
- In the OpenCode TUI, `/claude` opens an interactive dialog. Outside the TUI (OpenCode Desktop or headless), it posts a text summary of the menu. In Pi without a UI, it prints the status sections only.
468
-
469
- Command dialogs use a loopback-only RPC server (bound to `127.0.0.1`, bearer-authenticated) so the OpenCode server process can signal the separate TUI process. Its runtime directory defaults to a per-project path under the OpenCode state directory; override it with `OPENCODE_ANTHROPIC_AUTH_RPC_DIR`.
470
-
471
- ## Claude prompt cache control
472
-
473
- Both OpenCode and Pi control Anthropic's 1-hour ephemeral prompt-cache lifetime from the `/claude` menu's Cache group: **Enable cache**, **Disable cache**, and **Cache mode** (`explicit`, `automatic`, or `hybrid`). **Cache status** shows the current setting.
474
-
475
- Modes:
476
-
477
- - `explicit` keeps OpenCode's explicit cache breakpoints and adds `ttl: "1h"` to them.
478
- - `automatic` removes block-level cache controls and sends a top-level `cache_control` object.
479
- - `hybrid` (recommended) removes top-level automatic caching and uses explicit anchors for Magic Context's leading history plus a moving latest-user boundary. When the first message has multiple cacheable content blocks, hybrid anchors both the first and last block so a stable leading history block remains cached even if a volatile trailing block changes; otherwise it anchors the first two messages. It keeps the last stable system block in normal turns, and uses that slot for the previous user boundary when a tool-heavy step would exceed Anthropic's 20-block lookback.
480
-
481
- In OpenCode, subagent requests do not receive 1-hour TTL caching. The plugin detects child sessions through OpenCode's `x-parent-session-id` header, strips that internal header before forwarding to Anthropic, and leaves default ephemeral caching in place for those requests.
482
-
483
- ### Cache keepalive
484
-
485
- Cache keepalive keeps recently used hybrid-mode session caches warm while the agent process is running. Control it from the Cache group: **Keep cache warm always**, **Cache keep window** (start and end hour), **Disable cache keep**, and **Cache keep for subagents** (`on`/`off`).
486
-
487
- **Keep cache warm always** keeps tracked sessions warm continuously for as long as the agent process remains open. Windows use local 24-hour time and are start-inclusive/end-exclusive: start `9`, end `23` runs from 09:00 until 22:59, and overnight windows such as start `23`, end `9` are accepted.
488
-
489
- Cache keepalive only tracks requests when the cache is enabled in `hybrid` mode. For each active session seen in the configured schedule, the package keeps an in-memory clone of the latest rewritten Anthropic request and sends a non-streaming `max_tokens: 0` pre-warm request about five minutes before the 1-hour cache entry would expire. **Cache keep status** lists every live tracked session across OpenCode projects and plugin processes; Pi reports its own separately scoped live sessions.
490
-
491
- Request bodies, headers, and tokens remain in memory. A lease-backed file under the system temporary directory shares only session IDs and cache timing for cross-instance status; records from stopped processes disappear from status after about three minutes.
492
-
493
- Pre-warm requests preserve explicit cache anchors but remove response-only fields that Anthropic rejects with `max_tokens: 0`, such as streaming, enabled thinking, structured output format, and forced/any tool choice. The feature works only while OpenCode or Pi is running and the machine is awake, and cache writes are still billed when the cache entry is no longer warm.
494
-
495
- ## Claude quota window priming
496
-
497
- Quota-window priming is off by default. In OpenCode, turn it on or off with **Enable Prime** and **Disable Prime** in the `/claude` menu's Extras group; **Prime quota window status** shows its state and usage.
498
-
499
- When enabled, the plugin watches each OAuth account's 5-hour quota reset. About one minute after a confirmed reset, it sends one minimal `claude-haiku-4-5` request so the next window starts without waiting for a normal prompt. Usage is measured from response accounting.
500
-
501
- Scheduled fires happen only after the quota window has reset. If an idle account has no cached reset time, the plugin sends one bootstrap request to establish its first observed window. When several processes share an account store, each tries to create a claim file for that account and reset; creating the file is atomic, so exactly one process succeeds and sends the request.
502
-
503
- Claim files live in a temporary directory, separated by account store and credential lineage. Cleanup removes files older than six hours. Ordinary token refresh keeps the lineage; a new sign-in starts a new one. Private runtime state stores cumulative priming usage counters, not a history of primed windows. Legacy claim files are not migrated. Without the old claim, the new scheduler can treat an already primed window as unclaimed and send one extra request.
504
-
505
- Pi shows **Prime quota window status** but has no Prime on/off actions; enable or disable priming from OpenCode.
506
-
507
- ## OpenCode lane start
508
-
509
- **Fire lane start** in the `/claude` menu's Extras group is OpenCode-only. It queues one synthetic turn for the current session.
510
-
511
- The action fires immediately. The synthetic prompt, a turn generated by the plugin rather than typed by you, uses the session's current model, agent, and variant, then travels through the ordinary quota, routing, cache, relay, signing, and response pipeline. OpenCode shapes that OAuth request to `max_tokens: 1` while keeping streaming enabled, and correlates the request by its synthetic message ID. A queued turn means OpenCode accepted it into the session's queue; it does not mean Anthropic has completed the request.
512
-
513
- > [!IMPORTANT]
514
- > This is a real billed request. The one-token limit reduces generated output only; Anthropic still charges for prompt-cache reads and any new cache writes. Use it when you plan to resume the session before the refreshed cache expires.
515
-
516
- Pi does not offer **Fire lane start**, the command that warms the session's prompt cache.
517
-
518
- ### Cache diagnostics (beta)
519
-
520
- The `cache-diagnosis-2026-04-07` beta is measure-only. It asks Anthropic to report prompt-cache diagnostics; it does not change cache controls or routing. OpenCode captures the provider's top-level response ID as an opaque string and sends it as `diagnostics.previous_message_id` on the next request in the same session. The first request sends `null`.
521
-
522
- The `MC-CACHE-DIAG ` line is a versioned, one-line JSON record. Records and their beta side-channel are emitted only at debug level; choose **Logging level** → `debug` in the `/claude` menu's Diagnostics group to capture them. Because emission is gated on the runtime log level, an empty record stream is ambiguous between a quiet system and a level below debug — liveness checks must cross-reference an independent activity witness (billing, usage rows, or dumps) instead of reading silence as absence of cache traffic. Version `2` contains these fields:
523
-
524
- | Field | Type | Source |
525
- | --- | --- | --- |
526
- | `v` | `2` | Capture schema |
527
- | `source` | string | Observation path; known values are `"turn"`, `"start"`, and `"prewarm_cachekeep"`, but consumers must tolerate future values |
528
- | `synthetic` | boolean | Whether this observation was generated by plugin machinery rather than a real turn |
529
- | `account_id` | string | Persisted plugin-internal OAuth account identifier used by routing and the sidebar; stable across restarts and token refreshes, so consumers may key timelines on it. Opaque mixed key space (the main account is a sentinel string, fallbacks are UUIDs) — never validate its shape |
530
- | `betas_hash` | 16-character lowercase hex | xxHash64 (seed `0`) of the sorted `anthropic-beta` list actually sent, truncated to its first 16 hexadecimal characters |
531
- | `requested_model` | string, optional | Sent request-body model, present only when it differs from the served Anthropic response model |
532
- | `session_id` | string | OpenCode session affinity |
533
- | `ts_ms_received` | integer | Local response receipt time |
534
- | `model` | string | Anthropic response |
535
- | `is_subagent` | boolean | Original request context |
536
- | `ttl_sent` | `"1h" \| "5m" \| null` | Last valid cache breakpoint in the sent body |
537
- | `cache_read` | number | `usage.cache_read_input_tokens` |
538
- | `cache_creation` | number | `usage.cache_creation_input_tokens` |
539
- | `input_tokens` | number | `usage.input_tokens` |
540
- | `ephemeral_5m_tokens` | number | `usage.cache_creation.ephemeral_5m_input_tokens` |
541
- | `ephemeral_1h_tokens` | number | `usage.cache_creation.ephemeral_1h_input_tokens` |
542
- | `message_id` | string | Anthropic response top-level `id` |
543
- | `previous_message_id` | string \| null | Sent `diagnostics.previous_message_id` |
544
- | `diag_state` | `"absent" \| "server_null" \| "pending" \| "populated"` | Anthropic response envelope |
545
- | `miss_reason` | string, optional | `diagnostics.cache_miss_reason.type` |
546
- | `cache_missed_input_tokens` | number, optional | `diagnostics.cache_miss_reason.cache_missed_input_tokens` |
547
-
548
- `cache_missed_input_tokens` is a byte-derived, pre-tokenization magnitude indicator, not a token count: it can differ from and occasionally exceed `input_tokens`, so never difference it against usage fields.
549
-
550
- All required usage counters must be finite, non-negative numbers. A malformed required counter rejects the whole record rather than emitting a partial receipt.
551
-
552
- Consumers classifying these records should check `cache_read` before `miss_reason`: `cache_read > 0` is a fact and `miss_reason` is an interpretation, and facts win. On multi-turn agent traffic a populated `*_changed` reason routinely coexists with a full prefix hit (each turn appends messages), so a populated-first classifier inverts every such record into a false miss.
553
-
554
- Known sources map to `synthetic` as follows:
555
-
556
- | `source` | `synthetic` |
557
- | --- | --- |
558
- | `turn` | `false` |
559
- | `start` | `true` |
560
- | `prewarm_cachekeep` | `true` |
561
-
562
- Cache observations for the plugin-generated turn queued by **Fire lane start** appear as ordinary `MC-CACHE-DIAG ` records with `source: "start"`.
563
-
564
- `synthetic` wins on conflict. A disagreement for a known source is an emitter defect: OpenCode writes one warning and still emits the record with the supplied `synthetic` value. Unknown future sources have no mapping and must not be rejected by consumers.
565
-
566
- The first observation of each `betas_hash` in a process also writes `MC-CACHE-DIAG-BETAS {"hash":"…","betas":[…]}` at debug level on the `cache-diagnostics` logger channel. Its sorted beta list makes an observed hash interpretable without reconstructing headers; repeated hashes do not emit another side-channel line.
567
-
568
- The trailing space in `MC-CACHE-DIAG ` is load-bearing: a record line has a space after `MC-CACHE-DIAG`, while the beta side-channel line has a hyphen. Do not trim the delimiter or write a trimming consumer. `grep -c "MC-CACHE-DIAG"` over-counts because it includes beta lines; count records with `grep -c "MC-CACHE-DIAG "` or an anchored equivalent.
569
-
570
- The four diagnostic states are:
571
-
572
- | State | Response shape |
573
- | --- | --- |
574
- | `absent` | No `diagnostics` property |
575
- | `server_null` | `diagnostics: null` |
576
- | `pending` | `diagnostics.cache_miss_reason: null` |
577
- | `populated` | An object `diagnostics.cache_miss_reason` with a non-empty string `type`, including `"unavailable"` |
578
-
579
- Only valid Message envelopes produce an `MC-CACHE-DIAG ` record. Malformed or error responses are not mapped to `absent`; they retain ordinary response handling and dumps. `ttl_sent` is reduced from the last valid breakpoint in the actual body sent. A short-gap `previous_message_not_found` result is also recorded as a canary when the previous provider ID was captured less than five minutes earlier.
580
-
581
- `unavailable` is expected when any prompt-affecting parameter changes between requests. This includes the active Anthropic beta-header set; structured-output requests use a different beta set and can therefore produce `unavailable`. Diagnostics are scoped to the provider's cache fingerprint, organization, and workspace. Fingerprints expire, so a later request can miss after a long gap even when the body is unchanged. These records measure the result; they do not guarantee a cache hit.
582
-
583
- Diagnostics comparison requires a cacheable prefix. Requests below the model's cacheable minimum or without cache breakpoints return `diagnostics: null` even when the request genuinely changed; consumers must gate interpretation of `null` on observed cache activity.
584
-
585
- `diag_state` is always a string and never JSON null: `absent | server_null | pending | populated`.
586
-
587
- Version 1 records come from the unversioned-source era and cannot distinguish prewarms from turns; consumers must treat their source as unknown and cannot split machinery from traffic retroactively. Version 2 always states the source.
588
-
589
- When request dumps are enabled, each response gets a `.response.json` artifact containing status and parsed response metadata, but no response content. Lane-start requests are tagged `-start-`; CacheKeep prewarms retain `-prewarm-cachekeep-`. If Prime prewarming is enabled in a build that supports it, those artifacts use `-prewarm-prime`. Treat request bodies and related dump files as sensitive local debugging data.
590
-
591
- ## Claude fast mode
592
-
593
- Both OpenCode and Pi can save a fast-mode setting that applies to later requests and survives process restarts. It requests Anthropic fast mode for supported Opus models with **Enable fast mode** and **Disable fast mode** in the `/claude` menu's Extras group. **Fast mode status** shows the current setting.
594
-
595
- When enabled, supported requests add `speed: "fast"` to the Anthropic JSON body and include the `fast-mode-2026-02-01` beta header. Unsupported models are left at standard speed. Anthropic supports fast mode for `claude-opus-4-8`, `claude-opus-5`, and `claude-opus-5-5`. Opus 4.7 rejects `speed: "fast"`, while Opus 4.6 runs at standard speed; Claude Fable and Mythos 5/5.1 are not fast-mode models.
596
-
597
- Fast and standard speeds do not share prompt-cache prefixes, so switching this setting can cause cache misses.
598
-
599
- ### Estimate cache savings from OpenCode history
600
-
601
- The repo includes an OpenCode SQLite analyzer that compares estimated Claude cost under three scenarios: no prompt cache, Anthropic's default 5-minute cache, and this plugin's 1-hour cache mode.
602
-
603
- From a repo checkout:
604
-
605
- ```bash
606
- bun run analyze:cache -- --days 7
607
- ```
608
-
609
- Useful variants:
610
-
611
- ```bash
612
- # Restrict to one OpenCode session
613
- bun run analyze:cache -- --session ses_... --days 4
614
-
615
- # Emit machine-readable output
616
- bun run analyze:cache -- --days 7 --json
617
-
618
- # Use a non-default OpenCode DB path
619
- bun run analyze:cache -- --db ~/.local/share/opencode/opencode.db --days 30
620
- ```
621
-
622
- The script reads OpenCode usage data from `~/.local/share/opencode/opencode.db` by default. It uses recorded prompt, cache-read, cache-write, and output tokens, then estimates counterfactual 5-minute and no-cache costs from the same turns. Its pricing table includes Claude Opus 4.5 through 4.8. The default 5-minute expiry threshold is 5 minutes; override it with `--idle-threshold-min <minutes>` if needed.
623
-
624
- This analyzer is OpenCode-specific because it reads OpenCode's local message database.
625
-
626
- ## Optional Cloudflare relay
627
-
628
- The relay is opt-in and user-owned. CortexKit does not run shared relay infrastructure for this plugin.
629
-
630
- When enabled, the package sends large Anthropic request bodies to a Cloudflare Worker that you own. The first request for a session sends a full body; later requests send compact patches keyed by session affinity (`x-session-affinity` in OpenCode, Pi's stream `sessionId` in Pi). The Worker reconstructs the full Anthropic `/v1/messages` request and streams Anthropic's SSE response back to the client.
631
-
632
- `relay setup` saves HTTP transport:
633
-
634
- ```json
635
- "transport": "http"
636
- ```
637
-
638
- HTTP is the default because it also works with relay Workers deployed by older releases. It still sends compact payloads through your Worker: the full request body for a session's first request, then only the changes for later requests. WebSocket is an opt-in persistent session transport for OpenCode 1 and Pi:
639
-
640
- ```json
641
- "transport": "websocket"
642
- ```
643
-
644
- WebSocket mode uses protocol v2 on `/ws`, keeps one connection per session (OpenCode `x-session-affinity`, Pi stream `sessionId`), and serializes same-session requests until the previous stream finishes. Existing deployed Workers must be redeployed with this package's current Worker script before `"transport": "websocket"` will work; older relay Workers only understand the legacy protocol. OpenCode 2 supports direct and HTTP relay transport only; with WebSocket selected, it refuses requests before sending them with `request refused: WebSocket relay is not supported on OpenCode 2; select HTTP relay or direct transport`.
645
-
646
- Set up a relay in your Cloudflare account with the OpenCode package CLI. The CLI saves relay settings in OpenCode's local account pool, so run [setup](#quick-setup-recommended) for OpenCode first to prepare the local account pool before the CLI saves settings:
647
-
648
- ```bash
649
- CLOUDFLARE_API_TOKEN=... CLOUDFLARE_ACCOUNT_ID=... bunx @cortexkit/opencode-anthropic-auth relay setup
650
- ```
651
-
652
- Or with npm:
653
-
654
- ```bash
655
- CLOUDFLARE_API_TOKEN=... CLOUDFLARE_ACCOUNT_ID=... npx -y @cortexkit/opencode-anthropic-auth relay setup
656
- ```
657
-
658
- The setup command:
659
-
660
- 1. Creates a Cloudflare KV namespace.
661
- 2. Uploads the relay Worker module.
662
- 3. Generates a relay shared secret.
663
- 4. Enables the Worker.
664
- 5. Saves the relay URL, shared secret, and HTTP transport in OpenCode's local account pool.
665
-
666
- `relay setup` configures OpenCode's relay settings, not Pi's. During the first local setup, existing relay settings (including `transport`) are copied from `anthropic-auth.json` into that application's pool; the `/claude` menu has no relay actions.
667
-
668
- The Cloudflare API token is used only during setup and is not stored by the plugin. Re-running setup with the same Worker name uploads the current Worker script again; this is how existing relay Workers are upgraded for protocol changes such as WebSocket v2.
669
-
670
- If relay setup or transport fails before streaming begins, the plugin falls back to direct Anthropic requests unless `fallbackToDirect` is set to `false`.
671
-
672
- > [!NOTE]
673
- > The relay reduces upload bytes from your machine to Cloudflare. Anthropic still receives the complete `/v1/messages` request from the Worker, so the relay does not reduce Anthropic input tokens or billing by itself. Use prompt caching for server-side cache benefits.
674
-
675
- ### Relay diagnostics
676
-
677
- Relay diagnostics are written to a temp-file log:
678
-
679
- ```bash
680
- tail -f "$(node -p 'require("node:os").tmpdir()')/opencode-anthropic-auth.log"
681
- ```
682
-
683
- Successful relay usage logs entries such as:
684
-
685
- ```text
686
- configured transport=websocket protocol=2
687
- used relay transport=websocket protocol=2 mode=patch
688
- used relay transport=http protocol=1 mode=full_sync
689
- ```
690
-
691
- Direct fallback logs `falling back direct`.
692
-
693
- ### Request dumps
694
-
695
- For relay/cache debugging, enable exact request dumps from inside OpenCode or Pi with **Enable request dumps** and **Disable request dumps** in the `/claude` menu's Diagnostics group. **Dump status** shows the current setting.
696
-
697
- When enabled, the plugin writes artifacts under the OS temp directory:
698
-
699
- ```bash
700
- ls "$(node -p 'require("node:os").tmpdir()')/opencode-anthropic-auth-dumps"
701
- ```
702
-
703
- Each filename includes a sanitized session/affinity segment so dumps from different sessions are easier to find. Each request gets:
704
-
705
- - `*.body.json` — final rewritten Anthropic request body.
706
- - `*.meta.json` — hashes, byte counts, diff ranges, model, `messages[0]` hash, later-message hash, and cache-relevant structure.
707
- - `*.relay.json` — redacted relay payload/frame metadata for relay requests.
708
- - `*.request.json` — redacted direct request URL, method, and headers for direct requests.
709
-
710
- The dump setting is saved with the host's other plugin settings. Dumps may contain prompt content and should be treated as sensitive local debugging artifacts.
711
-
712
- ## Environment variables
713
-
714
- | Variable | Description |
715
- | --- | --- |
716
- | `ANTHROPIC_BASE_URL` | Override the Anthropic API endpoint. Must be HTTP(S). |
717
- | `ANTHROPIC_CUSTOM_HEADERS` | Add proxy-specific headers on API-key and proxy routes. Authentication, protocol, framing, and internal correlation headers cannot be overridden. Ignored for OAuth requests. |
718
- | `ANTHROPIC_MODEL` | Default proxy alias for any `claude-*` model. Ignored for OAuth requests. |
719
- | `ANTHROPIC_DEFAULT_SONNET_MODEL` | Proxy alias for `claude-sonnet-*` models. |
720
- | `ANTHROPIC_DEFAULT_OPUS_MODEL` | Proxy alias for `claude-opus-*` models. |
721
- | `ANTHROPIC_DEFAULT_HAIKU_MODEL` | Proxy alias for `claude-haiku-*` models. |
722
- | `ANTHROPIC_DEFAULT_FABLE_MODEL` | Proxy alias for `claude-fable-*` and `claude-mythos-*` models. |
723
- | `ANTHROPIC_INSECURE` | Set to `1` or `true` to skip TLS verification when `ANTHROPIC_BASE_URL` is set. |
724
- | `OPENCODE_ANTHROPIC_AUTH_FILE` | Override OpenCode's old sidecar path. The local account pool and its related files are created next to it. |
725
- | `OPENCODE_ANTHROPIC_AUTH_STATE_FILE` | Override the old sidecar state file that setup reads during migration. |
726
- | `OPENCODE_ANTHROPIC_AUTH_CLAUSTRUM_ENROLLMENT_FILE` | Override the owner-only OpenCode Claustrum enrollment-token path. |
727
- | `OPENCODE_ANTHROPIC_AUTH_CLAUSTRUM_CONNECTION_FILE` | Override the Claustrum connection file OpenCode uses. |
728
- | `OPENCODE_ANTHROPIC_AUTH_FALLBACK_MODE` | Set to `legacy` to bypass Anthropic's server policy and use deterministic 10-response client recovery exclusively. The default tries server-side safety fallback first and uses client recovery as a backstop. |
729
- | `OPENCODE_ANTHROPIC_AUTH_ROUTING_STATE_FILE` | Override the persistent sticky-balanced session assignment file. |
730
- | `OPENCODE_ANTHROPIC_AUTH_CACHEKEEP_REGISTRY_DIR` | Override the temporary OpenCode CacheKeep session lease directory. |
731
- | `OPENCODE_ANTHROPIC_AUTH_RPC_DIR` | Override the directory for the OpenCode TUI menu RPC bridge (port file + token). Defaults to a per-project path under the OpenCode state directory. |
732
- | `PI_ANTHROPIC_AUTH_FILE` | Override Pi's old sidecar path. The local account pool and its related files are created next to it. |
733
- | `PI_ANTHROPIC_AUTH_CLAUSTRUM_ENROLLMENT_FILE` | Override the owner-only Pi Claustrum enrollment-token path. |
734
- | `PI_ANTHROPIC_AUTH_CLAUSTRUM_CONNECTION_FILE` | Override the Claustrum connection file Pi uses. |
735
- | `PI_ANTHROPIC_AUTH_ROUTING_STATE_FILE` | Override the persistent Pi sticky-balanced session assignment file. |
736
- | `PI_ANTHROPIC_AUTH_CACHEKEEP_REGISTRY_DIR` | Override the temporary Pi CacheKeep session lease directory. |
737
- | `PI_CODING_AGENT_DIR`, `PI_AGENT_DIR` | Override Pi's agent directory when deriving default paths. |
738
- | `XDG_STATE_HOME` | Base directory for the default enrollment files (`cortexkit/anthropic-auth/<host>-enrollment.json`). Defaults to `~/.local/state`. |
739
- | `CLOUDFLARE_API_TOKEN` | Cloudflare token used by `bunx @cortexkit/opencode-anthropic-auth relay setup`. Not stored. |
740
- | `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account ID used by relay setup. |
741
-
742
- `ANTHROPIC_CUSTOM_HEADERS` and the model-alias variables apply only to API-key and proxy routes. OAuth requests keep the Claude Code header and model identity unchanged. Custom headers accept either a JSON object or comma/newline-separated `name: value` entries. A configuration containing an invalid or protected header is ignored as a whole with one redacted warning; it cannot replace route authentication, Anthropic protocol headers, body framing, or plugin-internal correlation headers.
743
-
744
- An `ANTHROPIC_BASE_URL` path is preserved. For example, `https://proxy.example/anthropic` sends requests to `/anthropic/v1/messages`, while a versioned base such as `https://proxy.example/anthropic/v2` sends to `/anthropic/v2/messages`. Existing version segments are not duplicated, and unrelated paths ending in `/messages` are not rewritten.
745
-
746
- ## Request rewriting
747
-
748
- For Claude Pro/Max OAuth requests, the plugin works at the final Anthropic wire-request layer:
749
-
750
- 1. Rewrites request URLs when `ANTHROPIC_BASE_URL` is configured.
751
- 2. Normalizes Claude-compatible OAuth headers and beta flags.
752
- 3. Removes OpenCode-specific identity text from system blocks.
753
- 4. Prepends Claude Code identity and billing-header blocks.
754
- 5. Rewrites cache controls according to the configured cache mode.
755
- 6. Renames MCP tool names into Claude-compatible PascalCase form.
756
- 7. Opts eligible Fable 5/5.1 and Opus 5 OAuth requests into Anthropic's server-side safety fallback, restores stored fallback boundaries, and activates replay-safe client recovery if the response still refuses.
757
- 8. Computes final-body `cch` over the fully serialized request body.
758
-
759
- The sanitizer is anchor-based: it removes paragraphs containing known OpenCode documentation or source anchors, performs a small set of inline replacements, and preserves the rest of the prompt including user/project instructions, tool policy, environment context, and file paths.
760
-
761
- ## Development
762
-
763
- Workspace layout:
764
-
765
- ```text
766
- packages/core Shared Anthropic auth core
767
- packages/opencode OpenCode plugin and CLI
768
- packages/pi Pi package/extension
769
- ```
770
-
771
- Install dependencies:
772
-
773
- ```bash
774
- bun install
775
- ```
776
-
777
- Run checks:
778
-
779
- ```bash
780
- bun run typecheck
781
- bun run test
782
- bun run build
783
- bun run lint
784
- bun run format:check
785
- ```
786
-
787
- ### Build modes
788
-
789
- Two build modes are available:
790
-
791
- ```bash
792
- bun run build # Deploy: bun build → bundled dist/ with all deps inlined (core + xxhash-wasm)
793
- bun run build:dev # Dev: tsc → individual dist/*.js files (requires workspace node_modules)
794
- ```
795
-
796
- The default `build` uses `bun build` to bundle `@cortexkit/anthropic-auth-core` and all transitive dependencies into self-contained output files. No `node_modules/` needed at runtime — the plugin works via `file://` path in OpenCode config:
797
-
798
- ```json
799
- {
800
- "plugin": ["file:///path/to/anthropic-auth/packages/opencode"]
801
- }
802
- ```
803
-
804
- `@opencode-ai/plugin` remains external (peer dep provided by OpenCode).
805
-
806
- Inspect package contents:
807
-
808
- ```bash
809
- bun run pack:core:dry
810
- bun run pack:opencode:dry
811
- bun run pack:pi:dry
812
- ```
813
-
814
- Test a local build with OpenCode:
815
-
816
- ```bash
817
- bun run dev
818
- ```
819
-
820
- This builds the plugin, symlinks the output into `.opencode/plugins/`, and starts `tsc --watch`. Restart OpenCode after starting the dev script and after rebuilds.
821
-
822
- Clean the local dev symlink with:
823
-
824
- ```bash
825
- bun run dev:clean
826
- ```
827
-
828
- ## Release
829
-
830
- This repo uses CortexKit's tag-driven release workflow.
831
-
832
- Preview a release:
833
-
834
- ```bash
835
- ./scripts/release.sh 1.9.0 --dry
19
+ bunx @cortexkit/opencode-anthropic-auth setup
836
20
  ```
837
21
 
838
- Create and push the release tag:
22
+ After setup:
839
23
 
840
- ```bash
841
- ./scripts/release.sh 1.9.0
842
- ```
843
-
844
- Wait for GitHub Actions:
24
+ OpenCode 1: open `/claude` → **Accounts** to sign in.
845
25
 
846
- ```bash
847
- ./scripts/wait-release.sh v1.9.0
848
- ```
26
+ OpenCode 2: In OpenCode, sign in to Anthropic with "Claude Pro / Max (native account pool)".
849
27
 
850
- The release workflow runs checks, publishes the core, OpenCode, and Pi packages to npm with provenance, and creates the GitHub release.
28
+ Pi: open `/claude` and use **Start OAuth sign-in**, then **Finish OAuth sign-in**.
851
29
 
852
- ## Troubleshooting
30
+ ## Documentation
853
31
 
854
- - Clear OpenCode's plugin cache after plugin config changes: `rm -rf ~/.cache/opencode`.
855
- - Start OpenCode or Pi again only after setup finishes; setup requires every host process to be stopped.
856
- - If an OpenCode fallback account shows `invalid_grant`, run `bunx @cortexkit/opencode-anthropic-auth login <label>` again for that account. For the main account, sign in again from the host (see [Signing in](#signing-in)) or stop the hosts and run `setup --login --no-claustrum`.
857
- - If requests refuse because the enrollment record cannot be read, repair the enrollment files or use **Disconnect from the vault** in `/claude`, which removes them and returns the host to local accounts.
858
- - If requests refuse because OpenCode holds a separate Anthropic login while enrolled in the vault, remove that login, then choose **Claude via credential vault** (OpenCode 1) or **Claude vault accounts** (OpenCode 2); or disconnect from the vault.
859
- - Tail relay diagnostics when debugging relay setup: `tail -f "$(node -p 'require("node:os").tmpdir()')/opencode-anthropic-auth.log"`.
860
- - Open `/claude` to inspect account status, quota, and refresh errors surfaced by the plugin.
32
+ - [Installation, configuration and manual registration](../../docs/installation.md#installation-and-configuration)
33
+ - [Features and host support](../../docs/features.md#features-and-host-support)
34
+ - [Models, thinking and fast mode](../../docs/models.md#models-thinking-and-fast-mode)
35
+ - [Accounts, routing and quota](../../docs/accounts-and-routing.md#accounts-routing-and-quota)
36
+ - [Settings and routing reference](../../docs/configuration.md#settings-and-routing-reference)
37
+ - [Vault custody](../../docs/vault.md#vault-custody)
38
+ - [Credential custody contract](../../docs/custody-state-machine.md#anthropic-credential-custody)
39
+ - [Commands and menus](../../docs/commands.md#commands-and-menus)
40
+ - [Cache, keepalive and quota priming](../../docs/cache.md#cache-keepalive-and-quota-priming)
41
+ - [Cache diagnostics](../../docs/cache-diagnostics.md#cache-diagnostics)
42
+ - [OpenCode 2](../../docs/opencode-2.md#opencode-2)
43
+ - [OpenCode sidebar and TUI preferences](../../docs/sidebar.md#opencode-sidebar-and-tui-preferences)
44
+ - [Environment variables](../../docs/environment.md#environment-variables)
45
+ - [Request rewriting and safety fallback](../../docs/request-rewriting.md#request-rewriting-and-safety-fallback)
46
+ - [Transports and request diagnostics](../../docs/transports.md#transports-and-request-diagnostics)
47
+ - [Troubleshooting](../../docs/troubleshooting.md#troubleshooting)
48
+ - [Development](../../docs/development.md#development)
49
+ - [Build modes](../../docs/build-modes.md#build-modes)
50
+ - [Upgrades, recovery and releases](../../docs/releases.md#upgrades-recovery-and-releases)
861
51
 
862
52
  ## License
863
53
 
864
- MIT
54
+ [MIT](../../LICENSE)