@askalf/dario 3.3.0 → 3.4.1

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.
package/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
  <h1 align="center">dario</h1>
3
3
  <p align="center"><strong>Use your Claude subscription as an API. The only proxy that bills correctly.</strong></p>
4
4
  <p align="center">
5
- No API key needed. Your Claude Max/Pro subscription becomes a local API endpoint<br/>that any tool, SDK, or framework can use. Template replay makes every request<br/>indistinguishable from real Claude Code — so your Max plan limits actually work.
5
+ No API key needed. Your Claude Max/Pro subscription becomes a local API endpoint<br/>
6
+ that any tool, SDK, or framework can use. Template replay makes every request<br/>
7
+ indistinguishable from real Claude Code — so your Max plan limits actually work.
6
8
  </p>
7
9
  </p>
8
10
 
@@ -17,8 +19,8 @@
17
19
  <p align="center">
18
20
  <a href="#quick-start">Quick Start</a> &bull;
19
21
  <a href="#openai-compatibility">OpenAI Compat</a> &bull;
20
- <a href="#cli-backend">CLI Backend</a> &bull;
21
22
  <a href="#usage-examples">Examples</a> &bull;
23
+ <a href="#askalf">askalf</a> &bull;
22
24
  <a href="#trust--transparency">Trust</a> &bull;
23
25
  <a href="#faq">FAQ</a>
24
26
  </p>
@@ -33,7 +35,9 @@ export ANTHROPIC_BASE_URL=http://localhost:3456 # or OPENAI_BASE_URL=http://lo
33
35
  export ANTHROPIC_API_KEY=dario # or OPENAI_API_KEY=dario
34
36
  ```
35
37
 
36
- Opus, Sonnet, Haiku — all models, streaming, tool use. **Zero dependencies.** ~2,100 lines of TypeScript. Works with Cursor, Continue, Aider, LiteLLM, Hermes, OpenClaw, or any tool that speaks the Anthropic or OpenAI API. When rate limited, `--cli` routes through Claude Code for uninterrupted Opus access. Auto-launches under [Bun](https://bun.sh) when available for TLS fingerprint fidelity.
38
+ Opus, Sonnet, Haiku — all models, streaming, tool use. **Zero dependencies.** ~2,000 lines of TypeScript. Works with Cursor, Continue, Aider, LiteLLM, Hermes, OpenClaw, or any tool that speaks the Anthropic or OpenAI API. Auto-launches under [Bun](https://bun.sh) when available for TLS fingerprint fidelity. **Auto-detects OAuth config from your installed CC binary** so dario stays in sync forever — Anthropic can rotate client IDs and dario picks them up on the next run.
39
+
40
+ dario is built and maintained by [askalf](https://askalf.org) — the open-source foundation of the askalf agent platform. If you need more than a proxy, [see below](#askalf).
37
41
 
38
42
  <table>
39
43
  <tr>
@@ -44,7 +48,7 @@ Opus, Sonnet, Haiku — all models, streaming, tool use. **Zero dependencies.**
44
48
 
45
49
  **Grok** (xAI)
46
50
 
47
- *"Dario works great and is safe. Fully functional with OpenClaw / Hermes. Gives you Opus 4.6, Sonnet & Haiku using your existing Claude Max/Pro sub. No extra API key or billing needed. Streaming + tools work perfectly. 100% open-source, runs locally only, proper OAuth (PKCE), no telemetry. Highly recommended if you want a clean local proxy."*
51
+ *"Dario works great and is safe. Fully functional with OpenClaw / Hermes. Gives you Opus, Sonnet & Haiku using your existing Claude Max/Pro sub. No extra API key or billing needed. Streaming + tools work perfectly. 100% open-source, runs locally only, proper OAuth (PKCE), no telemetry. Highly recommended if you want a clean local proxy."*
48
52
 
49
53
  </td>
50
54
  <td width="33%" valign="top">
@@ -80,7 +84,7 @@ Opus, Sonnet, Haiku — all models, streaming, tool use. **Zero dependencies.**
80
84
 
81
85
  Most Claude subscription proxies have a critical billing problem: **Anthropic classifies their requests as third-party and routes all usage to Extra Usage billing** — even when you have Max plan limits available. You're paying for your subscription twice.
82
86
 
83
- dario is the only proxy that solves this. Instead of transforming your requests signal by signal, dario uses **template replay** — it replaces the entire request with Claude Code's exact template, extracted via MITM capture from CC v2.1.104. 25 tool definitions, 25KB system prompt, exact field order, exact beta headers, exact metadata structure. Only your conversation content is preserved. When Bun is installed, dario auto-relaunches under Bun for TLS fingerprint fidelity matching CC's runtime. Anthropic's classifier sees a genuine Claude Code request because it IS one.
87
+ dario is the only proxy that solves this. Instead of transforming your requests signal by signal, dario uses **template replay** — it replaces the entire request with Claude Code's exact template. 25 tool definitions, 25KB system prompt, exact field order, exact beta headers, exact metadata structure. Only your conversation content is preserved. When Bun is installed, dario auto-relaunches under Bun for TLS fingerprint fidelity matching CC's runtime. Anthropic's classifier sees a genuine Claude Code request because it IS one.
84
88
 
85
89
  | | dario | Other proxies |
86
90
  |---|---|---|
@@ -93,15 +97,14 @@ dario is the only proxy that solves this. Instead of transforming your requests
93
97
  <details>
94
98
  <summary><strong>vs competitors</strong></summary>
95
99
 
96
- | Feature | dario | Meridian (710 stars) | CLIProxyAPI (24K stars) |
100
+ | Feature | dario | Meridian | CLIProxyAPI |
97
101
  |---------|-------|---------|------------|
98
- | Template replay (undetectable) | **Yes** | No | Inherited (CLI-only) |
102
+ | Template replay (undetectable) | **Yes** | No | No |
99
103
  | Direct OAuth (streaming, tools) | **Yes** | Yes (SDK-based) | No |
100
- | CLI fallback (rate limit bypass) | **Yes** | No | Yes (only mode) |
101
104
  | OpenAI API compat | **Yes** | Yes | Yes |
102
105
  | Orchestration sanitization | **Yes** | Yes | No |
103
106
  | Token anomaly detection | **Yes** | Yes | No |
104
- | Codebase size | ~2,100 lines | ~9,000 lines | Platform |
107
+ | Codebase size | ~2,000 lines | ~9,000 lines | Platform |
105
108
  | Dependencies | 0 | Many | Many |
106
109
  | Setup | 2 commands | Config + build | Config + dashboard |
107
110
 
@@ -111,15 +114,15 @@ dario is the only proxy that solves this. Instead of transforming your requests
111
114
 
112
115
  You pay $100-200/mo for Claude Max or Pro. But that subscription only works on claude.ai and Claude Code. If you want to use Claude with **any other tool** — Cursor, Continue, Aider, your own scripts — you need a separate API key with separate billing.
113
116
 
114
- **Note:** Claude subscriptions have [usage limits](https://support.claude.com/en/articles/11647753-how-do-usage-and-length-limits-work) that reset on rolling 5-hour and 7-day windows. When exceeded, Opus and Sonnet may return 429 errors while Haiku continues working. You can check your utilization via Claude Code's `/usage` command or [statusline](https://code.claude.com/docs/en/statusline). Use `--cli` mode to route through Claude Code's binary, which is not affected by these limits.
117
+ **dario fixes this.** It creates a local proxy that translates API key auth into your subscription's OAuth tokens. Your subscription handles the billing. No API key needed.
115
118
 
116
- **dario fixes this.** It creates a local proxy that translates API key auth into your subscription's OAuth tokens and with `--cli` mode, routes through the Claude Code binary for uninterrupted access.
119
+ **Note:** Claude subscriptions have [usage limits](https://support.claude.com/en/articles/11647753-how-do-usage-and-length-limits-work) that reset on rolling 5-hour and 7-day windows. You can check your utilization via Claude Code's `/usage` command or the [statusline](https://code.claude.com/docs/en/statusline).
117
120
 
118
121
  ## Quick Start
119
122
 
120
123
  ### Prerequisites
121
124
 
122
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) installed and logged in (recommended). Dario detects your existing Claude Code credentials automatically.
125
+ [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) installed and logged in (recommended). Dario detects your existing Claude Code credentials automatically and also auto-extracts the current OAuth client config from the installed CC binary so dario stays in sync with whatever CC version you have, even when Anthropic rotates client IDs.
123
126
 
124
127
  If Claude Code isn't installed, dario runs its own OAuth flow — opens your browser, you authorize, done.
125
128
 
@@ -178,46 +181,13 @@ continue # in VS Code, set base URL in config
178
181
  python my_script.py
179
182
  ```
