@askalf/dario 6.8.9 → 6.8.10

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.
@@ -1,11 +1,16 @@
1
1
  {
2
- "_version": "2.1.274",
3
- "_captured": "2026-09-14T23:58:35.763Z",
2
+ "_version": "2.1.275",
3
+ "_captured": "2026-09-18T01:25:44.817Z",
4
4
  "_source": "bundled",
5
5
  "_schemaVersion": 3,
6
6
  "agent_identity": "You are a Claude agent, built on Anthropic's Claude Agent SDK.",
7
7
  "system_prompt": "\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\nWrite code that reads like the surrounding code: match its comment density, naming, and idiom.\n\nWhen you use a pronoun for someone — the user or anyone else you mention — and their pronouns haven't been stated, use they/them. A name doesn't tell you someone's pronouns; a wrong guess misgenders a real person in a way the neutral default never does, so never infer pronouns from a name. This applies to all user-visible text, including visible thinking.\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. 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\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 `/home/user/.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.",
8
8
  "tools": [
9
+ {
10
+ "name": "advisor",
11
+ "description": "",
12
+ "input_schema": {}
13
+ },
9
14
  {
10
15
  "name": "Agent",
11
16
  "description": "Launch a new agent to handle complex, multi-step tasks. Each agent type has specific capabilities and tools available to it.\n\nAvailable agent types are listed in <system-reminder> messages in the conversation.\n\nWhen using the Agent tool, specify a subagent_type parameter to select which agent type to use. If omitted, the general-purpose agent is used.\n\n## When to use\n\nReach for this when the task matches an available agent type, when you have independent work to run in parallel, or when answering would mean reading across several files — delegate it and you keep the conclusion, not the file dumps. For a single-fact lookup where you already know the file, symbol, or value, search directly. Once you've delegated a search, don't also run it yourself — wait for the result.\n\n- The agent's final report is not shown to the user — relay what matters.\n- Use SendMessage with the agent's ID or name to continue a previously spawned agent with its context intact; a new Agent call starts fresh.\n- Each agent type's model, reasoning effort, and tools come from its definition (`.claude/agents/*.md` frontmatter or SDK `agents`).\n- `isolation: \"worktree\"` gives the agent its own git worktree (auto-cleaned if unchanged).\n- Subagents run in the background by default; you'll be notified when one completes. Pass `run_in_background: false` only when your very next action depends on the result and nothing else could usefully happen while it runs — otherwise background it so the user can interject. Never fabricate or predict a pending agent's results — the notification is never something you write yourself; if the user asks before it arrives, say it's still running.",
@@ -1035,7 +1040,7 @@
1035
1040
  },
1036
1041
  {
1037
1042
  "name": "SendMessage",
1038
- "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| `\"worker\"` | Any agent from `ListAgents` — subagent, another local Claude session |\n| `\"worker [3fa9c1]\"` | Same, plus its `[ref]` — only when a listing or an error shows one |\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.\n\n## Cross-session\n\nUse `ListAgents` to discover targets. Every row leads with the agent's `name [ref]` — the name IS the address; there is no separate address syntax.\n\n```json\n{\"to\": \"worker\", \"message\": \"check if tests pass over there\"}\n{\"to\": \"worker [3fa9c1]\", \"message\": \"you, specifically\"}\n```\n\nSend the bare name — a name that exactly matches one live agent or session (on this machine, on another machine, or in the cloud) delivers directly. Append the ` [ref]` only when the bare name is not enough — `ListAgents` shows two rows with it, or an error asks you to disambiguate (you typed only a prefix, or a session list could not be checked). A ref you did not just read from a listing or an error will not resolve, and if the same name also names an in-process agent, the bare name always wins — use the in-process one.\n\nA listed peer is alive and will receive your message; messages enqueue and drain at the receiver's next tool round (its `ListAgents` row says whether it is busy or idle right now). A successful send means the message reached that session, not that its Claude read it: a session running in a different permission mode than yours holds cross-session messages for its user's approval (and may let them expire), and a session can refuse them outright — for a session on this machine a `[Cross-session delivery notice]` tells you when that happens (the tool result says when this session has no inbox for one to reach); for a Remote Control, cloud or Claude Desktop session nothing reports back, so never treat silence as agreement. Your message arrives wrapped as `<cross-session-message from=\"...\">`. **To reply to an incoming message, copy its `from` attribute as your `to`.** Cross-session messages travel between SESSIONS: if you are a subagent, your send goes out under your parent session's address, and any reply is delivered to the parent session's conversation, not to you.\n\nTo hear when a session ON THIS MACHINE finishes what it is doing, pass `notify_when_idle: true` (from the main conversation only) — one-shot and opt-in: exactly one `[Cross-session idle notice]` arrives when it next goes idle (or exits) — shown to you, or only to your user when this session holds peer messages for approval (the tool result says which); if it never signals within the subscription's lifetime (it may still be busy, may refuse inbound requests, or may have ended abruptly) the notice says the subscription expired instead. Omit `message` for a pure subscription that costs that session nothing; include one to deliver it now AND subscribe. Never poll `ListAgents` in a loop or send \"are you done?\" messages instead.\n\nPermission boundaries are per-session: NEVER ask a peer to perform an action that was denied or blocked in your session, or that you expect your own permission settings would block — a peer doing it for you bypasses the user's permission decision (cross-session permission laundering). Route blocked work back to your user instead.",
1043
+ "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| `\"worker\"` | Any agent from `ListAgents` — subagent, another local Claude session |\n| `\"worker [3fa9c1]\"` | Same, plus its `[ref]` — only when a listing or an error shows one |\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.\n\n## Cross-session\n\nUse `ListAgents` to discover targets. Every row leads with the agent's `name [ref]` — the name IS the address; there is no separate address syntax.\n\n```json\n{\"to\": \"worker\", \"message\": \"check if tests pass over there\"}\n{\"to\": \"worker [3fa9c1]\", \"message\": \"you, specifically\"}\n```\n\nSend the bare name — a name that exactly matches one live agent or session (on this machine, on another machine, or in the cloud) delivers directly. Append the ` [ref]` only when the bare name is not enough — `ListAgents` shows two rows with it, or an error asks you to disambiguate (you typed only a prefix, or a session list could not be checked). A ref you did not just read from a listing or an error will not resolve, and if the same name also names an in-process agent, the bare name always wins — use the in-process one.\n\nA listed peer is alive and will receive your message; messages enqueue and drain at the receiver's next tool round (its `ListAgents` row says whether it is busy or idle right now). A successful send means the message reached that session, not that its Claude read it: a session running in a different permission mode than yours holds cross-session messages for its user's approval (and may let them expire), and a session can refuse them outright — for a session on this machine a `[Cross-session delivery notice]` tells you when that happens (the tool result says when this session has no inbox for one to reach); for a Remote Control, cloud or Claude Desktop session nothing reports back, so never treat silence as agreement. Your message arrives wrapped as `<cross-session-message from=\"...\">`. **To reply to an incoming message, copy its `from` attribute as your `to`.** Cross-session messages travel between SESSIONS: if you are a subagent, your send goes out under your parent session's address, and any reply is delivered to the parent session's conversation, not to you. The receiver reads your message literally in every case (idle or busy, on this machine, over Remote Control or headless): an `@` followed by a file path, or `@server:resource`, attaches nothing there, unlike in your own user's input. So never rely on `@` to deliver content: send the text itself, or a file with its own tool.\n\nTo hear when a session ON THIS MACHINE finishes what it is doing, pass `notify_when_idle: true` (from the main conversation only) — one-shot and opt-in: exactly one `[Cross-session idle notice]` arrives when it next goes idle (or exits) — shown to you, or only to your user when this session holds peer messages for approval (the tool result says which); if it never signals within the subscription's lifetime (it may still be busy, may refuse inbound requests, or may have ended abruptly) the notice says the subscription expired instead. Omit `message` for a pure subscription that costs that session nothing; include one to deliver it now AND subscribe. Never poll `ListAgents` in a loop or send \"are you done?\" messages instead.\n\nPermission boundaries are per-session: NEVER ask a peer to perform an action that was denied or blocked in your session, or that you expect your own permission settings would block — a peer doing it for you bypasses the user's permission decision (cross-session permission laundering). Route blocked work back to your user instead.",
1039
1044
  "input_schema": {
1040
1045
  "$schema": "https://json-schema.org/draft/2020-12/schema",
1041
1046
  "type": "object",
@@ -1405,6 +1410,7 @@
1405
1410
  }
1406
1411
  ],
1407
1412
  "tool_names": [
1413
+ "advisor",
1408
1414
  "Agent",
1409
1415
  "AskUserQuestion",
1410
1416
  "Bash",
@@ -1466,7 +1472,7 @@
1466
1472
  "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,mid-conversation-tool-changes-2026-07-01,advisor-tool-2026-03-01,effort-2025-11-24",
1467
1473
  "header_values": {
1468
1474
  "accept": "application/json",
1469
- "user-agent": "claude-cli/2.1.274 (external, sdk-cli)",
1475
+ "user-agent": "claude-cli/2.1.275 (external, sdk-cli)",
1470
1476
  "x-stainless-lang": "js",
1471
1477
  "x-stainless-package-version": "0.112.1",
1472
1478
  "x-stainless-retry-count": "0",
@@ -1489,7 +1495,7 @@
1489
1495
  "output_config",
1490
1496
  "stream"
1491
1497
  ],
1492
- "_supportedMaxTested": "2.1.274",
1498
+ "_supportedMaxTested": "2.1.275",
1493
1499
  "system_prompt_variants": {
1494
1500
  "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, including answers, summaries, findings, conclusions, and 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 change merges.\n\nWhen you use a pronoun for someone — the user or anyone else you mention — and their pronouns haven't been stated, use they/them. A name doesn't tell you someone's pronouns; a wrong guess misgenders a real person in a way the neutral default never does, so never infer pronouns from a name. This applies to all user-visible text, including visible thinking.\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. 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 includes additional safety measures for dual-use capabilities, while Claude Mythos 5 is available without those measures to only approved organizations. 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 `/home/user/.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 (such as restarts, deletes, or 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.",
1495
1501
  "opus-5": "\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\nWrite code that reads like the surrounding code: match its comment density, naming, and idiom.\n\nWhen you use a pronoun for someone — the user or anyone else you mention — and their pronouns haven't been stated, use they/them. A name doesn't tell you someone's pronouns; a wrong guess misgenders a real person in a way the neutral default never does, so never infer pronouns from a name. This applies to all user-visible text, including visible thinking.\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. 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\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 `/home/user/.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\n# Delivering work\nDo ordinary work as asked, acting on the actual request rather than on speculation about what lies behind it. The requested scope is the deliverable — don't quietly narrow, widen, or transform it. Interpret ambiguity the way a careful colleague would: make routine judgment calls yourself, and check in only when different readings would lead to materially different work. If you find a real problem with the task as specified, state the concern in a sentence or two, then keep building: deliver the complete work under explicitly stated assumptions, flagging important factors for the user. Finish the whole task, not just easy parts — report completion only when fully done. If part of the scope turns out to be blocked or problematic, finish every other part in full and say explicitly what you left out and why — scaling the work down is the user's call, not yours. Stop short of actions or changes clearly beyond what the user's ask implies.\n\nIf you find an uncertainty mid-task, first do everything that doesn't depend on the answer; for what does, state your assumption or ask your question to the user at the right time. Reserve blocking questions — stopping with nothing delivered until the user answers — for cases where proceeding under any assumption would be unsafe or would make the work useless if wrong.\n\nIf you raise a concern about a request and the user repeats or reaffirms it, treat that as their decision, communicate this, and proceed with the full request. Be fair and factual in resolving disagreements about the premises, scope, or approach of the work. Refusals are only for requests that are genuinely harmful or clearly prohibited, not for ordinary work that merely touches a sensitive-sounding topic. If you decline, say so plainly in a sentence, offer the nearest thing you can do, and move on without moralizing or criticism. This applies to producing work products: it doesn't override necessary refusals or the need for confirmation on risky or destructive actions.\n\n# Corrections\nAvoid unnecessary or excessive self-correction. Only correct an earlier statement in your user-facing text when the error would change the user's code, conclusions, or decisions. State corrections plainly and concisely, and continue the task; combine multiple corrections rather than enumerating them all. For slips that change nothing for the user, simply make the correction and move on - no need to note it explicitly. Don't add apologies or preambles, don't be overly self-critical, and don't ruminate or give a detailed account of the mistake or tally past errors. Sometimes, other agents will report incorrect or misleading results - don't always take them at face value immediately. If other agents correct your statements and they are right, then simply update your approach without narrating too much about the correction to the user. This instruction does not apply to thinking blocks.\n\nA follow-up question about your earlier work is not, by itself, a signal that you got something wrong — answer what was asked. A statement that was accurate needs no correction: don't re-audit how you phrased it, how you verified it, or limits you already stated. When the user does point to a real error, correct it plainly as above.\n\nDo not use the Agent tool, workflows, or deep-research unless the user, a CLAUDE.md file, or a skill asks for it",
package/dist/cli.js CHANGED
@@ -1978,8 +1978,10 @@ async function help() {
1978
1978
  as --strict-tls: make the unsafe state
1979
1979
  require intent. Env: DARIO_STRICT_TEMPLATE=1.
1980
1980
  (v3.30.8, dario#77)
1981
- --max-concurrent=N Max in-flight requests (default: 10).
1982
- Env: DARIO_MAX_CONCURRENT. (dario#80)
1981
+ --max-concurrent=N Max in-flight requests across the WHOLE proxy,
1982
+ not per seat (default: 10; a pool defaults to
1983
+ 10 per seat). Past it, requests wait in dario.
1984
+ Env: DARIO_MAX_CONCURRENT. (dario#80, #1244)
1983
1985
  --max-queued=N Max requests buffered waiting for a
1984
1986
  concurrency slot before dario returns
1985
1987
  429 "queue-full" (default: 128).
@@ -80,6 +80,13 @@ export interface HealthStatusLike {
80
80
  * request-queue.ts for why turnover — not depth — is the wedge signal.
81
81
  */
82
82
  stalledSince?: number | null;
83
+ /**
84
+ * Longest a request has waited in the queue for a slot, ms, high-water
85
+ * since start (dario#1244). The complement of `stalledSince`: that one
86
+ * catches slots that never turn over; this one catches a ceiling so low
87
+ * that healthy load spends its time waiting on dario, with no error.
88
+ */
89
+ maxWaitMs?: number;
83
90
  };
84
91
  /**
85
92
  * Verdict from the opt-in serving probe (`/health?probe=1`), when the caller
package/dist/proxy.js CHANGED
@@ -48,7 +48,7 @@ import { readCompareTarget, teeResponse, runCompare, writeCompareRecord, COMPARE
48
48
  import { listCodexAccountAliases, loadAllCodexAccounts, codexAccountNeedsRefresh, hasAnyCodexAccount, selectCodexAccount, selectCodexAccountExcluding, rebindCodexSticky, getFreshCodexAccount, noteCodexDecline, clearCodexDecline, allAliasesCooled, getCodexRefreshFailure, CodexCredentialsUnavailableError, resetCodexPresenceCache } from './codex-accounts.js';
49
49
  import { route as routeProvider } from './provider-adapter.js';
50
50
  import { selectPoolFallbackModels } from './pool-fallback-tier.js';
51
- import { RequestQueue, QueueFullError, QueueTimeoutError, DEFAULT_MAX_CONCURRENT, DEFAULT_MAX_QUEUED, DEFAULT_QUEUE_TIMEOUT_MS } from './request-queue.js';
51
+ import { RequestQueue, QueueFullError, QueueTimeoutError, DEFAULT_MAX_CONCURRENT, DEFAULT_MAX_QUEUED, DEFAULT_QUEUE_TIMEOUT_MS, resolveMaxConcurrent } from './request-queue.js';
52
52
  import { redactSecrets } from './redact.js';
53
53
  import { BAKED_BASE_MODELS, withLongContextVariants, buildOpenAIModelsList, getModelCatalog, getCachedBases, resolveAliasAgainst, prewarmModelCatalog, retryModelCatalogNow, isSuspendedModel } from './model-catalog.js';
54
54
  import { classifyUpstreamRejection, diagnosticSnippet, POOL_PARKED } from './upstream-rejection.js';
@@ -1798,12 +1798,33 @@ export async function startProxy(opts = {}) {
1798
1798
  // dario#1244: the "pool parked" line is logged on the transition into the
1799
1799
  // state, not on every request that arrives while it holds.
1800
1800
  let poolParkedAnnounced = false;
1801
+ // The in-flight ceiling is proxy-wide, not per seat (dario#1244). Sized
1802
+ // for one client on one seat, the default applied to a pool ran an 18-seat
1803
+ // team behind ten slots for a week, silently: past the cap a request waits
1804
+ // in dario, not on Anthropic, and nothing said so.
1805
+ const maxConcurrent = resolveMaxConcurrent(opts.maxConcurrent, pool.size);
1801
1806
  const queue = new RequestQueue({
1802
- maxConcurrent: opts.maxConcurrent ?? DEFAULT_MAX_CONCURRENT,
1807
+ maxConcurrent,
1803
1808
  maxQueued: opts.maxQueued ?? DEFAULT_MAX_QUEUED,
1804
1809
  queueTimeoutMs: opts.queueTimeoutMs ?? DEFAULT_QUEUE_TIMEOUT_MS,
1805
1810
  maxConcurrentPerConsumer: opts.maxConcurrentPerConsumer ?? 0,
1811
+ onSlotWait: ({ waitedMs, active, queued, maxConcurrent: cap, gate, consumer, maxConcurrentPerConsumer: perCap }) => {
1812
+ const secs = (waitedMs / 1000).toFixed(1);
1813
+ if (gate === 'consumer') {
1814
+ // The proxy-wide ceiling was not the limit here; naming it would send
1815
+ // the operator to the wrong flag.
1816
+ console.error(`[dario] consumer "${consumer}" waited ${secs}s for a slot at its --max-concurrent-per-consumer=${perCap} cap while ${active} of ${cap} proxy-wide slots were in flight (${queued} still waiting). That is the per-consumer ceiling, not --max-concurrent: raise the per-consumer cap if that client should run wider. Said once per episode. (dario#1244)`);
1817
+ return;
1818
+ }
1819
+ console.error(`[dario] concurrency slots exhausted: a request waited ${secs}s for one of ${cap} in-flight slots (${active} in flight, ${queued} still waiting). That wait is dario's --max-concurrent ceiling, not Anthropic. Raise it, or cap one heavy client with --max-concurrent-per-consumer. Said once per episode. (dario#1244)`);
1820
+ },
1806
1821
  });
1822
+ if (pool.size > 0 && opts.maxConcurrent === undefined) {
1823
+ console.log(`[dario] Pool of ${pool.size} seat${pool.size === 1 ? '' : 's'}: --max-concurrent defaults to ${DEFAULT_MAX_CONCURRENT} per seat = ${maxConcurrent} in flight across the proxy. Set it explicitly to override.`);
1824
+ }
1825
+ else if (pool.size > 0 && opts.maxConcurrent !== undefined && opts.maxConcurrent < pool.size) {
1826
+ console.error(`[dario] --max-concurrent=${opts.maxConcurrent} is below the ${pool.size} seats in the pool. That flag is a proxy-wide ceiling on in-flight requests, not a per-seat one: at most ${opts.maxConcurrent} requests can be in flight across all ${pool.size} seats, and the rest wait in dario. (dario#1244)`);
1827
+ }
1807
1828
  const upstreamTimeoutMs = opts.upstreamTimeoutMs ?? UPSTREAM_TIMEOUT_MS;
1808
1829
  // Cache context-1m beta availability. Set false once per account after the
1809
1830
  // first "long context" rejection, so we skip sending context-1m on every
@@ -52,6 +52,13 @@ export interface QueueState {
52
52
  */
53
53
  export interface QueueSnapshot extends QueueState {
54
54
  stalledSince: number | null;
55
+ /**
56
+ * Longest a request has waited in the queue for a slot, ms, high-water
57
+ * since start (dario#1244). `stalledSince` catches the wedge; this catches
58
+ * the other failure — a cap so low that healthy load spends its time
59
+ * waiting on dario instead of on Anthropic, with no error anywhere.
60
+ */
61
+ maxWaitMs: number;
55
62
  /** Per-consumer in-flight ceiling (`--max-concurrent-per-consumer`); 0 = off. */
56
63
  maxConcurrentPerConsumer: number;
57
64
  /** Distinct consumers with a request in flight right now. */
@@ -106,10 +113,50 @@ export interface RequestQueueOptions {
106
113
  unrefTimers?: boolean;
107
114
  /** Clock source for `saturatedSince`. Injectable so tests need no timers. */
108
115
  now?: () => number;
116
+ /**
117
+ * Called ONCE per saturation episode when a queued request is admitted
118
+ * after waiting `SLOT_WAIT_ANNOUNCE_MS` or longer (dario#1244). An episode
119
+ * ends when the queue drains to zero, which re-arms the announcement. The
120
+ * threshold, not the transition into capacity, is what fires it: a busy
121
+ * proxy sits at its cap with a backlog all day and is fine as long as the
122
+ * wait is short.
123
+ */
124
+ onSlotWait?: (info: SlotWaitInfo) => void;
125
+ }
126
+ /**
127
+ * Which ceiling held a queued request. A request waits behind the
128
+ * per-consumer cap while proxy-wide slots are free, or behind the proxy-wide
129
+ * cap; the operator's remedy differs, so the announcement must say which.
130
+ */
131
+ export type SlotWaitGate = 'global' | 'consumer';
132
+ export interface SlotWaitInfo {
133
+ waitedMs: number;
134
+ active: number;
135
+ queued: number;
136
+ maxConcurrent: number;
137
+ /** The ceiling that refused immediate admission when the request arrived. */
138
+ gate: SlotWaitGate;
139
+ /** Set when `gate` is `consumer`: the consumer whose cap held it. */
140
+ consumer?: string;
141
+ maxConcurrentPerConsumer: number;
109
142
  }
110
143
  export declare const DEFAULT_MAX_CONCURRENT = 10;
111
144
  export declare const DEFAULT_MAX_QUEUED = 128;
112
145
  export declare const DEFAULT_QUEUE_TIMEOUT_MS = 60000;
146
+ /** A queued request that waited this long for a slot is the cap hurting. */
147
+ export declare const SLOT_WAIT_ANNOUNCE_MS = 2000;
148
+ /**
149
+ * The in-flight ceiling to run with (dario#1244).
150
+ *
151
+ * `DEFAULT_MAX_CONCURRENT` was sized for one client on one seat (dario#80).
152
+ * Applied unchanged to a pool it caps the whole pool at ten: an 18-seat team
153
+ * ran behind the same ten slots one person gets, every request past the
154
+ * tenth queued silently, and the proxy read as "slow with zero errors" for a
155
+ * week. A pool gets the single-seat default PER SEAT. An explicit value is
156
+ * always honoured — the operator may want a ceiling — and `startProxy` warns
157
+ * when it is below the seat count.
158
+ */
159
+ export declare function resolveMaxConcurrent(explicit: number | undefined, poolSize: number): number;
113
160
  export declare class RequestQueue {
114
161
  readonly maxConcurrent: number;
115
162
  readonly maxQueued: number;
@@ -121,6 +168,9 @@ export declare class RequestQueue {
121
168
  private queue;
122
169
  private readonly now;
123
170
  private stalledSince;
171
+ private maxWaitMs;
172
+ private slowWaitAnnounced;
173
+ private readonly onSlotWait?;
124
174
  constructor(opts?: RequestQueueOptions);
125
175
  /**
126
176
  * Re-evaluate the stall stamp. Called after every state change, so it marks
@@ -57,6 +57,26 @@ export class QueueTimeoutError extends Error {
57
57
  export const DEFAULT_MAX_CONCURRENT = 10;
58
58
  export const DEFAULT_MAX_QUEUED = 128;
59
59
  export const DEFAULT_QUEUE_TIMEOUT_MS = 60_000;
60
+ /** A queued request that waited this long for a slot is the cap hurting. */
61
+ export const SLOT_WAIT_ANNOUNCE_MS = 2_000;
62
+ /**
63
+ * The in-flight ceiling to run with (dario#1244).
64
+ *
65
+ * `DEFAULT_MAX_CONCURRENT` was sized for one client on one seat (dario#80).
66
+ * Applied unchanged to a pool it caps the whole pool at ten: an 18-seat team
67
+ * ran behind the same ten slots one person gets, every request past the
68
+ * tenth queued silently, and the proxy read as "slow with zero errors" for a
69
+ * week. A pool gets the single-seat default PER SEAT. An explicit value is
70
+ * always honoured — the operator may want a ceiling — and `startProxy` warns
71
+ * when it is below the seat count.
72
+ */
73
+ export function resolveMaxConcurrent(explicit, poolSize) {
74
+ if (explicit !== undefined)
75
+ return explicit;
76
+ if (poolSize > 0)
77
+ return poolSize * DEFAULT_MAX_CONCURRENT;
78
+ return DEFAULT_MAX_CONCURRENT;
79
+ }
60
80
  export class RequestQueue {
61
81
  maxConcurrent;
62
82
  maxQueued;
@@ -68,6 +88,9 @@ export class RequestQueue {
68
88
  queue = [];
69
89
  now;
70
90
  stalledSince = null;
91
+ maxWaitMs = 0;
92
+ slowWaitAnnounced = false;
93
+ onSlotWait;
71
94
  constructor(opts = {}) {
72
95
  this.maxConcurrent = opts.maxConcurrent ?? DEFAULT_MAX_CONCURRENT;
73
96
  this.maxQueued = opts.maxQueued ?? DEFAULT_MAX_QUEUED;
@@ -75,6 +98,7 @@ export class RequestQueue {
75
98
  this.maxConcurrentPerConsumer = Math.max(0, opts.maxConcurrentPerConsumer ?? 0);
76
99
  this.unrefTimers = opts.unrefTimers ?? true;
77
100
  this.now = opts.now ?? Date.now;
101
+ this.onSlotWait = opts.onSlotWait;
78
102
  }
79
103
  /**
80
104
  * Re-evaluate the stall stamp. Called after every state change, so it marks
@@ -125,6 +149,10 @@ export class RequestQueue {
125
149
  if (decision.action === 'reject') {
126
150
  throw new QueueFullError();
127
151
  }
152
+ // `gated` is non-null only when the consumer is AT its cap, so an enqueue
153
+ // from it means the per-consumer ceiling refused this request, not the
154
+ // proxy-wide one — global slots may well be free (dario#1244 review).
155
+ const gate = gated !== null ? 'consumer' : 'global';
128
156
  return new Promise((resolve, reject) => {
129
157
  const enqueuedAt = this.now();
130
158
  const timeoutHandle = setTimeout(() => {
@@ -140,7 +168,7 @@ export class RequestQueue {
140
168
  // Opt-out for tests — see `unrefTimers` comment in RequestQueueOptions.
141
169
  if (this.unrefTimers)
142
170
  timeoutHandle.unref?.();
143
- const entry = { resolve, reject, enqueuedAt, timeoutHandle, consumer };
171
+ const entry = { resolve, reject, enqueuedAt, timeoutHandle, consumer, gate };
144
172
  this.queue.push(entry);
145
173
  this.updateStall();
146
174
  });
@@ -165,8 +193,28 @@ export class RequestQueue {
165
193
  const [next] = this.queue.splice(idx, 1);
166
194
  clearTimeout(next.timeoutHandle);
167
195
  this.admit(next.consumer);
196
+ // How long this request spent waiting on dario rather than on the
197
+ // model (dario#1244). Kept as a high-water mark for /health, and
198
+ // announced once per episode past the threshold.
199
+ const waited = this.now() - next.enqueuedAt;
200
+ if (waited > this.maxWaitMs)
201
+ this.maxWaitMs = waited;
202
+ if (waited >= SLOT_WAIT_ANNOUNCE_MS && !this.slowWaitAnnounced) {
203
+ this.slowWaitAnnounced = true;
204
+ try {
205
+ this.onSlotWait?.({
206
+ waitedMs: waited, active: this.active, queued: this.queue.length, maxConcurrent: this.maxConcurrent,
207
+ gate: next.gate, consumer: next.gate === 'consumer' ? next.consumer : undefined,
208
+ maxConcurrentPerConsumer: this.maxConcurrentPerConsumer,
209
+ });
210
+ }
211
+ catch { /* an observer must never break admission */ }
212
+ }
168
213
  next.resolve();
169
214
  }
215
+ // The queue drained: the episode is over and the next one may announce.
216
+ if (this.queue.length === 0)
217
+ this.slowWaitAnnounced = false;
170
218
  // A release IS turnover — the thing whose absence defines the wedge — so
171
219
  // clear the stamp unconditionally before re-evaluating. A queue that is
172
220
  // still at capacity immediately starts a FRESH stall window, which is why
@@ -183,6 +231,7 @@ export class RequestQueue {
183
231
  maxConcurrent: this.maxConcurrent,
184
232
  maxQueued: this.maxQueued,
185
233
  stalledSince: this.stalledSince,
234
+ maxWaitMs: this.maxWaitMs,
186
235
  maxConcurrentPerConsumer: this.maxConcurrentPerConsumer,
187
236
  consumersActive: this.activeByConsumer.size,
188
237
  };
package/docs/usage.md CHANGED
@@ -142,7 +142,8 @@ fail returns 503 instead of `ok`:
142
142
  "probe": { "ok": false, "reason": "auth-rejected", "status": 401,
143
143
  "latencyMs": 233, "ageMs": 4812, "model": "claude-haiku-4-5" },
144
144
  "queue": { "active": 10, "queued": 4, "maxConcurrent": 10,
145
- "stalledSince": 1754790000000, "stalledForMs": 28800000 }
145
+ "stalledSince": 1754790000000, "stalledForMs": 28800000,
146
+ "maxWaitMs": 1830 }
146
147
  }
147
148
  ```
148
149
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "6.8.9",
3
+ "version": "6.8.10",
4
4
  "description": "Use your Claude and ChatGPT subscriptions in Cursor, Cline, Aider, Claude Code and the Agent SDK — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint: either plan answers either wire shape, with automatic failover when one hits its limit.",
5
5
  "type": "module",
6
6
  "bin": {