Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This repo is a CortexKit-maintained Anthropic auth monorepo for OpenCode and Pi.
- Retry failed CacheKeep prewarms while the last confirmed cache can still be alive, and serialize overlapping manager ticks to avoid duplicate requests.
- Preserve fresh scoped-only fallback quota snapshots, permanent refresh-error classification across lock contention, and explicit re-login guidance for unusable fallback accounts.
- Evict complete request artifact groups when enforcing the dump-directory size cap.
- Add the OpenCode-only `/claude-start` command for explicit synthetic one-token lane starts; start requests use the `-start-` dump marker.
- Capture Anthropic cache diagnostics in versioned `MC-CACHE-DIAG ` debug records, preserve provider response IDs across requests and cachekeep prewarms, and write response/request dump artifacts without response content. Document the beta states and known fingerprint, organization, workspace, and beta-set limitations.

## 1.19.1
Expand Down
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This repo is a Bun workspace monorepo with two user-facing integrations and one
| Provider integration point | OpenCode plugin fetch/request transform | Pi `registerProvider("anthropic")` provider override |
| Sidecar config | `~/.config/opencode/anthropic-auth.json` | `~/.pi/agent/anthropic-auth.json` |
| Runtime state | `~/.config/opencode/anthropic-auth-state.json` | next to the Pi sidecar as `anthropic-auth-state.json` |
| Commands | `/claude-cache`, `/claude-cachekeep`, `/claude-prime`, `/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` |
| 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` |
| Quota sidebar widget | OpenCode TUI plugin via `tui.json` | Not available |
| Fallback accounts, quota routing, killswitch, relay, dumps, fast mode | Supported | Supported through the same shared core and Pi sidecar |

Expand All @@ -32,6 +32,7 @@ This repo is a Bun workspace monorepo with two user-facing integrations and one
- **Persistent Claude cache controls**: manage Anthropic 1-hour prompt caching from `/claude-cache` with explicit, automatic, or hybrid modes.
- **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.
- **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.
- **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.
- **Fast mode toggle**: use `/claude-fast on|off` to request Anthropic fast mode for supported Opus models.
- **Adaptive reasoning visibility**: request summarized adaptive thinking for Claude Fable 5, Mythos 5, and Opus 5. OpenCode receives native `low`, `medium`, `high`, `xhigh`, and `max` Opus 5 effort variants rather than legacy manual-thinking budgets.
- **Fable/Opus 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.
Expand All @@ -50,7 +51,7 @@ This repo is a Bun workspace monorepo with two user-facing integrations and one
- Support fallback Claude accounts stored in a local per-agent sidecar file.
- Keep fallback OAuth tokens fresh in the background.
- Apply quota thresholds before routing to main or fallback accounts.
- Add `/claude-cache`, `/claude-cachekeep`, `/claude-prime`, `/claude-fast`, `/claude-quota`, and `/claude-dump` commands.
- Add `/claude-cache`, `/claude-cachekeep`, `/claude-prime`, `/claude-start`, `/claude-fast`, `/claude-quota`, and `/claude-dump` commands to OpenCode.
- Optionally relay large requests through a Cloudflare Worker owned by the user.

## Install
Expand Down Expand Up @@ -220,6 +221,9 @@ The `routing` block controls `/claude-routing`, `claudeCache` controls `/claude-

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-balanced` session assignments use a separate `anthropic-auth-routing-state.json`; session IDs are SHA-256 hashed in that file. Background refresh and quota checks write only runtime state, so editing `anthropic-auth.json` does not get overwritten by another running plugin instance.

## OpenCode lane-start setting


## Fallback accounts

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.
Expand Down Expand Up @@ -507,6 +511,18 @@ Prime marker identities live in `anthropic-auth-state.json`. Plugin-owned refres

Pi exposes `/claude-prime` as a status-only command. Its `on` and `off` arguments are ignored; enable or disable priming from OpenCode.

## OpenCode lane start

`/claude-start` is an OpenCode-only command. It queues one synthetic turn for the current session:

```text
/claude-start
```

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.

Pi does not expose this command.

## Claude fast mode

Both OpenCode and Pi packages can persistently request Anthropic fast mode for supported Opus models:
Expand Down Expand Up @@ -638,6 +654,8 @@ Each filename includes a sanitized session/affinity segment so dumps from differ
- `*.relay.json` — redacted relay payload/frame metadata for relay requests.
- `*.request.json` — redacted direct request URL, method, and headers for direct requests.

Lane-start requests use the `-start-` dump marker; CacheKeep keeps `-prewarm-cachekeep-`. Their cache-diagnostics records use `source: "start"` with `synthetic: true`, alongside ordinary `turn` records.

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.

## Environment variables
Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/dump.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export type DumpCommandAction =
| { type: 'disable' }
| { type: 'usage' }

export type DumpTag = 'cachekeep'
export type DumpTag = 'cachekeep' | 'start'

export type DumpHandle = {
responsePath: string
Expand Down Expand Up @@ -362,7 +362,9 @@ function dumpRequestSegment(input: {
}

function dumpTagSegment(tag: DumpTag | undefined) {
return tag ? `-prewarm-${tag}` : ''
if (tag === 'cachekeep') return '-prewarm-cachekeep'
if (tag === 'start') return '-start'
return ''
}

function directDumpPreviousKey(input: {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export * from './quota-manager.ts'
export * from './quotas.ts'
export * from './relay.ts'
export * from './routing.ts'
export * from './start.ts'
export * from './sticky-routing.ts'
5 changes: 4 additions & 1 deletion packages/core/src/relay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,8 @@ export async function sendViaRelay(options: {
* within an attempt are ignored.
*/
onResponseHeaders?: (headers: Headers) => void
onDumpCreated?: (handle: { responsePath: string; tag?: 'cachekeep' }) => void
dumpTag?: import('./dump.ts').DumpTag
onDumpCreated?: (handle: import('./dump.ts').DumpHandle) => void
setTimeoutImpl?: typeof globalThis.setTimeout
clearTimeoutImpl?: typeof globalThis.clearTimeout
}): Promise<Response> {
Expand All @@ -1123,6 +1124,7 @@ export async function sendViaRelay(options: {
affinity: explicitAffinity,
optimisticResponse,
onResponseHeaders,
dumpTag,
onDumpCreated,
setTimeoutImpl = globalThis.setTimeout,
clearTimeoutImpl = globalThis.clearTimeout,
Expand Down Expand Up @@ -1249,6 +1251,7 @@ export async function sendViaRelay(options: {
previousBodyText: previous?.body,
payload: result.payload,
relayBytes: actualPayloadBytes,
tag: dumpTag,
})
try {
if (dumpHandle) onDumpCreated?.(dumpHandle)
Expand Down
39 changes: 39 additions & 0 deletions packages/core/src/start.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export const CLAUDE_START_COMMAND_NAME = 'claude-start'

const START_STATUS_TITLE = '## Claude Lane Start Status'
const START_QUEUED_TITLE = '## Claude Lane Start Queued'
const START_USAGE_TITLE = '## Claude Lane Start Usage'
const START_USAGE = 'Usage: `/claude-start`.'

export type LaneStartCommandAction = { type: 'fire' } | { type: 'usage' }

export function parseLaneStartCommandAction(
input: string,
): LaneStartCommandAction {
const normalized = input.trim().split(/\s+/).filter(Boolean)
if (normalized.length === 0) return { type: 'fire' }
return { type: 'usage' }
Comment thread
iceteaSA marked this conversation as resolved.
}

export function executeLaneStartCommand(input: { argumentsText: string }): {
action: LaneStartCommandAction
text: string
} {
const action = parseLaneStartCommandAction(input.argumentsText)
if (action.type === 'fire') {
return {
action,
text: [
START_QUEUED_TITLE,
'',
'- Queued an explicit lane-start request.',
].join('\n'),
}
}
return {
action,
text: [START_USAGE_TITLE, '', START_USAGE, '', START_STATUS_TITLE].join(
'\n',
),
}
}
25 changes: 25 additions & 0 deletions packages/core/src/tests/dump.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,31 @@ test('tagged prewarm dumps include the tag in filenames and metadata', async ()
expect(metadata.tag).toBe('cachekeep')
})

test('start dumps use the distinct start filename segment', async () => {
const dumpDir = await mkdtemp(
join(tmpdir(), 'opencode-anthropic-auth-dumps-test-'),
)
dumpDirs.push(dumpDir)
process.env.OPENCODE_ANTHROPIC_AUTH_DUMP_DIR = dumpDir
setDumpEnabled(true)
const handle = await dumpDirectRequest({
affinity: 'ses-start',
bodyText: '{}',
tag: 'start',
})
expect(handle?.tag).toBe('start')
expect(handle?.responsePath).toMatch(/-start-direct\.response\.json$/)
expect(handle?.responsePath).not.toContain('-prewarm-start')
const files = await readdir(dumpDir)
const metadata = JSON.parse(
await readFile(
join(dumpDir, files.find((name) => name.endsWith('.meta.json'))!),
'utf8',
),
)
expect(metadata.tag).toBe('start')
})

test('dump sweep recognizes response artifacts', async () => {
const dumpDir = await mkdtemp(
join(tmpdir(), 'opencode-anthropic-auth-dumps-test-'),
Expand Down
25 changes: 22 additions & 3 deletions packages/opencode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This repo is a Bun workspace monorepo with two user-facing integrations and one
| Provider integration point | OpenCode plugin fetch/request transform | Pi `registerProvider("anthropic")` provider override |
| Sidecar config | `~/.config/opencode/anthropic-auth.json` | `~/.pi/agent/anthropic-auth.json` |
| Runtime state | `~/.config/opencode/anthropic-auth-state.json` | next to the Pi sidecar as `anthropic-auth-state.json` |
| Commands | `/claude-cache`, `/claude-cachekeep`, `/claude-prime`, `/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` |
| 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` |
| Fallback accounts, quota routing, killswitch, relay, dumps, fast mode | Supported | Supported through the same shared core and Pi sidecar |