180
183
 
181
- ## CLI Backend
182
-
183
- If you're getting rate limited on Opus or Sonnet, use `--cli` mode. This routes requests through the Claude Code binary instead of hitting the API directly. Claude Code has priority routing that continues working even when direct API calls return 429.
184
-
185
- ```bash
186
- dario proxy --cli # Opus works even when rate limited
187
- dario proxy --cli --model=opus # Force Opus + CLI backend
188
- ```
189
-
190
- ```
191
- dario — http://localhost:3456
192
-
193
- Your Claude subscription is now an API.
194
-
195
- Usage:
196
- ANTHROPIC_BASE_URL=http://localhost:3456
197
- ANTHROPIC_API_KEY=dario
198
-
199
- Backend: Claude CLI (bypasses rate limits)
200
- Model: claude-opus-4-6 (all requests)
201
- ```
202
-
203
- **Trade-offs vs direct API mode:**
204
-
205
- | | Direct API (default) | CLI Backend (`--cli`) | Passthrough (`--passthrough`) |
206
- |---|---|---|---|
207
- | Streaming | Native SSE | SSE (converted from JSON) | Native SSE |
208
- | Tool use | Yes | No | Yes |
209
- | Thinking/billing injection | Yes (Claude-optimized) | N/A | No (OAuth swap only) |
210
- | Latency | Low | Higher (process spawn) | Low |
211
- | Rate limits | Priority routing | Not affected | Standard (no priority) |
212
- | Opus when throttled | Auto CLI fallback | **Always works** | May return 429 |
213
-
214
184
  ## Passthrough Mode
215
185
 
216
- For tools that need exact Anthropic protocol fidelity with zero modification, use `--passthrough`. This does OAuth swap only — no billing tag, no thinking injection, no device identity, no extra beta flags. Note: most tools (including Hermes and OpenClaw) work better through default mode, which handles billing classification and token optimization automatically.
186
+ For tools that need exact Anthropic protocol fidelity with zero modification, use `--passthrough` (alias: `--thin`). This does OAuth swap only — no billing tag, no template replay, no device identity, no extra beta flags. Note: most tools (including Hermes and OpenClaw) work better through default mode, which handles billing classification automatically.
217
187
 
