@askalf/dario 3.4.5 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,6 @@
1
1
  <p align="center">
2
2
  <h1 align="center">dario</h1>
3
- <p align="center"><strong>Use your Claude subscription as an API. The only proxy that bills correctly.</strong></p>
4
- <p align="center">
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.
8
- </p>
3
+ <p align="center"><strong>Use your Claude subscription inside your local tools and scripts — without moving to API billing or rebuilding your workflow around a separate stack.</strong></p>
9
4
  </p>
10
5
 
11
6
  <p align="center">
@@ -18,220 +13,252 @@
18
13
 
19
14
  <p align="center">
20
15
  <a href="#quick-start">Quick Start</a> &bull;
21
- <a href="#openai-compatibility">OpenAI Compat</a> &bull;
22
- <a href="#usage-examples">Examples</a> &bull;
23
- <a href="#askalf">askalf</a> &bull;
16
+ <a href="#who-this-is-for">Who it's for</a> &bull;
17
+ <a href="#why-switch">Why switch</a> &bull;
18
+ <a href="#how-it-works">How it works</a> &bull;
19
+ <a href="#from-standalone-to-askalf">Standalone → askalf</a> &bull;
24
20
  <a href="#trust--transparency">Trust</a> &bull;
25
21
  <a href="#faq">FAQ</a>
26
22
  </p>
27
23
 
28
24
  ---
29
25
 
30
- ```bash
31
- npx @askalf/dario login # detects Claude Code credentials, starts proxy
26
+ ## What it is
32
27
 
33
- # now use it from anywhereAnthropic or OpenAI SDK
34
- export ANTHROPIC_BASE_URL=http://localhost:3456 # or OPENAI_BASE_URL=http://localhost:3456/v1
35
- export ANTHROPIC_API_KEY=dario # or OPENAI_API_KEY=dario
36
- ```
28
+ dario is a local process that turns your Claude Max or Pro subscription into an API endpoint that any tool on your machine can use. It talks to Anthropic the same way Claude Code does, so your subscription's rate limits are what you spend against not a separate API billing tier.
37
29
 
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.
30
+ Install it once, log in once (using your existing Claude Code credentials if you have them), and from that point on every tool that speaks the Anthropic API or the OpenAI chat completions API Cursor, Continue, Aider, LiteLLM, your own scripts, whatever — can reach Claude through `http://localhost:3456`.
39
31
 