## What CortexKit adds over the original plugin
Expand All @@ -31,6 +31,7 @@ This repo is a Bun workspace monorepo with two user-facing integrations and one
- **Persistent Claude cache controls**: manage Anthropic 1-hour prompt caching from `/claude-cache` with explicit, automatic, or hybrid modes.
- **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.
- **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.
- **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.
- **Fast mode toggle**: use `/claude-fast on|off` to request Anthropic fast mode for supported Opus models.
- **Adaptive reasoning visibility**: request summarized adaptive thinking for Claude Fable 5, Mythos 5, and Opus 5. OpenCode receives native `low`, `medium`, `high`, `xhigh`, and `max` Opus 5 effort variants rather than legacy manual-thinking budgets.
- **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.
Expand Down Expand Up @@ -218,6 +219,9 @@ The `routing` block controls `/claude-routing`, `claudeCache` controls `/claude-

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.

## OpenCode lane-start setting


## Fallback accounts

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.
Expand Down Expand Up @@ -412,6 +416,18 @@ Prime marker identities live in `anthropic-auth-state.json`. Plugin-owned refres

Pi exposes `/claude-prime` as a status-only command. Its `on` and `off` arguments are ignored; enable or disable priming from OpenCode.

## OpenCode lane start

`/claude-start` is an OpenCode-only command. It queues one synthetic turn for the current session:

```text
/claude-start
```

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.

Pi does not expose this command.

### Cache diagnostics (beta)

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`.
Expand All @@ -421,7 +437,7 @@ The `MC-CACHE-DIAG ` line is a versioned, one-line JSON record. Records and thei
| Field | Type | Source |
| --- | --- | --- |
| `v` | `2` | Capture schema |
| `source` | string | Observation path; known values are `"turn"` and `"prewarm_cachekeep"`, but consumers must tolerate future values |
| `source` | string | Observation path; known values are `"turn"`, `"start"`, and `"prewarm_cachekeep"`, but consumers must tolerate future values |
| `synthetic` | boolean | Whether this observation was generated by plugin machinery rather than a real turn |
| `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 |
| `betas_hash` | 16-character lowercase hex | xxHash64 (seed `0`) of the sorted `anthropic-beta` list actually sent, truncated to its first 16 hexadecimal characters |
Expand Down Expand Up @@ -453,8 +469,11 @@ Known sources map to `synthetic` as follows:
| `source` | `synthetic` |
| --- | --- |
| `turn` | `false` |
| `start` | `true` |
| `prewarm_cachekeep` | `true` |

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.

`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.

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.
Expand All @@ -480,7 +499,7 @@ Diagnostics comparison requires a cacheable prefix. Requests below the model's c

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.

When request dumps are enabled, each response gets a `.response.json` artifact containing status and parsed response metadata, but no response content. Cache keepalive prewarms are tagged `-prewarm-cachekeep` in dump filenames and metadata. 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.
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.

## Claude fast mode

Expand Down
1 change: 1 addition & 0 deletions packages/opencode/src/cache-diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type CacheDiagnosticsSource = string

export const CACHE_DIAGNOSTICS_SOURCE_SYNTHETIC = {
turn: false,
start: true,
prewarm_cachekeep: true,
} as const

Expand Down
Loading
Loading