218
188
  ```bash
219
189
  dario proxy --passthrough # Thin proxy, zero injection
220
- dario proxy --passthrough --model=opus # Thin proxy + model override
190
+ dario proxy --thin --model=opus # Thin proxy + model override
221
191
  ```
222
192
 
223
193
  ## Model Selection
@@ -233,12 +203,6 @@ dario proxy # Passthrough (client decides)
233
203
 
234
204
  Full model IDs also work: `--model=claude-opus-4-6`
235
205
 
236
- Combine with `--cli` for rate-limit-proof Opus:
237
-
238
- ```bash
239
- dario proxy --cli --model=opus
240
- ```
241
-
242
206
  ## OpenAI Compatibility
243
207
 
244
208
  Dario implements `/v1/chat/completions` — any tool built for the OpenAI API works with your Claude subscription. No code changes needed.
@@ -342,8 +306,6 @@ model:
342
306
  default: claude-opus-4-6
343
307
  ```
344
308
 
345
- Then run `hermes` normally — it routes through dario using your Claude subscription.
346
-
347
309
  ### OpenClaw
348
310
 
349
311
  Add to your `openclaw.json` models config:
@@ -382,52 +344,81 @@ Add to your `openclaw.json` models config:
382
344
 
383
345
  **Note:** Use `http://127.0.0.1:3456` without `/v1` — OpenClaw adds the path itself.
384
346
 
347
+ ---
348
+
385
349
  ## How It Works
386
350
 
387
351
  ### Direct API Mode (default) — Template Replay
388
352
 
389
353
  ```
390
- ┌──────────┐ ┌─────────────────────┐ ┌──────────────────┐
391
- │ Your App │ ──> │ dario (proxy) │ ──> │ api.anthropic.com│
392
- │ │ localhost:3456 │ │ │
393
- │ sends │ │ │ │ sees a genuine │
394
- │ its own │ │ replaces request │ │ Claude Code │
395
- │ tools & │ │ with CC template │ │ request │
396
- │ params │ │ keeps only content │ │ │
397
- └──────────┘ └─────────────────────┘ └──────────────────┘
354
+ ┌───────────┐ ┌─────────────────────┐ ┌──────────────────┐
355
+ │ Your App │ ──> │ dario (proxy) │ ──> │ api.anthropic.com│
356
+ │ │ localhost:3456 │ │ │
357
+ │ sends │ │ │ │ sees a genuine │
358
+ │ its own │ │ replaces request │ │ Claude Code │
359
+ │ tools & │ │ with CC template │ │ request │
360
+ │ params │ │ keeps only content │ │ │
361
+ └───────────┘ └─────────────────────┘ └──────────────────┘
398
362
  ```
399
363
 
400
364
  Your app sends whatever it wants — any tools, any parameters. dario replaces the entire request with Claude Code's template and injects only your conversation content. The upstream sees CC's exact tool definitions, field structure, and parameters.
401
365
 
402
- ### CLI Backend Mode (`--cli`)
366
+ ### Passthrough Mode (`--passthrough`)
403
367
 
404
368
  ```
405
- ┌──────────┐ ┌─────────────────┐ ┌──────────────────┐
406
- │ Your App │ ──> │ dario (proxy) │ ──> │ claude --print
407
- │ │ localhost:3456 │ │ (Claude Code)
408
- │ sends │ │ extracts prompt│ │
409
- │ API │ │ spawns CLI │ │ has priority
410
- │ request │ │ wraps response │ │ routing
411
- └──────────┘ └─────────────────┘ └──────────────────┘
369
+ ┌───────────┐ ┌─────────────────┐ ┌──────────────────┐
370
+ │ Your App │ ──> │ dario (proxy) │ ──> │ api.anthropic.com
371
+ │ │ localhost:3456 │ │
372
+ │ sends │ │ swaps API key │ │ sees valid
373
+ │ API │ │ for OAuth │ │ OAuth bearer
374
+ │ request │ │ nothing else │ │ token
375
+ └───────────┘ └─────────────────┘ └──────────────────┘
412
376
  ```
413
377
 
414
- ### Passthrough Mode (`--passthrough`)
378
+ ### What dario actually sends upstream
379
+
380
+ In direct mode, every request dario sends to Anthropic is a genuine Claude Code request. Key fields injected or enforced:
415
381
 
382
+ **Billing tag** — reconstructed using Claude Code's own algorithm extracted from the CC binary:
416
383
  ```
417
- ┌──────────┐ ┌─────────────────┐ ┌──────────────────┐
418
- │ Your App │ ──> │ dario (proxy) │ ──> │ api.anthropic.com│
419
- │ │ │ localhost:3456 │ │ │
420
- │ sends │ │ swaps API key │ │ sees valid │
421
- │ API │ │ for OAuth │ │ OAuth bearer │
422
- │ request │ │ nothing else │ │ token │
423
- └──────────┘ └─────────────────┘ └──────────────────┘
384
+ x-anthropic-billing-header: cc_version=<version>.<build_tag>; cc_entrypoint=cli; cch=<5-char-hex>;
424
385
  ```
