@askalf/dario 5.4.16 → 5.4.19

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.
@@ -0,0 +1,295 @@
1
+ # dario + hands — battletested setup
2
+
3
+ End-to-end walkthrough for running [hands](https://github.com/askalf/hands) — a local computer-use agent that drives your OS through its native shell — through dario so the model spend bills against your Claude Pro / Max subscription instead of per-token overage on the computer-use beta. Covers install → mode selection → first run → verification → the gotchas that bite first-time users.
4
+
5
+ This is the **first-party** walkthrough. hands is one of dario's sister projects under [askalf](https://github.com/askalf), so unlike the OpenHands / OpenClaw guides where dario is *integrating* with someone else's tool, this is the canonical end-to-end stack we run ourselves. Most of the integration work has already been done on both ends: dario v3.33.0 auto-detects hands via system-prompt identity match and preserves the computer-use beta tools (`computer`, `bash`, `str_replace_based_edit_tool`) without you needing any flag.
6
+
7
+ ## Why hands + dario
8
+
9
+ Hosted "AI controls your computer" products charge $20–50/mo on top of any LLM costs. The math is unfavorable on at least four axes:
10
+
11
+ | Axis | Hosted product | hands + dario |
12
+ |---|---|---|
13
+ | **Per-task cost** | Bundled into the $20–50/mo tier | **$0** — bills against the Claude Max plan you already pay for |
14
+ | **Where your screenshots go** | Vendor's servers | Your machine. The only outbound is to your chosen LLM endpoint |
15
+ | **What drives your OS** | A screenshot loop simulating clicks | Your actual shell — PowerShell on Windows, `open` + AppleScript on macOS, `xdotool` / `ydotool` on Linux. Faster, cheaper, more reliable |
16
+ | **Audit trail** | Vendor's logs (good luck exporting) | `~/.hands/audit.jsonl` — every tool call, locally, line-delimited JSON. `--dry-run` to plan without acting |
17
+
18
+ The walkthrough below puts that stack together in 5 minutes.
19
+
20
+ ## Two modes — pick the right one
21
+
22
+ hands ships with two authentication paths. Same agent loop, same tools — the difference is **where** the model runs and **what it costs.**
23
+
24
+ | Mode | What it uses | Per-task cost via dario | Audit log | Best for |
25
+ |---|---|---|---|---|
26
+ | **Claude Login** *(default)* | The `claude` CLI as a child process | $0 (the CLI already uses your subscription) | None — `claude` runs the tools internally | Daily use, lowest setup |
27
+ | **SDK mode** | Anthropic SDK directly | **$0** when routed through dario | ✅ `~/.hands/audit.jsonl` | Programmatic access, dry-run planning, security review |
28
+
29
+ If you already pay for Claude Max and want zero friction, **Claude Login mode** is fine — dario isn't strictly required because the `claude` binary handles subscription billing on its own. dario becomes useful when you want SDK mode's audit log, `--dry-run` planning, or to run hands programmatically from your own scripts — those don't work on Claude Login.
30
+
31
+ This walkthrough covers both. SDK + dario gets the spotlight because that's where dario actually adds value.
32
+
33
+ ## Prerequisites
34
+
35
+ | Thing | Version | Why |
36
+ |---|---|---|
37
+ | **Node.js** | 20+ | hands and dario both target Node 20 minimum |
38
+ | **hands** | latest from npm — `npm i -g @askalf/hands` | The agent itself |
39
+ | **dario** | v3.33.0+ (latest preferred — `npm i -g @askalf/dario@latest`) | v3.33.0 added the system-prompt identity match that auto-preserves hands' computer-use tools |
40
+ | **A Claude OAuth login** | run `dario login` once | A Pro / Max subscription on a Claude account |
41
+ | **`claude` CLI** | latest | Required for Claude Login mode; `hands init` will install for you if missing |
42
+ | **Bun** (recommended) | 1.1+ | dario auto-relaunches under Bun for TLS-fingerprint fidelity. Skip if you're fine with a runtime banner; install via [bun.sh](https://bun.sh) for the full subscription wire shape. |
43
+
44
+ Verify dario before starting:
45
+
46
+ ```bash
47
+ dario doctor # all green = ready
48
+ dario status # OAuth healthy, expires in N hours
49
+ ```
50
+
51
+ ## Install + init
52
+
53
+ One npm install, one interactive command:
54
+
55
+ ```bash
56
+ npm install -g @askalf/hands
57
+ hands init
58
+ ```
59
+
60
+ `hands init` walks every choice a new user has to make — auth mode, optional voice (whisper.cpp), `claude` CLI install if missing, dario routing tip. It's safe to re-run; pick a different mode any time.
61
+
62
+ ## Mode 1 — Claude Login (default, simplest)
63
+
64
+ This is the path `hands init` recommends. Pick "Claude Login" when prompted. Done.
65
+
66
+ ```bash
67
+ hands run "open notepad and type hello world"
68
+ ```
69
+
70
+ What happens under the hood:
71
+
72
+ 1. hands spawns the `claude` CLI as a child process
73
+ 2. `claude` uses your Claude Code subscription (the same OAuth login you have for CC)
74
+ 3. The agent loop runs inside `claude`, dispatching computer-use tools via hands' shell wrappers
75
+ 4. You see the result in your terminal
76
+
77
+ dario isn't on the path here because `claude` handles subscription billing directly. That's by design — Claude Login mode is the "I want it to just work" path.
78
+
79
+ If you're using Claude Login mode, **you can stop reading this walkthrough now** — you're done. The rest of this guide covers SDK mode.
80
+
81
+ ## Mode 2 — SDK + dario (audit-logged, programmatic, dry-run)
82
+
83
+ Pick this mode when you want one of:
84
+
85
+ - **`--dry-run`** — see exactly what the agent would do before letting it act
86
+ - **`~/.hands/audit.jsonl`** — every tool call timestamped, with args, durations, outcomes. Useful for security review or post-incident forensics.
87
+ - **Programmatic agent runs** from your own Node scripts (importing hands as a library)
88
+ - **A specific Claude account** different from the one your `claude` CLI is logged into (via `dario accounts add`)
89
+
90
+ Setup is two env vars and one running dario instance:
91
+
92
+ ```bash
93
+ # In whatever shell starts hands:
94
+ export ANTHROPIC_BASE_URL=http://localhost:3456
95
+ export ANTHROPIC_API_KEY=dario # or your DARIO_API_KEY if set
96
+ ```
97
+
98
+ Add those to your shell profile (`~/.bashrc`, `~/.zshrc`, fish config, PowerShell `$PROFILE`) so they're set for every session.
99
+
100
+ Then in one terminal:
101
+
102
+ ```bash
103
+ dario proxy --verbose
104
+ ```
105
+
106
+ In another:
107
+
108
+ ```bash
109
+ hands auth # pick "API Key" — when prompted for the key, paste: dario
110
+ hands run "open notepad and type hello world"
111
+ ```
112
+
113
+ That's it. The Anthropic SDK reads the env vars by default, so no hands-side config is needed beyond `hands auth` once.
114
+
115
+ ### What dario does for hands automatically
116
+
117
+ You don't need any flag. Dario v3.33.0+ recognizes hands via a system-prompt identity match and:
118
+
119
+ - **Preserves** the Anthropic computer-use beta tools (`computer`, `bash`, `str_replace_based_edit_tool`) instead of remapping them to CC's canonical set. The computer-use beta tools have schema fields CC's tools don't carry; trying to translate them would corrupt the calls.
120
+ - **Strips** orchestration tags from the prompt to keep the wire shape on the subscription path.
121
+ - **Forwards** the `anthropic-beta: computer-use-*` header so the upstream model knows to enable the beta.
122
+ - Everything else (template replay, OAuth swap, sticky session) runs identically to a Claude Code request.
123
+
124
+ You'll see this in `dario proxy --verbose` as a log line like:
125
+
126
+ ```
127
+ [dario] #1 POST /v1/messages (model: claude-sonnet-4-6, client: hands, preserve_tools: true, beta: computer-use-2025-01-24) → 200 (1842 ms)
128
+ ```
129
+
130
+ ## Voice (optional)
131
+
132
+ If you opted into voice during `hands init`, you'll have whisper.cpp installed locally. Then:
133
+
134
+ ```bash
135
+ hands run "open chrome and go to amazon.com" --voice
136
+ ```
137
+
138
+ Press Enter to start recording, Enter again to stop. Whisper transcribes locally (no audio leaves your machine), and the transcribed task feeds into the agent loop the same as a typed prompt.
139
+
140
+ ## Verifying subscription billing
141
+
142
+ Two checks, one at the dario layer and one at Anthropic's:
143
+
144
+ ### Check 1: dario doctor --usage
145
+
146
+ ```bash
147
+ dario doctor --usage
148
+ ```
149
+
150
+ You should see your 5-hour bucket showing non-zero usage with `claim=five_hour (subscription)`:
151
+
152
+ ```
153
+ [ OK ] Usage 5h (all) 14.2% used • status=allowed • claim=five_hour (subscription)
154
+ ```
155
+
156
+ If `claim=five_hour (subscription)` shows up, you're billing against the Claude Max plan, not API. Done.
157
+
158
+ If `claim=api` shows up, something flipped you to per-token billing — usually because you started hands in Claude Login mode (where `claude` doesn't go through dario at all) but then ran SDK mode without setting the env vars. `hands doctor` reports the effective base URL hands sees; cross-check it.
159
+
160
+ ### Check 2: hands' audit log
161
+
162
+ ```bash
163
+ tail -f ~/.hands/audit.jsonl
164
+ ```
165
+
166
+ Every tool call is one JSON-ND record. If you ran `hands run "open notepad"` and the audit log is silent, you're on Claude Login mode (which bypasses hands' tool dispatcher). Switch with `hands auth` to API Key mode if you want the audit trail.
167
+
168
+ ### Check 3: Anthropic dashboard
169
+
170
+ Log into [console.anthropic.com](https://console.anthropic.com) → Usage. **Your API spend should be flat** (no new charges since you started hands). If it's climbing, the env vars didn't take effect — restart your shell and re-export.
171
+
172
+ ## Battletested patterns
173
+
174
+ After running hands+dario in production for months, here are the patterns we lean on:
175
+
176
+ ### Plan first, act second
177
+
178
+ Always run a `--dry-run` before letting hands actually touch anything irreversible:
179
+
180
+ ```bash
181
+ hands run --dry-run "delete every file in ~/Downloads older than 30 days"
182
+ ```
183
+
184
+ `--dry-run` forces SDK mode (which is the only mode where hands sees individual tool calls before they execute), prints the planned action sequence, and exits without doing anything. If the plan looks right, run it without `--dry-run`.
185
+
186
+ ### Pin the model for cost-sensitive runs
187
+
188
+ Long autonomous loops on Sonnet are usually right. For exploratory single-shot tasks where you just want a quick answer, Haiku is dramatically cheaper *in API mode* — but on subscription via dario, the bucket is the same. Pin Sonnet for everything unless you have a specific reason; the model-choice tradeoff is real on direct API but neutralized through dario.
189
+
190
+ ### Multi-account pool for parallel runs
191
+
192
+ If you run two or more hands sessions in parallel — say, one task on the desktop and another headless on a server — you'll exhaust a single Claude account's 5-hour bucket. Add a second account to dario's pool and pool mode load-balances:
193
+
194
+ ```bash
195
+ dario login # log in to a second Claude account
196
+ dario accounts add work
197
+ ```
198
+
199
+ See [`docs/multi-account-pool.md`](./multi-account-pool.md). Session stickiness ensures multi-turn hands conversations stay on one account.
200
+
201
+ ### Audit-log review before deploying agents into shared environments
202
+
203
+ Before letting hands SDK-mode loose on a shared machine (CI agent, family computer, etc.), run a representative task with `--dry-run` and read `~/.hands/audit.jsonl` end-to-end. The audit log is exactly the visibility you'd want before signing off on agentic access to a shared OS — and it's local, not vendor-side.
204
+
205
+ ## Common gotchas
206
+
207
+ ### `claude` CLI not found, hands won't start in Claude Login mode
208
+
209
+ ```bash
210
+ hands init # offers to install claude CLI for you, then re-runs hands setup
211
+ ```
212
+
213
+ Or install Claude Code yourself per [Anthropic's docs](https://docs.anthropic.com/en/docs/claude-code).
214
+
215
+ ### `Connection refused` to localhost:3456 in SDK mode
216
+
217
+ dario isn't running:
218
+
219
+ ```bash
220
+ curl -s http://localhost:3456/health
221
+ # expected: {"status":"ok",...}
222
+ ```
223
+
224
+ If that fails, start dario (`dario proxy --verbose`) before invoking hands.
225
+
226
+ ### Claim flips to api in SDK mode
227
+
228
+ Three causes, in order of likelihood:
229
+
230
+ 1. **You're not actually on dario.** Run `hands doctor` — if `Effective base URL` doesn't show `localhost:3456`, the env vars didn't take effect. Restart your shell.
231
+ 2. **Your dario template is stale.** Run `dario doctor` and check the template-age line. If it's >48 hours old, the captured CC system prompt may not match what Anthropic's classifier currently expects. `dario doctor --bun-bootstrap` to force a fresh capture.
232
+ 3. **You're running hands SDK mode against a different account than the one paying for Max.** Run `dario status` and confirm the OAuth account is the subscription account.
233
+
234
+ ### "computer use" beta header dropped
235
+
236
+ If dario isn't preserving the `anthropic-beta: computer-use-*` header, you're probably on a dario version older than v3.33.0. Upgrade — the system-prompt identity match and beta-preserve behavior both landed in that release.
237
+
238
+ ```bash
239
+ npm install -g @askalf/dario@latest
240
+ ```
241
+
242
+ ### Voice mode says "whisper.cpp not found"
243
+
244
+ ```bash
245
+ hands init # offers to download whisper.cpp for you
246
+ ```
247
+
248
+ Or install it yourself: clone [ggerganov/whisper.cpp](https://github.com/ggerganov/whisper.cpp), `make`, and put the binary on your `PATH`.
249
+
250
+ ### Hands hangs on a screenshot in SDK mode
251
+
252
+ Computer-use beta requests with multiple screenshots can be slow on first response. Bump retry config in your shell:
253
+
254
+ ```bash
255
+ export ANTHROPIC_REQUEST_TIMEOUT_MS=120000
256
+ ```
257
+
258
+ dario's outbound timeout is 5 min by default, so this is purely about hands' own client-side timeout.
259
+
260
+ ## What this guide doesn't cover
261
+
262
+ - **hands as a library** (importing into your own Node scripts). The dario integration works the same way — env vars route the underlying SDK to `localhost:3456`. See hands' README for the programmatic API surface.
263
+ - **Custom agents extending hands' core.** Subclassing the agent loop is supported but out of scope here. The dario integration is at the LLM layer; agent code doesn't need to change.
264
+
265
+ ## Quick reference card
266
+
267
+ ```bash
268
+ # One-time setup
269
+ npm install -g @askalf/dario @askalf/hands
270
+ dario login
271
+ hands init
272
+
273
+ # Per-session — Claude Login mode (default, no dario needed)
274
+ hands run "your task here"
275
+
276
+ # Per-session — SDK + dario mode (audit-logged, programmatic, --dry-run)
277
+ export ANTHROPIC_BASE_URL=http://localhost:3456
278
+ export ANTHROPIC_API_KEY=dario
279
+ dario proxy --verbose &
280
+ hands run "your task here"
281
+
282
+ # Verify subscription billing
283
+ dario doctor --usage # claim=five_hour (subscription) ✓
284
+ hands doctor # effective base URL shows localhost:3456
285
+ tail -f ~/.hands/audit.jsonl # tool calls flowing in real time (SDK mode only)
286
+ ```
287
+
288
+ ## Related guides
289
+
290
+ - [`openhands-walkthrough.md`](./openhands-walkthrough.md) — sister walkthrough for the OpenHands software-engineer agent
291
+ - [`openclaw-walkthrough.md`](./openclaw-walkthrough.md) — sister walkthrough for OpenClaw
292
+ - [`agent-compat.md`](./agent-compat.md) — short setup snippets for every other agent dario supports
293
+ - [`multi-account-pool.md`](./multi-account-pool.md) — adding 2+ Claude accounts to extend rate limits for parallel hands runs
294
+ - [`commands.md`](./commands.md) — full dario CLI reference
295
+ - [hands repo](https://github.com/askalf/hands) — full hands documentation, security model, and architecture deep-dive
@@ -0,0 +1,248 @@
1
+ # dario + OpenClaw — battletested setup
2
+
3
+ End-to-end walkthrough for running OpenClaw through dario so it routes against your Claude Pro / Max subscription instead of paying per-token API rates. Covers install → config → first run → verification → the gotchas that bite first-time users — including the `openclaw.inbound_meta.v1` classifier filter that dario's default mode silently protects against.
4
+
5
+ This is opinionated. There are several ways to wire OpenClaw to dario; this is the one we run in production and trust to not surprise us. Where we omit options it's because they're worse, not because they don't exist.
6
+
7
+ ## What you'll have at the end
8
+
9
+ - OpenClaw running locally, talking to dario at `localhost:3456`
10
+ - All Claude API calls routed through your Pro / Max subscription via the Claude Code wire shape
11
+ - OpenClaw's tool schema (`exec`, `process`, `web_search`, `web_fetch`, `browser`, `message`) auto-translated to CC's canonical set on the outbound path and rebuilt back on the inbound path — **no flag required**
12
+ - Your `openclaw.inbound_meta.v1` namespace stripped at the proxy boundary so Anthropic's billing classifier doesn't flip you to extra-usage
13
+ - `dario doctor --usage` showing the OpenClaw traffic in your 5-hour bucket with `claim=five_hour (subscription)`
14
+
15
+ Total install + config: 5–10 minutes if dario is already installed.
16
+
17
+ ## Prerequisites
18
+
19
+ | Thing | Version | Why |
20
+ |---|---|---|
21
+ | **OpenClaw** | 2026.2.17+ recommended | Older versions read auth differently — see auth-profiles gotcha below |
22
+ | **dario** | v3.31.2+ (latest preferred — `npm i -g @askalf/dario@latest`) | Auth-mismatch reject log, structural-fallback tool detection, classifier-fingerprint protection |
23
+ | **A Claude OAuth login** | run `dario login` once | The whole point — a Pro / Max subscription on a Claude account |
24
+ | **Bun** (recommended) | 1.1+ | dario auto-relaunches under Bun for TLS-fingerprint fidelity. Skip if you're fine with a runtime banner; install via [bun.sh](https://bun.sh) for the full subscription wire shape. |
25
+
26
+ Verify dario before starting OpenClaw — saves you from chasing OpenClaw errors that are actually dario auth issues:
27
+
28
+ ```bash
29
+ dario doctor # all green = ready
30
+ dario status # OAuth healthy, expires in N hours
31
+ ```
32
+
33
+ If `dario status` shows expired or missing OAuth, run `dario login` and retry. Don't continue past this step until both are clean.
34
+
35
+ ## Install OpenClaw
36
+
37
+ Follow the install instructions in [OpenClaw's own README](https://github.com/openclaw/openclaw) — installation steps move with their releases and we'd rather link the canonical source than copy-paste a snapshot that goes stale.
38
+
39
+ Verify after install:
40
+
41
+ ```bash
42
+ openclaw --version
43
+ ```
44
+
45
+ The rest of this guide assumes a working `openclaw` CLI on your `PATH`.
46
+
47
+ ## Configure OpenClaw → dario
48
+
49
+ OpenClaw reads its Anthropic configuration from three places, in priority order (2026.2.17+):
50
+
51
+ 1. `~/.openclaw/agents/main/agent/auth-profiles.json` — wins if the `anthropic:default` entry exists
52
+ 2. `openclaw.json` — `apiKey` field
53
+ 3. `ANTHROPIC_API_KEY` and `ANTHROPIC_BASE_URL` env vars — fallback
54
+
55
+ **This priority order is the single most common source of "why doesn't dario see my requests" tickets** ([dario#97](https://github.com/askalf/dario/issues/97)). Read the next section carefully.
56
+
57
+ ### Step 1 — Set the env vars
58
+
59
+ Put this in your shell profile (`~/.bashrc`, `~/.zshrc`, fish `config.fish`, or PowerShell `$PROFILE`):
60
+
61
+ ```bash
62
+ export ANTHROPIC_BASE_URL=http://localhost:3456
63
+ export ANTHROPIC_API_KEY=dario
64
+ ```
65
+
66
+ Two things to know:
67
+
68
+ - `ANTHROPIC_BASE_URL=http://localhost:3456` — points OpenClaw at dario instead of `api.anthropic.com`. dario speaks the Anthropic protocol on this port.
69
+ - `ANTHROPIC_API_KEY=dario` — this string is a literal placeholder. dario doesn't validate it (the real auth lives in dario's stored OAuth token). If you're running dario with `DARIO_API_KEY` set (LAN/multi-host mode), use that value here instead.
70
+
71
+ ### Step 2 — Clear or overwrite the auth-profiles.json entry
72
+
73
+ If you've ever set up OpenClaw with a real Anthropic API key, the env vars above won't take effect — `auth-profiles.json` wins. Pick one of two fixes:
74
+
75
+ **Option A: delete the Anthropic entry from auth-profiles.json (preferred — confirmed working by [@tetsuco in dario#97](https://github.com/askalf/dario/issues/97))**
76
+
77
+ Open `~/.openclaw/agents/main/agent/auth-profiles.json` in any editor, remove the `"anthropic:default"` entry (or the whole file if Anthropic is the only profile in there), save. OpenClaw falls back to the env vars on next run.
78
+
79
+ **Option B: overwrite the auth-profiles.json entry with `dario`**
80
+
81
+ ```bash
82
+ openclaw models auth paste-token --provider anthropic
83
+ # When prompted, paste the literal string: dario
84
+ ```
85
+
86
+ This replaces whatever was in the file with `dario`. Keep a backup if you use the original key elsewhere.
87
+
88
+ > **Loopback escape hatch.** If you're running dario at `--host=127.0.0.1` (the default), you don't need `DARIO_API_KEY` set at all and the auth-profiles content matters less — dario only enforces auth on non-loopback binds. So if you can stay on loopback, do; the auth-profiles dance is only needed for LAN reach setups (Tailscale, multi-host).
89
+
90
+ ### Step 3 — Verify the config takes effect
91
+
92
+ ```bash
93
+ echo "$ANTHROPIC_BASE_URL"
94
+ # expected: http://localhost:3456
95
+ ```
96
+
97
+ If that's empty, restart your shell or `source` your profile.
98
+
99
+ ### Battletested model choices
100
+
101
+ OpenClaw exposes its model selection through its own config. We default to:
102
+
103
+ | Model | When to use | Notes |
104
+ |---|---|---|
105
+ | `claude-sonnet-4-6` | **Default for everything.** | Best quality/speed for agent loops. What we run 95% of the time. |
106
+ | `claude-opus-5` | Hard reasoning tasks, refactors, novel architecture | ~3× slower per turn, ~3× more tokens. Subscription absorbs the cost; your wall-clock pays. Worth it for one-shot heavy lifts, overkill for routine. |
107
+ | `claude-haiku-4-5` | Fast scripts, quick lookups, smoke tests | Cheap on tokens, weak on multi-step reasoning. Don't run a long autonomous OpenClaw session on Haiku. |
108
+
109
+ Set the model in OpenClaw's config (the field name varies by OpenClaw version — check `openclaw config --help`). Use the canonical Anthropic model ID (no provider prefix) — OpenClaw is already on the Anthropic protocol.
110
+
111
+ ## First run
112
+
113
+ Start dario in one terminal:
114
+
115
+ ```bash
116
+ dario proxy --verbose
117
+ ```
118
+
119
+ Leave it running. You'll watch real-time request logs here.
120
+
121
+ In a second terminal, run an OpenClaw task:
122
+
123
+ ```bash
124
+ openclaw "Add a function to utils.py that takes a list of strings and returns them sorted by length, longest first. Include a docstring and a basic test."
125
+ ```
126
+
127
+ (Exact invocation may differ by OpenClaw version — check `openclaw --help`. The above is the conceptual shape; substitute the right flags for your install.)
128
+
129
+ Watch the dario terminal — you should see one log line per request, looking like:
130
+
131
+ ```
132
+ [dario] #1 POST /v1/messages (model: claude-sonnet-4-6) → 200 (1843 ms)
133
+ [dario] #2 POST /v1/messages (model: claude-sonnet-4-6) → 200 (2104 ms)
134
+ ...
135
+ ```
136
+
137
+ If you see `→ 200` lines and OpenClaw is making progress, you're good. dario's `client: 'unknown-non-cc'` structural fallback is silently auto-translating OpenClaw's `exec` / `process` / `web_search` / `web_fetch` / `browser` / `message` tools to CC's canonical set on the outbound path and rebuilding the OpenClaw shape on the inbound path — no flag, no config.
138
+
139
+ ## Verifying subscription billing (the important part)
140
+
141
+ This is what separates "OpenClaw talking to dario" from "OpenClaw actually using your Claude subscription." Two checks:
142
+
143
+ ### Check 1: dario doctor --usage
144
+
145
+ ```bash
146
+ dario doctor --usage
147
+ ```
148
+
149
+ You should see your 5-hour bucket showing non-zero usage with `claim=five_hour (subscription)`:
150
+
151
+ ```
152
+ [ OK ] Usage 5h (all) 12.3% used • status=allowed • claim=five_hour (subscription)
153
+ ```
154
+
155
+ If `claim=five_hour (subscription)` shows up, you're billing against subscription, not API. Done.
156
+
157
+ If `claim=api` shows up, something flipped you to per-token billing. The most common cause for OpenClaw users is the next section.
158
+
159
+ ### Check 2: Anthropic dashboard
160
+
161
+ Log into [console.anthropic.com](https://console.anthropic.com) → Usage. **Your API spend should be flat** (no new charges since you started OpenClaw). If it's climbing, something is bypassing dario.
162
+
163
+ ## How dario protects you from the classifier filter
164
+
165
+ Anthropic's billing classifier fingerprints the string `openclaw.inbound_meta.v1` and routes any request containing it to extra-usage billing — not subscription. This was reproduced in [dario discussion #178](https://github.com/askalf/dario/discussions/178) following Theo Browne's original finding.
166
+
167
+ The filter triggers on the `openclaw.inbound_meta.v1` namespace appearing in the request body — which is easy to hit accidentally. If you've ever made a commit message or branch name containing that string in any of your repos, Claude Code's environment block (which CC adds to its prompt) will surface those names back to the model in the system prompt, and the classifier flips your request.
168
+
169
+ **dario's default template-replay mode protects you from this automatically.** Every outbound request gets rebuilt from dario's captured-fresh CC system prompt — your local git context (commit messages, branch names, modified-file lists) is discarded at the proxy boundary. The `openclaw.inbound_meta.v1` string never leaves your machine.
170
+
171
+ You don't need to do anything to get this protection — it's the default. The protection is validated by `scripts/research/test-dario-protects-openclaw.mjs` against real Anthropic upstream traffic.
172
+
173
+ > **If you want to verify it on your own machine:** create a temp git repo with `{"schema": "openclaw.inbound_meta.v1"}` as a commit message, run OpenClaw against dario from inside that repo, and check `dario doctor --usage` — you should still see `claim=five_hour`. Without dario, the same setup would 400 or flip to api-billing.
174
+
175
+ ## Common gotchas
176
+
177
+ ### `401 Unauthorized` from dario, even though `ANTHROPIC_API_KEY=dario` is set
178
+
179
+ This is the auth-profiles.json priority issue ([dario#97](https://github.com/askalf/dario/issues/97)). OpenClaw is reading a stale Anthropic key from `~/.openclaw/agents/main/agent/auth-profiles.json` instead of your env var. Run `dario proxy -v` to confirm — you'll see `Authorization present but value mismatch (header: x-api-key)` in the reject log. Fix with one of the three options in Step 2 above.
180
+
181
+ ### `Connection refused` to localhost:3456
182
+
183
+ dario isn't running, or it's bound to a different port:
184
+
185
+ ```bash
186
+ curl -s http://localhost:3456/health
187
+ # expected: {"status":"ok",...}
188
+ ```
189
+
190
+ If that fails, start dario (`dario proxy --verbose`). If it's running on a custom port, match it: `ANTHROPIC_BASE_URL=http://localhost:<port>`.
191
+
192
+ ### `claim=api` showing up in dario doctor --usage
193
+
194
+ Something is sneaking the `openclaw.inbound_meta.v1` string past dario's template replay. The most common cause is running with `dario proxy --passthrough` (thin proxy, no template injection) — passthrough mode does an OAuth swap only and does NOT scrub the system prompt, so any classifier triggers in your local env survive. Drop the `--passthrough` flag and the default template-replay mode will protect you.
195
+
196
+ If you actually need passthrough mode for some other reason, you'll need to clean your local git state — rename branches with `openclaw` in their names, rewrite commit messages with that string, and remove any files in your working tree that contain the classifier-fingerprint namespace.
197
+
198
+ ### Long sessions failing with rate limits
199
+
200
+ If you run multiple parallel OpenClaw sessions on a single Claude account, you'll hit the 5-hour rate limit fast. Two fixes:
201
+
202
+ 1. **Add a second account to dario's pool** (`dario accounts add work` after running `dario login` on a second account). Pool mode routes each request to whichever account has the most headroom and uses session stickiness so multi-turn chats stay on one account. See [`docs/multi-account-pool.md`](./multi-account-pool.md).
203
+ 2. **Stagger the runs** — finish one before starting the next. Cheaper, no extra subscription needed.
204
+
205
+ ### Tools come back empty / wrong shape
206
+
207
+ Symptom: OpenClaw's tool calls round-trip with stripped fields, or your runtime complains about a required field being absent only when routed through dario.
208
+
209
+ If you see this, run dario with `--preserve-tools`:
210
+
211
+ ```bash
212
+ dario proxy --preserve-tools
213
+ ```
214
+
215
+ This skips the CC tool remap entirely and forwards OpenClaw's tool definitions through to the model unchanged. You lose the CC wire shape (and may lose subscription billing), but you keep all custom tool fields. Reserve for cases where the auto-detection can't reconstruct your schema cleanly.
216
+
217
+ ## What this guide doesn't cover
218
+
219
+ - **OpenClaw's own internal config flags.** OpenClaw has a rich CLI with options for sandbox, project root, agent loop tuning, etc. We don't shadow them here; check `openclaw --help`. The dario integration is at the LLM layer; agent code doesn't need to change.
220
+ - **OpenClaw derivatives** (forks like `openclaw-billing-proxy`, `nanoclaw`, etc.). These typically work the same way — point them at `localhost:3456` and dario's structural-fallback tool detection (the 3+ tools, ≥80% not in TOOL_MAP rule) catches them automatically. If a specific fork doesn't work, open an issue with the request body shape and we'll add explicit detection.
221
+
222
+ ## Quick reference card
223
+
224
+ ```bash
225
+ # One-time setup
226
+ # (install OpenClaw per its README)
227
+ npm install -g @askalf/dario
228
+ dario login
229
+
230
+ # Per-session
231
+ export ANTHROPIC_BASE_URL=http://localhost:3456
232
+ export ANTHROPIC_API_KEY=dario
233
+ # (clear ~/.openclaw/agents/main/agent/auth-profiles.json first if you have a stale Anthropic key)
234
+ dario proxy --verbose &
235
+ openclaw "your task here"
236
+
237
+ # Verify subscription billing
238
+ dario doctor --usage # claim=five_hour (subscription) ✓
239
+ ```
240
+
241
+ ## Related guides
242
+
243
+ - [`openhands-walkthrough.md`](./openhands-walkthrough.md) — sister walkthrough for OpenHands
244
+ - [`agent-compat.md`](./agent-compat.md) — short setup snippets for every other agent dario supports
245
+ - [`multi-account-pool.md`](./multi-account-pool.md) — adding 2+ Claude accounts to extend rate limits
246
+ - [`commands.md`](./commands.md) — full dario CLI reference
247
+ - [`faq.md`](./faq.md) — common dario questions, including the OpenClaw auth-profiles 401 entry
248
+ - [`research/system-prompt-classifier-study.md`](./research/system-prompt-classifier-study.md) — empirical work on what the billing classifier reads (and doesn't)