@cortexkit/opencode-anthropic-auth 1.22.0 → 2.0.0

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 (91) hide show
  1. package/README.md +259 -198
  2. package/dist/billing-lineage.d.ts +51 -0
  3. package/dist/cli-failure.d.ts +69 -0
  4. package/dist/cli.d.ts +16 -10
  5. package/dist/cli.js +111 -6
  6. package/dist/custody-dimensions.d.ts +19 -0
  7. package/dist/custody-mode.d.ts +46 -0
  8. package/dist/effort-history.d.ts +11 -2
  9. package/dist/fable-fallback.d.ts +1 -1
  10. package/dist/index-1jkyhgyr.js +2 -0
  11. package/dist/{index-bx5hsgf8.js → index-2arfb1y3.js} +2 -2
  12. package/dist/{index-926t2bzc.js → index-4ya27n12.js} +1 -1
  13. package/dist/{index-cgez4m0h.js → index-aaajxwzd.js} +1 -1
  14. package/dist/index-ae3fq4n6.js +42 -0
  15. package/dist/index-fds0s2j4.js +2 -0
  16. package/dist/index-nngmvczq.js +450 -0
  17. package/dist/index-pn597b6f.js +2 -0
  18. package/dist/{index-7f57ewkp.js → index-rqync0pc.js} +1 -1
  19. package/dist/index.js +1 -33
  20. package/dist/native-command.d.ts +19 -0
  21. package/dist/prime-manager-registry.d.ts +5 -1
  22. package/dist/rpc/notifications.d.ts +4 -3
  23. package/dist/rpc/port-file.js +1 -1
  24. package/dist/rpc/protocol.d.ts +15 -4
  25. package/dist/rpc/protocol.js +1 -1
  26. package/dist/rpc/rpc-client.d.ts +3 -1
  27. package/dist/rpc/rpc-client.js +1 -1
  28. package/dist/rpc/rpc-dir.js +1 -1
  29. package/dist/rpc/rpc-server.d.ts +5 -1
  30. package/dist/rpc/server-registry.d.ts +10 -0
  31. package/dist/setup/activation.d.ts +7 -0
  32. package/dist/setup/claustrum.d.ts +26 -0
  33. package/dist/setup/command-runner.d.ts +2 -0
  34. package/dist/setup/command.d.ts +20 -0
  35. package/dist/setup/command.test.d.ts +1 -0
  36. package/dist/setup/detect.d.ts +5 -0
  37. package/dist/setup/jsonc.d.ts +9 -0
  38. package/dist/setup/native-activation.d.ts +29 -0
  39. package/dist/setup/native-enrollment.d.ts +26 -0
  40. package/dist/setup/native-enrollment.test.d.ts +1 -0
  41. package/dist/setup/native-local.d.ts +20 -0
  42. package/dist/setup/native-login.d.ts +3 -0
  43. package/dist/setup/native-paths.d.ts +15 -0
  44. package/dist/setup/native-paths.test.d.ts +1 -0
  45. package/dist/setup/opencode-config.d.ts +18 -0
  46. package/dist/setup/paths.d.ts +15 -0
  47. package/dist/setup/pi.d.ts +18 -0
  48. package/dist/setup/process-fence.d.ts +20 -0
  49. package/dist/setup/process-fence.test.d.ts +1 -0
  50. package/dist/setup/types.d.ts +37 -0
  51. package/dist/sidebar-state.d.ts +3 -1
  52. package/dist/sidebar-state.js +1 -1
  53. package/dist/transform.d.ts +5 -1
  54. package/dist/tui/command-dialogs.d.ts +32 -2
  55. package/dist/tui-preferences.js +2 -2
  56. package/dist/v2/activation.d.ts +7 -0
  57. package/dist/v2/adapter.d.ts +276 -0
  58. package/dist/v2/install.d.ts +13 -0
  59. package/dist/v2/lifecycle.d.ts +8 -0
  60. package/dist/v2/menu-contract.d.ts +8 -0
  61. package/dist/v2/menu.d.ts +10 -0
  62. package/dist/v2/models.d.ts +6 -0
  63. package/dist/v2/ownership.d.ts +11 -0
  64. package/dist/v2/prime.d.ts +12 -0
  65. package/dist/v2/rpc.d.ts +50 -0
  66. package/dist/v2/server.d.ts +8 -0
  67. package/dist/v2/server.js +4 -0
  68. package/dist/v2/setup.d.ts +58 -0
  69. package/dist/v2/source.d.ts +41 -0
  70. package/dist/v2/tui.d.ts +13 -0
  71. package/dist/v2/tui.js +2 -0
  72. package/dist/v2/wire.d.ts +36 -0
  73. package/package.json +26 -6
  74. package/src/rpc/notifications.ts +37 -26
  75. package/src/rpc/protocol.ts +24 -7
  76. package/src/rpc/rpc-client.ts +18 -1
  77. package/src/rpc/rpc-server.ts +38 -8
  78. package/src/rpc/server-registry.ts +61 -0
  79. package/src/sidebar-state.ts +26 -2
  80. package/src/tui/command-dialogs.tsx +537 -68
  81. package/src/tui/entry.mjs +44 -18
  82. package/src/tui-compiled/rpc/protocol.ts +24 -7
  83. package/src/tui-compiled/rpc/rpc-client.ts +18 -1
  84. package/src/tui-compiled/sidebar-state.ts +26 -2
  85. package/src/tui-compiled/tui/command-dialogs.tsx +488 -95
  86. package/src/tui-compiled/tui.tsx +25 -7
  87. package/src/tui.tsx +38 -9
  88. package/dist/index-8aga2zwv.js +0 -4
  89. package/dist/index-d3f8g6ve.js +0 -428
  90. package/dist/index-sh51yqxs.js +0 -2
  91. package/dist/logger-jrkranbz.js +0 -1
