@askalf/dario 3.4.4 → 3.4.6
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 +216 -473
- package/dist/cc-template.d.ts +1 -0
- package/dist/cc-template.js +47 -9
- package/dist/proxy.js +1 -0
- 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,200 @@
|
|
|
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
|
+
**Standalone 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
|
+
**Dario is also the local bridge for [askalf](https://askalf.org).** When your workload outgrows a single subscription — multi-account pooling, session shaping to stay under Anthropic's behavioral classifiers, 24/7 fleets, scheduled workflows — dario is the component that keeps running on your machine and connects to the askalf platform. Same install, same commands, extra capabilities unlocked when you link it. You don't have to use askalf to use dario today, and you won't have to change how you use dario when you join askalf later.
|
|
48
35
|
|
|
49
|
-
|
|
36
|
+
---
|
|
50
37
|
|
|
51
|
-
|
|
38
|
+
## Who this is for
|
|
52
39
|
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
**Best fit:**
|
|
41
|
+
- 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.
|
|
42
|
+
- 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.
|
|
43
|
+
- Anyone who wants Claude Code's billing behavior on their own requests, from their own code.
|
|
55
44
|
|
|
56
|
-
**
|
|
45
|
+
**Not a fit:**
|
|
46
|
+
- You need vendor-managed production SLAs on every request. Use the Anthropic API directly.
|
|
47
|
+
- You need high-scale agent orchestration, multi-account pooling, or session-level classifier shaping. That's [askalf](https://askalf.org), which dario bridges into.
|
|
48
|
+
- You want a hosted chat UI. Use claude.ai.
|
|
57
49
|
|
|
58
|
-
|
|
50
|
+
---
|
|
59
51
|
|
|
60
|
-
|
|
61
|
-
<td width="33%" valign="top">
|
|
52
|
+
## First use case
|
|
62
53
|
|
|
63
|
-
|
|
54
|
+
> 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.
|
|
64
55
|
|
|
65
|
-
|
|
56
|
+
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.
|
|
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
|
+
Flow on a fresh machine:
|
|
74
59
|
|
|
75
|
-
|
|
60
|
+
1. `npm install -g @askalf/dario`
|
|
61
|
+
2. `dario login` — detects your installed Claude Code credentials, or runs its own OAuth flow if you don't have CC installed
|
|
62
|
+
3. `dario proxy` — starts the local server on port 3456
|
|
63
|
+
4. Set two environment variables in the tool you already use:
|
|
64
|
+
```bash
|
|
65
|
+
ANTHROPIC_BASE_URL=http://localhost:3456
|
|
66
|
+
ANTHROPIC_API_KEY=dario
|
|
67
|
+
```
|
|
68
|
+
5. That tool now uses your Claude subscription. Streaming works, tool use works, prompt caching works.
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
</tr>
|
|
79
|
-
</table>
|
|
70
|
+
No separate API key. No Extra Usage charges. No rebuilding your workflow around a new provider.
|
|
80
71
|
|
|
81
72
|
---
|
|
82
73
|
|
|
83
|
-
## Why
|
|
84
|
-
|
|
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.
|
|
86
|
-
|
|
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.
|
|
88
|
-
|
|
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 without flagging CC itself | Detected by tool names, field order, effort level, etc. |
|
|
95
|
-
| **Dependencies** | 0 | Many |
|
|
96
|
-
|
|
97
|
-
<details>
|
|
98
|
-
<summary><strong>vs competitors</strong></summary>
|
|
74
|
+
## Why switch
|
|
99
75
|
|
|
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 |
|
|
76
|
+
**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.
|
|
110
77
|
|
|
111
|
-
|
|
78
|
+
**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.
|
|
112
79
|
|
|
113
|
-
|
|
80
|
+
**Use dario + askalf if** you're running multi-agent workloads, hitting session-level rate limits that a single account can't clear, or need a 24/7 fleet. Dario keeps running on your machine as the local bridge; askalf adds multi-account pooling, session shaping, and the platform pieces a single-subscription proxy can't deliver. See [below](#from-standalone-to-askalf).
|
|
114
81
|
|
|
115
|
-
|
|
82
|
+
**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.
|
|
116
83
|
|
|
117
|
-
|
|
118
|
-
|
|
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).
|
|
84
|
+
---
|
|
120
85
|
|
|
121
86
|
## Quick Start
|
|
122
87
|
|
|
123
|
-
|
|
88
|
+
```bash
|
|
89
|
+
# Install
|
|
90
|
+
npm install -g @askalf/dario
|
|
124
91
|
|
|
125
|
-
|
|
92
|
+
# Log in (detects Claude Code credentials if installed)
|
|
93
|
+
dario login
|
|
126
94
|
|
|
127
|
-
|
|
95
|
+
# Start the proxy
|
|
96
|
+
dario proxy
|
|
128
97
|
|
|
129
|
-
|
|
98
|
+
# Anthropic SDK
|
|
99
|
+
export ANTHROPIC_BASE_URL=http://localhost:3456
|
|
100
|
+
export ANTHROPIC_API_KEY=dario
|
|
130
101
|
|
|
131
|
-
|
|
132
|
-
|
|
102
|
+
# or OpenAI-compatible tools
|
|
103
|
+
export OPENAI_BASE_URL=http://localhost:3456/v1
|
|
104
|
+
export OPENAI_API_KEY=dario
|
|
133
105
|
```
|
|
134
106
|
|
|
135
|
-
|
|
107
|
+
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.
|
|
136
108
|
|
|
137
|
-
|
|
138
|
-
npx @askalf/dario login
|
|
139
|
-
```
|
|
109
|
+
---
|
|
140
110
|
|
|
141
|
-
|
|
111
|
+
## How It Works
|
|
142
112
|
|
|
143
|
-
|
|
144
|
-
dario login
|
|
145
|
-
```
|
|
113
|
+
Dario has two modes: **direct API mode** (the default) and **passthrough mode** (`--passthrough`).
|
|
146
114
|
|
|
147
|
-
|
|
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.
|
|
115
|
+
### Direct API Mode — Template Replay
|
|
149
116
|
|
|
150
|
-
|
|
117
|
+
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.
|
|
151
118
|
|
|
152
|
-
```bash
|
|
153
|
-
dario proxy
|
|
154
119
|
```
|
|
155
|
-
|
|
120
|
+
┌───────────┐ ┌─────────────────────┐ ┌──────────────────┐
|
|
121
|
+
│ Your App │ ──> │ dario (proxy) │ ──> │ api.anthropic.com│
|
|
122
|
+
│ │ │ localhost:3456 │ │ │
|
|
123
|
+
│ sends │ │ │ │ sees a genuine │
|
|
124
|
+
│ its own │ │ replaces request │ │ Claude Code │
|
|
125
|
+
│ tools & │ │ with CC template │ │ request │
|
|
126
|
+
│ params │ │ keeps only content │ │ │
|
|
127
|
+
└───────────┘ └─────────────────────┘ └──────────────────┘
|
|
156
128
|
```
|
|
157
|
-
dario — http://localhost:3456
|
|
158
129
|
|
|
159
|
-
|
|
130
|
+
The details that matter:
|
|
160
131
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
132
|
+
- **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)`.
|
|
133
|
+
- **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.
|
|
134
|
+
- **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.
|
|
135
|
+
- **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.
|
|
136
|
+
- **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.
|
|
137
|
+
- **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.
|
|
164
138
|
|
|
165
|
-
|
|
166
|
-
OAuth: healthy (expires in 11h 42m)
|
|
167
|
-
Model: passthrough (client decides)
|
|
168
|
-
```
|
|
139
|
+
### Passthrough Mode — `--passthrough`
|
|
169
140
|
|
|
170
|
-
|
|
141
|
+
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.
|
|
171
142
|
|
|
172
143
|
```bash
|
|
173
|
-
|
|
174
|
-
export ANTHROPIC_BASE_URL=http://localhost:3456
|
|
175
|
-
export ANTHROPIC_API_KEY=dario
|
|
176
|
-
|
|
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
|
|
144
|
+
dario proxy --passthrough
|
|
182
145
|
```
|
|
183
146
|
|
|
184
|
-
|
|
147
|
+
Use it when the upstream tool already builds a Claude-Code-shaped request on its own and you just need the token auth.
|
|
185
148
|
|
|
186
|
-
|
|
149
|
+
### Detection scope
|
|
187
150
|
|
|
188
|
-
|
|
189
|
-
dario proxy --passthrough # Thin proxy, zero injection
|
|
190
|
-
dario proxy --thin --model=opus # Thin proxy + model override
|
|
191
|
-
```
|
|
151
|
+
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 and account-level classifiers — those operate on cumulative per-OAuth behavioral aggregates (token throughput, conversation depth, streaming duration, inter-arrival timing) and no amount of per-request hardening reaches them. That's a different problem at a different layer, and it's [askalf](https://askalf.org)'s job rather than dario's. See the [FAQ entry](#faq) for the full explanation.
|
|
192
152
|
|
|
193
|
-
|
|
153
|
+
---
|
|
194
154
|
|
|
195
|
-
|
|
155
|
+
## From standalone to askalf
|
|
196
156
|
|
|
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
|
-
```
|
|
157
|
+
Dario is fully useful on its own. You don't need an account, you don't need to wait for anything, and the standalone mode is and will remain the default.
|
|
203
158
|
|
|
204
|
-
|
|
159
|
+
When your workload grows past what a single Claude subscription can hold, dario is also the local-edge component of the [askalf](https://askalf.org) platform. Same binary, same commands, same local proxy — linking to askalf adds what a per-request layer alone can't deliver:
|
|
205
160
|
|
|
206
|
-
|
|
161
|
+
| | dario standalone | dario + askalf |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| **Accounts** | 1 (yours) | Pool of 2–20+ |
|
|
164
|
+
| **Rate limits** | Your subscription's 5h / 7d windows | Distributed across the pool, near-zero 429s |
|
|
165
|
+
| **Session shaping** | Per-request scrub | Per-session cumulative tracking, rotation, classifier avoidance |
|
|
166
|
+
| **Browser / desktop control** | No | Yes — full computer use |
|
|
167
|
+
| **Scheduling** | No | Cron, webhooks, triggers |
|
|
168
|
+
| **Persistent memory** | No | Per-agent context and state |
|
|
169
|
+
| **Hosted dashboard** | No | Yes |
|
|
170
|
+
| **Local proxy component** | dario | dario |
|
|
207
171
|
|
|
208
|
-
|
|
172
|
+
When the askalf bridge endpoint is live, a single command (`dario link`) will pair this local instance with your askalf account and the extra capabilities unlock in place. Until then, standalone is the only mode that runs — nothing to wait for to use dario as it is today.
|
|
209
173
|
|
|
210
|
-
|
|
211
|
-
dario proxy --model=opus
|
|
174
|
+
**[Join the askalf waitlist →](https://askalf.org)**
|
|
212
175
|
|
|
213
|
-
|
|
214
|
-
export OPENAI_API_KEY=dario
|
|
176
|
+
Dario will always be open-source and free. askalf is the hosted tier for teams who need the layer above.
|
|
215
177
|
|
|
216
|
-
|
|
217
|
-
```
|
|
178
|
+
---
|
|
218
179
|
|
|
219
|
-
|
|
180
|
+
## Commands
|
|
220
181
|
|
|
221
|
-
|
|
182
|
+
| Command | Description |
|
|
183
|
+
|---------|-------------|
|
|
184
|
+
| `dario login` | Log in (detects CC credentials or runs its own OAuth flow) |
|
|
185
|
+
| `dario proxy` | Start the local API proxy on port 3456 |
|
|
186
|
+
| `dario status` | Show OAuth token health and expiry |
|
|
187
|
+
| `dario refresh` | Force an immediate token refresh |
|
|
188
|
+
| `dario logout` | Delete stored credentials |
|
|
189
|
+
| `dario help` | Full command reference |
|
|
222
190
|
|
|
223
|
-
###
|
|
191
|
+
### Proxy options
|
|
224
192
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
193
|
+
| Flag / env | Description | Default |
|
|
194
|
+
|---|---|---|
|
|
195
|
+
| `--passthrough` / `--thin` | Thin proxy — OAuth swap only, no template injection | off |
|
|
196
|
+
| `--preserve-tools` / `--keep-tools` | Keep client tool schemas instead of remapping to CC tools | off |
|
|
197
|
+
| `--model=<name>` | Force a model (`opus`, `sonnet`, `haiku`, or full ID) | passthrough |
|
|
198
|
+
| `--port=<n>` | Port to listen on | `3456` |
|
|
199
|
+
| `--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` |
|
|
200
|
+
| `--verbose` / `-v` | Log every request | off |
|
|
201
|
+
| `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) |
|
|
202
|
+
| `DARIO_CORS_ORIGIN` | Override the browser CORS `Access-Control-Allow-Origin`. Useful for browser clients reaching dario over a mesh network. | `http://localhost:${port}` |
|
|
203
|
+
| `DARIO_NO_BUN` | Disable automatic Bun relaunch | unset |
|
|
204
|
+
| `DARIO_MIN_INTERVAL_MS` | Minimum ms between requests (rate governor) | `500` |
|
|
205
|
+
| `DARIO_CC_PATH` | Override path to the Claude Code binary for OAuth detection | auto-detect |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Usage
|
|
235
210
|
|
|
236
211
|
### Python
|
|
237
212
|
|
|
@@ -240,15 +215,15 @@ import anthropic
|
|
|
240
215
|
|
|
241
216
|
client = anthropic.Anthropic(
|
|
242
217
|
base_url="http://localhost:3456",
|
|
243
|
-
api_key="dario"
|
|
218
|
+
api_key="dario",
|
|
244
219
|
)
|
|
245
220
|
|
|
246
|
-
|
|
221
|
+
msg = client.messages.create(
|
|
247
222
|
model="claude-opus-4-6",
|
|
248
223
|
max_tokens=1024,
|
|
249
|
-
messages=[{"role": "user", "content": "Hello!"}]
|
|
224
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
250
225
|
)
|
|
251
|
-
print(
|
|
226
|
+
print(msg.content[0].text)
|
|
252
227
|
```
|
|
253
228
|
|
|
254
229
|
### TypeScript / Node.js
|
|
@@ -261,222 +236,64 @@ const client = new Anthropic({
|
|
|
261
236
|
apiKey: "dario",
|
|
262
237
|
});
|
|
263
238
|
|
|
264
|
-
const
|
|
239
|
+
const msg = await client.messages.create({
|
|
265
240
|
model: "claude-opus-4-6",
|
|
266
241
|
max_tokens: 1024,
|
|
267
242
|
messages: [{ role: "user", content: "Hello!" }],
|
|
268
243
|
});
|
|
269
244
|
```
|
|
270
245
|
|
|
271
|
-
###
|
|
246
|
+
### OpenAI-compatible (Cursor, Continue, LiteLLM, Aider, …)
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
export OPENAI_BASE_URL=http://localhost:3456/v1
|
|
250
|
+
export OPENAI_API_KEY=dario
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
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.
|
|
254
|
+
|
|
255
|
+
### curl
|
|
272
256
|
|
|
273
257
|
```bash
|
|
274
258
|
curl http://localhost:3456/v1/messages \
|
|
275
259
|
-H "Content-Type: application/json" \
|
|
276
260
|
-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
|
-
}'
|
|
261
|
+
-d '{"model":"claude-opus-4-6","max_tokens":1024,"messages":[{"role":"user","content":"Hello!"}]}'
|
|
283
262
|
```
|
|
284
263
|
|
|
285
|
-
###
|
|
264
|
+
### Streaming, tool use, prompt caching, extended thinking
|
|
286
265
|
|
|
287
|
-
|
|
288
|
-
# Cursor / Continue / any OpenAI-compatible tool
|
|
289
|
-
OPENAI_BASE_URL=http://localhost:3456/v1 OPENAI_API_KEY=dario cursor
|
|
266
|
+
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
267
|
|
|
291
|
-
|
|
292
|
-
ANTHROPIC_BASE_URL=http://localhost:3456 ANTHROPIC_API_KEY=dario aider --model claude-opus-4-6
|
|
268
|
+
### Library mode
|
|
293
269
|
|
|
294
|
-
|
|
295
|
-
ANTHROPIC_BASE_URL=http://localhost:3456 ANTHROPIC_API_KEY=dario your-tool-here
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### Hermes
|
|
270
|
+
Dario is also importable:
|
|
299
271
|
|
|
300
|
-
|
|
272
|
+
```typescript
|
|
273
|
+
import { startProxy, getAccessToken, getStatus } from "@askalf/dario";
|
|
301
274
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
api_key: "dario"
|
|
306
|
-
default: claude-opus-4-6
|
|
275
|
+
await startProxy({ port: 3456, verbose: true });
|
|
276
|
+
const token = await getAccessToken();
|
|
277
|
+
const status = await getStatus();
|
|
307
278
|
```
|
|
308
279
|
|
|
309
|
-
###
|
|
280
|
+
### Health check
|
|
310
281
|
|
|
311
|
-
|
|
282
|
+
```bash
|
|
283
|
+
curl http://localhost:3456/health
|
|
284
|
+
```
|
|
312
285
|
|
|
313
286
|
```json
|
|
314
287
|
{
|
|
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
|
-
}
|
|
288
|
+
"status": "ok",
|
|
289
|
+
"oauth": "healthy",
|
|
290
|
+
"expiresIn": "11h 42m",
|
|
291
|
+
"requests": 47
|
|
342
292
|
}
|
|
343
293
|
```
|
|
344
294
|
|
|
345
|
-
**Note:** Use `http://127.0.0.1:3456` without `/v1` — OpenClaw adds the path itself.
|
|
346
|
-
|
|
347
|
-
---
|
|
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
295
|
---
|
|
422
296
|
|
|
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
297
|
## Endpoints
|
|
481
298
|
|
|
482
299
|
| Path | Description |
|
|
@@ -487,179 +304,100 @@ End-to-end verification lives at [`test/oauth-detector.mjs`](test/oauth-detector
|
|
|
487
304
|
| `GET /health` | Proxy health + OAuth status + request count |
|
|
488
305
|
| `GET /status` | Detailed OAuth token status |
|
|
489
306
|
|
|
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
307
|
---
|
|
521
308
|
|
|
522
|
-
##
|
|
523
|
-
|
|
524
|
-
dario solves the API access problem — your $200/mo subscription, usable everywhere, billed correctly.
|
|
525
|
-
|
|
526
|
-
But a proxy has a ceiling. Every request still runs on your single account, with your subscription's rate limits, on your machine. When you need to scale beyond that — multiple accounts, persistent browser sessions, desktop control, scheduled workflows, a fleet of agents that can run while you sleep — that's what [askalf](https://askalf.org) is built for.
|
|
309
|
+
## Trust & Transparency
|
|
527
310
|
|
|
528
|
-
|
|
311
|
+
Dario handles your OAuth tokens. Here's why you can trust it:
|
|
529
312
|
|
|
530
|
-
|
|
|
531
|
-
|
|
532
|
-
| **
|
|
533
|
-
| **
|
|
534
|
-
| **
|
|
535
|
-
| **
|
|
536
|
-
| **
|
|
537
|
-
| **
|
|
538
|
-
| **
|
|
313
|
+
| Signal | Status |
|
|
314
|
+
|---|---|
|
|
315
|
+
| **Source code** | ~2,000 lines of TypeScript across 7 files — small enough to audit in one sitting |
|
|
316
|
+
| **Dependencies** | 0 runtime dependencies. Verify: `npm ls --production` |
|
|
317
|
+
| **npm provenance** | Every release is [SLSA-attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions |
|
|
318
|
+
| **Security scanning** | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) runs on every push and weekly |
|
|
319
|
+
| **Credential handling** | Tokens never logged, redacted from errors, stored with `0600` permissions |
|
|
320
|
+
| **OAuth flow** | PKCE (Proof Key for Code Exchange) — no client secret |
|
|
321
|
+
| **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 |
|
|
322
|
+
| **SSRF protection** | Only `/v1/messages` and `/v1/complete` proxy upstream — hardcoded allowlist |
|
|
323
|
+
| **Telemetry** | None. Zero analytics, tracking, or data collection |
|
|
324
|
+
| **Audit trail** | [CHANGELOG.md](CHANGELOG.md) documents every release |
|
|
539
325
|
|
|
540
|
-
|
|
326
|
+
Verify the npm tarball matches this repo:
|
|
541
327
|
|
|
542
|
-
|
|
328
|
+
```bash
|
|
329
|
+
npm audit signatures
|
|
330
|
+
npm view @askalf/dario dist.integrity
|
|
331
|
+
cd $(npm root -g)/@askalf/dario && npm ls --production
|
|
332
|
+
```
|
|
543
333
|
|
|
544
334
|
---
|
|
545
335
|
|
|
546
336
|
## FAQ
|
|
547
337
|
|
|
548
338
|
**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.
|
|
339
|
+
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
340
|
|
|
551
341
|
**What subscription plans work?**
|
|
552
342
|
Claude Max and Claude Pro. Any plan that lets you use Claude Code.
|
|
553
343
|
|
|
554
|
-
**Does it work with
|
|
555
|
-
Should work if your plan includes Claude Code access. Not tested yet —
|
|
344
|
+
**Does it work with Team / Enterprise?**
|
|
345
|
+
Should work if your plan includes Claude Code access. Not widely tested yet — open an issue with results.
|
|
556
346
|
|
|
557
347
|
**Do I need Claude Code installed?**
|
|
558
|
-
Recommended
|
|
348
|
+
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.
|
|
559
349
|
|
|
560
|
-
**
|
|
561
|
-
|
|
350
|
+
**Do I need Bun?**
|
|
351
|
+
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`.
|
|
352
|
+
|
|
353
|
+
**First time setup on a fresh account.**
|
|
354
|
+
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
355
|
```bash
|
|
563
356
|
claude --print "hello"
|
|
564
357
|
claude --print "hello"
|
|
565
|
-
claude --print "hello"
|
|
566
358
|
```
|
|
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`
|
|
359
|
+
This establishes a session baseline. Without priming, brand-new accounts occasionally see billing classification issues on first use.
|
|
571
360
|
|
|
572
361
|
**What happens when my token expires?**
|
|
573
|
-
Dario auto-refreshes tokens 30 minutes before expiry.
|
|
362
|
+
Dario auto-refreshes tokens 30 minutes before expiry. `dario refresh` forces an immediate refresh if something goes wrong.
|
|
574
363
|
|
|
575
364
|
**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
|
|
365
|
+
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
366
|
|
|
578
367
|
**I'm hitting rate limits. What do I do?**
|
|
579
|
-
Claude subscriptions have rolling 5-hour and 7-day usage windows. Check
|
|
580
|
-
|
|
581
|
-
If you're running a multi-agent workload and consistently hitting limits, [askalf](https://askalf.org) distributes load across multiple accounts automatically.
|
|
368
|
+
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.
|
|
582
369
|
|
|
583
|
-
**
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
**Can I run this on a server?**
|
|
587
|
-
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.
|
|
370
|
+
**My multi-agent workload is getting reclassified to overage even though dario template-replays per request. Why?**
|
|
371
|
+
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.
|
|
588
372
|
|
|
589
373
|
**Why "dario"?**
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
## Programmatic API
|
|
593
|
-
|
|
594
|
-
Use dario as a library in your own Node.js app:
|
|
595
|
-
|
|
596
|
-
```typescript
|
|
597
|
-
import { startProxy, getAccessToken, getStatus } from "@askalf/dario";
|
|
598
|
-
|
|
599
|
-
// Start the proxy programmatically
|
|
600
|
-
await startProxy({ port: 3456, verbose: true });
|
|
601
|
-
|
|
602
|
-
// Passthrough mode (OAuth swap only, no injection)
|
|
603
|
-
await startProxy({ port: 3456, passthrough: true });
|
|
374
|
+
It's a name, not an acronym. Don't overthink it.
|
|
604
375
|
|
|
605
|
-
|
|
606
|
-
await startProxy({ port: 3456, preserveTools: true });
|
|
607
|
-
|
|
608
|
-
// Or just get a raw access token
|
|
609
|
-
const token = await getAccessToken();
|
|
610
|
-
|
|
611
|
-
// Check token health
|
|
612
|
-
const status = await getStatus();
|
|
613
|
-
console.log(status.expiresIn); // "11h 42m"
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
## Trust & Transparency
|
|
617
|
-
|
|
618
|
-
Dario handles your OAuth tokens. Here's why you can trust it:
|
|
619
|
-
|
|
620
|
-
| Signal | Status |
|
|
621
|
-
|--------|--------|
|
|
622
|
-
| **Source code** | ~2,000 lines of TypeScript — small enough to audit in one sitting |
|
|
623
|
-
| **Dependencies** | 0 runtime dependencies. Verify: `npm ls --production` |
|
|
624
|
-
| **npm provenance** | Every release is [SLSA attested](https://www.npmjs.com/package/@askalf/dario) via GitHub Actions |
|
|
625
|
-
| **Security scanning** | [CodeQL](https://github.com/askalf/dario/actions/workflows/codeql.yml) runs on every push and weekly |
|
|
626
|
-
| **Credential handling** | Tokens never logged, redacted from errors, stored with 0600 permissions |
|
|
627
|
-
| **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 |
|
|
628
|
-
| **No telemetry** | Zero analytics, tracking, or data collection of any kind |
|
|
629
|
-
| **Audit trail** | [CHANGELOG.md](CHANGELOG.md) documents every release |
|
|
630
|
-
| **Branch protection** | CI must pass before merge. CODEOWNERS enforces review |
|
|
376
|
+
---
|
|
631
377
|
|
|
632
|
-
|
|
378
|
+
## Technical Deep Dives
|
|
633
379
|
|
|
634
|
-
|
|
635
|
-
# Check provenance attestation
|
|
636
|
-
npm audit signatures 2>/dev/null; npm view @askalf/dario dist.integrity
|
|
380
|
+
Longer-form writing on how dario works and why it works that way:
|
|
637
381
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
382
|
+
- [v3.0 Template Replay — why we stopped matching signals](https://github.com/askalf/dario/discussions/14)
|
|
383
|
+
- [Claude Code defaults are detection signals, not optimizations](https://github.com/askalf/dario/discussions/13)
|
|
384
|
+
- [Why Opus feels worse through other proxies and how to fix it](https://github.com/askalf/dario/discussions/9)
|
|
385
|
+
- [Billing tag algorithm and fingerprint analysis](https://github.com/askalf/dario/discussions/8)
|
|
386
|
+
- [Rate limit header analysis](https://github.com/askalf/dario/discussions/1)
|
|
641
387
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
| Topic | Link |
|
|
645
|
-
|-------|------|
|
|
646
|
-
| v3.0 Template Replay — why we stopped matching signals | [Discussion 14](https://github.com/askalf/dario/discussions/14) |
|
|
647
|
-
| Claude Code defaults are detection signals, not optimizations | [Discussion 13](https://github.com/askalf/dario/discussions/13) |
|
|
648
|
-
| Why Opus feels worse through other proxies and how to fix it | [Discussion 9](https://github.com/askalf/dario/discussions/9) |
|
|
649
|
-
| Billing tag algorithm and fingerprint analysis | [Discussion 8](https://github.com/askalf/dario/discussions/8) |
|
|
650
|
-
| Rate limit header analysis | [Discussion 1](https://github.com/askalf/dario/discussions/1) |
|
|
388
|
+
---
|
|
651
389
|
|
|
652
390
|
## Contributing
|
|
653
391
|
|
|
654
392
|
PRs welcome. The codebase is ~2,000 lines of TypeScript across 7 files:
|
|
655
393
|
|
|
656
394
|
| File | Purpose |
|
|
657
|
-
|
|
395
|
+
|---|---|
|
|
658
396
|
| `src/proxy.ts` | HTTP proxy server, rate governor, billing tag, response forwarding |
|
|
659
|
-
| `src/cc-template.ts` | Template engine, tool mapping, orchestration
|
|
397
|
+
| `src/cc-template.ts` | Template engine, tool mapping, orchestration & framework scrubbing |
|
|
660
398
|
| `src/cc-template-data.json` | CC request template data (25 tools, 25KB system prompt) |
|
|
661
|
-
| `src/cc-oauth-detect.ts` |
|
|
662
|
-
| `src/oauth.ts` | Token storage, PKCE flow, auto-refresh
|
|
399
|
+
| `src/cc-oauth-detect.ts` | OAuth config auto-detection from the installed CC binary |
|
|
400
|
+
| `src/oauth.ts` | Token storage, PKCE flow, auto-refresh |
|
|
663
401
|
| `src/cli.ts` | CLI entry point, command routing, Bun auto-relaunch |
|
|
664
402
|
| `src/index.ts` | Library exports |
|
|
665
403
|
|
|
@@ -667,15 +405,20 @@ PRs welcome. The codebase is ~2,000 lines of TypeScript across 7 files:
|
|
|
667
405
|
git clone https://github.com/askalf/dario
|
|
668
406
|
cd dario
|
|
669
407
|
npm install
|
|
670
|
-
npm run dev # runs with tsx
|
|
408
|
+
npm run dev # runs with tsx, no build step
|
|
671
409
|
```
|
|
672
410
|
|
|
411
|
+
---
|
|
412
|
+
|
|
673
413
|
## Contributors
|
|
674
414
|
|
|
675
415
|
| Who | Contributions |
|
|
676
|
-
|
|
416
|
+
|---|---|
|
|
677
417
|
| [@GodsBoy](https://github.com/GodsBoy) | Proxy authentication, token redaction, error sanitization ([#2](https://github.com/askalf/dario/pull/2)) |
|
|
678
|
-
| [@belangertrading](https://github.com/belangertrading) | Billing classification investigation ([#4](https://github.com/askalf/dario/issues/4)), billing reclassification root cause ([#7](https://github.com/askalf/dario/issues/7)) |
|
|
418
|
+
| [@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)) |
|
|
419
|
+
| [@nathan-widjaja](https://github.com/nathan-widjaja) | README positioning rewrite structure ([#21](https://github.com/askalf/dario/issues/21)) |
|
|
420
|
+
|
|
421
|
+
---
|
|
679
422
|
|
|
680
423
|
## License
|
|
681
424
|
|
package/dist/cc-template.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare const CC_TOOL_DEFINITIONS: {
|
|
|
15
15
|
export declare const CC_SYSTEM_PROMPT: string;
|
|
16
16
|
/** CC's agent identity string. */
|
|
17
17
|
export declare const CC_AGENT_IDENTITY: string;
|
|
18
|
+
export declare function scrubFrameworkIdentifiers(text: string): string;
|
|
18
19
|
/** Client tool name → CC tool mapping with parameter translation. */
|
|
19
20
|
interface ToolMapping {
|
|
20
21
|
ccTool: string;
|
package/dist/cc-template.js
CHANGED
|
@@ -17,6 +17,28 @@ export const CC_TOOL_DEFINITIONS = TEMPLATE.tools;
|
|
|
17
17
|
export const CC_SYSTEM_PROMPT = TEMPLATE.system_prompt;
|
|
18
18
|
/** CC's agent identity string. */
|
|
19
19
|
export const CC_AGENT_IDENTITY = TEMPLATE.agent_identity;
|
|
20
|
+
// Framework identifiers that would flag non-CC usage. Stripped from the system
|
|
21
|
+
// prompt and from message content text blocks before the request goes upstream.
|
|
22
|
+
const FRAMEWORK_PATTERNS = [
|
|
23
|
+
// Compound/hyphenated patterns run first so their halves can't be eaten
|
|
24
|
+
// by the simpler word-level patterns below.
|
|
25
|
+
/\b(roo[- ]?cline|big[- ]?agi|claude[- ]?bridge)\b/gi,
|
|
26
|
+
/\b(openclaw|hermes|aider|cursor|windsurf|cline|continue|copilot|cody)\b/gi,
|
|
27
|
+
/\b(librechat|typingmind)\b/gi,
|
|
28
|
+
/\b(openai|gpt-4|gpt-3\.5)\b/gi,
|
|
29
|
+
/powered by [a-z]+/gi,
|
|
30
|
+
/\bgateway\b/gi,
|
|
31
|
+
// OC's sessions_* tool-name prefix — flagged as a fingerprint in dario#23.
|
|
32
|
+
/\bsessions_[a-z_]+\b/gi,
|
|
33
|
+
];
|
|
34
|
+
export function scrubFrameworkIdentifiers(text) {
|
|
35
|
+
let result = text;
|
|
36
|
+
for (const pattern of FRAMEWORK_PATTERNS) {
|
|
37
|
+
pattern.lastIndex = 0;
|
|
38
|
+
result = result.replace(pattern, '');
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
20
42
|
const TOOL_MAP = {
|
|
21
43
|
// Direct maps
|
|
22
44
|
bash: { ccTool: 'Bash', translateArgs: (a) => ({ command: a.cmd || a.command || a.c || '' }) },
|
|
@@ -194,15 +216,31 @@ export function buildCCRequest(clientBody, billingTag, cache1h, identity, opts =
|
|
|
194
216
|
.map(b => b.text)
|
|
195
217
|
.join('\n\n');
|
|
196
218
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
219
|
+
systemText = scrubFrameworkIdentifiers(systemText);
|
|
220
|
+
// Also scrub framework identifiers from message content text blocks.
|
|
221
|
+
// Clients often inject their product name into user/tool messages as well,
|
|
222
|
+
// and the system-prompt-only scrub used to miss those.
|
|
223
|
+
for (const msg of messages) {
|
|
224
|
+
if (typeof msg.content === 'string') {
|
|
225
|
+
msg.content = scrubFrameworkIdentifiers(msg.content);
|
|
226
|
+
}
|
|
227
|
+
else if (Array.isArray(msg.content)) {
|
|
228
|
+
for (const block of msg.content) {
|
|
229
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
230
|
+
block.text = scrubFrameworkIdentifiers(block.text);
|
|
231
|
+
}
|
|
232
|
+
if (block.type === 'tool_result' && typeof block.content === 'string') {
|
|
233
|
+
block.content = scrubFrameworkIdentifiers(block.content);
|
|
234
|
+
}
|
|
235
|
+
if (block.type === 'tool_result' && Array.isArray(block.content)) {
|
|
236
|
+
for (const sub of block.content) {
|
|
237
|
+
if (sub.type === 'text' && typeof sub.text === 'string') {
|
|
238
|
+
sub.text = scrubFrameworkIdentifiers(sub.text);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
206
244
|
}
|
|
207
245
|
// ── Build the CC request from template ──
|
|
208
246
|
// Key order matches CC v2.1.104 exactly:
|
package/dist/proxy.js
CHANGED
|
@@ -147,6 +147,7 @@ const ORCHESTRATION_TAG_NAMES = [
|
|
|
147
147
|
'system-reminder', 'env', 'system_information', 'current_working_directory',
|
|
148
148
|
'operating_system', 'default_shell', 'home_directory', 'task_metadata',
|
|
149
149
|
'directories', 'thinking',
|
|
150
|
+
'agent_persona', 'agent_context', 'tool_context', 'persona', 'tool_call',
|
|
150
151
|
];
|
|
151
152
|
const ORCHESTRATION_PATTERNS = ORCHESTRATION_TAG_NAMES.flatMap(tag => [
|
|
152
153
|
new RegExp(`<${tag}\\b[^>]*>[\\s\\S]*?<\\/${tag}>`, 'gi'),
|