386
+ The build tag is `SHA-256(seed + chars[4,7,20] of user message + version).slice(0,3)`. The `cch` is a fresh random 5-char hex per request. Both were extracted via MITM capture.
425
387
 
426
- 1. **`dario login`** Detects your existing Claude Code credentials (`~/.claude/.credentials.json`) and starts the proxy automatically. If Claude Code isn't installed, runs a PKCE OAuth flow with a local callback server to capture the token automatically.
388
+ **Beta set**exactly 8 betas from CC, in CC's order:
389
+ ```
390
+ claude-code-20250219, oauth-2025-04-20, context-1m-2025-08-07,
391
+ interleaved-thinking-2025-05-14, context-management-2025-06-27,
392
+ prompt-caching-scope-2026-01-05, advisor-tool-2026-03-01, effort-2025-11-24
393
+ ```
394
+
395
+ **Request headers** — CC's exact Stainless SDK headers, including `x-stainless-runtime-version: v24.3.0` (the Node.js compat version CC reports when running on Bun), `x-app: cli`, `user-agent: claude-cli/<version>`, `anthropic-dangerous-direct-browser-access: true`.
396
+
397
+ **Upstream URL** — `api.anthropic.com/v1/messages?beta=true`, matching CC's own request format.
398
+
399
+ **Device identity** — `metadata.user_id` loaded from `~/.claude/.claude.json`. Without this, Anthropic classifies the request as third-party and routes it to Extra Usage billing instead of the Max plan allocation.
400
+
401
+ **Session ID** — rotates per request via `x-claude-code-session-id`. A persistent session ID across many rapid requests is a behavioral detection signal; CC `--print` creates a new session each invocation.
402
+
403
+ **Rate governor** — 500ms minimum between requests (configurable via `DARIO_MIN_INTERVAL_MS`). Configurable for agent workloads that need tighter pacing.
404
+
405
+ ### OAuth Config Auto-Detection
427
406
 
428
- 2. **`dario proxy`** — Starts an HTTP server on localhost that implements the Anthropic Messages API. In direct mode, it swaps your API key for an OAuth bearer token. In CLI mode, it routes through the Claude Code binary.
407
+ Anthropic periodically rotates the OAuth `client_id`, authorize URL, token URL, and scopes that Claude Code uses. Historically this caused `"Invalid client id"` errors until a new dario release shipped.
429
408
 
430
- 3. **Auto-refresh** OAuth tokens expire. Dario refreshes them automatically in the background every 15 minutes. Refresh tokens rotate on each use.
409
+ Dario scans the installed CC binary at startup and extracts the current config directly:
410
+
411
+ - **Anchor**: `OAUTH_FILE_SUFFIX:"-local-oauth"` — the config block CC uses for clients that run their own localhost callback.
412
+ - **Extracted**: `CLIENT_ID`, `CLAUDE_AI_AUTHORIZE_URL`, `TOKEN_URL`, and the full `user:*` scope string.
413
+ - **Cached**: Results stored at `~/.dario/cc-oauth-cache.json` keyed by binary fingerprint (first 64KB sha256 + size + mtime). Cold scan ~500ms, cache hit ~5ms. Re-scans only when CC is upgraded.
414
+ - **Fallback**: If CC is not installed or scanning fails, dario uses known-good hardcoded values. No user action needed.
415
+ - **Override**: Set `DARIO_CC_PATH=/path/to/claude` to point dario at a non-standard CC binary location.
416
+
417
+ CC ships **two** OAuth client configurations in one binary — a `-local-oauth` flow (localhost callback) and a platform-hosted flow (`platform.claude.com/oauth/code/callback`). Dario must use the former. The scanner anchors specifically on the local block.
418
+
419
+ End-to-end verification lives at [`test/oauth-detector.mjs`](test/oauth-detector.mjs).
420
+
421
+ ---
431
422
 
432
423
  ## Commands
433
424
 
@@ -444,49 +435,45 @@ Your app sends whatever it wants — any tools, any parameters. dario replaces t
444
435
 
445
436
  | Flag/Env | Description | Default |
446
437
  |----------|-------------|---------|
447
- | `--cli` | Use Claude CLI as backend (bypasses rate limits) | off |
448
- | `--passthrough` | Thin proxy OAuth swap only, no injection | off |
438
+ | `--passthrough` / `--thin` | Thin proxy OAuth swap only, no injection | off |
439
+ | `--preserve-tools` / `--keep-tools` | Keep client tool schemas instead of remapping to CC tools | off |
449
440
  | `--model=MODEL` | Force a model (`opus`, `sonnet`, `haiku`, or full ID) | passthrough |
450
441
  | `--port=PORT` | Port to listen on | `3456` |
451
442
  | `--verbose` / `-v` | Log every request | off |
452
- | `DARIO_API_KEY` | If set, all endpoints (except `/health`) require matching `x-api-key` header or `Authorization: Bearer` header | unset (open) |
443
+ | `DARIO_API_KEY` | If set, all endpoints (except `/health`) require matching `x-api-key` or `Authorization: Bearer` | unset (open) |
453
444
  | `DARIO_NO_BUN` | Disable automatic Bun relaunch (stay on Node.js) | unset |
454
445
  | `DARIO_MIN_INTERVAL_MS` | Minimum ms between requests (rate governor) | `500` |
446
+ | `DARIO_CC_PATH` | Override path to Claude Code binary for OAuth detection | auto-detect |
455
447
 
