@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 +256 -464
- package/dist/accounts.d.ts +23 -0
- package/dist/accounts.js +253 -0
- package/dist/analytics.d.ts +99 -0
- package/dist/analytics.js +198 -0
- package/dist/cli.js +113 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/pool.d.ts +68 -0
- package/dist/pool.js +212 -0
- package/dist/proxy.js +142 -10
- package/package.json +1 -1
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
|
|
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> •
|
|
21
|
-
<a href="#
|
|
22
|
-
<a href="#
|
|
23
|
-
<a href="#
|
|
16
|
+
<a href="#who-this-is-for">Who it's for</a> •
|
|
17
|
+
<a href="#why-switch">Why switch</a> •
|
|
18
|
+
<a href="#how-it-works">How it works</a> •
|
|
19
|
+
<a href="#from-standalone-to-askalf">Standalone → askalf</a> •
|
|
24
20
|
<a href="#trust--transparency">Trust</a> •
|
|
25
21
|
<a href="#faq">FAQ</a>
|
|
26
22
|
</p>
|
|
27
23
|
|
|
28
24
|
---
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
npx @askalf/dario login # detects Claude Code credentials, starts proxy
|
|
26
|
+
## What it is
|
|
32
27
|
|
|
33
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
38
|
+
---
|
|
52
39
|
|
|
53
|
-
|
|
54
|
-
<td width="33%" valign="top">
|
|
40
|
+
## Who this is for
|
|
55
41
|
|
|
56
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
61
|
-
<td width="33%" valign="top">
|
|
52
|
+
---
|
|
62
53
|
|
|
63
|
-
|
|
54
|
+
## First use case
|
|
64
55
|
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
60
|
+
Flow on a fresh machine:
|
|
76
61
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
76
|
+
## Why switch
|
|
84
77
|
|
|
85
|
-
|
|
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
|
|
80
|
+
**Use dario pool mode if** you're running multi-agent workloads and hitting per-subscription rate limits — add 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
88
|
+
## Quick Start
|
|
112
89
|
|
|
113
|
-
|
|
90
|
+
```bash
|
|
91
|
+
# Install
|
|
92
|
+
npm install -g @askalf/dario
|
|
114
93
|
|
|
115
|
-
|
|
94
|
+
# Log in (detects Claude Code credentials if installed)
|
|
95
|
+
dario login
|
|
116
96
|
|
|
117
|
-
|
|
97
|
+
# Start the proxy
|
|
98
|
+
dario proxy
|
|
118
99
|
|
|
119
|
-
|
|
100
|
+
# Anthropic SDK
|
|
101
|
+
export ANTHROPIC_BASE_URL=http://localhost:3456
|
|
102
|
+
export ANTHROPIC_API_KEY=dario
|
|
120
103
|
|
|
121
|
-
|
|
104
|
+
# or OpenAI-compatible tools
|
|
105
|
+
export OPENAI_BASE_URL=http://localhost:3456/v1
|
|
106
|
+
export OPENAI_API_KEY=dario
|
|
107
|
+
```
|
|
122
108
|
|
|
123
|
-
|
|
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
|
-
|
|
111
|
+
---
|
|
126
112
|
|
|
127
|
-
|
|
113
|
+
## How It Works
|
|
128
114
|
|
|
129
|
-
|
|
115
|
+
Dario has two modes: **direct API mode** (the default) and **passthrough mode** (`--passthrough`).
|
|
130
116
|
|
|
131
|
-
|
|
132
|
-
npm install -g @askalf/dario
|
|
133
|
-
```
|
|
117
|
+
### Direct API Mode — Template Replay
|
|
134
118
|
|
|
135
|
-
|
|
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
|
-
###
|
|
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
|
|
146
|
+
dario proxy --passthrough
|
|
145
147
|
```
|
|
146
148
|
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
###
|
|
190
|
+
### Inspection endpoints
|
|
171
191
|
|
|
172
192
|
```bash
|
|
173
|
-
#
|
|
174
|
-
|
|
175
|
-
export ANTHROPIC_API_KEY=dario
|
|
193
|
+
# Live pool snapshot — per-account utilization, claim, status
|
|
194
|
+
curl http://localhost:3456/accounts
|
|
176
195
|
|
|
177
|
-
#
|
|
178
|
-
|
|
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
|
-
|
|
200
|
+
### Known scope for v3.5.0
|
|
185
201
|
|
|
186
|
-
|
|
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
|
-
|
|
189
|
-
dario proxy --passthrough # Thin proxy, zero injection
|
|
190
|
-
dario proxy --thin --model=opus # Thin proxy + model override
|
|
191
|
-
```
|
|
204
|
+
---
|
|
192
205
|
|
|
193
|
-
##
|
|
206
|
+
## Dario and askalf
|
|
194
207
|
|
|
195
|
-
|
|
208
|
+
Dario is fully useful on its own — single-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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
225
|
+
**[Join the askalf waitlist →](https://askalf.org)**
|
|
209
226
|
|
|
210
|
-
|
|
211
|
-
dario proxy --model=opus
|
|
227
|
+
---
|
|
212
228
|
|
|
213
|
-
|
|
214
|
-
export OPENAI_API_KEY=dario
|
|
229
|
+
## Commands
|
|
215
230
|
|
|
216
|
-
|
|
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
|
-
|
|
243
|
+
### Proxy options
|
|
220
244
|
|
|
221
|
-
|
|
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
|
-
|
|
259
|
+
---
|
|
224
260
|
|
|
225
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
###
|
|
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
|
-
###
|
|
316
|
+
### Streaming, tool use, prompt caching, extended thinking
|
|
286
317
|
|
|
287
|
-
|
|
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
|
-
|
|
292
|
-
ANTHROPIC_BASE_URL=http://localhost:3456 ANTHROPIC_API_KEY=dario aider --model claude-opus-4-6
|
|
320
|
+
### Library mode
|
|
293
321
|
|
|
294
|
-
|
|
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
|
-
|
|
324
|
+
```typescript
|
|
325
|
+
import { startProxy, getAccessToken, getStatus } from "@askalf/dario";
|
|
301
326
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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
|
-
###
|
|
332
|
+
### Health check
|
|
310
333
|
|
|
311
|
-
|
|
334
|
+
```bash
|
|
335
|
+
curl http://localhost:3456/health
|
|
336
|
+
```
|
|
312
337
|
|
|
313
338
|
```json
|
|
314
339
|
{
|
|
315
|
-
"
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
363
|
+
Dario handles your OAuth tokens. Here's why you can trust it:
|
|
529
364
|
|
|
530
|
-
|
|
|
531
|
-
|
|
532
|
-
| **
|
|
533
|
-
| **
|
|
534
|
-
| **
|
|
535
|
-
| **
|
|
536
|
-
| **
|
|
537
|
-
| **
|
|
538
|
-
| **
|
|
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
|
-
|
|
378
|
+
Verify the npm tarball matches this repo:
|
|
541
379
|
|
|
542
|
-
|
|
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
|
|
555
|
-
Should work if your plan includes Claude Code access. Not tested yet —
|
|
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
|
|
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
|
|
561
|
-
If dario is the first thing you
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
430
|
+
## Technical Deep Dives
|
|
636
431
|
|
|
637
|
-
|
|
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
|
-
|
|
642
|
-
|
|
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
|
-
|
|
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
|
|
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` |
|
|
665
|
-
| `src/oauth.ts` | Token storage, PKCE flow, auto-refresh
|
|
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
|
|
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
|
|