@askalf/dario 4.8.153 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -265,7 +265,6 @@ Tune via `~/.dario/config.json` → `overageGuard`, or CLI flags: `--overage-beh
265
265
  - **Honor client thinking (`--honor-client-thinking`).** By default dario rebuilds the outbound request with CC's interactive thinking shape regardless of what the client sent. Pass this flag (or `DARIO_HONOR_CLIENT_THINKING=1`) to pass a non-CC client's own `thinking` block through unchanged. Off by default; the rebuild-to-CC path is what keeps the subscription pool routing.
266
266
  - **Preserve structured output (`--preserve-output-format`).** By default dario rebuilds `output_config` from CC's template (effort only), dropping a client's `output_config.format` JSON schema, so structured-output clients get unconstrained prose their strict parser rejects. Pass this flag (or `DARIO_PRESERVE_OUTPUT_FORMAT=1`) to carry the client's schema through unchanged — SDK clients like the Vercel AI SDK's `generateObject` then get schema-constrained output. Off by default; empirically without flipping billing (verified `five_hour` on `claude-sonnet-4-6`).
267
267
  - **Reachable from inside CC / any MCP client.** `dario subagent install` registers a CC sub-agent for in-session diagnostics; `dario mcp` exposes dario as a read-only MCP server. → [`docs/sub-agent.md`](./docs/sub-agent.md) · [`docs/mcp-server.md`](./docs/mcp-server.md)
268
- - **Shim mode** *(deprecated v4.2, removal scheduled v5.x)*. The original "no HTTP hop" path empirically matched only 3 of the 8 classifier axes and fell back to passthrough for the 1-block system prompts `claude -p` and the Agent SDK both send. Use **proxy mode** for any non-CC client — it's the only mode that rebuilds every request to CC's full canonical shape.
269
268
 
270
269
  ---
271
270
 
@@ -311,7 +310,7 @@ New *product* work happens in [askalf](https://askalf.org), the AI operation tha
311
310
 
312
311
  ## Commands
313
312
 
314
- `dario` (TUI) · `login` · `proxy` · `doctor` · `accounts {list,add,remove}` · `backend {list,add,remove}` · `shim` · `mcp` · `subagent {install,status,remove}` · `usage` · `config` · `upgrade` · `status` · `refresh` · `resume` · `logout` · `help`
313
+ `dario` (TUI) · `login` · `proxy` · `doctor` · `accounts {list,add,remove}` · `backend {list,add,remove}` · `mcp` · `subagent {install,status,remove}` · `usage` · `config` · `upgrade` · `status` · `refresh` · `resume` · `logout` · `help`
315
314
 
316
315
  Full flag/env reference: [`docs/commands.md`](./docs/commands.md) · SDK examples + per-tool setup: [`docs/usage.md`](./docs/usage.md)
317
316
 
@@ -1,6 +1,6 @@
1
1
  {
2
- "_version": "2.1.206",
3
- "_captured": "2026-07-02T02:12:18.750Z",
2
+ "_version": "2.1.207",
3
+ "_captured": "2026-07-11T06:31:35.366Z",
4
4
  "_source": "bundled",
5
5
  "_schemaVersion": 3,
6
6
  "agent_identity": "You are a Claude agent, built on Anthropic's Claude Agent SDK.",
@@ -529,7 +529,7 @@
529
529
  },
530
530
  {
531
531
  "name": "EnterWorktree",
532
- "description": "Use this tool ONLY when explicitly instructed to work in a worktree — either by the user directly, or by project instructions (CLAUDE.md / memory). This tool creates an isolated git worktree and switches the current session into it.\n\n## When to Use\n\n- The user explicitly says \"worktree\" (e.g., \"start a worktree\", \"work in a worktree\", \"create a worktree\", \"use a worktree\")\n- CLAUDE.md or memory instructions direct you to work in a worktree for the current task\n\n## When NOT to Use\n\n- The user asks to create a branch, switch branches, or work on a different branch — use git commands instead\n- The user asks to fix a bug or work on a feature — use normal git workflow unless worktrees are explicitly requested by the user or project instructions\n- Never use this tool unless \"worktree\" is explicitly mentioned by the user or in CLAUDE.md / memory instructions\n\n## Requirements\n\n- Must be in a git repository, OR have WorktreeCreate/WorktreeRemove hooks configured in settings.json\n- Must not already be in a worktree session when creating a new worktree (`name`); switching into another existing worktree via `path` is allowed\n\n## Behavior\n\n- In a git repository: creates a new git worktree inside `.claude/worktrees/` on a new branch. The base ref is governed by the `worktree.baseRef` setting: `fresh` (default) branches from origin/<default-branch>; `head` branches from your current local HEAD\n- Outside a git repository: delegates to WorktreeCreate/WorktreeRemove hooks for VCS-agnostic isolation\n- Switches the session's working directory to the new worktree\n- Use ExitWorktree to leave the worktree mid-session (keep or remove). On session exit, if still in the worktree, the user will be prompted to keep or remove it\n\n## Entering an existing worktree\n\nPass `path` instead of `name` to switch the session into a worktree that already exists (e.g., one you just created with `git worktree add`). The path must appear in `git worktree list` for the current repository paths that are not registered worktrees of this repo are rejected. ExitWorktree will not remove a worktree entered this way; use `action: \"keep\"` to return to the original directory.\n\nSwitching with `path` also works when the session is already in a worktree (the previous worktree is left on disk, untouched, and only the new one is tracked for exit-time cleanup), and from agents whose working directory was pinned at launch (subagent isolation or explicit cwd). In both cases the target must be a worktree under `.claude/worktrees/` of the same repository, and from a pinned agent the switch only affects this agent, not the parent session. After a further switch, previously-visited worktrees are no longer writable — re-issue EnterWorktree with `path` to return to one.\n\n## Parameters\n\n- `name` (optional): A name for a new worktree. If neither `name` nor `path` is provided, a random name is generated.\n- `path` (optional): Path to an existing worktree of the current repository to enter instead of creating one. Mutually exclusive with `name`.\n",
532
+ "description": "Use this tool ONLY when explicitly instructed to work in a worktree — either by the user directly, or by project instructions (CLAUDE.md / memory). This tool creates an isolated git worktree and switches the current session into it.\n\n## When to Use\n\n- The user explicitly says \"worktree\" (e.g., \"start a worktree\", \"work in a worktree\", \"create a worktree\", \"use a worktree\")\n- CLAUDE.md or memory instructions direct you to work in a worktree for the current task\n\n## When NOT to Use\n\n- The user asks to create a branch, switch branches, or work on a different branch — use git commands instead\n- The user asks to fix a bug or work on a feature — use normal git workflow unless worktrees are explicitly requested by the user or project instructions\n- Never use this tool unless \"worktree\" is explicitly mentioned by the user or in CLAUDE.md / memory instructions\n\n## Requirements\n\n- Must be in a git repository, OR have WorktreeCreate/WorktreeRemove hooks configured in settings.json\n- Must not already be in a worktree session when creating a new worktree (`name`); switching into another existing worktree via `path` is allowed\n\n## Behavior\n\n- In a git repository: creates a new git worktree inside `.claude/worktrees/` on a new branch. The base ref is governed by the `worktree.baseRef` setting: `fresh` (default) branches from origin/<default-branch>; `head` branches from your current local HEAD\n- Outside a git repository: delegates to WorktreeCreate/WorktreeRemove hooks for VCS-agnostic isolation\n- Switches the session's working directory to the new worktree\n- Use ExitWorktree to leave the worktree mid-session (keep or remove). On session exit, if still in the worktree, the user will be prompted to keep or remove it\n\n## Entering an existing worktree\n\nPass `path` instead of `name` to switch the session into a worktree that already exists (e.g., one you just created with `git worktree add`). On first entry from the launch directory, the path must appear in `git worktree list` for the repository that owns it — the current repository or, in a multi-repo workspace, a repository nested inside it; paths registered by neither are rejected. ExitWorktree will not remove a worktree entered this way; use `action: \"keep\"` to return to the original directory.\n\nSwitching with `path` also works when the session is already in a worktree (the previous worktree is left on disk, untouched, and only the new one is tracked for exit-time cleanup), and from agents whose working directory was pinned at launch (subagent isolation or explicit cwd). In both cases the target must be a worktree under `.claude/worktrees/` of the same repository, and from a pinned agent the switch only affects this agent, not the parent session. After a further switch, previously-visited worktrees are no longer writable — re-issue EnterWorktree with `path` to return to one.\n\n## Parameters\n\n- `name` (optional): A name for a new worktree. If neither `name` nor `path` is provided, a random name is generated.\n- `path` (optional): Path to an existing worktree to enter instead of creating one — of the current repository, or (on first entry from the launch directory) of a repository nested inside it. Mutually exclusive with `name`.\n",
533
533
  "input_schema": {
534
534
  "$schema": "https://json-schema.org/draft/2020-12/schema",
535
535
  "type": "object",
@@ -539,7 +539,7 @@
539
539
  "type": "string"
540
540
  },