456
448
  ## Supported Features
457
449
 
458
450
  ### Direct API Mode
459
451
  - All Claude models (Opus 4.6, Sonnet 4.6, Haiku 4.5) + 1M extended context aliases (`opus1m`, `sonnet1m`)
460
- - **Template replay** (v3.0+) — replaces the entire request with Claude Code's exact template, extracted via MITM capture from CC v2.1.104. 25 tool definitions, 25KB system prompt, exact body key order, exact beta headers (model-conditional), exact metadata structure. Client tools are mapped to CC equivalents and reverse-mapped in responses. Template data stored as JSON for easy updates. See [Discussion 13](https://github.com/askalf/dario/discussions/13) and [Discussion 14](https://github.com/askalf/dario/discussions/14).
461
- - **Bun auto-relaunch** (v3.2) auto-detects Bun and relaunches under it for TLS fingerprint fidelity. CC runs on Bun; Node.js has a different TLS fingerprint visible at the network level.
462
- - **Session ID rotation** (v3.2) each request gets a fresh session ID, matching CC `--print` behavior.
463
- - **Rate governor** (v3.2) 500ms minimum interval between requests prevents inhuman cadence. Configurable via `DARIO_MIN_INTERVAL_MS`.
464
- - **Enriched 429 errors** — rate limit errors include utilization %, limiting window, and reset time instead of Anthropic's default `"Error"` message
465
- - **Auto CLI fallback** — if the API returns 429 and Claude Code is installed, transparently retries through `claude --print` with SSE conversion
466
- - **OpenAI-compatible** (`/v1/chat/completions`) works with any OpenAI SDK or tool
467
- - Streaming and non-streaming (both Anthropic and OpenAI SSE formats, including tool_use streaming)
468
- - Tool use / function calling
469
- - System prompts and multi-turn conversations
470
- - Prompt caching and extended thinking
471
- - **Billable beta filtering** — strips `extended-cache-ttl` from client betas (the only prefix requiring Extra Usage)
472
- - **Beta deduplication** client-provided betas are deduplicated against the base set before appending
473
- - **Orchestration tag sanitization** — strips agent-injected XML (`<system-reminder>`, `<env>`, `<task_metadata>`, etc.) before forwarding
474
- - **Token anomaly detection** — warns on context spike (>60% input growth) or output explosion (>2x previous)
475
- - Concurrency control (max 10 concurrent upstream requests)
476
- - CORS enabled (works from browser apps on localhost)
477
-
478
- ### CLI Backend Mode
479
- - All Claude models — including Opus when rate limited
480
- - Streaming via SSE conversion (client sends `stream: true`, CLI JSON response is converted to Anthropic or OpenAI SSE events)
481
- - OpenAI compatibility (translates OpenAI → Anthropic before CLI, Anthropic → OpenAI after)
482
- - System prompts and multi-turn conversations (via context injection)
483
- - Not affected by API rate limits
452
+ - **Template replay** — replaces the entire request with Claude Code's exact template. 25 tool definitions, 25KB system prompt, exact body key order, exact beta headers (model-conditional), exact metadata structure. Client tools are mapped to CC equivalents and reverse-mapped in responses. Template data stored as JSON for easy updates.
453
+ - **`--preserve-tools` mode** — opt-out of CC tool schema replacement for agent frameworks that rely on their own custom tool definitions. Default mode still remaps for maximum detection resistance.
454
+ - **OAuth auto-detect** — scans the installed CC binary for OAuth config at startup. Stays in sync with whatever CC version you have; falls back to known-good hardcoded values if no binary is found. Override with `DARIO_CC_PATH`.
455
+ - **Bun auto-relaunch** — auto-detects Bun and relaunches under it for TLS fingerprint fidelity. CC runs on Bun; Node.js has a different TLS fingerprint visible at the network level.
456
+ - **Session ID rotation** — each request gets a fresh session ID via `x-claude-code-session-id`, matching CC behavior.
457
+ - **Rate governor** — configurable minimum interval between requests via `DARIO_MIN_INTERVAL_MS`.
458
+ - **Enriched 429 errors** — rate limit errors include utilization %, limiting window, and reset time instead of Anthropic's default `"Error"` message.
459
+ - **Auto-retry on long-context errors** — when Anthropic returns 400 or 429 with `"long context beta is not yet available"` or `"Extra usage is required"`, dario transparently retries without the `context-1m-2025-08-07` beta flag.
460
+ - **OpenAI-compatible** (`/v1/chat/completions`) works with any OpenAI SDK or tool.
461
+ - Streaming and non-streaming (both Anthropic and OpenAI SSE formats, including tool_use streaming).
462
+ - Tool use / function calling.
463
+ - System prompts and multi-turn conversations.
464
+ - Prompt caching and extended thinking.
465
+ - **Billable beta filtering** — strips `extended-cache-ttl` from client betas (the only beta requiring Extra Usage enabled on the account).
466
+ - **Beta deduplication** — client-provided betas are deduplicated against the base set before appending.
467
+ - **Orchestration tag sanitization** — strips agent-injected XML (`<system-reminder>`, `<env>`, `<task_metadata>`, etc.) before forwarding.
468
+ - **Token anomaly detection** — warns on context spike (>60% input growth) or output explosion (>2x previous).
469
+ - Concurrency control (max 10 concurrent upstream requests).
470
+ - CORS enabled (works from browser apps on localhost).
484
471
 