package/README.md CHANGED
@@ -2,57 +2,94 @@
2
2
 
3
3
  Claude Pro/Max OAuth support for both [OpenCode](https://opencode.ai) and [Pi](https://pi.dev), maintained by CortexKit.
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 provider extension that overrides Pi's built-in Anthropic provider. Both integrations share the same Anthropic OAuth, fallback-account, quota, prompt-cache, relay, dump, and request-signing logic through `@cortexkit/anthropic-auth-core`.
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`.
6
+
7
+ > [!IMPORTANT]
8
+ > These instructions describe the upcoming native release, which is not yet published.
6
9
 
7
10
  ## Packages
8
11
 
9
12
  | Package | Agent | Purpose |
10
13
  | --- | --- | --- |
11
14
  | `@cortexkit/opencode-anthropic-auth` | OpenCode | OpenCode plugin and CLI for Claude OAuth, request rewriting, fallback accounts, quotas, cache controls, dumps, and relay setup. |
12
- | `@cortexkit/pi-anthropic-auth` | Pi | Pi package/extension that registers a CortexKit Anthropic provider under Pi's built-in `anthropic` provider ID. |
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. |
13
16
  | `@cortexkit/anthropic-auth-core` | Shared | Reusable OAuth, account, quota, cache, relay, dump, SSE, and request-signing logic used by both integrations. |
14
17
 
15
18
  ## Support matrix
16
19
 
17
20
  | Capability | OpenCode | Pi |
18
21
  | --- | --- | --- |
19
- | Primary Claude Pro/Max OAuth | OpenCode `/connect anthropic` | Pi `/login anthropic` |
20
- | Provider integration point | OpenCode plugin fetch/request transform | Pi `registerProvider("anthropic")` provider override |
21
- | Sidecar config | `~/.config/opencode/anthropic-auth.json` | `~/.pi/agent/anthropic-auth.json` |
22
- | Runtime state | `~/.config/opencode/anthropic-auth-state.json` | next to the Pi sidecar as `anthropic-auth-state.json` |
23
- | Commands | `/claude-cache`, `/claude-cachekeep`, `/claude-prime`, `/claude-start`, `/claude-routing`, `/claude-fast`, `/claude-quota`, `/claude-dump`, `/claude-killswitch` | `/claude-cache`, `/claude-cachekeep`, `/claude-prime` (status only), `/claude-routing`, `/claude-fast`, `/claude-quota`, `/claude-dump` |
24
- | Fallback accounts, quota routing, killswitch, relay, dumps, fast mode | Supported | Supported through the same shared core and Pi sidecar |
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 |
25
31
 
26
32
  ## What CortexKit adds over the original plugin
27
33
 
28
- - **Fallback Claude accounts**: keep each agent's normal Anthropic login as the primary account, then route to ordered fallback OAuth accounts on auth/quota/rate-limit failures.
29
- - **Routing modes**: use `/claude-routing sticky-balanced` to distribute cold sessions by current OAuth quota headroom while keeping each session on one account, or choose `main-first` / `fallback-first` ordering.
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.
30
36
  - **Quota-aware routing**: skip main or fallback accounts when their 5-hour or 7-day Claude quota falls below your configured minimum.
31
- - **Persistent Claude cache controls**: manage Anthropic 1-hour prompt caching from `/claude-cache` with explicit, automatic, or hybrid modes.
32
- - **Cache keepalive**: use `/claude-cachekeep always` or `/claude-cachekeep HH-HH` to pre-warm hybrid cache anchors for active sessions before the 1-hour TTL expires.
33
- - **Quota window priming**: opt in with `/claude-prime on` to start each 5-hour quota window about one minute after it resets instead of waiting for the next normal prompt.
34
- - **Lane start (OpenCode only)**: use `/claude-start` to fire one synthetic, one-token turn through the current session's normal model, agent, variant, quota, routing, cache, and request pipeline.
35
- - **Fast mode toggle**: use `/claude-fast on|off` to request Anthropic fast mode for supported Opus models.
36
- - **Adaptive reasoning visibility**: request summarized adaptive thinking for Claude Fable 5/5.1, Mythos 5/5.1, and Opus 5. OpenCode exposes native `low`, `medium`, `high`, `xhigh`, and `max` effort variants for Fable 5.1 and Opus 5. OAuth Fable 5.1 sessions can change effort between turns without rewriting the cached prefix.
37
- - **Fable/Opus 5 safety fallback**: 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.
38
- - **Live quota visibility**: use `/claude-quota` to see main and fallback quota state, reset times, and refresh errors.
39
- - **Host-local quota feed**: 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.
40
- - **Killswitch**: per-account hard-block thresholds that stop requests before hitting Anthropic's rate limits, with synthetic 429 retry-after when all accounts are exhausted.
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.
41
49
  - **User-owned Cloudflare relay**: optionally provision your own Worker relay to reduce repeated client upload bytes for large OpenCode or Pi requests.
42
- - **Claude-compatible request hardening**: Claude Code 2.1.258 identity and final-body billing signing, live-session-stable billing suffixes, Fable 5.1 thinking-prefix recovery, safer token refresh persistence, replay-safe fallback retries, and subagent cache isolation.
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.
43
52
 
44
53
  ## What these integrations do
45
54
 
46
55
  - Let OpenCode and Pi use Claude Pro/Max OAuth credentials instead of an Anthropic API key.
47
56
  - In OpenCode, intercept the final Anthropic request and rewrite it into the Claude-compatible shape expected by Anthropic OAuth access.
48
- - In Pi, replace Pi's built-in Anthropic provider with a CortexKit provider override that uses the same Claude-compatible request path.
49
- - Add Claude billing headers with stable `cc_version` and body-derived `cch` signing.
50
- - Support fallback Claude accounts stored in a local per-agent sidecar file.
51
- - Keep fallback OAuth tokens fresh in the background.
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.
52
61
  - Apply quota thresholds before routing to main or fallback accounts.
53
- - Add `/claude-cache`, `/claude-cachekeep`, `/claude-prime`, `/claude-start`, `/claude-fast`, `/claude-quota`, and `/claude-dump` commands.
62
+ - Add one `/claude` menu for accounts, quota, routing, limits, cache, diagnostics, fast mode, Prime, and lane start.
54
63
  - Optionally relay large requests through a Cloudflare Worker owned by the user.
55
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
+ ---
92
+
56
93
  ## Install
57
94
 
58
95
  ### OpenCode
@@ -65,15 +102,15 @@ Add the OpenCode plugin to your OpenCode configuration:
65
102
  }
66
103
  ```
67
104
 
68
- Pinning is strongly recommended for any OpenCode plugin:
105
+ Pinning is strongly recommended for any OpenCode plugin. Replace `VERSION` with the release you install:
69
106
 
70
107
  ```json
71
108
  {
72
- "plugin": ["@cortexkit/opencode-anthropic-auth@1.0.0"]
109
+ "plugin": ["@cortexkit/opencode-anthropic-auth@VERSION"]
73
110
  }
74
111
  ```
75
112
 
76
- After changing plugin config, restart OpenCode.
113
+ OpenCode 1 and OpenCode 2 load the same package. After changing plugin config, restart OpenCode.
77
114
 
78
115
  > [!TIP]
79
116
  > If OpenCode keeps using an old build, clear OpenCode's plugin cache with `rm -rf ~/.cache/opencode` and restart.
@@ -82,81 +119,122 @@ After changing plugin config, restart OpenCode.
82
119
 
83
120
  Install the Pi package with Pi's package manager:
84
121
 
85
- ```bash
86
- pi install npm:@cortexkit/pi-anthropic-auth@1.0.0
87
- ```
88
-
89
- For an unpinned install:
90
-
91
122
  ```bash
92
123
  pi install npm:@cortexkit/pi-anthropic-auth
93
124
  ```
94
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
+
95
128
  To try it for one run without adding it to Pi settings:
96
129
 
97
130
  ```bash
98
131
  pi -e npm:@cortexkit/pi-anthropic-auth
99
132
  ```
100
133
 
101
- The Pi package registers a CortexKit Anthropic provider extension under Pi's built-in `anthropic` provider ID. After installation, start or restart Pi and authenticate with Pi's normal login command:
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.
102
135
 
103
- ```text
104
- /login anthropic
105
- ```
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.
106
137
 
107
- Pi package state lives separately from OpenCode in:
138
+ ## Accounts and credential custody
108
139
 
109
- ```text
110
- ~/.pi/agent/anthropic-auth.json
111
- ```
140
+ OpenCode and Pi each take Claude credentials from exactly one source:
112
141
 
113
- Override the path with `PI_ANTHROPIC_AUTH_FILE`. The package also respects `PI_AGENT_DIR` when deriving the default sidecar path.
142
+ - **Local custody** (default): the host's local account pool.
143
+ - **Vault custody**: the Claustrum vault, after the host is enrolled through setup.
114
144
 
115
- ## Primary account authentication
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.
116
146
 
117
- Each integration keeps the host agent's normal Anthropic login as the primary account.
147
+ ### Local account pool
118
148
 
119
- For OpenCode, use OpenCode's Anthropic auth flow:
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.
120
150
 
121
- ```text
122
- /connect anthropic
123
- ```
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` |
124
155
 
125
- The primary account remains OpenCode's built-in `anthropic` auth entry. The OpenCode plugin intercepts final Anthropic requests and supplies the OAuth headers and request transforms needed for Claude Pro/Max access.
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.
126
157
 
127
- OpenCode's upstream authentication options are still supported:
158
+ Setup migrates each host once, while OpenCode, LiteCode, and Pi are closed:
128
159
 
129
- - Claude Pro/Max OAuth through `claude.ai`.
130
- - Anthropic Console OAuth that creates an API key.
131
- - Manually entered Anthropic API key.
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.
132
163
 
133
- For Pi, install the Pi package, restart Pi, then use Pi's Anthropic login flow:
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:
134
165
 
135
- ```text
136
- /login anthropic
166
+ ```bash
167
+ bunx @cortexkit/opencode-anthropic-auth setup --login --no-claustrum
137
168
  ```
138
169
 
139
- The Pi package registers under Pi's built-in `anthropic` provider ID and stores primary OAuth credentials through Pi's normal credential flow. CortexKit package state, fallback accounts, cache mode, dump mode, and relay config live in the Pi sidecar file.
170
+ `--login` opens a Claude sign-in during setup and stores the account as the main account.
140
171
 
141
- ## Sidecar config
172
+ ### Signing in
142
173
 
143
- OpenCode package state lives in:
174
+ In local custody, after running setup (see [Local account pool](#local-account-pool)), add the main account in any of these ways:
144
175
 
145
- ```text
146
- ~/.config/opencode/anthropic-auth.json
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
147
191
  ```
148
192
 
149
- Override the OpenCode path with `OPENCODE_ANTHROPIC_AUTH_FILE`.
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:
150
206
 
151
- Pi package state uses the same JSON shape but a separate file:
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:
152
224
 
153
225
  ```text
154
- ~/.pi/agent/anthropic-auth.json
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.
155
227
  ```
156
228
 
157
- Override the Pi path with `PI_ANTHROPIC_AUTH_FILE`.
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.
158
230
 
159
- Example:
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:
160
238
 
161
239
  ```json
162
240
  {
@@ -184,9 +262,6 @@ Example:
184
262
  "quotaHeaderFeed": {
185
263
  "enabled": false
186
264
  },
187
- "claustrum": {
188
- "accounts": {}
189
- },
190
265
  "killswitch": {
191
266
  "enabled": false,
192
267
  "main": { "five_hour": 5, "seven_day": 10, "scoped": 0 },
@@ -225,28 +300,23 @@ Example:
225
300
  }
226
301
  ```
227
302
 
228
- The `routing` block controls `/claude-routing`, `claudeCache` controls `/claude-cache`, `cacheKeep` controls `/claude-cachekeep`, and `claudeFast` controls `/claude-fast`. 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. The `main` field identifies OpenCode's primary auth entry; Pi keeps primary OAuth credentials in Pi's own credential store, but uses the same sidecar shape for CortexKit settings and fallback account labels.
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.
229
304
 
230
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.
231
306
 
232
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`.
233
308
 
234
- `claustrum.accounts.<fallback-account-id>.enabled` is a per-account opt-in for fallback credential custody. It is inert unless that account's capability handle has been provisioned in `anthropic-auth-state.json`; handles are bearer credentials and must not be copied into the public config file.
235
-
236
- Runtime data is stored separately in `anthropic-auth-state.json`: fallback OAuth tokens, API-route keys, token refresh backoff, quota snapshots, and quota API backoff. Sticky session assignments use `anthropic-auth-routing-state.json` and store only SHA-256 hashes of session IDs. Background refresh and quota checks write only runtime state, so editing `anthropic-auth.json` does not get overwritten by another running plugin instance.
237
-
238
- ## OpenCode lane-start setting
239
-
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.
240
310
 
241
311
  ## Fallback accounts
242
312
 
243
- Fallback accounts are separate Claude OAuth accounts or Anthropic-compatible API-key routes managed by this plugin. By default, the main account is tried first unless quota policy says it is currently unusable. Fallbacks are then tried in sidecar order when the primary request returns a configured fallback status.
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.
244
314
 
245
- Use `/claude-routing fallback-first` to prefer usable fallback accounts before the main account, `/claude-routing main-first` to restore the default, or `/claude-routing sticky-balanced` to allocate each new session according to spendable 5-hour, 7-day, and matching model-scoped OAuth quota headroom. The command persists `routing.mode` and takes effect on the next request without restarting. `/claude-routing reset` clears only the current session's assignment so its next request is allocated again.
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.
246
316
 
247
- `sticky-balanced` normalizes quota headroom by time until reset and tracks weighted initial-prompt deficit until the next quota refresh. Assignments are persisted by hashed session ID in `anthropic-auth-routing-state.json`, shared safely across OpenCode plugin instances and restarts. Active hybrid CacheKeep sessions seed their current route when the mode is first enabled.
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.
248
318
 
249
- Affinity 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`. Fable content-filter recovery keeps Fable, Opus 4.8, and Fable prewarms on the same sticky account. Direct Opus sessions first prefer an otherwise usable account whose Fable quota is exhausted.
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.
250
320
 
251
321
  Default fallback statuses:
252
322
 
@@ -254,7 +324,7 @@ Default fallback statuses:
254
324
  [401, 403, 429]
255
325
  ```
256
326
 
257
- Add and inspect OpenCode fallback accounts with the CLI:
327
+ Add and inspect OpenCode fallback accounts with the CLI (local custody only, after running setup for OpenCode):
258
328
 
259
329
  ```bash
260
330
  bunx @cortexkit/opencode-anthropic-auth login personal-alt
@@ -262,44 +332,23 @@ bunx @cortexkit/opencode-anthropic-auth api add kie-opus
262
332
  bunx @cortexkit/opencode-anthropic-auth list
263
333
  ```
264
334
 
265
- Prefer npm? Use `npx -y @cortexkit/opencode-anthropic-auth ...` with the same subcommands.
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.
266
336
 
267
- 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 token-bound quota snapshot at 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 in `anthropic-auth-state.json`, while `anthropic-auth.json` keeps the route label, type, enabled flag, base URL, and auth-header mode.
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.
268
338
 
269
- 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. Advanced users can set `costZeroing.enabled` to `false` to show Anthropic model pricing for OAuth sessions too.
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.
270
340
 
271
- For Pi fallback accounts, write the same account JSON shape to `~/.pi/agent/anthropic-auth.json`. The CLI helper currently lives in the OpenCode package, so you can also point it at Pi's sidecar path when logging in a fallback account:
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.
272
342
 
273
- ```bash
274
- OPENCODE_ANTHROPIC_AUTH_FILE="$HOME/.pi/agent/anthropic-auth.json" \
275
- bunx @cortexkit/opencode-anthropic-auth login personal-alt
276
- ```
343
+ The CLI manages only OpenCode's locally stored Claude accounts and API-key fallbacks. Add Pi fallback accounts from Pi's `/claude` menu.
277
344
 
278
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.
279
346
 
280
347
  ### Token refresh
281
348
 
282
- Fallback 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 sidecar 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 its stale latch.
283
-
284
- If Anthropic reports `invalid_grant`, that account must be logged in again. `/claude-account reset-backoff` manually clears the main account's refresh backoff and its matching quota backoff.
285
-
286
- ### Optional Claustrum custody
287
-
288
- OpenCode can obtain an opted-in fallback OAuth account's access credential from a local [Claustrum](https://github.com/cortexkit/claustrum) daemon instead of refreshing that account independently. After provisioning the account's runtime handle, enable custody by account ID:
289
-
290
- ```json
291
- {
292
- "claustrum": {
293
- "accounts": {
294
- "personal-alt": { "enabled": true }
295
- }
296
- }
297
- }
298
- ```
299
-
300
- The request path reads only a resident in-memory credential. Startup warming and periodic custody ticks perform vault I/O and keep idle credentials refreshed; a cold or unavailable vault falls back to the sidecar credential path. Vault-served 401 reports carry the exact record version and response provenance, including relay-stream 401s, so a sidecar-served failure cannot invalidate a healthy vault credential. `/claude-account` and the account modal show the gate, current vault service, and vault reauthentication state without exposing capability handles.
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.
301
350
 
302
- Custody currently applies only to fallback OAuth accounts. Main-account vault service is not implemented. If Claustrum has replaced the main host credential with its provider-bound tombstone, the plugin rejects refresh locally without contacting Anthropic or persisting a permanent `invalid_grant` state.
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.
303
352
 
304
353
  ## Quota-aware routing
305
354
 
@@ -318,15 +367,17 @@ With this config, an account is skipped when it has less than 10% remaining in t
318
367
 
319
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.
320
369
 
321
- Show current quota state:
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.
322
371
 
323
- ```text
324
- /claude-quota
325
- ```
372
+ Reset times are rendered as relative durations, such as `resets in 10m` or `resets in 1h 15m`.
326
373
 
327
- In OpenCode, this includes the main Anthropic account and sidecar fallback accounts. In Pi, the command reports sidecar fallback account quota state from `~/.pi/agent/anthropic-auth.json`.
374
+ ### Quota header feed
328
375
 
329
- Reset times are rendered as relative durations, such as `resets in 10m` or `resets in 1h 15m`.
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.
330
381
 
331
382
  ## Safety fallback
332
383
 
@@ -348,7 +399,7 @@ Legacy mode routes a refused Fable 5/5.1 or Opus 5 session through Opus 4.8 for
348
399
 
349
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.
350
401
 
351
- Add a `killswitch` block to the sidecar config:
402
+ Killswitch settings have this shape; setup imports an existing `killswitch` block from the old sidecar file (`anthropic-auth.json`):
352
403
 
353
404
  ```json
354
405
  "killswitch": {
@@ -368,42 +419,58 @@ Add a `killswitch` block to the sidecar config:
368
419
  }
369
420
  ```
370
421
 
371
- 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 matching model-scoped quota windows (for example Fable weekly quota) 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.
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.
372
429
 
373
430
  Behavior:
374
431
 
375
432
  - When an account is killed, it is skipped during routing. Surviving accounts are tried instead.
376
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.
377
434
  - On the first request after restart, the plugin eagerly fetches main quota so the killswitch evaluates immediately.
378
- - `/claude-quota` shows killswitch status and per-account killed/active state.
435
+ - **Killswitch status** in the `/claude` menu's Limits group shows killswitch status and per-account killed/active state.
379
436
 
380
- Manage the killswitch from inside OpenCode:
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:
381
438
 
382
- ```text
383
- /claude-killswitch — show status and command cheatsheet
384
- /claude-killswitch on — enable with current or default thresholds
385
- /claude-killswitch off — disable
386
- /claude-killswitch set all:5,10 — set all accounts to 5h≥5%, 1w≥10%
387
- /claude-killswitch set main:3,8,0 — set main to 5h≥3%, 1w≥8%, scoped≤0%
388
- /claude-killswitch set main:3,8,0 work-alt:5,10,0 — per-account thresholds
439
+ ```json
440
+ [{"account":"main","fh":3,"sd":8,"scoped":0},{"account":"<account-id>","fh":5,"sd":10,"scoped":0}]
389
441
  ```
390
442
 
391
- Changes made with `/claude-killswitch` are persisted to the sidecar config.
443
+ Killswitch changes are persisted with the host's other plugin settings. Pi does not offer killswitch enable, disable, or threshold editing.
392
444
 
393
- ## Claude prompt cache control
445
+ ## The /claude menu
394
446
 
395
- Both OpenCode and Pi packages add a slash command for Anthropic's 1-hour ephemeral prompt-cache TTL:
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.
396
448
 
397
- ```text
398
- /claude-cache
399
- /claude-cache on
400
- /claude-cache off
401
- /claude-cache mode explicit
402
- /claude-cache mode automatic
403
- /claude-cache mode hybrid
404
- ```
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.
405
466
 
406
- Without arguments, `/claude-cache` shows the current setting.
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.
407
474
 
408
475
  Modes:
409
476
 
@@ -415,18 +482,11 @@ In OpenCode, subagent requests do not receive 1-hour TTL caching. The plugin det
415
482
 
416
483
  ### Cache keepalive
417
484
 
418
- `/claude-cachekeep` keeps recently used hybrid-mode session caches warm while the agent process is running:
419
-
420
- ```text
421
- /claude-cachekeep
422
- /claude-cachekeep always
423
- /claude-cachekeep 09-23
424
- /claude-cachekeep off
425
- ```
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`).
426
486
 
427
- `always` keeps tracked sessions warm continuously for as long as the OpenCode process remains open. Hour ranges use local 24-hour time and are start-inclusive/end-exclusive: `09-23` runs from 09:00 until 22:59, and overnight windows such as `23-09` are accepted.
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.
428
488
 
429
- Cache keepalive only tracks requests when `/claude-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. Running `/claude-cachekeep` without arguments lists every live tracked session across OpenCode projects and plugin processes.
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.
430
490
 
431
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.
432
492
 
@@ -434,42 +494,32 @@ Pre-warm requests preserve explicit cache anchors but remove response-only field
434
494
 
435
495
  ## Claude quota window priming
436
496
 
437
- Quota-window priming is off by default. OpenCode controls it with:
438
-
439
- ```text
440
- /claude-prime
441
- /claude-prime on
442
- /claude-prime off
443
- ```
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.
444
498
 
445
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.
446
500
 
447
- 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. Atomic temporary-file claims ensure that multiple OpenCode processes sharing the same account config send only one request per account and reset.
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.
448
502
 
449
- Prime marker identities live in `anthropic-auth-state.json`. Plugin-owned refresh rotations preserve the main account's lineage, while a host credential replacement creates a new lineage. An existing main lineage without a refresh-token binding attaches to the current credential on its first check without changing identity. On upgrade, an existing fallback account receives an identity during its first prime check; that one-time marker change can send one extra request in the current window.
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.
450
504
 
451
- Pi exposes `/claude-prime` as a status-only command. Its `on` and `off` arguments are ignored; enable or disable priming from OpenCode.
505
+ Pi shows **Prime quota window status** but has no Prime on/off actions; enable or disable priming from OpenCode.
452
506
 
453
507
  ## OpenCode lane start
454
508
 
455
- `/claude-start` is an OpenCode-only command. It queues one synthetic turn for the current session:
456
-
457
- ```text
458
- /claude-start
459
- ```
509
+ **Fire lane start** in the `/claude` menu's Extras group is OpenCode-only. It queues one synthetic turn for the current session.
460
510
 
461
- The bare command fires immediately. The synthetic prompt 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 modal is a request to start the turn, not a provider-success claim.
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.
462
512
 
463
513
  > [!IMPORTANT]
464
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.
465
515
 
466
- Pi does not expose this command.
516
+ Pi does not offer **Fire lane start**, the command that warms the session's prompt cache.
467
517
 
468
518
  ### Cache diagnostics (beta)
469
519
 
470
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`.
471
521
 
472
- The `MC-CACHE-DIAG ` line is a versioned, one-line JSON record. Records and their beta side-channel are emitted only at debug level; use `/claude-logging debug` 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:
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:
473
523
 
474
524
  | Field | Type | Source |
475
525
  | --- | --- | --- |
@@ -509,7 +559,7 @@ Known sources map to `synthetic` as follows:
509
559
  | `start` | `true` |
510
560
  | `prewarm_cachekeep` | `true` |
511
561
 
512
- Lane-start cache observations therefore appear as ordinary `MC-CACHE-DIAG ` records with `source: "start"`; the row above is the diagnostics-side companion to the `/claude-start` pipeline described earlier.
562
+ Cache observations for the plugin-generated turn queued by **Fire lane start** appear as ordinary `MC-CACHE-DIAG ` records with `source: "start"`.
513
563
 
514
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.
515
565
 
@@ -540,15 +590,9 @@ When request dumps are enabled, each response gets a `.response.json` artifact c
540
590
 
541
591
  ## Claude fast mode
542
592
 
543
- Both OpenCode and Pi packages can persistently request Anthropic fast mode for supported Opus models:
544
-
545
- ```text
546
- /claude-fast
547
- /claude-fast on
548
- /claude-fast off
549
- ```
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.
550
594
 
551
- 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 currently documents fast mode for `claude-opus-4-6`, `claude-opus-4-7`, `claude-opus-4-8`, and `claude-opus-5`; Claude Fable and Mythos 5/5.1 are not fast-mode models.
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.
552
596
 
553
597
  Fast and standard speeds do not share prompt-cache prefixes, so switching this setting can cause cache misses.
554
598
 
@@ -585,21 +629,21 @@ The relay is opt-in and user-owned. CortexKit does not run shared relay infrastr
585
629
 
586
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.
587
631
 
588
- New relay setups default to HTTP transport:
632
+ `relay setup` saves HTTP transport:
589
633
 
590
634
  ```json
591
635
  "transport": "http"
592
636
  ```
593
637
 
594
- HTTP is the safest release default and still sends compact full-sync/patch payloads through your Worker. WebSocket is available as an opt-in persistent session transport:
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:
595
639
 
596
640
  ```json
597
641
  "transport": "websocket"
598
642
  ```
599
643
 
600
- WebSocket mode uses protocol v2 on `/ws`, keeps one connection per OpenCode `x-session-affinity`, 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.
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`.
601
645
 
602
- Set up a relay in your Cloudflare account with the OpenCode package CLI:
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:
603
647
 
604
648
  ```bash
605
649
  CLOUDFLARE_API_TOKEN=... CLOUDFLARE_ACCOUNT_ID=... bunx @cortexkit/opencode-anthropic-auth relay setup
@@ -617,9 +661,9 @@ The setup command:
617
661
  2. Uploads the relay Worker module.
618
662
  3. Generates a relay shared secret.
619
663
  4. Enables the Worker.
620
- 5. Writes the local `relay` block to `~/.config/opencode/anthropic-auth.json`.
664
+ 5. Saves the relay URL, shared secret, and HTTP transport in OpenCode's local account pool.
621
665
 
622
- For Pi, copy the generated `relay` block into `~/.pi/agent/anthropic-auth.json` if you want the Pi package to use the same user-owned Worker.
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.
623
667
 
624
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.
625
669
 
@@ -648,13 +692,7 @@ Direct fallback logs `falling back direct`.
648
692
 
649
693
  ### Request dumps
650
694
 
651
- For relay/cache debugging, enable exact request dumps from inside OpenCode or Pi:
652
-
653
- ```text
654
- /claude-dump on
655
- /claude-dump off
656
- /claude-dump
657
- ```
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.
658
696
 
659
697
  When enabled, the plugin writes artifacts under the OS temp directory:
660
698
 
@@ -669,21 +707,42 @@ Each filename includes a sanitized session/affinity segment so dumps from differ
669
707
  - `*.relay.json` — redacted relay payload/frame metadata for relay requests.
670
708
  - `*.request.json` — redacted direct request URL, method, and headers for direct requests.
671
709
 
672
- Dump state is persisted in the active sidecar config as `dump.enabled` (`~/.config/opencode/anthropic-auth.json` for OpenCode, `~/.pi/agent/anthropic-auth.json` for Pi). Dumps may contain prompt content and should be treated as sensitive local debugging artifacts.
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.
673
711
 
674
712
  ## Environment variables
675
713
 
676
714
  | Variable | Description |
677
715
  | --- | --- |
678
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. |
679
723
  | `ANTHROPIC_INSECURE` | Set to `1` or `true` to skip TLS verification when `ANTHROPIC_BASE_URL` is set. |
680
- | `OPENCODE_ANTHROPIC_AUTH_FILE` | Override the OpenCode sidecar config path. |
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. |
681
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. |
682
- | `PI_ANTHROPIC_AUTH_FILE` | Override the Pi sidecar config path. |
683
- | `PI_AGENT_DIR` | Override Pi's agent directory when deriving the default sidecar path. |
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`. |
684
739
  | `CLOUDFLARE_API_TOKEN` | Cloudflare token used by `bunx @cortexkit/opencode-anthropic-auth relay setup`. Not stored. |
685
740
  | `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account ID used by relay setup. |
686
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
+
687
746
  ## Request rewriting
688
747
 
689
748
  For Claude Pro/Max OAuth requests, the plugin works at the final Anthropic wire-request layer:
@@ -692,7 +751,7 @@ For Claude Pro/Max OAuth requests, the plugin works at the final Anthropic wire-
692
751
  2. Normalizes Claude-compatible OAuth headers and beta flags.
693
752
  3. Removes OpenCode-specific identity text from system blocks.
694
753
  4. Prepends Claude Code identity and billing-header blocks.
695
- 5. Rewrites cache controls according to `/claude-cache` mode.
754
+ 5. Rewrites cache controls according to the configured cache mode.
696
755
  6. Renames MCP tool names into Claude-compatible PascalCase form.
697
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.
698
757
  8. Computes final-body `cch` over the fully serialized request body.
@@ -793,10 +852,12 @@ The release workflow runs checks, publishes the core, OpenCode, and Pi packages
793
852
  ## Troubleshooting
794
853
 
795
854
  - Clear OpenCode's plugin cache after plugin config changes: `rm -rf ~/.cache/opencode`.
796
- - Restart OpenCode or Pi after changing sidecar config; some settings are loaded at startup.
797
- - If an OpenCode fallback account shows `invalid_grant`, run `bunx @cortexkit/opencode-anthropic-auth login <label>` again for that account.
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.
798
859
  - Tail relay diagnostics when debugging relay setup: `tail -f "$(node -p 'require("node:os").tmpdir()')/opencode-anthropic-auth.log"`.
799
- - Use `/claude-quota` to inspect quota and refresh errors surfaced by the plugin.
860
+ - Open `/claude` to inspect account status, quota, and refresh errors surfaced by the plugin.
800
861
 
801
862
  ## License
802
863