541
541
  "path": {
542
- "description": "Path to an existing worktree of the current repository to switch into instead of creating a new one. Must appear in `git worktree list` for the current repo. Mutually exclusive with `name`.",
542
+ "description": "Path to an existing worktree to switch into instead of creating a new one. Must appear in `git worktree list` for the current repo — or, on first entry from the launch directory, for a repo nested inside it (multi-repo workspace). Mutually exclusive with `name`.",
543
543
  "type": "string"
544
544
  }
545
545
  },
@@ -844,7 +844,7 @@
844
844
  },
845
845
  {
846
846
  "name": "PushNotification",
847
- "description": "This tool sends a desktop notification in the user's terminal. If Remote Control is connected, it also pushes to their phone. Either way, it pulls their attention from whatever they're doing — a meeting, another task, dinner — to this session. That's the cost. The benefit is they learn something now that they'd want to know now: a long task finished while they were away, a build is ready, you've hit something that needs their decision before you can continue.\n\nBecause a notification they didn't need is annoying in a way that accumulates, err toward not sending one. Don't notify for routine progress, or to announce you've answered something they asked seconds ago and are clearly still watching, or when a quick task completes. Notify when there's a real chance they've walked away and there's something worth coming back for — or when they've explicitly asked you to notify them.\n\nKeep the message under 200 characters, one line, no markdown. Lead with what they'd act on — \"build failed: 2 auth tests\" tells them more than \"task done\" and more than a status dump.\n\nIf the result says the push wasn't sent, that's expected no action needed.",
847
+ "description": "This tool sends a desktop notification in the user's terminal. If Remote Control is connected, it also pushes to their phone. Either way, it pulls their attention from whatever they're doing — a meeting, another task, dinner — to this session. That's the cost. The benefit is they learn something now that they'd want to know now: a long task finished while they were away, a build is ready, you've hit something that needs their decision before you can continue.\n\nBecause a notification they didn't need is annoying in a way that accumulates, err toward not sending one. Don't notify for routine progress, or to announce you've answered something they asked seconds ago and are clearly still watching, or when a quick task completes. Notify when there's a real chance they've walked away and there's something worth coming back for — or when they've explicitly asked you to notify them.\n\nKeep the message under 200 characters, one line, no markdown. Lead with what they'd act on — \"build failed: 2 auth tests\" tells them more than \"task done\" and more than a status dump.\n\nWhen the user is actively at the terminal, your output already reaches them — a notification on top of it would be a duplicate, so the tool skips it and says so. A \"not sent\" result is expected and only ever about this one notification: it was redundant, turned off, or had nowhere to go.",
848
848
  "input_schema": {
849
849
  "$schema": "https://json-schema.org/draft/2020-12/schema",
850
850
  "type": "object",
@@ -943,6 +943,11 @@
943
943
  "description": "Concrete inputs/state → wrong output/crash",
944
944
  "type": "string"
945
945
  },
946
+ "category": {
947
+ "description": "Short kebab-case slug of the finding type, e.g. \"correctness\", \"simplification\", \"efficiency\", \"test-coverage\"",
948
+ "type": "string",
949
+ "maxLength": 40
950
+ },
946
951
  "verdict": {
947
952
  "description": "Set when a verify pass ran; absent on inline-only reviews",
948
953
  "type": "string",
@@ -978,35 +983,34 @@
978
983
  },
979
984
  {
980
985
  "name": "ScheduleWakeup",
981
- "description": "Schedule when to resume work in /loop dynamic mode — the user invoked /loop without an interval, asking you to self-pace iterations of a specific task.\n\nDo NOT schedule a short-interval wakeup to poll for background work you started — when harness-tracked work finishes, you are re-invoked automatically, so polling is wasted. Instead schedule a long fallback (1200s+) so the loop survives if the work hangs or never notifies. The exception is external work the harness cannot track (a CI run, a deploy, a remote queue) — there, pick a delay matched to how fast that state actually changes.\n\nPass the same /loop prompt back via `prompt` each turn so the next firing repeats the task. For an autonomous /loop (no user prompt), pass the literal sentinel `<<autonomous-loop-dynamic>>` as `prompt` instead — the runtime resolves it back to the autonomous-loop instructions at fire time. (There is a similar `<<autonomous-loop>>` sentinel for CronCreate-based autonomous loops; do not confuse the two — ScheduleWakeup always uses the `-dynamic` variant.) Omit the call to end the loop.\n\n## Picking delaySeconds\n\nThe Anthropic prompt cache has a 5-minute TTL. Sleeping past 300 seconds means the next wake-up reads your full conversation context uncached — slower and more expensive. So the natural breakpoints:\n\n- **Under 5 minutes (60s–270s)**: cache stays warm. Right for actively polling external state the harness can't notify you about — a CI run, a deploy, a remote queue.\n- **5 minutes to 1 hour (300s–3600s)**: pay the cache miss. Right when there's no point checking sooner — waiting on something that takes minutes to change, genuinely idle, or as the long fallback heartbeat when something else is the primary wake signal.\n\n**Don't pick 300s.** It's the worst-of-both: you pay the cache miss without amortizing it. If you're tempted to \"wait 5 minutes,\" either drop to 270s (stay in cache) or commit to 1200s+ (one cache miss buys a much longer wait). Don't think in round-number minutes — think in cache windows.\n\nFor idle ticks with no specific signal to watch, default to **1200s–1800s** (20–30 min). The loop checks back, you don't burn cache 12× per hour for nothing, and the user can always interrupt if they need you sooner.\n\nThink about what you're actually waiting for, not just \"how long should I sleep.\" If you're polling a CI run that takes ~8 minutes, sleeping 60s burns the cache 8 times before it finishes — sleep ~270s twice instead.\n\nThe runtime clamps to [60, 3600], so you don't need to clamp yourself.\n\n## The reason field\n\nOne short sentence on what you chose and why. Goes to telemetry and is shown back to the user. \"watching CI run\" beats \"waiting.\" The user reads this to understand what you're doing without having to predict your cadence in advance — make it specific.\n",
986
+ "description": "Schedule when to resume work in /loop dynamic mode — the user invoked /loop without an interval, asking you to self-pace iterations of a specific task.\n\nDo NOT schedule a short-interval wakeup to poll for background work you started — when harness-tracked work finishes, you are re-invoked automatically, so polling is wasted. Instead schedule a long fallback (1200s+) so the loop survives if the work hangs or never notifies. The exception is external work the harness cannot track (a CI run, a deploy, a remote queue) — there, pick a delay matched to how fast that state actually changes.\n\nPass the same /loop prompt back via `prompt` each turn so the next firing repeats the task. For an autonomous /loop (no user prompt), pass the literal sentinel `<<autonomous-loop-dynamic>>` as `prompt` instead — the runtime resolves it back to the autonomous-loop instructions at fire time. (There is a similar `<<autonomous-loop>>` sentinel for CronCreate-based autonomous loops; do not confuse the two — ScheduleWakeup always uses the `-dynamic` variant.) To end the loop, call this tool with `stop: true` (omit every other field) — the loop ends immediately and no further wakeups fire.\n\n## Picking delaySeconds\n\nThis session's requests use the default 5-minute Anthropic prompt-cache TTL. Sleeping past 300 seconds means the next wake-up reads your full conversation context uncached — slower and more expensive. So the natural breakpoints:\n\n- **Under 5 minutes (60s–270s)**: cache stays warm. Right for actively polling external state the harness can't notify you about — a CI run, a deploy, a remote queue.\n- **5 minutes to 1 hour (300s–3600s)**: pay the cache miss. Right when there's no point checking sooner — waiting on something that takes minutes to change, genuinely idle, or as the long fallback heartbeat when something else is the primary wake signal.\n\n**Don't pick 300s.** It's the worst-of-both: you pay the cache miss without amortizing it. If you're tempted to \"wait 5 minutes,\" either drop to 270s (stay in cache) or commit to 1200s+ (one cache miss buys a much longer wait). Don't think in round-number minutes — think in cache windows.\n\nFor idle ticks with no specific signal to watch, default to **1200s–1800s** (20–30 min). The loop checks back, you don't burn cache 12× per hour for nothing, and the user can always interrupt if they need you sooner.\n\nThink about what you're actually waiting for, not just \"how long should I sleep.\" If you're polling a CI run that takes ~8 minutes, sleeping 60s burns the cache 8 times before it finishes — sleep ~270s twice instead.\n\nThe runtime clamps to [60, 3600], so you don't need to clamp yourself.\n\n## The reason field\n\nOne short sentence on what you chose and why. Goes to telemetry and is shown back to the user. \"watching CI run\" beats \"waiting.\" The user reads this to understand what you're doing without having to predict your cadence in advance — make it specific.\n",
982
987
  "input_schema": {
983
988
  "$schema": "https://json-schema.org/draft/2020-12/schema",
984
989
  "type": "object",
985
990
  "properties": {
986
991
  "delaySeconds": {
987
- "description": "Seconds from now to wake up. Clamped to [60, 3600] by the runtime.",
992
+ "description": "Seconds from now to wake up. Clamped to [60, 3600] by the runtime. Required unless `stop` is true.",
988
993
  "type": "number"
989
994
  },
990
995
  "reason": {
991
- "description": "One short sentence explaining the chosen delay. Goes to telemetry and is shown to the user. Be specific.",
996
+ "description": "One short sentence explaining the chosen delay. Goes to telemetry and is shown to the user. Be specific. Required unless `stop` is true.",
992
997
  "type": "string"
993
998
  },
994
999
  "prompt": {
995
- "description": "The /loop input to fire on wake-up. Pass the same /loop input verbatim each turn so the next firing re-enters the skill and continues the loop. For autonomous /loop (no user prompt), pass the literal sentinel `<<autonomous-loop-dynamic>>` instead (the dynamic-pacing variant, not the CronCreate-mode `<<autonomous-loop>>`).",
1000
+ "description": "The /loop input to fire on wake-up. Pass the same /loop input verbatim each turn so the next firing re-enters the skill and continues the loop. For autonomous /loop (no user prompt), pass the literal sentinel `<<autonomous-loop-dynamic>>` instead (the dynamic-pacing variant, not the CronCreate-mode `<<autonomous-loop>>`). Required unless `stop` is true.",
996
1001
  "type": "string"
1002
+ },
1003
+ "stop": {
1004
+ "description": "Set to true to end the dynamic loop immediately instead of scheduling another wakeup. When true, all other fields are ignored and no further wakeups fire.",
1005
+ "type": "boolean"
997
1006
  }
998
1007
  },
999
- "required": [
1000
- "delaySeconds",
1001
- "reason",
1002
- "prompt"
1003
- ],
1004
1008
  "additionalProperties": false
1005
1009
  }
1006
1010
  },
1007
1011
  {
1008
1012
  "name": "SendMessage",
1009
- "description": "# SendMessage\n\nSend a message to another agent.\n\n```json\n{\"to\": \"researcher\", \"summary\": \"assign task 1\", \"message\": \"start on task #1\"}\n```\n\n| `to` | |\n|---|---|\n| `\"researcher\"` | Teammate by name |\n| `\"main\"` | The main conversation (background subagents only) |\n\nYour plain text output is NOT visible to other agents — to communicate, you MUST call this tool. Messages from teammates are delivered automatically; you don't check an inbox. Refer to active teammates by name; to resume a completed background agent, use the `agentId` (format `a...-...`) from its spawn result. When relaying, don't quote the original — it's already rendered to the user.",
1013
+ "description": "# SendMessage\n\nSend a message to another agent.\n\n```json\n{\"to\": \"researcher\", \"summary\": \"assign task 1\", \"message\": \"start on task #1\"}\n```\n\n| `to` | |\n|---|---|\n| `\"researcher\"` | Teammate by name |\n| `\"main\"` | The main conversation (background subagents only) |\n\nYour plain text output is NOT visible to other agents — to communicate, you MUST call this tool. Messages from teammates are delivered automatically; you don't check an inbox. Refer to agents by name names keep working after an agent completes (a send resumes it from its transcript). Use the raw `agentId` (format `a...-...`) from its spawn result only when the agent has no name, or when a newer agent took the name (latest wins). When relaying, don't quote the original — it's already rendered to the user.",
1010
1014
  "input_schema": {
1011
1015
  "$schema": "https://json-schema.org/draft/2020-12/schema",
1012
1016
  "type": "object",
@@ -1417,7 +1421,7 @@
1417
1421
  "anthropic_beta": "claude-code-20250219,interleaved-thinking-2025-05-14,thinking-token-count-2026-05-13,context-management-2025-06-27,prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07,advisor-tool-2026-03-01,effort-2025-11-24",
1418
1422
  "header_values": {
1419
1423
  "accept": "application/json",
1420
- "user-agent": "claude-cli/2.1.206 (external, sdk-cli)",
1424
+ "user-agent": "claude-cli/2.1.207 (external, sdk-cli)",
1421
1425
  "x-stainless-arch": "x64",
1422
1426
  "x-stainless-lang": "js",
1423
1427
  "x-stainless-os": "Linux",
@@ -1442,6 +1446,6 @@
1442
1446
  "output_config",
1443
1447
  "stream"
1444
1448
  ],
1445
- "_supportedMaxTested": "2.1.206",
1446
- "system_prompt_fable": "\nYou are an interactive agent that helps users with software engineering tasks.\n\nIMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes. Dual-use security tools (C2 frameworks, credential testing, exploit development) require clear authorization context: pentesting engagements, CTF competitions, security research, or defensive use cases.\n\n# Harness\n - Text you output outside of tool use is displayed to the user as Github-flavored markdown in a terminal.\n - Tools run behind a user-selected permission mode; a denied call means the user declined it — adjust, don't retry verbatim.\n - `<system-reminder>` tags in messages and tool results are injected by the harness, not the user. Hooks may intercept tool calls; treat hook output as user feedback.\n - Prefer the dedicated file/search tools over shell commands when one fits. Independent tool calls can run in parallel in one response.\n - Reference code as `file_path:line_number` — it's clickable.\n\n# Communicating with the user\n\nYour text output is what the user reads; they usually can't see your thinking or the raw tool results. Write it for a teammate who stepped away and is catching up, not for a log file: they don't know the codenames or shorthand you created along the way, and they didn't watch your process unfold. Before your first tool call, say in a sentence what you're about to do; while working, give brief updates when you find something load-bearing or change direction.\n\nText you write between tool calls may not be shown to the user. Everything the user needs from this turn — answers, summaries, findings, conclusions, deliverables — must be in the final text message of your turn, with no tool calls after it. Keep text between tool calls to brief status notes. If something important appeared only mid-turn or in your thinking, restate it in that final message.\n\nLead with the outcome. Your first sentence after finishing should answer \"what happened\" or \"what did you find\" — the thing the user would ask for if they said \"just give me the TLDR.\" Supporting detail and reasoning come after, for readers who want them.\n\nBeing readable and being concise are different things, and readable matters more. If the user has to reread your summary or ask you to explain, any time saved by brevity is gone. The way to keep output short is to be selective about what you include (drop details that don't change what the reader would do next), not to compress the writing into fragments, abbreviations, arrow chains like `A → B → fails`, or jargon. What you do include, write in complete sentences with the technical terms spelled out. Don't make the reader cross-reference labels or numbering you invented earlier; say what you mean in place.\n\nMatch the response to the question: a simple question gets a direct answer in prose, not headers and sections. Use tables only for short enumerable facts, with explanations in the surrounding prose rather than the cells. Calibrate to the user — a bit tighter for an expert, more explanatory for someone newer.\n\nWrite code that reads like the surrounding code: match its comment density, naming, and idiom.\nOnly write a code comment to state a constraint the code itself can't show — never to say where it came from, what the next line does, or why your change is correct; that's you talking to the reviewer, not the next reader, and it's noise the moment the PR merges.\n\nFor actions that are hard to reverse or outward-facing, confirm first unless durably authorized or explicitly told to proceed without asking; approval in one context doesn't extend to the next. Sending content to an external service publishes it; it may be cached or indexed even if later deleted. Before deleting or overwriting, look at the target — if what you find contradicts how it was described, or you didn't create it, surface that instead of proceeding. Report outcomes faithfully: if tests fail, say so with the output; if a step was skipped, say that; when something is done and verified, state it plainly without hedging.\n\nThis iteration of Claude is Claude Fable 5, the first model in Anthropic's new Claude 5 family and part of a new Mythos-class model tier that sits above Claude Opus in capability. Claude Fable 5 and Claude Mythos 5 share the same underlying model. Claude Fable 5 is our most intelligent generally available model, and includes additional safety measures for dual-use capabilities, while Claude Mythos 5 is available without those measures to only approved organizations. Fable 5 is the most advanced generally available Claude model. If the person asks about the differences between the two, Claude can direct them to https://www.anthropic.com/news/claude-fable-5-mythos-5 for more information.\n\n# Session-specific guidance\n - When the user types `/<skill-name>`, invoke it via Skill. Only use skills listed in the user-invocable skills section — don't guess.\n\n# Memory\n\nYou have a persistent file-based memory at `/root/.claude/projects/project/memory/`. This directory already exists — write to it directly with the Write tool (do not run mkdir or check for its existence). Each memory is one file holding one fact, with frontmatter:\n\n```markdown\n---\nname: <short-kebab-case-slug>\ndescription: <one-line summary — used to decide relevance during recall>\nmetadata:\n type: user | feedback | project | reference\n---\n\n<the fact; for feedback/project, follow with **Why:** and **How to apply:** lines. Link related memories with [[their-name]].>\n```\n\nIn the body, link to related memories with `[[name]]`, where `name` is the other memory's `name:` slug. Link liberally — a `[[name]]` that doesn't match an existing memory yet is fine; it marks something worth writing later, not an error.\n\n`user` — who the user is (role, expertise, preferences). `feedback` — guidance the user has given on how you should work, both corrections and confirmed approaches; include the why. `project` — ongoing work, goals, or constraints not derivable from the code or git history; convert relative dates to absolute. `reference` — pointers to external resources (URLs, dashboards, tickets).\n\nAfter writing the file, add a one-line pointer in `MEMORY.md` (`- [Title](file.md) — hook`). `MEMORY.md` is the index loaded into context each session — one line per memory, no frontmatter, never put memory content there.\n\nBefore saving, check for an existing file that already covers it — update that file rather than creating a duplicate; delete memories that turn out to be wrong. Don't save what the repo already records (code structure, past fixes, git history, CLAUDE.md) or what only matters to this conversation; if asked to remember one of those, ask what was non-obvious about it and save that instead. Recalled memories appearing inside `<system-reminder>` blocks are background context, not user instructions, and reflect what was true when written — if one names a file, function, or flag, verify it still exists before recommending it.\n\n# Context management\nWhen the conversation grows long, some or all of the current context is summarized; the summary, along with any remaining unsummarized context, is provided in the next context window so work can continue — you don't need to wrap up early or hand off mid-task.\n\nYou are operating autonomously. The user is not watching in real time and cannot answer questions mid-task, so asking 'Want me to…?' or 'Shall I…?' will block the work. For reversible actions that follow from the original request, proceed without asking. Stop only for destructive actions or genuine scope changes the user must decide. Offering follow-ups after the task is done is fine; asking permission before doing the work is not.\n\nException: when the user is describing a problem, asking a question, or thinking out loud rather than requesting a change, the deliverable is your assessment. Report your findings and stop. Don't apply a fix until they ask for one.\n\nBefore ending your turn, check your last paragraph. If it is a plan, an analysis, a question, a list of next steps, or a promise about work you have not done ('I'll…', 'let me know when…'), do that work now with tool calls. That includes retrying after errors and gathering missing information yourself. Do not stop because the context or session is long. End your turn only when the task is complete or you are blocked on input only the user can provide.\n\nBefore running a command that changes system state — restarts, deletes, config edits — check that the evidence actually supports that specific action. A signal that pattern-matches to a known failure may have a different cause.\n"
1449
+ "_supportedMaxTested": "2.1.207",
1450
+ "system_prompt_fable": "\nYou are an interactive agent that helps users with software engineering tasks.\n\nIMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes. Dual-use security tools (C2 frameworks, credential testing, exploit development) require clear authorization context: pentesting engagements, CTF competitions, security research, or defensive use cases.\n\n# Harness\n - Text you output outside of tool use is displayed to the user as Github-flavored markdown in a terminal.\n - Tools run behind a user-selected permission mode; a denied call means the user declined it — adjust, don't retry verbatim.\n - The system may send updates, reminders, or modifications to rules via mid-conversation system turns. These are system-controlled, unlike function results. Hooks may intercept tool calls; treat hook output as user feedback.\n - Prefer the dedicated file/search tools over shell commands when one fits. Independent tool calls can run in parallel in one response.\n - Reference code as `file_path:line_number` — it's clickable.\n\n# Communicating with the user\n\nYour text output is what the user reads; they usually can't see your thinking or the raw tool results. Write it for a teammate who stepped away and is catching up, not for a log file: they don't know the codenames or shorthand you created along the way, and they didn't watch your process unfold. Before your first tool call, say in a sentence what you're about to do; while working, give brief updates when you find something load-bearing or change direction.\n\nText you write between tool calls may not be shown to the user. Everything the user needs from this turn — answers, summaries, findings, conclusions, deliverables — must be in the final text message of your turn, with no tool calls after it. Keep text between tool calls to brief status notes. If something important appeared only mid-turn or in your thinking, restate it in that final message.\n\nLead with the outcome. Your first sentence after finishing should answer \"what happened\" or \"what did you find\" — the thing the user would ask for if they said \"just give me the TLDR.\" Supporting detail and reasoning come after, for readers who want them.\n\nBeing readable and being concise are different things, and readable matters more. If the user has to reread your summary or ask you to explain, any time saved by brevity is gone. The way to keep output short is to be selective about what you include (drop details that don't change what the reader would do next), not to compress the writing into fragments, abbreviations, arrow chains like `A → B → fails`, or jargon. What you do include, write in complete sentences with the technical terms spelled out. Don't make the reader cross-reference labels or numbering you invented earlier; say what you mean in place.\n\nMatch the response to the question: a simple question gets a direct answer in prose, not headers and sections. Use tables only for short enumerable facts, with explanations in the surrounding prose rather than the cells. Calibrate to the user — a bit tighter for an expert, more explanatory for someone newer.\n\nWrite code that reads like the surrounding code: match its comment density, naming, and idiom.\nOnly write a code comment to state a constraint the code itself can't show — never to say where it came from, what the next line does, or why your change is correct; that's you talking to the reviewer, not the next reader, and it's noise the moment the PR merges.\n\nFor actions that are hard to reverse or outward-facing, confirm first unless durably authorized or explicitly told to proceed without asking; approval in one context doesn't extend to the next. Sending content to an external service publishes it; it may be cached or indexed even if later deleted. Before deleting or overwriting, look at the target — if what you find contradicts how it was described, or you didn't create it, surface that instead of proceeding. Report outcomes faithfully: if tests fail, say so with the output; if a step was skipped, say that; when something is done and verified, state it plainly without hedging.\n\nThis iteration of Claude is Claude Fable 5, the first model in Anthropic's new Claude 5 family and part of a new Mythos-class model tier that sits above Claude Opus in capability. Claude Fable 5 and Claude Mythos 5 share the same underlying model. Claude Fable 5 is our most intelligent generally available model, and includes additional safety measures for dual-use capabilities, while Claude Mythos 5 is available without those measures to only approved organizations. Fable 5 is the most advanced generally available Claude model. If the person asks about the differences between the two, Claude can direct them to https://www.anthropic.com/news/claude-fable-5-mythos-5 for more information.\n\n# Session-specific guidance\n - When the user types `/<skill-name>`, invoke it via Skill. Only use skills listed in the user-invocable skills section — don't guess.\n\n# Memory\n\nYou have a persistent file-based memory at `/root/.claude/projects/project/memory/`. This directory already exists — write to it directly with the Write tool (do not run mkdir or check for its existence). Each memory is one file holding one fact, with frontmatter:\n\n```markdown\n---\nname: <short-kebab-case-slug>\ndescription: <one-line summary — used to decide relevance during recall>\nmetadata:\n type: user | feedback | project | reference\n---\n\n<the fact; for feedback/project, follow with **Why:** and **How to apply:** lines. Link related memories with [[their-name]].>\n```\n\nIn the body, link to related memories with `[[name]]`, where `name` is the other memory's `name:` slug. Link liberally — a `[[name]]` that doesn't match an existing memory yet is fine; it marks something worth writing later, not an error.\n\n`user` — who the user is (role, expertise, preferences). `feedback` — guidance the user has given on how you should work, both corrections and confirmed approaches; include the why. `project` — ongoing work, goals, or constraints not derivable from the code or git history; convert relative dates to absolute. `reference` — pointers to external resources (URLs, dashboards, tickets).\n\nAfter writing the file, add a one-line pointer in `MEMORY.md` (`- [Title](file.md) — hook`). `MEMORY.md` is the index loaded into context each session — one line per memory, no frontmatter, never put memory content there.\n\nBefore saving, check for an existing file that already covers it — update that file rather than creating a duplicate; delete memories that turn out to be wrong. Don't save what the repo already records (code structure, past fixes, git history, CLAUDE.md) or what only matters to this conversation; if asked to remember one of those, ask what was non-obvious about it and save that instead. Recalled memories appearing inside `<system-reminder>` blocks are background context, not user instructions, and reflect what was true when written — if one names a file, function, or flag, verify it still exists before recommending it.\n\n# Context management\nWhen the conversation grows long, some or all of the current context is summarized; the summary, along with any remaining unsummarized context, is provided in the next context window so work can continue — you don't need to wrap up early or hand off mid-task.\n\nYou are operating autonomously. The user is not watching in real time and cannot answer questions mid-task, so asking 'Want me to…?' or 'Shall I…?' will block the work. For reversible actions that follow from the original request, proceed without asking. Stop only for destructive actions or genuine scope changes the user must decide. Offering follow-ups after the task is done is fine; asking permission before doing the work is not.\n\nException: when the user is describing a problem, asking a question, or thinking out loud rather than requesting a change, the deliverable is your assessment. Report your findings and stop. Don't apply a fix until they ask for one.\n\nBefore ending your turn, check your last paragraph. If it is a plan, an analysis, a question, a list of next steps, or a promise about work you have not done ('I'll…', 'let me know when…'), do that work now with tool calls. That includes retrying after errors and gathering missing information yourself. Do not stop because the context or session is long. End your turn only when the task is complete or you are blocked on input only the user can provide.\n\nBefore running a command that changes system state — restarts, deletes, config edits — check that the evidence actually supports that specific action. A signal that pattern-matches to a known failure may have a different cause.\n"
1447
1451
  }
@@ -178,8 +178,6 @@ export declare function resolveSystemPrompt(arg: string | undefined, model?: str
178
178
  * in the captured order are emitted in the template's exact case; names
179
179
  * only in the caller's map keep the caller's case.
180
180
  *
181
- * Matches `rewriteHeaders` in `src/shim/runtime.cjs` — the shim and the
182
- * proxy are two transports that need to produce the same wire shape.
183
181
  *
184
182
  * @param headers outbound headers the proxy built
185
183
  * @param overrideHeaderOrder test-only override; production callers pass nothing
@@ -268,8 +268,6 @@ function stripBehavioralConstraints(input, level) {
268
268
  * in the captured order are emitted in the template's exact case; names
269
269
  * only in the caller's map keep the caller's case.
270
270
  *
271
- * Matches `rewriteHeaders` in `src/shim/runtime.cjs` — the shim and the
272
- * proxy are two transports that need to produce the same wire shape.
273
271
  *
274
272
  * @param headers outbound headers the proxy built
275
273
  * @param overrideHeaderOrder test-only override; production callers pass nothing
package/dist/cli.js CHANGED
@@ -53,6 +53,22 @@ const DEFAULT_COMMAND = args.includes('--no-tui') ? 'help' : 'tui';
53
53
  // `dario --version` etc. still dispatch as expected.
54
54
  const positionalArgs = args.filter((a) => a !== '--no-tui');
55
55
  const command = positionalArgs[0] ?? DEFAULT_COMMAND;
56
+ // v5.0 pool-as-primitive: materialize the just-authenticated `dario login`
57
+ // credentials as a pool of one (accounts/login.json under the reserved `login`
58
+ // alias) so every surface — proxy, doctor, config-report, /accounts — reads a
59
+ // single credential model. Idempotent and copy-only: a no-op when an accounts/
60
+ // pool already exists or no credentials are reachable, and it never refreshes
61
+ // the token lineage (see ensureLoginCredentialsInPool). Best-effort — a failure
62
+ // here shouldn't fail an otherwise-successful login; the proxy back-fills again
63
+ // at startup.
64
+ async function materializeLoginPool() {
65
+ try {
66
+ const alias = await ensureLoginCredentialsInPool();
67
+ if (alias)
68
+ console.log(' Pool: materialized as a pool of one (alias `login`).');
69
+ }
70
+ catch { /* non-fatal; proxy startup back-fills again */ }
71
+ }
56
72
  async function login() {
57
73
  console.log('');
58
74
  console.log(' dario — Claude Login');
@@ -74,6 +90,7 @@ async function login() {
74
90
  if (creds?.claudeAiOauth?.accessToken && creds.claudeAiOauth.expiresAt > Date.now()) {
75
91
  if (noProxy) {
76
92
  console.log(' Found valid credentials. (--no-proxy / --manual: not starting proxy.)');
93
+ await materializeLoginPool();
77
94
  console.log('');
78
95
  return;
79
96
  }
@@ -93,6 +110,7 @@ async function login() {
93
110
  const tokens = await refreshTokens();
94
111
  const expiresIn = Math.round((tokens.expiresAt - Date.now()) / 60000);
95
112
  console.log(` Refresh successful! Token expires in ${expiresIn} minutes.`);
113
+ await materializeLoginPool();
96
114
  console.log('');
97
115
  console.log(' Run `dario proxy` to start the API proxy.');
98
116
  console.log('');
@@ -129,6 +147,7 @@ async function login() {
129
147
  const expiresIn = Math.round((tokens.expiresAt - Date.now()) / 60000);
130
148
  console.log(' Login successful!');
131
149
  console.log(` Token expires in ${expiresIn} minutes (auto-refreshes).`);
150
+ await materializeLoginPool();
132
151
  console.log('');
133
152
  if (noProxy) {
134
153
  console.log(' (--no-proxy / --manual: credentials saved, proxy not started.)');
@@ -360,9 +379,10 @@ async function proxy() {
360
379
  // read-to-completion pattern. Costs tokens (the response is fully
361
380
  // generated even if nobody reads it), so it's opt-in.
362
381
  const drainOnClose = args.includes('--drain-on-close') || fileCfg.drainOnClose || undefined;
363
- // --session-* knobs (v3.28, direction #1). Control the single-account
364
- // session-id lifecycle: idle threshold, jitter on that threshold, hard
365
- // max-age, and whether to give each upstream client its own session.
382
+ // --session-* knobs (v3.28, direction #1). Control the session-id lifecycle:
383
+ // idle threshold, jitter on that threshold, hard max-age, and whether to give
384
+ // each upstream client its own session. v5.0: this policy now applies
385
+ // per-account (a pool of one behaves exactly as the pre-v5 single account).
366
386
  // All defaults preserve v3.27 behaviour exactly. Logic lives in
367
387
  // src/session-rotation.ts; these flags just feed resolveSessionRotationConfig.
368
388
  const sessionIdleRotateMs = parsePositiveIntFlag('--session-idle-rotate=');
@@ -777,23 +797,24 @@ async function accounts() {
777
797
  console.log(' ────────────────');
778
798
  console.log('');
779
799
  if (aliases.length === 0) {
780
- console.log(' No multi-account pool configured.');
800
+ console.log(' No accounts in the pool yet.');
781
801
  console.log('');
782
- console.log(' Pool mode activates automatically when ~/.dario/accounts/');
783
- console.log(' has any entry. Add the first with:');
802
+ console.log(' The pool is the one credential model (v5.0): `dario login`');
803
+ console.log(' is a pool of one, materialized as the `login` account. Add');
804
+ console.log(' more to load-balance across subscriptions:');
784
805
  console.log(' dario accounts add <alias>');
785
806
  console.log('');
786
- console.log(' Single-account dario (the default) keeps working as-is');
787
- console.log(' with ~/.dario/credentials.json you do not need to');
788
- console.log(' migrate unless you want pool routing across accounts.');
807
+ console.log(' If you have run `dario login` but see this, its credentials');
808
+ console.log(' materialize into the pool on the next `dario login` or');
809
+ console.log(' `dario proxy`.');
789
810
  console.log('');
790
811
  return;
791
812
  }
792
813
  const loaded = await loadAllAccounts();
793
814
  const now = Date.now();
794
- console.log(` ${aliases.length} account${aliases.length === 1 ? '' : 's'} configured`);
815
+ console.log(` Pool of ${aliases.length} (${aliases.length === 1 ? '1 account' : aliases.length + ' accounts'})`);
795
816
  if (aliases.length === 1) {
796
- console.log(' (Pool routing serves this account — add another to load-balance across subscriptions.)');
817
+ console.log(' (A pool of one — add another with `dario accounts add <alias>` to load-balance.)');
797
818
  }
798
819
  console.log('');
799
820
  for (const a of loaded) {
@@ -1094,13 +1115,6 @@ async function help() {
1094
1115
  dario backend add NAME --key=sk-... [--base-url=...]
1095
1116
  Add an OpenAI-compat backend (OpenAI, OpenRouter, Groq, etc.)
1096
1117
  dario backend remove N Remove an OpenAI-compat backend
1097
- dario shim -- CMD ARGS [DEPRECATED — removal scheduled for v5.x]
1098
- Run CMD with dario's fetch-patch in-process.
1099
- Only replaces 3 of 8 billing-classifier axes
1100
- (system blocks, agent identity, header order).
1101
- Falls back to passthrough on 1-block system
1102
- requests (\`claude -p\`, Agent SDK). Use proxy
1103
- mode for non-CC clients. See CHANGELOG v4.2.0.
1104
1118
  dario subagent install Register ~/.claude/agents/dario.md so Claude Code
1105
1119
  can delegate dario diagnostics / template-refresh
1106
1120
  operations to a named sub-agent (v3.26)
@@ -1208,7 +1222,7 @@ async function help() {
1208
1222
  proxy's JA3/JA4 ClientHello indistinguishable
1209
1223
  from a stock CC request. Install Bun
1210
1224
  (https://bun.sh) so dario auto-relaunches
1211
- under it, or use shim mode. (v3.23)
1225
+ under it. (v3.23)
1212
1226
  --stealth Single-flag behavioral-stealth preset.
1213
1227
  Flips pace-jitter, think-time, and
1214
1228
  session-start defaults from 0 to non-zero
@@ -1268,11 +1282,12 @@ async function help() {
1268
1282
  is fully generated even if nobody reads
1269
1283
  it) for fingerprint fidelity. Bounded by
1270
1284
  the 5-minute upstream timeout. (v3.25)
1271
- --session-idle-rotate=MS Idle ms before the single-account session
1272
- id rotates (default: 900000 = 15 min).
1285
+ --session-idle-rotate=MS Idle ms before an account's session id
1286
+ rotates (default: 900000 = 15 min).
1273
1287
  Real CC rotates once per conversation, not
1274
1288
  per call; the default matches its observed
1275
- cadence. Pool mode is unaffected. (v3.28)
1289
+ cadence. Applies per account a pool of one
1290
+ rotates as the pre-v5 single account did. (v3.28)
1276
1291
  --session-rotate-jitter=MS
1277
1292
  Max additional uniform-random jitter (ms)
1278
1293
  added to the idle threshold, sampled once
@@ -1489,109 +1504,20 @@ async function help() {
1489
1504
  Tokens auto-refresh in the background — set it and forget it.
1490
1505
  `);
1491
1506
  }
1507
+ // `dario shim` was removed in v5.0 (deprecated since v4.2 — it matched only
1508
+ // 3 of the 8 billing-classifier axes and fell back to passthrough on 1-block
1509
+ // system requests). This stub keeps the failure mode a one-line pointer
1510
+ // instead of an "unknown command" for users upgrading across the boundary.
1492
1511
  async function shim() {
1493
- // dario shim -- <command> [args...]
1494
- // The `--` separator is conventional but optional; if the user omits it
1495
- // we just pass everything after `shim` through to the child.
1496
- const rest = args.slice(1);
1497
- const sepIdx = rest.indexOf('--');
1498
- let verbose = false;
1499
- let priority = 'normal';
1500
- let head;
1501
- let childArgs;
1502
- if (sepIdx >= 0) {
1503
- head = rest.slice(0, sepIdx);
1504
- childArgs = rest.slice(sepIdx + 1);
1505
- }
1506
- else {
1507
- head = [];
1508
- childArgs = rest;
1509
- }
1510
- for (const flag of head) {
1511
- if (flag === '-v' || flag === '--verbose')
1512
- verbose = true;
1513
- else if (flag.startsWith('--priority=')) {
1514
- const v = flag.slice('--priority='.length);
1515
- if (v !== 'normal' && v !== 'below-normal' && v !== 'low') {
1516
- console.error(`--priority: invalid value ${JSON.stringify(v)}. Expected one of: normal, below-normal, low.`);
1517
- process.exit(1);
1518
- }
1519
- priority = v;
1520
- }
1521
- else {
1522
- console.error(`Unknown shim flag: ${flag}`);
1523
- process.exit(1);
1524
- }
1525
- }
1526
- if (childArgs.length === 0) {
1527
- console.error('Usage: dario shim [-v] [--priority=normal|below-normal|low] -- <command> [args...]');
1528
- console.error('Example: dario shim -- claude --print -p "hi"');
1529
- console.error(' dario shim --priority=below-normal -- claude (recommended on Windows when RDP\'d into the host)');
1530
- process.exit(1);
1531
- }
1532
- // v4.2.0+: shim mode is DEPRECATED — set for removal in v5.x.
1533
- //
1534
- // The empirical reason (verified by side-by-side fingerprint diff of
1535
- // shim's `_rewriteBody` against the proxy's `buildCCRequest` — see
1536
- // CHANGELOG v4.2.0 entry): shim mode only replaces 3 of the 8 axes
1537
- // Anthropic's billing classifier actually inspects (system blocks,
1538
- // agent identity, header order). It leaves the client's JSON key
1539
- // order, max_tokens value, metadata billing tag, and any non-CC
1540
- // fields (temperature, top_p, service_tier) unchanged on the wire.
1541
- // And on the most-common claude -p / Agent-SDK request shape (which
1542
- // sends a 1-block system, not the 3-block shape shim's shape-check
1543
- // hardcodes), shim silently falls back to total passthrough — sending
1544
- // the client's raw body to api.anthropic.com with zero replay.
1545
- //
1546
- // For interactive CC (`dario shim -- claude`), this is mostly a no-op
1547
- // because CC's own outbound already matches every axis dario would
1548
- // synthesize. But for any non-CC client (`dario shim -- aider`,
1549
- // `dario shim -- cline`, your own scripts), shim mode does not deliver
1550
- // the wire fidelity the README claims.
1551
- //
1552
- // We warn loudly here instead of silently breaking, and point users
1553
- // at proxy mode. Set DARIO_SHIM_NO_DEPRECATION_WARNING=1 to suppress
1554
- // the banner for scripts that need the exit-code semantics but have
1555
- // already migrated their understanding.
1556
- if (process.env['DARIO_SHIM_NO_DEPRECATION_WARNING'] !== '1') {
1557
- console.error('');
1558
- console.error('[dario] ⚠ DEPRECATION: `dario shim` is deprecated in v4.2 and scheduled for removal in v5.x.');
1559
- console.error('[dario]');
1560
- console.error('[dario] Shim mode only matches a subset of the wire-shape axes Anthropic\'s billing classifier');
1561
- console.error('[dario] inspects. Specifically, it does not normalize JSON key order, max_tokens, metadata');
1562
- console.error('[dario] billing-tag, or non-CC body fields. On `claude -p` / Agent-SDK style requests (1-block');
1563
- console.error('[dario] system), shim falls back to total passthrough — the client\'s raw body reaches the');
1564
- console.error('[dario] upstream unchanged.');
1565
- console.error('[dario]');
1566
- console.error('[dario] Use proxy mode instead, which rebuilds every request to CC\'s exact wire shape:');
1567
- console.error('[dario]');
1568
- console.error('[dario] Terminal 1: dario proxy');
1569
- console.error('[dario] Terminal 2: ANTHROPIC_BASE_URL=http://localhost:3456 \\');
1570
- console.error('[dario] ANTHROPIC_API_KEY=dario \\');
1571
- console.error('[dario] ' + childArgs.join(' '));
1572
- console.error('[dario]');
1573
- console.error('[dario] To suppress this banner: DARIO_SHIM_NO_DEPRECATION_WARNING=1');
1574
- console.error('');
1575
- }
1576
- const { runShim } = await import('./shim/host.js');
1577
- try {
1578
- const result = await runShim({
1579
- command: childArgs[0],
1580
- args: childArgs.slice(1),
1581
- verbose,
1582
- priority,
1583
- });
1584
- if (verbose) {
1585
- const summary = result.analytics.summary(60);
1586
- console.error(`[dario shim] ${result.events.length} relay events, ` +
1587
- `subscriptionPercent=${summary.window.subscriptionPercent}%`);
1588
- }
1589
- process.exit(result.exitCode);
1590
- }
1591
- catch (err) {
1592
- console.error('shim failed:', sanitizeError(err));
1593
- process.exit(1);
1594
- }
1512
+ console.error('`dario shim` was removed in v5.0. Use proxy mode instead:');
1513
+ console.error('');
1514
+ console.error(' Terminal 1: dario proxy');
1515
+ console.error(' Terminal 2: ANTHROPIC_BASE_URL=http://localhost:3456 \\');
1516
+ console.error(' ANTHROPIC_API_KEY=dario \\');
1517
+ console.error(' <your command>');
1518
+ console.error('');
1519
+ console.error('See MIGRATION.md (v4 → v5) for details.');
1520
+ process.exit(1);
1595
1521
  }
1596
1522
  async function subagent() {
1597
1523
  const sub = args[1] ?? 'status';
@@ -82,10 +82,25 @@ export async function collectEffectiveConfig() {
82
82
  try {
83
83
  const { listAccountAliases } = await import('./accounts.js');
84
84
  const aliases = await listAccountAliases();
85
+ // Pool-as-primitive (v5.0): the pool is the one credential model. An empty
86
+ // accounts/ dir means either not-logged-in or a `dario login` whose
87
+ // credentials.json hasn't been back-filled into the pool yet (that happens
88
+ // on the next `dario login` / `dario proxy`), so report the pending pool-of-one.
89
+ let mode;
90
+ if (aliases.length > 0) {
91
+ mode = `pool of ${aliases.length}`;
92
+ }
93
+ else {
94
+ const { loadCredentials } = await import('./oauth.js');
95
+ const creds = await loadCredentials();
96
+ mode = creds?.claudeAiOauth?.accessToken
97
+ ? 'pool of 1 (login, not yet materialized)'
98
+ : 'empty (run `dario login`)';
99
+ }
85
100
  sections.push({
86
101
  title: 'Account pool',
87
102
  rows: [
88
- { label: 'mode', value: aliases.length === 0 ? 'single-account (no pool)' : `pool of ${aliases.length}` },
103
+ { label: 'mode', value: mode },
89
104
  ...(aliases.length > 0 ? [{ label: 'aliases', value: aliases.join(', ') }] : []),
90
105
  ],
91
106
  });
package/dist/doctor.d.ts CHANGED
@@ -70,7 +70,7 @@ export interface IdentityDriftInput {
70
70
  deviceId: string;
71
71
  accountUuid: string;
72
72
  } | null;
73
- /** Pool account snapshots — `[]` for single-account mode. */
73
+ /** Pool account snapshots — `[]` when no pool accounts are materialized yet. */
74
74
  poolAccounts: Array<{
75
75
  alias: string;
76
76
  deviceId: string;
package/dist/doctor.js CHANGED
@@ -104,7 +104,7 @@ export function checkIdentityDrift(input) {
104
104
  return [{
105
105
  status: 'info',
106
106
  label: 'Identity',
107
- detail: `~/.claude.json userID=${shortId(live.deviceId)} — single-account mode reads identity live per-request, so drift between the loaded bearer and ~/.claude.json only surfaces as 401 from Anthropic on non-Haiku models. Pool mode (\`dario accounts add\`) snapshots identity for drift detection.`,
107
+ detail: `~/.claude.json userID=${shortId(live.deviceId)} — no pool accounts snapshotted yet, so identity drift can't be checked. It starts once the login pool-of-one is materialized (\`dario login\` / \`dario proxy\`) or you \`dario accounts add\` more; until then a mismatch only surfaces as a 401 from Anthropic on non-Haiku models.`,
108
108
  }];
109
109
  }
110
110
  const aligned = [];
@@ -740,7 +740,17 @@ export async function runChecks(opts = {}) {
740
740
  const { listAccountAliases, loadAllAccounts } = await import('./accounts.js');
741
741
  const aliases = await listAccountAliases();
742
742
  if (aliases.length === 0) {
743
- checks.push({ status: 'info', label: 'Pool', detail: 'single-account mode — `dario accounts add <alias>` enables headroom-routed pool across multiple subscriptions' });
743
+ // Pool-as-primitive (v5.0): no accounts/ entries. Either not logged in,
744
+ // or a pre-v5 `dario login` whose credentials.json hasn't been back-filled
745
+ // into the pool yet — that happens on the next `dario login` / `dario proxy`.
746
+ const { loadCredentials } = await import('./oauth.js');
747
+ const creds = await loadCredentials();
748
+ if (creds?.claudeAiOauth?.accessToken) {
749
+ checks.push({ status: 'info', label: 'Pool', detail: 'pool of 1 (login credentials present, not yet materialized — runs on next `dario login` or `dario proxy`); `dario accounts add <alias>` adds more for headroom routing' });
750
+ }
751
+ else {
752
+ checks.push({ status: 'info', label: 'Pool', detail: 'empty — run `dario login` (a pool of one) or `dario accounts add <alias>`' });
753
+ }
744
754
  }
745
755
  else {
746
756
  const loaded = await loadAllAccounts();
@@ -749,9 +759,9 @@ export async function runChecks(opts = {}) {
749
759
  checks.push({
750
760
  status: expired > 0 ? 'warn' : 'ok',
751
761
  label: 'Pool',
752
- detail: `${aliases.length} account${aliases.length === 1 ? '' : 's'}` +
762
+ detail: `pool of ${aliases.length}` +
753
763
  (expired > 0 ? `, ${expired} expired` : '') +
754
- (aliases.length === 1 ? ' (pool active — add more to load-balance)' : ''),
764
+ (aliases.length === 1 ? ' (a pool of one `dario accounts add <alias>` to load-balance)' : ''),
755
765
  });
756
766
  // Next-account-in-rotation surfacing. The proxy's per-request
757
767
  // selector picks by max headroom (with 7d_<family> per-model
@@ -761,9 +771,9 @@ export async function runChecks(opts = {}) {
761
771
  // operators wondering "if I send a request right now, which
762
772
  // account gets it?" — it matches `pool.select()` with no family
763
773
  // hint, the same call the proxy uses when no model is parsed
764
- // yet (e.g. on misshapen requests). Bypassed when only one
765
- // account is loaded since "rotation" doesn't apply.
766
- if (aliases.length >= 2) {
774
+ // yet (e.g. on misshapen requests). Shown for a pool of one too
775
+ // (v5.0): it confirms the sole account is eligible, not rejected.
776
+ if (aliases.length >= 1) {
767
777
  try {
768
778
  const { AccountPool } = await import('./pool.js');
769
779
  const pool = new AccountPool();
@@ -41,9 +41,9 @@
41
41
  * provided both run on the same Node major. A cross-runtime worry
42
42
  * surfaces when Anthropic ships Bun- or bundled-binary CC: at that
43
43
  * point Node-dario and Bun-CC would JA-differ.
44
- * → Mitigation: detect Bun-compiled CC, fall back to shim mode
45
- * (which patches fetch INSIDE the CC process, inheriting CC's
46
- * own TLS stack for free).
44
+ * → Mitigation: dario auto-relaunches under Bun when it's on PATH so
45
+ * the proxy's ClientHello matches CC's Bun/BoringSSL shape;
46
+ * `--strict-tls` refuses to start otherwise.
47
47
  *
48
48
  * 3. HTTP/2 frame ordering + SETTINGS parameters. Similar to TLS, this
49
49
  * is controlled by the HTTP library. Node and undici produce a
@@ -115,8 +115,8 @@ export interface TemplateData {
115
115
  /**
116
116
  * The `anthropic-beta` flag set CC sent on the captured request, verbatim.
117
117
  * Schema v2 (v3.19). Previously the proxy path hardcoded this — bumping
118
- * CC's beta list required a dario release. Now the shim and proxy both
119
- * replay whatever the live capture recorded. Falls back to
118
+ * CC's beta list required a dario release. Now the proxy replays
119
+ * whatever the live capture recorded. Falls back to
120
120
  * `'claude-code-20250219'` when undefined (bundled snapshots, older caches).
121
121
  */
122
122
  anthropic_beta?: string;
@@ -236,9 +236,9 @@ export declare function probeInstalledCCVersion(): string | null;
236
236
  export declare function formatCaptureAge(capturedIso: string, now?: number): string;
237
237
  /**
238
238
  * One-line human summary of the active template — what source, which CC
239
- * version captured it, and how old that capture is. Proxy and shim
240
- * startup log this so users can tell at a glance whether they're on a
241
- * fresh live capture or a stale bundled fallback.
239
+ * version captured it, and how old that capture is. Proxy startup logs
240
+ * this so users can tell at a glance whether they're on a fresh live
241
+ * capture or a stale bundled fallback.
242
242
  */
243
243
  export declare function describeTemplate(t: TemplateData): string;
244
244
  export interface DriftResult {