485
472
  ### Passthrough Mode
486
- - All Claude models with native streaming and tool use
487
- - OAuth token swap only — no billing tag, thinking, effort, or device identity injection
488
- - Minimal beta flags (`oauth-2025-04-20` + client betas only)
489
- - For tools that need exact Anthropic protocol fidelity with zero modification
473
+ - All Claude models with native streaming and tool use.
474
+ - OAuth token swap only — no billing tag, no template injection, no device identity.
475
+ - Minimal beta flags (`oauth-2025-04-20` + client betas only).
476
+ - For tools that need exact Anthropic protocol fidelity with zero modification.
490
477
 
491
478
  ## Endpoints
492
479
 
@@ -519,17 +506,45 @@ curl http://localhost:3456/health
519
506
  |---------|---------------------|
520
507
  | Credential storage | Reads from Claude Code (`~/.claude/.credentials.json`) or its own store (`~/.dario/credentials.json`) with `0600` permissions |
521
508
  | OAuth flow | PKCE (Proof Key for Code Exchange) — no client secret needed |
522
- | Token transmission | OAuth tokens never leave localhost. Only forwarded to `api.anthropic.com` over HTTPS |
523
- | Network exposure | Proxy binds to `127.0.0.1` only not accessible from other machines |
524
- | SSRF protection | Hardcoded allowlist of API paths only `/v1/messages`, `/v1/models`, `/v1/complete` are proxied |
525
- | Token rotation | Refresh tokens rotate on every use (single-use) |
526
- | Error sanitization | Token patterns redacted from all error messages |
527
- | Data collection | Zero. No telemetry, no analytics, no phoning home |
509
+ | OAuth config source | Auto-detected from local CC binary at runtime; cached at `~/.dario/cc-oauth-cache.json`. Detector reads binary in read-only mode, never modifies it. |
510
+ | Token exposure | Tokens never logged; redacted from all error messages. |
511
+ | Network binding | Binds exclusively to `127.0.0.1`. Upstream traffic goes only to `api.anthropic.com` over HTTPS. |
512
+ | Auth timing | `timingSafeEqual` used for `DARIO_API_KEY` comparison. |
513
+ | SSRF protection | Only `/v1/messages` and `/v1/complete` are proxied upstream — hardcoded allowlist. |
514
+ | Body size | 10MB hard cap per request. 30s read timeout prevents slow-loris. |
515
+ | Token refresh | Auto-refreshes 30 minutes before expiry. Refresh tokens rotate on each use. Mutex prevents concurrent refresh races. |
516
+ | Telemetry | None. Zero analytics, tracking, or data collection of any kind. |
517
+
518
+ ---
519
+
520
+ ## askalf
521
+
522
+ dario solves the API access problem — your $200/mo subscription, usable everywhere, billed correctly.
523
+
524
+ But a proxy has a ceiling. Every request still runs on your single account, with your subscription's rate limits, on your machine. When you need to scale beyond that — multiple accounts, persistent browser sessions, desktop control, scheduled workflows, a fleet of agents that can run while you sleep — that's what [askalf](https://askalf.org) is built for.
525
+
526
+ **askalf** is the agent platform built on top of the same OAuth and billing infrastructure that powers dario:
527
+
528
+ | | dario | askalf |
529
+ |---|---|---|
530
+ | **What it is** | Local proxy, single account | Hosted agent fleet, multi-account |
531
+ | **Rate limits** | Your subscription's limits | Distributed across fleet, near-zero 429s |
532
+ | **Browser / desktop** | No | Yes — full computer use |
533
+ | **Scheduling** | No | Yes — cron, webhooks, triggers |
534
+ | **Persistent memory** | No | Yes — per-agent memory and context |
535
+ | **Custom tools** | Via `--preserve-tools` | Native MCP tool server |
536
+ | **Setup** | 2 commands | Waitlist → dashboard |
537
+
538
+ If you're running multi-agent workflows, hitting rate limits on Claude Max, or want agents that run 24/7 without babysitting, **[join the waitlist at askalf.org](https://askalf.org)**.
539
+
540
+ dario will always be open-source and free. askalf is the hosted tier for teams who need more.
541
+
542
+ ---
528
543
 
529
544
  ## FAQ
530
545
 
531
546
  **Does this violate Anthropic's terms of service?**
532
- Dario uses your existing Claude Code credentials with the same OAuth tokens. It authenticates you as you, with your subscription, through Anthropic's official API. The `--cli` mode literally uses Claude Code itself as the backend.
547
+ Dario uses your existing Claude Code credentials with the same OAuth tokens. It authenticates you as you, with your subscription, through Anthropic's official API.
533
548
 
534
549
  **What subscription plans work?**
535
550
  Claude Max and Claude Pro. Any plan that lets you use Claude Code.
@@ -538,7 +553,7 @@ Claude Max and Claude Pro. Any plan that lets you use Claude Code.
538
553
  Should work if your plan includes Claude Code access. Not tested yet — please open an issue with results.
539
554
 
540
555
  **Do I need Claude Code installed?**
541
- Recommended but not required. If Claude Code is installed and logged in, `dario login` picks up your credentials automatically. Without Claude Code, dario runs its own OAuth flow to authenticate directly. Note: `--cli` mode requires Claude Code (`npm install -g @anthropic-ai/claude-code`).
556
+ Recommended but not required. If Claude Code is installed and logged in, `dario login` picks up your credentials automatically. Without Claude Code, dario runs its own OAuth flow to authenticate directly.
542
557
 
543
558
  **First time setup — account priming**
544
559
  If dario is the first thing you use with a new Claude account, run a few real Claude Code commands first to establish a session baseline:
@@ -555,14 +570,19 @@ Optional but recommended. If [Bun](https://bun.sh) is installed, dario auto-rela
555
570
  **What happens when my token expires?**
556
571
  Dario auto-refreshes tokens 30 minutes before expiry. You should never see an auth error in normal use. If something goes wrong, `dario refresh` forces an immediate refresh.
557
572
 
558
- **I'm getting rate limited on Opus. What do I do?**
559
- Use `--cli` mode: `dario proxy --cli`. This routes through the Claude Code binary, which continues working when direct API calls are rate limited. In default mode, dario automatically falls back to CLI when it detects a 429 (if Claude Code is installed). Rate limit errors include utilization percentages and reset times so you can see exactly when capacity returns. You can also enable [extra usage](https://support.claude.com/en/articles/12429409-manage-extra-usage-for-paid-claude-plans) in your Anthropic account settings to extend your limits at API rates.
573
+ **What happens when Anthropic rotates the OAuth client_id or URL?**
574
+ Dario auto-detects OAuth config from your installed Claude Code binary. When CC ships a new version with rotated values, dario picks them up on the next startup no dario release needed. The detector is cached at `~/.dario/cc-oauth-cache.json` and only re-scans when the binary fingerprint changes. If CC isn't installed, dario falls back to known-good hardcoded values.
575
+
576
+ **I'm hitting rate limits. What do I do?**
577
+ Claude subscriptions have rolling 5-hour and 7-day usage windows. Check your utilization with Claude Code's `/usage` command or the [statusline](https://code.claude.com/docs/en/statusline). Rate limit errors from dario include utilization percentages and reset times so you can see exactly when capacity returns.
578
+
579
+ If you're running a multi-agent workload and consistently hitting limits, [askalf](https://askalf.org) distributes load across multiple accounts automatically.
560
580
 
561
581
  **What are the usage limits?**
562
- Claude subscriptions have rolling 5-hour and 7-day usage windows shared across claude.ai and Claude Code. See [Anthropic's docs](https://support.claude.com/en/articles/11647753-how-do-usage-and-length-limits-work) for details. In Claude Code, use `/usage` to check your current limits, or configure the [statusline](https://code.claude.com/docs/en/statusline) to show real-time 5h and 7d utilization percentages.
582
+ Claude subscriptions have rolling 5-hour and 7-day usage windows shared across claude.ai and Claude Code. See [Anthropic's docs](https://support.claude.com/en/articles/11647753-how-do-usage-and-length-limits-work) for details.
563
583
 
564
584
  **Can I run this on a server?**
565
- Dario binds to localhost by default. For server use, you'd need to handle the initial login on a machine with a browser, then copy `~/.claude/.credentials.json` (or `~/.dario/credentials.json`) to your server. Auto-refresh will keep it alive from there.
585
+ Dario binds to localhost by default. For server use, handle the initial login on a machine with a browser, then copy `~/.claude/.credentials.json` (or `~/.dario/credentials.json`) to your server. Auto-refresh will keep it alive from there.
566
586
 
567
587
  **Why "dario"?**
568
588
  Named after [Dario Amodei](https://en.wikipedia.org/wiki/Dario_Amodei), CEO of Anthropic.
@@ -577,12 +597,12 @@ import { startProxy, getAccessToken, getStatus } from "@askalf/dario";
577
597
  // Start the proxy programmatically
578
598
  await startProxy({ port: 3456, verbose: true });
579
599
 
580
- // CLI backend mode
581
- await startProxy({ port: 3456, cliBackend: true, model: "opus" });
582
-
583
600
  // Passthrough mode (OAuth swap only, no injection)
584
601
  await startProxy({ port: 3456, passthrough: true });
585
602
 
603
+ // Preserve-tools mode (keep client tool schemas)
604
+ await startProxy({ port: 3456, preserveTools: true });
605
+
586
606
  // Or just get a raw access token
587
607
  const token = await getAccessToken();
588
608
 
@@ -597,7 +617,7 @@ Dario handles your OAuth tokens. Here's why you can trust it:
597
617
 
598
618
  | Signal | Status |
599
619
  |--------|--------|
600
- | **Source code** | ~2,100 lines of TypeScript — small enough to audit in one sitting |
620
+ | **Source code** | ~2,000 lines of TypeScript — small enough to audit in one sitting |
601
621
  | **Dependencies** | 0 runtime dependencies. Verify: `npm ls --production` |
602
622
  | **npm provenance** | Every release is [SLSA attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions |
603
623
  | **Security scanning** | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) runs on every push and weekly |
@@ -623,21 +643,22 @@ cd $(npm root -g)/@askalf/dario && npm ls --production
623
643
  |-------|------|
624
644
  | v3.0 Template Replay — why we stopped matching signals | [Discussion 14](https://github.com/askalf/dario/discussions/14) |
625
645
  | Claude Code defaults are detection signals, not optimizations | [Discussion 13](https://github.com/askalf/dario/discussions/13) |
626
- | Why Opus 4.6 feels worse and how to fix it | [Discussion 9](https://github.com/askalf/dario/discussions/9) |
646
+ | Why Opus feels worse through other proxies and how to fix it | [Discussion 9](https://github.com/askalf/dario/discussions/9) |
627
647
  | Billing tag algorithm and fingerprint analysis | [Discussion 8](https://github.com/askalf/dario/discussions/8) |
628
648
  | Rate limit header analysis | [Discussion 1](https://github.com/askalf/dario/discussions/1) |
629
649
 
630
650
  ## Contributing
631
651
 
632
- PRs welcome. The codebase is ~2,100 lines of TypeScript across 5 files:
652
+ PRs welcome. The codebase is ~2,000 lines of TypeScript across 7 files:
633
653
 
634
654
  | File | Purpose |
635
655
  |------|---------|
636
- | `src/proxy.ts` | HTTP proxy server, CLI backend, rate governor |
637
- | `src/cc-template.ts` | CC template engine + tool mapping |
638
- | `src/cc-template-data.json` | MITM-extracted CC data (25 tools, 25KB system prompt) |
639
- | `src/oauth.ts` | Token storage, refresh, credential detection |
640
- | `src/cli.ts` | CLI entry point + Bun auto-relaunch |
656
+ | `src/proxy.ts` | HTTP proxy server, rate governor, billing tag, response forwarding |
657
+ | `src/cc-template.ts` | Template engine, tool mapping, orchestration sanitization |
658
+ | `src/cc-template-data.json` | CC request template data (25 tools, 25KB system prompt) |
659
+ | `src/cc-oauth-detect.ts` | Auto-detect OAuth config from the installed CC binary |
660
+ | `src/oauth.ts` | Token storage, PKCE flow, auto-refresh, credential detection |
661
+ | `src/cli.ts` | CLI entry point, command routing, Bun auto-relaunch |
641
662
  | `src/index.ts` | Library exports |
642
663
 
643
664
  ```bash
@@ -652,7 +673,7 @@ npm run dev # runs with tsx (no build needed)
652
673
  | Who | Contributions |
653
674
  |-----|---------------|
654
675
  | [@GodsBoy](https://github.com/GodsBoy) | Proxy authentication, token redaction, error sanitization ([#2](https://github.com/askalf/dario/pull/2)) |
655
- | [@belangertrading](https://github.com/belangertrading) | Billing classification investigation ([#4](https://github.com/askalf/dario/issues/4)), Opus/Sonnet 429 diagnosis + CLI fallback workaround ([#6](https://github.com/askalf/dario/issues/6)), billing reclassification root cause ([#7](https://github.com/askalf/dario/issues/7)) |
676
+ | [@belangertrading](https://github.com/belangertrading) | Billing classification investigation ([#4](https://github.com/askalf/dario/issues/4)), billing reclassification root cause ([#7](https://github.com/askalf/dario/issues/7)) |
656
677
 
657
678
  ## License
658
679
 
@@ -0,0 +1,47 @@
1
+ /**
2
+ * CC OAuth Auto-Detection
3
+ *
4
+ * Scans the installed Claude Code binary to extract its OAuth configuration
5
+ * (client_id, authorize URL, token URL, scopes). Eliminates the need to
6
+ * hardcode values that Anthropic rotates between CC releases.
7
+ *
8
+ * CC ships two OAuth client configurations in one binary:
9
+ *
10
+ * 1. LOCAL flow — used when the OAuth client owns the callback
11
+ * (i.e. runs an HTTP server on localhost). This is what dario does.
12
+ * Identified by OAUTH_FILE_SUFFIX:"-local-oauth" next to the CLIENT_ID.
13
+ *
14
+ * 2. PLATFORM flow — used when the callback is hosted at
15
+ * platform.claude.com/oauth/code/callback. Different CLIENT_ID.
16
+ * Not applicable to dario.
17
+ *
18
+ * We scan for the LOCAL block and extract its config.
19
+ *
20
+ * Results are cached per-binary-hash at ~/.dario/cc-oauth-cache.json so
21
+ * startup only re-scans when the user upgrades Claude Code.
22
+ */
23
+ export interface DetectedOAuthConfig {
24
+ clientId: string;
25
+ authorizeUrl: string;
26
+ tokenUrl: string;
27
+ scopes: string;
28
+ source: 'detected' | 'cached' | 'fallback';
29
+ ccPath?: string;
30
+ ccHash?: string;
31
+ }
32
+ /**
33
+ * Scan binary bytes for the LOCAL-oauth OAuth block.
34
+ * Uses Buffer.indexOf to locate anchor strings, then slices a small
35
+ * window of context to run regexes on. This avoids converting the
36
+ * whole binary to a JS string.
37
+ */
38
+ export declare function scanBinaryForOAuthConfig(buf: Buffer): Omit<DetectedOAuthConfig, 'source' | 'ccPath' | 'ccHash'> | null;
39
+ /**
40
+ * Get the OAuth config for dario to use. Scans the installed CC binary
41
+ * on first call, caches to disk, and memoizes in-process for subsequent
42
+ * calls. If no binary is found or scanning fails, falls back to the
43
+ * known-good v2.1.104 values.
44
+ */
45
+ export declare function detectCCOAuthConfig(): Promise<DetectedOAuthConfig>;
46
+ /** Test-only: reset in-process memoization. */
47
+ export declare function _resetDetectorCache(): void;