40
- dario is the **per-request layer** — one account, one workload, every request indistinguishable from CC on the wire. Session-level and account-level concerns (multi-account pooling, behavioral-classifier shaping, 24/7 fleets) live a layer above dario, in [askalf](https://askalf.org) [see below](#askalf). Both are built by the same team on the same OAuth and billing infrastructure.
32
+ **Single-account mode is the default.** You don't need an account anywhere, you don't need to wait for anything, and nothing phones home. Install and run.
41
33
 
42
- <table>
43
- <tr>
44
- <td colspan="3" align="center"><br/><strong>Independently reviewed by 3 competing AI companies</strong><br/><br/></td>
45
- </tr>
46
- <tr>
47
- <td width="33%" valign="top">
34
+ **Pool mode** (new in v3.5.0) lifts multi-account routing into dario itself. Add two or more Claude subscriptions with `dario accounts add`, and dario starts selecting per request by the account with the most headroom, marking exhausted accounts rejected until they reset. No hosted platform required — you run the pool on your machine, against your own subscriptions. See [Multi-Account Pool Mode](#multi-account-pool-mode) below for the details.
48
35
 
49
- **Grok** (xAI)
36
+ Separately, [askalf](https://askalf.org) is the hosted platform that does the things a local proxy on your machine can't — browser and desktop control, scheduling, persistent memory, 24/7 hosted fleets. Different problem, different tool. Dario does not depend on askalf, and askalf is not required to use any dario feature.
50
37
 
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."*
38
+ ---
52
39
 
53
- </td>
54
- <td width="33%" valign="top">
40
+ ## Who this is for
55
41
 
56
- **Copilot** (Microsoft)
42
+ **Best fit:**
43
+ - Power users already paying for Claude Max or Pro who want Claude available inside their local stack — editors, terminals, scripts, internal tools — without moving to API billing.
44
+ - Small teams that work in terminals and IDEs, not in hosted agent stacks, and want Claude as a drop-in provider for whatever tools they already use.
45
+ - Anyone who wants Claude Code's billing behavior on their own requests, from their own code.
57
46
 
58
- *"Verdict: Safe for local use — well-implemented with strong security practices. Minimal attack surface: zero runtime dependencies, PKCE OAuth, localhost-only binding, timing-safe auth, zero telemetry. The main risk vector is operator error rather than code defects."*
47
+ **Not a fit:**
48
+ - You need vendor-managed production SLAs on every request. Use the Anthropic API directly.
49
+ - You need high-scale agent orchestration, multi-account pooling, or session-level classifier shaping. That's [askalf](https://askalf.org), which dario bridges into.
50
+ - You want a hosted chat UI. Use claude.ai.
59
51
 
60
- </td>
61
- <td width="33%" valign="top">
52
+ ---
62
53
 
63
- **Gemini** (Google)
54
+ ## First use case
64
55
 
65
- *"Highly recommended for personal, local development. Solves a massive pain point for developers by bridging Claude Max/Pro subscriptions with developer IDEs, saving substantial API costs. Modular & lean, modern PKCE auth, SSRF protection, mature CI/CD pipeline with CodeQL and npm provenance attestations."*
56
+ > Use Claude in your local automation and developer workflows the way you'd normally reach for an API but backed by the subscription you already pay for.
66
57
 
67
- </td>
68
- </tr>
69
- <tr>
70
- <td colspan="3" align="center"><br/><strong>In production</strong><br/><br/></td>
71
- </tr>
72
- <tr>
73
- <td colspan="3" valign="top">
58
+ You install dario, point your existing tool at `http://localhost:3456`, and that tool now sees Claude. The tool doesn't know it's going through a proxy; from its perspective dario *is* the Anthropic API. Your subscription handles the billing. Your Max plan limits are what count against usage.
74
59
 
75
- *"The 429s were driving us crazy running a multi-agent stack on Claude Max. You found the billing tag, fixed the checksum, reverse-engineered the per-request hash from the binary — running clean, zero reclassification."* — [@belangertrading](https://github.com/belangertrading), multi-agent stack on Claude Max
60
+ Flow on a fresh machine:
76
61
 
77
- </td>
78
- </tr>
79
- </table>
62
+ 1. `npm install -g @askalf/dario`
63
+ 2. `dario login` — detects your installed Claude Code credentials, or runs its own OAuth flow if you don't have CC installed
64
+ 3. `dario proxy` — starts the local server on port 3456
65
+ 4. Set two environment variables in the tool you already use:
66
+ ```bash
67
+ ANTHROPIC_BASE_URL=http://localhost:3456
68
+ ANTHROPIC_API_KEY=dario
69
+ ```
70
+ 5. That tool now uses your Claude subscription. Streaming works, tool use works, prompt caching works.
71
+
72
+ No separate API key. No Extra Usage charges. No rebuilding your workflow around a new provider.
80
73
 
81
74
  ---
82
75
 
83
- ## Why dario
76
+ ## Why switch
84
77
 
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.
78
+ **Use dario if** you already pay for Claude Max or Pro and you want Claude inside the tools you already use, without paying API rates for every request or routing your work through a second hosted stack.
86
79
 
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.
80
+ **Use dario pool mode if** you're running multi-agent workloads and hitting per-subscription rate limitsadd 2–N accounts with `dario accounts add` and dario handles headroom-aware routing across them, all on your machine, against your own subscriptions. No hosted stack to sign up for. See [Multi-Account Pool Mode](#multi-account-pool-mode).
88
81
 
89
- | | dario | Other proxies |
90
- |---|---|---|
91
- | **Approach** | Template replay — sends CC's actual request | Signal matching or none |
92
- | **Tools** | CC's exact tool definitions sent upstream | Client tools (detected) |
93
- | **Max plan limits** | Used correctly | Bypassed — billed separately |
94
- | **Detection resistance** | Undetectable at the per-request level without flagging CC itself | Detected by tool names, field order, effort level, etc. |
95
- | **Dependencies** | 0 | Many |
82
+ **Use the Anthropic API directly if** you need platform-native primitives, vendor-managed production usage, high-scale control, or SLAs your subscription tier doesn't cover. Dario isn't trying to replace the API — it's trying to unlock the subscription you already bought.
96
83
 
97
- <details>
98
- <summary><strong>vs competitors</strong></summary>
84
+ **Don't use dario if** you want a subprocess bridge that shells out to `claude --print` under the hood. Those tools (openclaw-claude-bridge and similar) work well for single-team single-machine workloads that can accept a one-subscription rate ceiling and a one-machine deployment. Dario is the API-path alternative, which trades that simplicity for pooling-friendly behavior on the wire. Different tradeoffs, different tool.
99
85
 
100
- | Feature | dario | Meridian | CLIProxyAPI |
101
- |---------|-------|---------|------------|
102
- | Template replay (undetectable) | **Yes** | No | No |
103
- | Direct OAuth (streaming, tools) | **Yes** | Yes (SDK-based) | No |
104
- | OpenAI API compat | **Yes** | Yes | Yes |
105
- | Orchestration sanitization | **Yes** | Yes | No |
106
- | Token anomaly detection | **Yes** | Yes | No |
107
- | Codebase size | ~2,000 lines | ~9,000 lines | Platform |
108
- | Dependencies | 0 | Many | Many |
109
- | Setup | 2 commands | Config + build | Config + dashboard |
86
+ ---
110
87
 
111
- </details>
88
+ ## Quick Start
112
89
 
113
- ## The Problem
90
+ ```bash
91
+ # Install
92
+ npm install -g @askalf/dario
114
93
 
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.
94
+ # Log in (detects Claude Code credentials if installed)
95
+ dario login
116
96
 
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.
97
+ # Start the proxy
98
+ dario proxy
118
99
 
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).
100
+ # Anthropic SDK
101
+ export ANTHROPIC_BASE_URL=http://localhost:3456
102
+ export ANTHROPIC_API_KEY=dario
120
103
 
121
- ## Quick Start
104
+ # or OpenAI-compatible tools
105
+ export OPENAI_BASE_URL=http://localhost:3456/v1
106
+ export OPENAI_API_KEY=dario
107
+ ```
122
108
 
123
- ### Prerequisites
109
+ Opus, Sonnet, Haiku — all models, streaming, tool use, prompt caching, extended thinking. **Zero runtime dependencies.** ~2,000 lines of TypeScript. Auto-launches under [Bun](https://bun.sh) when available for TLS fingerprint fidelity with Claude Code's runtime. **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.
124
110
 
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.
111
+ ---
126
112
 
127
- If Claude Code isn't installed, dario runs its own OAuth flow — opens your browser, you authorize, done.
113
+ ## How It Works
128
114
 
129
- ### Install
115
+ Dario has two modes: **direct API mode** (the default) and **passthrough mode** (`--passthrough`).
130
116
 
131
- ```bash
132
- npm install -g @askalf/dario
133
- ```
117
+ ### Direct API Mode — Template Replay
134
118
 
135
- Or use npx (no install needed):
119
+ This is the mode you want for almost every case. Dario takes each request you send it and replaces it with a Claude Code request: same 25 tool definitions, same 25KB system prompt, same field order, same beta headers, same metadata structure, same device identity. Only your conversation content is preserved. Anthropic's classifier sees what looks like a Claude Code session because, from the wire up, it *is* one — and that's what keeps your usage on subscription billing instead of Extra Usage.
136
120
 
137
- ```bash
138
- npx @askalf/dario login
139
121
  ```
122
+ ┌───────────┐ ┌─────────────────────┐ ┌──────────────────┐
123
+ │ Your App │ ──> │ dario (proxy) │ ──> │ api.anthropic.com│
124
+ │ │ │ localhost:3456 │ │ │
125
+ │ sends │ │ │ │ sees a genuine │
126
+ │ its own │ │ replaces request │ │ Claude Code │
127
+ │ tools & │ │ with CC template │ │ request │
128
+ │ params │ │ keeps only content │ │ │
129
+ └───────────┘ └─────────────────────┘ └──────────────────┘
130
+ ```
131
+
132
+ The details that matter:
133
+
134
+ - **Billing tag** reconstructed using CC's own algorithm extracted from the binary: `x-anthropic-billing-header: cc_version=<version>.<build_tag>; cc_entrypoint=cli; cch=<5-char-hex>;` where `build_tag = SHA-256(seed + chars[4,7,20] of user message + version).slice(0,3)`.
135
+ - **Beta set** — CC's exact beta list in CC's order, minus any beta that would require Extra Usage to be enabled on your account.
136
+ - **OAuth config** auto-detected from the installed CC binary at startup. When Anthropic rotates `client_id`, authorize URL, or scopes, dario picks up the new values on the next run without needing a new release. Falls back to hardcoded CC 2.1.104 prod values if CC isn't installed. Cache at `~/.dario/cc-oauth-cache-v3.json`, keyed by binary fingerprint.
137
+ - **Session ID** rotates per request via `x-claude-code-session-id`, matching how `claude --print` behaves. A persistent session ID across rapid requests is a behavioral signal.
138
+ - **Framework scrub** — framework identifiers and known fingerprint tokens (`OpenClaw`, `sessions_*` tool prefixes, orchestration tags, etc.) are stripped from both the system prompt and message content before the request goes upstream.
139
+ - **Bun auto-relaunch** — when Bun is installed, dario relaunches under it so its TLS fingerprint matches CC's runtime. Without Bun, dario runs on Node.js and works fine; the TLS fingerprint is the only difference.
140
140
 
141
- ### Login
141
+ ### Passthrough Mode — `--passthrough`
142
+
143
+ For tools that need exact Anthropic protocol fidelity with nothing injected. This mode does an OAuth token swap and nothing else: no billing tag, no template, no device identity.
142
144
 
143
145
  ```bash
144
- dario login
146
+ dario proxy --passthrough
145
147
  ```
146
148
 
147
- - **With Claude Code installed:** Detects your credentials automatically and starts the proxy. No browser needed.
148
- - **Without Claude Code:** Opens your browser to Claude's OAuth page. Authorize, and dario captures the token automatically via a local callback server. Then run `dario proxy` to start the server.
149
+ Use it when the upstream tool already builds a Claude-Code-shaped request on its own and you just need the token auth.
150
+
151
+ ### Detection scope
152
+
153
+ Dario is a **per-request layer**. Every request it sends upstream is designed to be indistinguishable from a Claude Code request, and the per-request scrubbing hardened in v3.4.5 makes that meaningfully harder to fingerprint than it was when v3.0 first shipped. What dario cannot do at the per-request level is defend against Anthropic's session-level behavioral classifiers — those operate on cumulative per-OAuth aggregates (token throughput, conversation depth, streaming duration, inter-arrival timing) and no amount of per-request hardening reaches them. The practical answer to that problem is *distributing* load across multiple subscriptions so no single account accumulates enough signal to trip the classifier — which is what pool mode (below) does.
154
+
155
+ ---
156
+
157
+ ## Multi-Account Pool Mode
149
158
 
150
- ### Start the proxy
159
+ *New in v3.5.0.* Dario can manage multiple Claude subscriptions and route each request to the account with the most headroom. Single-account dario is unchanged and remains the default — pool mode activates **only** when `~/.dario/accounts/` contains 2+ accounts.
151
160
 
152
161
  ```bash
162
+ # Add accounts to the pool. Each runs its own OAuth flow.
163
+ dario accounts add work
164
+ dario accounts add personal
165
+ dario accounts add side-project
166
+
167
+ # List them
168
+ dario accounts list
169
+
170
+ # Start the proxy — pool mode activates automatically
153
171
  dario proxy
154
172
  ```
155
173
 
174
+ ### How it routes
175
+
176
+ Each incoming request picks the account with the highest **headroom**:
177
+
178
+ ```
179
+ headroom = 1 - max(util_5h, util_7d)
156
180
  ```
157
- dario — http://localhost:3456
158
181
 
159
- Your Claude subscription is now an API.
182
+ The response's `anthropic-ratelimit-unified-*` headers are parsed back into the pool so the next request sees fresh utilization. An account that returns a 429 is marked `rejected` and routed around until its window resets. When every account is exhausted, incoming requests queue for up to 60 seconds waiting for headroom to reappear, with backoff-aware draining.
160
183
 
161
- Usage:
162
- ANTHROPIC_BASE_URL=http://localhost:3456
163
- ANTHROPIC_API_KEY=dario
184
+ Accounts can use different plans — mix Max and Pro accounts freely. The pool doesn't care about tier, only headroom.
164
185
 
165
- Auth: open (no DARIO_API_KEY set)
166
- OAuth: healthy (expires in 11h 42m)
167
- Model: passthrough (client decides)
168
- ```
186
+ ### Why pool over per-request tricks alone
187
+
188
+ Per-request template replay is necessary but not sufficient for multi-agent workloads. Anthropic's classifier operates on cumulative per-OAuth-session aggregates (see the [FAQ entry](#faq) on multi-agent reclassification), and no amount of per-request hardening reaches that layer. The practical answer is *distribution* — spread load so no single account accumulates enough signal to trip anything. Pool mode is the piece that does that, and the headroom-aware selection means you don't have to think about which account is which; dario picks.
169
189
 
170
- ### Use it
190
+ ### Inspection endpoints
171
191
 
172
192
  ```bash
173
- # Set these two env vars every Anthropic SDK respects them
174
- export ANTHROPIC_BASE_URL=http://localhost:3456
175
- export ANTHROPIC_API_KEY=dario
193
+ # Live pool snapshotper-account utilization, claim, status
194
+ curl http://localhost:3456/accounts
176
195
 
177
- # Now any tool just works
178
- openclaw start
179
- aider --model claude-opus-4-6
180
- continue # in VS Code, set base URL in config
181
- python my_script.py
196
+ # Pool analytics per-account / per-model stats, burn-rate, exhaustion predictions
197
+ curl http://localhost:3456/analytics
182
198
  ```
183
199
 
184
- ## Passthrough Mode
200
+ ### Known scope for v3.5.0
185
201
 
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.
202
+ Pool mode v3.5.0 ships **headroom-aware selection across requests**. It does not yet retry a single in-flight request against a different account when that request 429s that ships in v3.5.1 along with analytics recording wiring. Across-request routing is already effective: a 429 on one request immediately marks that account rejected, and the next request goes somewhere else.
187
203
 
188
- ```bash
189
- dario proxy --passthrough # Thin proxy, zero injection
190
- dario proxy --thin --model=opus # Thin proxy + model override
191
- ```
204
+ ---
192
205
 
193
- ## Model Selection
206
+ ## Dario and askalf
194
207
 
195
- Force a specific model for all requestsuseful when your tool doesn't let you configure the model:
208
+ Dario is fully useful on its ownsingle-account mode is the default, pool mode (above) scales to as many Claude subscriptions as you want to add, and neither mode requires an account anywhere. Everything dario does is open-source and self-hosted.
196
209
 
197
- ```bash
198
- dario proxy --model=opus # Force Opus 4.6
199
- dario proxy --model=sonnet # Force Sonnet 4.6
200
- dario proxy --model=haiku # Force Haiku 4.5
201
- dario proxy # Passthrough (client decides)
202
- ```
210
+ [askalf](https://askalf.org) is the hosted platform built on top of the same OAuth and billing infrastructure, targeting the things a local proxy can't deliver by design:
203
211
 
204
- Full model IDs also work: `--model=claude-opus-4-6`
212
+ | | dario | askalf |
213
+ |---|---|---|
214
+ | **Accounts** | 1 (single) or N (pool mode) | Managed pool, no setup |
215
+ | **Rate limits** | Distributed across your own pool | Distributed across the hosted fleet |
216
+ | **Browser / desktop control** | No | Yes — full computer use |
217
+ | **Scheduling** | No | Cron, webhooks, triggers |
218
+ | **Persistent memory** | No | Per-agent context and state |
219
+ | **Hosted dashboard** | No | Yes |
220
+ | **Runs where** | Your machine | Hosted |
221
+ | **Price** | Free | Paid |
205
222
 
206
- ## OpenAI Compatibility
223
+ Pool mode in dario covers the "I want multi-account routing on my own machine with my own subscriptions" case. askalf covers the "I want someone else to run this, with a dashboard, and 24/7 fleet capabilities my own machine can't give me" case. Dario is and will remain open-source and free.
207
224
 
208
- Dario implements `/v1/chat/completions` — any tool built for the OpenAI API works with your Claude subscription. No code changes needed.
225
+ **[Join the askalf waitlist →](https://askalf.org)**
209
226
 
210
- ```bash
211
- dario proxy --model=opus
227
+ ---
212
228
 
213
- export OPENAI_BASE_URL=http://localhost:3456/v1
214
- export OPENAI_API_KEY=dario
229
+ ## Commands
215
230
 
216
- # Cursor, Continue, LiteLLM, any OpenAI SDK — all work
217
- ```
231
+ | Command | Description |
232
+ |---------|-------------|
233
+ | `dario login` | Log in (detects CC credentials or runs its own OAuth flow) |
234
+ | `dario proxy` | Start the local API proxy on port 3456 |
235
+ | `dario status` | Show OAuth token health and expiry |
236
+ | `dario refresh` | Force an immediate token refresh |
237
+ | `dario logout` | Delete stored credentials |
238
+ | `dario accounts list` | List accounts in the multi-account pool |
239
+ | `dario accounts add <alias>` | Add a new account to the pool (runs OAuth flow) |
240
+ | `dario accounts remove <alias>` | Remove an account from the pool |
241
+ | `dario help` | Full command reference |
218
242
 
219
- Use `--model=opus` to force the model regardless of what the client sends. Or pass `claude-opus-4-6` as the model name directly — Claude model names work as-is.
243
+ ### Proxy options
220
244
 
221
- ## Usage Examples
245
+ | Flag / env | Description | Default |
246
+ |---|---|---|
247
+ | `--passthrough` / `--thin` | Thin proxy — OAuth swap only, no template injection | off |
248
+ | `--preserve-tools` / `--keep-tools` | Keep client tool schemas instead of remapping to CC tools | off |
249
+ | `--model=<name>` | Force a model (`opus`, `sonnet`, `haiku`, or full ID) | passthrough |
250
+ | `--port=<n>` | Port to listen on | `3456` |
251
+ | `--host=<addr>` / `DARIO_HOST` | Bind address. Use `0.0.0.0` for LAN, or a specific IP (e.g. a Tailscale interface). When non-loopback, also set `DARIO_API_KEY`. | `127.0.0.1` |
252
+ | `--verbose` / `-v` | Log every request | off |
253
+ | `DARIO_API_KEY` | If set, all endpoints (except `/health`) require a matching `x-api-key` or `Authorization: Bearer` header. Required when `--host` binds non-loopback. | unset (open) |
254
+ | `DARIO_CORS_ORIGIN` | Override the browser CORS `Access-Control-Allow-Origin`. Useful for browser clients reaching dario over a mesh network. | `http://localhost:${port}` |
255
+ | `DARIO_NO_BUN` | Disable automatic Bun relaunch | unset |
256
+ | `DARIO_MIN_INTERVAL_MS` | Minimum ms between requests (rate governor) | `500` |
257
+ | `DARIO_CC_PATH` | Override path to the Claude Code binary for OAuth detection | auto-detect |
222
258
 
223
- ### curl
259
+ ---
224
260
 
225
- ```bash
226
- curl http://localhost:3456/v1/messages \
227
- -H "Content-Type: application/json" \
228
- -H "anthropic-version: 2023-06-01" \
229
- -d '{
230
- "model": "claude-opus-4-6",
231
- "max_tokens": 1024,
232
- "messages": [{"role": "user", "content": "Hello!"}]
233
- }'
234
- ```
261
+ ## Usage
235
262
 
236
263
  ### Python
237
264
 
@@ -240,15 +267,15 @@ import anthropic
240
267
 
241
268
  client = anthropic.Anthropic(
242
269
  base_url="http://localhost:3456",
243
- api_key="dario"
270
+ api_key="dario",
244
271
  )
245
272
 
246
- message = client.messages.create(
273
+ msg = client.messages.create(
247
274
  model="claude-opus-4-6",
248
275
  max_tokens=1024,
249
- messages=[{"role": "user", "content": "Hello!"}]
276
+ messages=[{"role": "user", "content": "Hello!"}],
250
277
  )
251
- print(message.content[0].text)
278
+ print(msg.content[0].text)
252
279
  ```
253
280
 
254
281
  ### TypeScript / Node.js
@@ -261,222 +288,64 @@ const client = new Anthropic({
261
288
  apiKey: "dario",
262
289
  });
263
290
 
264
- const message = await client.messages.create({
291
+ const msg = await client.messages.create({
265
292
  model: "claude-opus-4-6",
266
293
  max_tokens: 1024,
267
294
  messages: [{ role: "user", content: "Hello!" }],
268
295
  });
269
296
  ```
270
297
 
271
- ### Streaming
298
+ ### OpenAI-compatible (Cursor, Continue, LiteLLM, Aider, …)
299
+
300
+ ```bash
301
+ export OPENAI_BASE_URL=http://localhost:3456/v1
302
+ export OPENAI_API_KEY=dario
303
+ ```
304
+
305
+ Any tool that accepts an OpenAI base URL works as-is. Claude model names pass through directly; GPT-style names (`gpt-4`, `gpt-5.4`, etc.) map to their closest Claude equivalents so tools with hardcoded OpenAI model lists work without code changes.
306
+
307
+ ### curl
272
308
 
273
309
  ```bash
274
310
  curl http://localhost:3456/v1/messages \
275
311
  -H "Content-Type: application/json" \
276
312
  -H "anthropic-version: 2023-06-01" \
277
- -d '{
278
- "model": "claude-opus-4-6",
279
- "max_tokens": 1024,
280
- "stream": true,
281
- "messages": [{"role": "user", "content": "Write a haiku about APIs"}]
282
- }'
313
+ -d '{"model":"claude-opus-4-6","max_tokens":1024,"messages":[{"role":"user","content":"Hello!"}]}'
283
314
  ```
284
315
 
285
- ### With Other Tools
316
+ ### Streaming, tool use, prompt caching, extended thinking
286
317
 
287
- ```bash
288
- # Cursor / Continue / any OpenAI-compatible tool
289
- OPENAI_BASE_URL=http://localhost:3456/v1 OPENAI_API_KEY=dario cursor
318
+ All supported in both Anthropic and OpenAI SSE formats. Tool-use streaming emits `input_json_delta` events. Prompt caching works as-is. Extended thinking is routed through `reasoning_effort` in OpenAI format or the native `thinking` field in Anthropic format.
290
319
 
291
- # Aider
292
- ANTHROPIC_BASE_URL=http://localhost:3456 ANTHROPIC_API_KEY=dario aider --model claude-opus-4-6
320
+ ### Library mode
293
321
 
294
- # Any tool that uses ANTHROPIC_BASE_URL
295
- ANTHROPIC_BASE_URL=http://localhost:3456 ANTHROPIC_API_KEY=dario your-tool-here
296
- ```
297
-
298
- ### Hermes
322
+ Dario is also importable:
299
323
 
300
- Add to `~/.hermes/config.yaml`:
324
+ ```typescript
325
+ import { startProxy, getAccessToken, getStatus } from "@askalf/dario";
301
326
 
302
- ```yaml
303
- model:
304
- base_url: "http://localhost:3456/v1"
305
- api_key: "dario"
306
- default: claude-opus-4-6
327
+ await startProxy({ port: 3456, verbose: true });
328
+ const token = await getAccessToken();
329
+ const status = await getStatus();
307
330
  ```
308
331
 
309
- ### OpenClaw
332
+ ### Health check
310
333
 
311
- Add to your `openclaw.json` models config:
334
+ ```bash
335
+ curl http://localhost:3456/health
336
+ ```
312
337
 
313
338
  ```json
314
339
  {
315
- "models": {
316
- "providers": {
317
- "anthropic": {
318
- "baseUrl": "http://127.0.0.1:3456",
319
- "apiKey": "dario",
320
- "api": "anthropic-messages",
321
- "models": [
322
- {
323
- "id": "claude-sonnet-4-6",
324
- "name": "claude-sonnet-4-6",
325
- "contextWindow": 1000000,
326
- "maxTokens": 64000,
327
- "input": ["text"],
328
- "reasoning": true
329
- },
330
- {
331
- "id": "claude-opus-4-6",
332
- "name": "claude-opus-4-6",
333
- "contextWindow": 1000000,
334
- "maxTokens": 64000,
335
- "input": ["text"],
336
- "reasoning": true
337
- }
338
- ]
339
- }
340
- }
341
- }
340
+ "status": "ok",
341
+ "oauth": "healthy",
342
+ "expiresIn": "11h 42m",
343
+ "requests": 47
342
344
  }
343
345
  ```
344
346
 
345
- **Note:** Use `http://127.0.0.1:3456` without `/v1` — OpenClaw adds the path itself.
346
-
347
347
  ---
348
348
 
349
- ## How It Works
350
-
351
- ### Direct API Mode (default) — Template Replay
352
-
353
- ```
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
- └───────────┘ └─────────────────────┘ └──────────────────┘
362
- ```
363
-
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.
365
-
366
- ### Passthrough Mode (`--passthrough`)
367
-
368
- ```
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
- └───────────┘ └─────────────────┘ └──────────────────┘
376
- ```
377
-
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:
381
-
382
- **Billing tag** — reconstructed using Claude Code's own algorithm extracted from the CC binary:
383
- ```
384
- x-anthropic-billing-header: cc_version=<version>.<build_tag>; cc_entrypoint=cli; cch=<5-char-hex>;
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.
387
-
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
406
-
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.
408
-
409
- Dario scans the installed CC binary at startup and extracts the current config directly:
410
-
411
- - **Anchor**: `BASE_API_URL:"https://api.anthropic.com"` — this literal appears only inside CC's live prod OAuth config block, so the scanner reliably lands in the right object even when the minifier reorders fields across CC releases.
412
- - **Extracted**: `CLIENT_ID`, `CLAUDE_AI_AUTHORIZE_URL`, `TOKEN_URL`, and the full `user:*` scope string. A defensive check rejects any scan result that matches a known-dead internal client_id.
413
- - **Cached**: Results stored at `~/.dario/cc-oauth-cache-v2.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 the CC 2.1.104 prod config values hardcoded in-tree. 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 three OAuth config factories (`local`, `staging`, `prod`) in one binary, selected at runtime by a function that is hardcoded to `prod` in shipped builds. Only the prod block is live; the other two are dead code paths CC uses when pointing at internal dev/staging infrastructure. The scanner targets the prod block specifically.
418
-
419
- End-to-end verification lives at [`test/oauth-detector.mjs`](test/oauth-detector.mjs).
420
-
421
- ---
422
-
423
- ## Commands
424
-
425
- | Command | Description |
426
- |---------|-------------|
427
- | `dario login` | Detect credentials and start proxy |
428
- | `dario proxy` | Start the local API proxy |
429
- | `dario status` | Check if your token is healthy |
430
- | `dario refresh` | Force an immediate token refresh |
431
- | `dario logout` | Delete stored credentials |
432
- | `dario help` | Show usage information |
433
-
434
- ### Proxy Options
435
-
436
- | Flag/Env | Description | Default |
437
- |----------|-------------|---------|
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 |
440
- | `--model=MODEL` | Force a model (`opus`, `sonnet`, `haiku`, or full ID) | passthrough |
441
- | `--port=PORT` | Port to listen on | `3456` |
442
- | `--host=ADDRESS` / `DARIO_HOST` | Bind address. Use `0.0.0.0` to accept LAN connections, or a specific IP to bind selectively (e.g. a Tailscale interface). When non-loopback, also set `DARIO_API_KEY`. | `127.0.0.1` |
443
- | `--verbose` / `-v` | Log every request | off |
444
- | `DARIO_API_KEY` | If set, all endpoints (except `/health`) require matching `x-api-key` or `Authorization: Bearer`. **Required** when `--host` binds to anything other than loopback. | unset (open) |
445
- | `DARIO_CORS_ORIGIN` | Override the browser CORS `Access-Control-Allow-Origin`. Useful for browser-based clients (open-webui, librechat) connecting over a mesh network. | `http://localhost:${port}` |
446
- | `DARIO_NO_BUN` | Disable automatic Bun relaunch (stay on Node.js) | unset |
447
- | `DARIO_MIN_INTERVAL_MS` | Minimum ms between requests (rate governor) | `500` |
448
- | `DARIO_CC_PATH` | Override path to Claude Code binary for OAuth detection | auto-detect |
449
-
450
- ## Supported Features
451
-
452
- ### Direct API Mode
453
- - All Claude models (Opus 4.6, Sonnet 4.6, Haiku 4.5) + 1M extended context aliases (`opus1m`, `sonnet1m`)
454
- - **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.
455
- - **`--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.
456
- - **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`.
457
- - **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.
458
- - **Session ID rotation** — each request gets a fresh session ID via `x-claude-code-session-id`, matching CC behavior.
459
- - **Rate governor** — configurable minimum interval between requests via `DARIO_MIN_INTERVAL_MS`.
460
- - **Enriched 429 errors** — rate limit errors include utilization %, limiting window, and reset time instead of Anthropic's default `"Error"` message.
461
- - **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.
462
- - **OpenAI-compatible** (`/v1/chat/completions`) — works with any OpenAI SDK or tool.
463
- - Streaming and non-streaming (both Anthropic and OpenAI SSE formats, including tool_use streaming).
464
- - Tool use / function calling.
465
- - System prompts and multi-turn conversations.
466
- - Prompt caching and extended thinking.
467
- - **Billable beta filtering** — strips `extended-cache-ttl` from client betas (the only beta requiring Extra Usage enabled on the account).
468
- - **Beta deduplication** — client-provided betas are deduplicated against the base set before appending.
469
- - **Orchestration tag sanitization** — strips agent-injected XML (`<system-reminder>`, `<env>`, `<task_metadata>`, etc.) before forwarding.
470
- - **Token anomaly detection** — warns on context spike (>60% input growth) or output explosion (>2x previous).
471
- - Concurrency control (max 10 concurrent upstream requests).
472
- - CORS enabled (works from browser apps on localhost).
473
-
474
- ### Passthrough Mode
475
- - All Claude models with native streaming and tool use.
476
- - OAuth token swap only — no billing tag, no template injection, no device identity.
477
- - Minimal beta flags (`oauth-2025-04-20` + client betas only).
478
- - For tools that need exact Anthropic protocol fidelity with zero modification.
479
-
480
349
  ## Endpoints
481
350
 
482
351
  | Path | Description |
@@ -487,182 +356,100 @@ End-to-end verification lives at [`test/oauth-detector.mjs`](test/oauth-detector
487
356
  | `GET /health` | Proxy health + OAuth status + request count |
488
357
  | `GET /status` | Detailed OAuth token status |
489
358
 
490
- ## Health Check
491
-
492
- ```bash
493
- curl http://localhost:3456/health
494
- ```
495
-
496
- ```json
497
- {
498
- "status": "ok",
499
- "oauth": "healthy",
500
- "expiresIn": "11h 42m",
501
- "requests": 47
502
- }
503
- ```
504
-
505
- ## Security
506
-
507
- | Concern | How dario handles it |
508
- |---------|---------------------|
509
- | Credential storage | Reads from Claude Code (`~/.claude/.credentials.json`) or its own store (`~/.dario/credentials.json`) with `0600` permissions |
510
- | OAuth flow | PKCE (Proof Key for Code Exchange) — no client secret needed |
511
- | OAuth config source | Auto-detected from local CC binary at runtime; cached at `~/.dario/cc-oauth-cache-v2.json`. Detector reads binary in read-only mode, never modifies it. |
512
- | Token exposure | Tokens never logged; redacted from all error messages. |
513
- | Network binding | Binds to `127.0.0.1` by default. Override with `--host` / `DARIO_HOST` for mesh/LAN use; dario refuses to treat non-loopback binds as safe and requires you to set `DARIO_API_KEY` to avoid an unauthenticated LAN-reachable proxy. Upstream traffic goes only to `api.anthropic.com` over HTTPS. |
514
- | Auth timing | `timingSafeEqual` used for `DARIO_API_KEY` comparison. |
515
- | SSRF protection | Only `/v1/messages` and `/v1/complete` are proxied upstream — hardcoded allowlist. |
516
- | Body size | 10MB hard cap per request. 30s read timeout prevents slow-loris. |
517
- | Token refresh | Auto-refreshes 30 minutes before expiry. Refresh tokens rotate on each use. Mutex prevents concurrent refresh races. |
518
- | Telemetry | None. Zero analytics, tracking, or data collection of any kind. |
519
-
520
359
  ---
521
360
 
522
- ## askalf
523
-
524
- **dario and askalf solve different layers of the same problem.**
525
-
526
- dario is the per-request layer: one account, one workload, every request on the wire indistinguishable from Claude Code. It's what you reach for when you want your Max/Pro subscription usable from any tool that speaks the Anthropic or OpenAI API. It does not pool accounts, shape sessions, distribute load, or care about cumulative behavioral signals — those are not per-request concerns, and solving them at the per-request layer is a category error.
361
+ ## Trust & Transparency
527
362
 
528
- **askalf** is the layer above that: multi-account pooling behind one endpoint, session and workload shaping to stay under Anthropic's session-level classifiers, persistent browser and desktop sessions, scheduling, and a hosted fleet that runs 24/7. Built on the same OAuth and billing infrastructure as dario.
363
+ Dario handles your OAuth tokens. Here's why you can trust it:
529
364
 
530
- | | dario | askalf |
531
- |---|---|---|
532
- | **What it is** | Local proxy, single account | Hosted agent fleet, multi-account |
533
- | **Rate limits** | Your subscription's limits | Distributed across fleet, near-zero 429s |
534
- | **Browser / desktop** | No | Yes full computer use |
535
- | **Scheduling** | No | Yes cron, webhooks, triggers |
536
- | **Persistent memory** | No | Yes per-agent memory and context |
537
- | **Custom tools** | Via `--preserve-tools` | Native MCP tool server |
538
- | **Setup** | 2 commands | Waitlist dashboard |
365
+ | Signal | Status |
366
+ |---|---|
367
+ | **Source code** | ~2,000 lines of TypeScript across 7 files small enough to audit in one sitting |
368
+ | **Dependencies** | 0 runtime dependencies. Verify: `npm ls --production` |
369
+ | **npm provenance** | Every release is [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions |
370
+ | **Security scanning** | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) runs on every push and weekly |
371
+ | **Credential handling** | Tokens never logged, redacted from errors, stored with `0600` permissions |
372
+ | **OAuth flow** | PKCE (Proof Key for Code Exchange) no client secret |
373
+ | **Network scope** | Binds to `127.0.0.1` by default. `--host` allows LAN/mesh with `DARIO_API_KEY` gating. Upstream traffic goes only to `api.anthropic.com` over HTTPS |
374
+ | **SSRF protection** | Only `/v1/messages` and `/v1/complete` proxy upstream — hardcoded allowlist |
375
+ | **Telemetry** | None. Zero analytics, tracking, or data collection |
376
+ | **Audit trail** | [CHANGELOG.md](CHANGELOG.md) documents every release |
539
377
 
540
- 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)**.
378
+ Verify the npm tarball matches this repo:
541
379
 
542
- dario will always be open-source and free. askalf is the hosted tier for teams who need more.
380
+ ```bash
381
+ npm audit signatures
382
+ npm view @askalf/dario dist.integrity
383
+ cd $(npm root -g)/@askalf/dario && npm ls --production
384
+ ```
543
385
 
544
386
  ---
545
387
 
546
388
  ## FAQ
547
389
 
548
390
  **Does this violate Anthropic's terms of service?**
549
- 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.
391
+ Dario uses your existing Claude Code credentials with the same OAuth tokens CC uses. It authenticates you as you, with your subscription, through Anthropic's official API endpoints.
550
392
 
551
393
  **What subscription plans work?**
552
394
  Claude Max and Claude Pro. Any plan that lets you use Claude Code.
553
395
 
554
- **Does it work with Claude Team / Enterprise?**
555
- Should work if your plan includes Claude Code access. Not tested yet — please open an issue with results.
396
+ **Does it work with Team / Enterprise?**
397
+ Should work if your plan includes Claude Code access. Not widely tested yet — open an issue with results.
556
398
 
557
399
  **Do I need Claude Code installed?**
558
- 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.
400
+ Recommended, not required. With CC installed, `dario login` picks up your credentials automatically. Without CC, dario runs its own OAuth flow against Anthropic's authorize endpoint.
401
+
402
+ **Do I need Bun?**
403
+ Optional, recommended. Dario auto-relaunches under Bun when it's available so the TLS fingerprint matches CC's runtime. Without Bun, dario runs on Node.js and works fine; the TLS fingerprint is the only difference. Install: `curl -fsSL https://bun.sh/install | bash`.
559
404
 
560
- **First time setup account priming**
561
- 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:
405
+ **First time setup on a fresh account.**
406
+ If dario is the first thing you run against a brand-new Claude account, prime the account with a few real Claude Code commands first:
562
407
  ```bash
563
408
  claude --print "hello"
564
409
  claude --print "hello"
565
- claude --print "hello"
566
410
  ```
567
- This primes the account with legitimate Claude Code sessions. Then start dario normally. Without priming, new accounts may see billing classification issues on first use.
568
-
569
- **Do I need Bun installed?**
570
- Optional but recommended. If [Bun](https://bun.sh) is installed, dario auto-relaunches under it for TLS fingerprint fidelity with Claude Code's runtime. Without Bun, dario runs on Node.js and works fine — the TLS fingerprint is the only difference. Install Bun: `curl -fsSL https://bun.sh/install | bash`
411
+ This establishes a session baseline. Without priming, brand-new accounts occasionally see billing classification issues on first use.
571
412
 
572
413
  **What happens when my token expires?**
573
- 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.
414
+ Dario auto-refreshes tokens 30 minutes before expiry. `dario refresh` forces an immediate refresh if something goes wrong.
574
415
 
575
416
  **What happens when Anthropic rotates the OAuth client_id or URL?**
576
- 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-v2.json` and only re-scans when the binary fingerprint changes. If CC isn't installed, dario falls back to hardcoded CC 2.1.104 prod values.
417
+ 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 run — no dario release needed. Cache at `~/.dario/cc-oauth-cache-v3.json`, keyed by the CC binary fingerprint. If CC isn't installed, dario falls back to hardcoded CC 2.1.104 prod values.
577
418
 
578
419
  **I'm hitting rate limits. What do I do?**
579
- 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.
420
+ Claude subscriptions have rolling 5-hour and 7-day usage windows. Check utilization with Claude Code's `/usage` command or the [statusline](https://code.claude.com/docs/en/statusline). Dario's rate-limit errors include utilization percentages and reset times so you can see exactly when capacity returns.
580
421
 
581
422
  **My multi-agent workload is getting reclassified to overage even though dario template-replays per request. Why?**
582
- Because reclassification at high agent volume is not a per-request problem. Anthropic's classifier operates on cumulative per-OAuth-session behavioral aggregates — token throughput, conversation depth, streaming duration, inter-arrival timing, thinking-block volume. Dario can make each individual request indistinguishable from Claude Code and still hit this wall on a long-running agent session, because the wall isn't at the request level. Thorough diagnostic work on this was contributed by [@belangertrading](https://github.com/belangertrading) in [#23](https://github.com/askalf/dario/issues/23), including the per-request v3.4.3 hardening that landed as a result. For the session-layer shaping itself — multi-account pooling, session rotation, workload distribution that keeps any single account from concentrating the behavioral signal — that's what [askalf](https://askalf.org) is built for. Different layer, different tool.
583
-
584
- If you're running a multi-agent workload and consistently hitting limits, [askalf](https://askalf.org) distributes load across multiple accounts automatically.
585
-
586
- **What are the usage limits?**
587
- 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.
588
-
589
- **Can I run this on a server?**
590
- 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. If you want dario reachable from other machines on the same LAN or a Tailscale mesh, pass `--host=0.0.0.0` (or a specific interface IP) and set `DARIO_API_KEY` to gate access.
423
+ Because reclassification at high agent volume is not a per-request problem. Anthropic's classifier operates on cumulative per-OAuth-session behavioral aggregates — token throughput, conversation depth, streaming duration, inter-arrival timing, thinking-block volume. Dario can make each individual request indistinguishable from Claude Code and still hit this wall on a long-running agent session, because the wall isn't at the request level. Thorough diagnostic work on this was contributed by [@belangertrading](https://github.com/belangertrading) in [#23](https://github.com/askalf/dario/issues/23), including the per-request v3.4.3 and v3.4.5 hardening that landed as a result. For the session-layer shaping itself — multi-account pooling, session rotation, workload distribution that keeps any single account from concentrating the behavioral signal — that's what [askalf](https://askalf.org) is built for. Different layer, different tool.
591
424
 
592
425
  **Why "dario"?**
593
- Named after [Dario Amodei](https://en.wikipedia.org/wiki/Dario_Amodei), CEO of Anthropic.
594
-
595
- ## Programmatic API
596
-
597
- Use dario as a library in your own Node.js app:
598
-
599
- ```typescript
600
- import { startProxy, getAccessToken, getStatus } from "@askalf/dario";
601
-
602
- // Start the proxy programmatically
603
- await startProxy({ port: 3456, verbose: true });
426
+ It's a name, not an acronym. Don't overthink it.
604
427
 
605
- // Passthrough mode (OAuth swap only, no injection)
606
- await startProxy({ port: 3456, passthrough: true });
607
-
608
- // Preserve-tools mode (keep client tool schemas)
609
- await startProxy({ port: 3456, preserveTools: true });
610
-
611
- // Or just get a raw access token
612
- const token = await getAccessToken();
613
-
614
- // Check token health
615
- const status = await getStatus();
616
- console.log(status.expiresIn); // "11h 42m"
617
- ```
618
-
619
- ## Trust & Transparency
620
-
621
- Dario handles your OAuth tokens. Here's why you can trust it:
622
-
623
- | Signal | Status |
624
- |--------|--------|
625
- | **Source code** | ~2,000 lines of TypeScript — small enough to audit in one sitting |
626
- | **Dependencies** | 0 runtime dependencies. Verify: `npm ls --production` |
627
- | **npm provenance** | Every release is [SLSA attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions |
628
- | **Security scanning** | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) runs on every push and weekly |
629
- | **Credential handling** | Tokens never logged, redacted from errors, stored with 0600 permissions |
630
- | **Network scope** | Binds to 127.0.0.1 by default; `--host` / `DARIO_HOST` allows LAN/mesh exposure with `DARIO_API_KEY` gating. Upstream traffic goes exclusively to `api.anthropic.com` over HTTPS |
631
- | **No telemetry** | Zero analytics, tracking, or data collection of any kind |
632
- | **Audit trail** | [CHANGELOG.md](CHANGELOG.md) documents every release |
633
- | **Branch protection** | CI must pass before merge. CODEOWNERS enforces review |
428
+ ---
634
429
 
635
- Verify the npm package matches this repo:
430
+ ## Technical Deep Dives
636
431
 
637
- ```bash
638
- # Check provenance attestation
639
- npm audit signatures 2>/dev/null; npm view @askalf/dario dist.integrity
432
+ Longer-form writing on how dario works and why it works that way:
640
433
 
641
- # Check dependency tree (should be minimal)
642
- cd $(npm root -g)/@askalf/dario && npm ls --production
643
- ```
434
+ - [v3.0 Template Replay why we stopped matching signals](https://github.com/askalf/dario/discussions/14)
435
+ - [Claude Code defaults are detection signals, not optimizations](https://github.com/askalf/dario/discussions/13)
436
+ - [Why Opus feels worse through other proxies and how to fix it](https://github.com/askalf/dario/discussions/9)
437
+ - [Billing tag algorithm and fingerprint analysis](https://github.com/askalf/dario/discussions/8)
438
+ - [Rate limit header analysis](https://github.com/askalf/dario/discussions/1)
644
439
 
645
- ## Technical Deep Dives
646
-
647
- | Topic | Link |
648
- |-------|------|
649
- | v3.0 Template Replay — why we stopped matching signals | [Discussion 14](https://github.com/askalf/dario/discussions/14) |
650
- | Claude Code defaults are detection signals, not optimizations | [Discussion 13](https://github.com/askalf/dario/discussions/13) |
651
- | Why Opus feels worse through other proxies and how to fix it | [Discussion 9](https://github.com/askalf/dario/discussions/9) |
652
- | Billing tag algorithm and fingerprint analysis | [Discussion 8](https://github.com/askalf/dario/discussions/8) |
653
- | Rate limit header analysis | [Discussion 1](https://github.com/askalf/dario/discussions/1) |
440
+ ---
654
441
 
655
442
  ## Contributing
656
443
 
657
444
  PRs welcome. The codebase is ~2,000 lines of TypeScript across 7 files:
658
445
 
659
446
  | File | Purpose |
660
- |------|---------|
447
+ |---|---|
661
448
  | `src/proxy.ts` | HTTP proxy server, rate governor, billing tag, response forwarding |
662
- | `src/cc-template.ts` | Template engine, tool mapping, orchestration sanitization |
449
+ | `src/cc-template.ts` | Template engine, tool mapping, orchestration & framework scrubbing |
663
450
  | `src/cc-template-data.json` | CC request template data (25 tools, 25KB system prompt) |
664
- | `src/cc-oauth-detect.ts` | Auto-detect OAuth config from the installed CC binary |
665
- | `src/oauth.ts` | Token storage, PKCE flow, auto-refresh, credential detection |
451
+ | `src/cc-oauth-detect.ts` | OAuth config auto-detection from the installed CC binary |
452
+ | `src/oauth.ts` | Token storage, PKCE flow, auto-refresh |
666
453
  | `src/cli.ts` | CLI entry point, command routing, Bun auto-relaunch |
667
454
  | `src/index.ts` | Library exports |
668
455
 
@@ -670,15 +457,20 @@ PRs welcome. The codebase is ~2,000 lines of TypeScript across 7 files:
670
457
  git clone https://github.com/askalf/dario
671
458
  cd dario
672
459
  npm install
673
- npm run dev # runs with tsx (no build needed)
460
+ npm run dev # runs with tsx, no build step
674
461
  ```
675
462
 
463
+ ---
464
+
676
465
  ## Contributors
677
466
 
678
467
  | Who | Contributions |
679
- |-----|---------------|
468
+ |---|---|
680
469
  | [@GodsBoy](https://github.com/GodsBoy) | Proxy authentication, token redaction, error sanitization ([#2](https://github.com/askalf/dario/pull/2)) |
681
470
  | [@belangertrading](https://github.com/belangertrading) | Billing classification investigation ([#4](https://github.com/askalf/dario/issues/4)), cache_control fingerprinting ([#6](https://github.com/askalf/dario/issues/6)), billing reclassification root cause ([#7](https://github.com/askalf/dario/issues/7)), OAuth client_id discovery ([#12](https://github.com/askalf/dario/issues/12)), multi-agent session-level billing analysis ([#23](https://github.com/askalf/dario/issues/23)) |
471
+ | [@nathan-widjaja](https://github.com/nathan-widjaja) | README positioning rewrite structure ([#21](https://github.com/askalf/dario/issues/21)) |
472
+
473
+ ---
682
474
 
683
475
  ## License
684
476