@askalf/dario 3.4.0 → 3.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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">
@@ -74,15 +78,13 @@ Opus, Sonnet, Haiku — all models, streaming, tool use. **Zero dependencies.**
74
78
  </tr>
75
79
  </table>
76
80
 
77
- > **Need more than a proxy?** Dario solves the API access problem. If you need a full agent fleet — desktop control, browser automation, scheduling, custom tools, persistent memory — check out the [askalf platform](https://askalf.org). Same team, different execution model that solves the proxy ceiling entirely.
78
-
79
81
  ---
80
82
 
81
83
  ## Why dario
82
84
 
83
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.
84
86
 
85
- 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.
86
88
 
87
89
  | | dario | Other proxies |
88
90
  |---|---|---|
@@ -95,15 +97,14 @@ dario is the only proxy that solves this. Instead of transforming your requests
95
97
  <details>
96
98
  <summary><strong>vs competitors</strong></summary>
97
99
 
98
- | Feature | dario | Meridian (710 stars) | CLIProxyAPI (24K stars) |
100
+ | Feature | dario | Meridian | CLIProxyAPI |
99
101
  |---------|-------|---------|------------|
100
- | Template replay (undetectable) | **Yes** | No | Inherited (CLI-only) |
102
+ | Template replay (undetectable) | **Yes** | No | No |
101
103
  | Direct OAuth (streaming, tools) | **Yes** | Yes (SDK-based) | No |
102
- | CLI fallback (rate limit bypass) | **Yes** | No | Yes (only mode) |
103
104
  | OpenAI API compat | **Yes** | Yes | Yes |
104
105
  | Orchestration sanitization | **Yes** | Yes | No |
105
106
  | Token anomaly detection | **Yes** | Yes | No |
106
- | Codebase size | ~2,100 lines | ~9,000 lines | Platform |
107
+ | Codebase size | ~2,000 lines | ~9,000 lines | Platform |
107
108
  | Dependencies | 0 | Many | Many |
108
109
  | Setup | 2 commands | Config + build | Config + dashboard |
109
110
 
@@ -113,15 +114,15 @@ dario is the only proxy that solves this. Instead of transforming your requests
113
114
 
114
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.
115
116
 
116
- **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.
117
118
 
118
- **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).
119
120
 
120
121
  ## Quick Start
121
122
 
122
123
  ### Prerequisites
123
124
 
124
- [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.
125
126
 
126
127
  If Claude Code isn't installed, dario runs its own OAuth flow — opens your browser, you authorize, done.
127
128
 
@@ -180,46 +181,13 @@ continue # in VS Code, set base URL in config
180
181
  python my_script.py
181
182
  ```
182
183
 
183
- ## CLI Backend
184
-
185
- 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.
186
-
187
- ```bash
188
- dario proxy --cli # Opus works even when rate limited
189
- dario proxy --cli --model=opus # Force Opus + CLI backend
190
- ```
191
-
192
- ```
193
- dario — http://localhost:3456
194
-
195
- Your Claude subscription is now an API.
196
-
197
- Usage:
198
- ANTHROPIC_BASE_URL=http://localhost:3456
199
- ANTHROPIC_API_KEY=dario
200
-
201
- Backend: Claude CLI (bypasses rate limits)
202
- Model: claude-opus-4-6 (all requests)
203
- ```
204
-
205
- **Trade-offs vs direct API mode:**
206
-
207
- | | Direct API (default) | CLI Backend (`--cli`) | Passthrough (`--passthrough`) |
208
- |---|---|---|---|
209
- | Streaming | Native SSE | SSE (converted from JSON) | Native SSE |
210
- | Tool use | Yes | No | Yes |
211
- | Thinking/billing injection | Yes (Claude-optimized) | N/A | No (OAuth swap only) |
212
- | Latency | Low | Higher (process spawn) | Low |
213
- | Rate limits | Priority routing | Not affected | Standard (no priority) |
214
- | Opus when throttled | Auto CLI fallback | **Always works** | May return 429 |
215
-
216
184
  ## Passthrough Mode
217
185
 
218
- 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.
219
187
 
220
188
  ```bash
221
189
  dario proxy --passthrough # Thin proxy, zero injection
222
- dario proxy --passthrough --model=opus # Thin proxy + model override
190
+ dario proxy --thin --model=opus # Thin proxy + model override
223
191
  ```
224
192
 
225
193
  ## Model Selection
@@ -235,12 +203,6 @@ dario proxy # Passthrough (client decides)
235
203
 
236
204
  Full model IDs also work: `--model=claude-opus-4-6`
237
205
 
238
- Combine with `--cli` for rate-limit-proof Opus:
239
-
240
- ```bash
241
- dario proxy --cli --model=opus
242
- ```
243
-
244
206
  ## OpenAI Compatibility
245
207
 
246
208
  Dario implements `/v1/chat/completions` — any tool built for the OpenAI API works with your Claude subscription. No code changes needed.
@@ -344,8 +306,6 @@ model:
344
306
  default: claude-opus-4-6
345
307
  ```
346
308
 
347
- Then run `hermes` normally — it routes through dario using your Claude subscription.
348
-
349
309
  ### OpenClaw
350
310
 
351
311
  Add to your `openclaw.json` models config:
@@ -384,52 +344,81 @@ Add to your `openclaw.json` models config:
384
344
 
385
345
  **Note:** Use `http://127.0.0.1:3456` without `/v1` — OpenClaw adds the path itself.
386
346
 
347
+ ---
348
+
387
349
  ## How It Works
388
350
 
389
351
  ### Direct API Mode (default) — Template Replay
390
352
 
391
353
  ```
392
- ┌──────────┐ ┌─────────────────────┐ ┌──────────────────┐
393
- │ Your App │ ──> │ dario (proxy) │ ──> │ api.anthropic.com│
394
- │ │ localhost:3456 │ │ │
395
- │ sends │ │ │ │ sees a genuine │
396
- │ its own │ │ replaces request │ │ Claude Code │
397
- │ tools & │ │ with CC template │ │ request │
398
- │ params │ │ keeps only content │ │ │
399
- └──────────┘ └─────────────────────┘ └──────────────────┘
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
+ └───────────┘ └─────────────────────┘ └──────────────────┘
400
362
  ```
401
363
 
402
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.
403
365
 
404
- ### CLI Backend Mode (`--cli`)
366
+ ### Passthrough Mode (`--passthrough`)
405
367
 
406
368
  ```
407
- ┌──────────┐ ┌─────────────────┐ ┌──────────────────┐
408
- │ Your App │ ──> │ dario (proxy) │ ──> │ claude --print
409
- │ │ localhost:3456 │ │ (Claude Code)
410
- │ sends │ │ extracts prompt│ │
411
- │ API │ │ spawns CLI │ │ has priority
412
- │ request │ │ wraps response │ │ routing
413
- └──────────┘ └─────────────────┘ └──────────────────┘
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
+ └───────────┘ └─────────────────┘ └──────────────────┘
414
376
  ```
415
377
 
416
- ### 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:
417
381
 
382
+ **Billing tag** — reconstructed using Claude Code's own algorithm extracted from the CC binary:
418
383
  ```
419
- ┌──────────┐ ┌─────────────────┐ ┌──────────────────┐
420
- │ Your App │ ──> │ dario (proxy) │ ──> │ api.anthropic.com│
421
- │ │ │ localhost:3456 │ │ │
422
- │ sends │ │ swaps API key │ │ sees valid │
423
- │ API │ │ for OAuth │ │ OAuth bearer │
424
- │ request │ │ nothing else │ │ token │
425
- └──────────┘ └─────────────────┘ └──────────────────┘
384
+ x-anthropic-billing-header: cc_version=<version>.<build_tag>; cc_entrypoint=cli; cch=<5-char-hex>;
426
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.
427
387
 
428
- 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
429
406
 
430
- 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.
431
408
 
432
- 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
+ ---
433
422
 
434
423
  ## Commands
435
424
 
@@ -446,49 +435,45 @@ Your app sends whatever it wants — any tools, any parameters. dario replaces t
446
435
 
447
436
  | Flag/Env | Description | Default |
448
437
  |----------|-------------|---------|
449
- | `--cli` | Use Claude CLI as backend (bypasses rate limits) | off |
450
- | `--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 |
451
440
  | `--model=MODEL` | Force a model (`opus`, `sonnet`, `haiku`, or full ID) | passthrough |
452
441
  | `--port=PORT` | Port to listen on | `3456` |
453
442
  | `--verbose` / `-v` | Log every request | off |
454
- | `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) |
455
444
  | `DARIO_NO_BUN` | Disable automatic Bun relaunch (stay on Node.js) | unset |
456
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 |
457
447
 
458
448
  ## Supported Features
459
449
 
460
450
  ### Direct API Mode
461
451
  - All Claude models (Opus 4.6, Sonnet 4.6, Haiku 4.5) + 1M extended context aliases (`opus1m`, `sonnet1m`)
462
- - **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).
463
- - **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.
464
- - **Session ID rotation** (v3.2) each request gets a fresh session ID, matching CC `--print` behavior.
465
- - **Rate governor** (v3.2) 500ms minimum interval between requests prevents inhuman cadence. Configurable via `DARIO_MIN_INTERVAL_MS`.
466
- - **Enriched 429 errors** — rate limit errors include utilization %, limiting window, and reset time instead of Anthropic's default `"Error"` message
467
- - **Auto CLI fallback** — if the API returns 429 and Claude Code is installed, transparently retries through `claude --print` with SSE conversion
468
- - **OpenAI-compatible** (`/v1/chat/completions`) works with any OpenAI SDK or tool
469
- - Streaming and non-streaming (both Anthropic and OpenAI SSE formats, including tool_use streaming)
470
- - Tool use / function calling
471
- - System prompts and multi-turn conversations
472
- - Prompt caching and extended thinking
473
- - **Billable beta filtering** — strips `extended-cache-ttl` from client betas (the only prefix requiring Extra Usage)
474
- - **Beta deduplication** client-provided betas are deduplicated against the base set before appending
475
- - **Orchestration tag sanitization** — strips agent-injected XML (`<system-reminder>`, `<env>`, `<task_metadata>`, etc.) before forwarding
476
- - **Token anomaly detection** — warns on context spike (>60% input growth) or output explosion (>2x previous)
477
- - Concurrency control (max 10 concurrent upstream requests)
478
- - CORS enabled (works from browser apps on localhost)
479
-
480
- ### CLI Backend Mode
481
- - All Claude models — including Opus when rate limited
482
- - Streaming via SSE conversion (client sends `stream: true`, CLI JSON response is converted to Anthropic or OpenAI SSE events)
483
- - OpenAI compatibility (translates OpenAI → Anthropic before CLI, Anthropic → OpenAI after)
484
- - System prompts and multi-turn conversations (via context injection)
485
- - 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).
486
471
 
487
472
  ### Passthrough Mode
488
- - All Claude models with native streaming and tool use
489
- - OAuth token swap only — no billing tag, thinking, effort, or device identity injection
490
- - Minimal beta flags (`oauth-2025-04-20` + client betas only)
491
- - 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.
492
477
 
493
478
  ## Endpoints
494
479
 
@@ -521,17 +506,45 @@ curl http://localhost:3456/health
521
506
  |---------|---------------------|
522
507
  | Credential storage | Reads from Claude Code (`~/.claude/.credentials.json`) or its own store (`~/.dario/credentials.json`) with `0600` permissions |
523
508
  | OAuth flow | PKCE (Proof Key for Code Exchange) — no client secret needed |
524
- | Token transmission | OAuth tokens never leave localhost. Only forwarded to `api.anthropic.com` over HTTPS |
525
- | Network exposure | Proxy binds to `127.0.0.1` only not accessible from other machines |
526
- | SSRF protection | Hardcoded allowlist of API paths only `/v1/messages`, `/v1/models`, `/v1/complete` are proxied |
527
- | Token rotation | Refresh tokens rotate on every use (single-use) |
528
- | Error sanitization | Token patterns redacted from all error messages |
529
- | 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
+ ---
530
543
 
531
544
  ## FAQ
532
545
 
533
546
  **Does this violate Anthropic's terms of service?**
534
- 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.
535
548
 
536
549
  **What subscription plans work?**
537
550
  Claude Max and Claude Pro. Any plan that lets you use Claude Code.
@@ -540,7 +553,7 @@ Claude Max and Claude Pro. Any plan that lets you use Claude Code.
540
553
  Should work if your plan includes Claude Code access. Not tested yet — please open an issue with results.
541
554
 
542
555
  **Do I need Claude Code installed?**
543
- 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.
544
557
 
545
558
  **First time setup — account priming**
546
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:
@@ -557,14 +570,19 @@ Optional but recommended. If [Bun](https://bun.sh) is installed, dario auto-rela
557
570
  **What happens when my token expires?**
558
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.
559
572
 
560
- **I'm getting rate limited on Opus. What do I do?**
561
- 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.
562
580
 
563
581
  **What are the usage limits?**
564
- 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.
565
583
 
566
584
  **Can I run this on a server?**
567
- 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.
568
586
 
569
587
  **Why "dario"?**
570
588
  Named after [Dario Amodei](https://en.wikipedia.org/wiki/Dario_Amodei), CEO of Anthropic.
@@ -579,12 +597,12 @@ import { startProxy, getAccessToken, getStatus } from "@askalf/dario";
579
597
  // Start the proxy programmatically
580
598
  await startProxy({ port: 3456, verbose: true });
581
599
 
582
- // CLI backend mode
583
- await startProxy({ port: 3456, cliBackend: true, model: "opus" });
584
-
585
600
  // Passthrough mode (OAuth swap only, no injection)
586
601
  await startProxy({ port: 3456, passthrough: true });
587
602
 
603
+ // Preserve-tools mode (keep client tool schemas)
604
+ await startProxy({ port: 3456, preserveTools: true });
605
+
588
606
  // Or just get a raw access token
589
607
  const token = await getAccessToken();
590
608
 
@@ -599,7 +617,7 @@ Dario handles your OAuth tokens. Here's why you can trust it:
599
617
 
600
618
  | Signal | Status |
601
619
  |--------|--------|
602
- | **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 |
603
621
  | **Dependencies** | 0 runtime dependencies. Verify: `npm ls --production` |
604
622
  | **npm provenance** | Every release is [SLSA attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions |
605
623
  | **Security scanning** | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) runs on every push and weekly |
@@ -625,21 +643,22 @@ cd $(npm root -g)/@askalf/dario && npm ls --production
625
643
  |-------|------|
626
644
  | v3.0 Template Replay — why we stopped matching signals | [Discussion 14](https://github.com/askalf/dario/discussions/14) |
627
645
  | Claude Code defaults are detection signals, not optimizations | [Discussion 13](https://github.com/askalf/dario/discussions/13) |
628
- | 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) |
629
647
  | Billing tag algorithm and fingerprint analysis | [Discussion 8](https://github.com/askalf/dario/discussions/8) |
630
648
  | Rate limit header analysis | [Discussion 1](https://github.com/askalf/dario/discussions/1) |
631
649
 
632
650
  ## Contributing
633
651
 
634
- 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:
635
653
 
636
654
  | File | Purpose |
637
655
  |------|---------|
638
- | `src/proxy.ts` | HTTP proxy server, CLI backend, rate governor |
639
- | `src/cc-template.ts` | CC template engine + tool mapping |
640
- | `src/cc-template-data.json` | MITM-extracted CC data (25 tools, 25KB system prompt) |
641
- | `src/oauth.ts` | Token storage, refresh, credential detection |
642
- | `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 |
643
662
  | `src/index.ts` | Library exports |
644
663
 
645
664
  ```bash
@@ -654,7 +673,7 @@ npm run dev # runs with tsx (no build needed)
654
673
  | Who | Contributions |
655
674
  |-----|---------------|
656
675
  | [@GodsBoy](https://github.com/GodsBoy) | Proxy authentication, token redaction, error sanitization ([#2](https://github.com/askalf/dario/pull/2)) |
657
- | [@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)) |
658
677
 
659
678
  ## License
660
679
 
@@ -5,20 +5,32 @@
5
5
  * (client_id, authorize URL, token URL, scopes). Eliminates the need to
6
6
  * hardcode values that Anthropic rotates between CC releases.
7
7
  *
8
- * CC ships two OAuth client configurations in one binary:
8
+ * CC ships three OAuth config factories in one binary (dev/staging/prod),
9
+ * selected at runtime by an environment switch that is hardcoded to "prod"
10
+ * in shipped builds. Only the PROD block is live; "local" and "staging"
11
+ * are dead code paths.
9
12
  *
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
+ * PROD block (the one we want):
14
+ * BASE_API_URL: "https://api.anthropic.com"
15
+ * CLAUDE_AI_AUTHORIZE_URL: "https://claude.com/cai/oauth/authorize"
16
+ * TOKEN_URL: "https://platform.claude.com/v1/oauth/token"
17
+ * CLIENT_ID: "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
18
+ * OAUTH_FILE_SUFFIX: ""
13
19
  *
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.
20
+ * LOCAL block (dead code in shipped builds CC pointing at localhost:8000
21
+ * etc. as its own dev stack, NOT about "client uses a localhost callback"):
22
+ * BASE_API_URL: "http://localhost:8000"
23
+ * CLIENT_ID: "22422756-60c9-4084-8eb7-27705fd5cf9a"
24
+ * OAUTH_FILE_SUFFIX: "-local-oauth"
17
25
  *
18
- * We scan for the LOCAL block and extract its config.
26
+ * Dario uses CC's own automatic OAuth flow the prod client is registered
27
+ * with `http://localhost:${port}/callback` exactly as dario sends. (The
28
+ * "MANUAL_REDIRECT_URL" on platform.claude.com is only used when dario's
29
+ * local HTTP server can't bind a port; dario never hits that path.)
19
30
  *
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.
31
+ * Results are cached per-binary-hash at ~/.dario/cc-oauth-cache-v2.json so
32
+ * startup only re-scans when the user upgrades Claude Code. The -v2 suffix
33
+ * invalidates the v3.4.0-v3.4.2 caches that held the wrong (dev) client_id.
22
34
  */
23
35
  export interface DetectedOAuthConfig {
24
36
  clientId: string;
@@ -30,10 +42,14 @@ export interface DetectedOAuthConfig {
30
42
  ccHash?: string;
31
43
  }
32
44
  /**
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.
45
+ * Scan binary bytes for the PROD OAuth config block.
46
+ *
47
+ * Anchors on `BASE_API_URL:"https://api.anthropic.com"` this literal
48
+ * only appears inside the prod config object (`nh$`). The LOCAL-dev block
49
+ * uses `http://localhost:8000` for the same key, and there's no staging
50
+ * block present in shipped builds. Once we find the anchor, the CLIENT_ID,
51
+ * CLAUDE_AI_AUTHORIZE_URL, TOKEN_URL, and scopes all live within a ~1.5KB
52
+ * window after it.
37
53
  */
38
54
  export declare function scanBinaryForOAuthConfig(buf: Buffer): Omit<DetectedOAuthConfig, 'source' | 'ccPath' | 'ccHash'> | null;
39
55
  /**