@dreb/coding-agent 2.45.3 → 2.46.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.
Files changed (71) hide show
  1. package/README.md +7 -3
  2. package/dist/core/agent-session.d.ts +10 -2
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +75 -15
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/context-buffer.d.ts +2 -0
  7. package/dist/core/context-buffer.d.ts.map +1 -1
  8. package/dist/core/context-buffer.js +8 -0
  9. package/dist/core/context-buffer.js.map +1 -1
  10. package/dist/core/dispatch-arbiter.d.ts +94 -0
  11. package/dist/core/dispatch-arbiter.d.ts.map +1 -0
  12. package/dist/core/dispatch-arbiter.js +316 -0
  13. package/dist/core/dispatch-arbiter.js.map +1 -0
  14. package/dist/core/extensions/types.d.ts +1 -1
  15. package/dist/core/extensions/types.d.ts.map +1 -1
  16. package/dist/core/extensions/types.js.map +1 -1
  17. package/dist/core/git-repo-state.d.ts +2 -0
  18. package/dist/core/git-repo-state.d.ts.map +1 -1
  19. package/dist/core/git-repo-state.js +19 -0
  20. package/dist/core/git-repo-state.js.map +1 -1
  21. package/dist/core/model-registry.d.ts +1 -0
  22. package/dist/core/model-registry.d.ts.map +1 -1
  23. package/dist/core/model-registry.js +49 -25
  24. package/dist/core/model-registry.js.map +1 -1
  25. package/dist/core/model-routing-guide.d.ts +15 -0
  26. package/dist/core/model-routing-guide.d.ts.map +1 -0
  27. package/dist/core/model-routing-guide.js +186 -0
  28. package/dist/core/model-routing-guide.js.map +1 -0
  29. package/dist/core/settings-manager.d.ts +18 -0
  30. package/dist/core/settings-manager.d.ts.map +1 -1
  31. package/dist/core/settings-manager.js +33 -0
  32. package/dist/core/settings-manager.js.map +1 -1
  33. package/dist/core/thinking.d.ts +14 -0
  34. package/dist/core/thinking.d.ts.map +1 -1
  35. package/dist/core/thinking.js +35 -2
  36. package/dist/core/thinking.js.map +1 -1
  37. package/dist/core/tools/index.d.ts +7 -1
  38. package/dist/core/tools/index.d.ts.map +1 -1
  39. package/dist/core/tools/index.js.map +1 -1
  40. package/dist/core/tools/subagent.d.ts +53 -6
  41. package/dist/core/tools/subagent.d.ts.map +1 -1
  42. package/dist/core/tools/subagent.js +343 -53
  43. package/dist/core/tools/subagent.js.map +1 -1
  44. package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  45. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  46. package/dist/modes/interactive/components/settings-selector.js +99 -1
  47. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  48. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  49. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  50. package/dist/modes/interactive/interactive-mode.js +75 -1
  51. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  52. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  53. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  54. package/dist/modes/rpc/rpc-mode.js +65 -0
  55. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  56. package/dist/modes/rpc/rpc-types.d.ts +8 -0
  57. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  58. package/dist/modes/rpc/rpc-types.js.map +1 -1
  59. package/docs/agent-models.md +33 -1
  60. package/docs/custom-provider.md +22 -8
  61. package/docs/dashboard.md +8 -2
  62. package/docs/extensions.md +1 -1
  63. package/docs/json.md +31 -5
  64. package/docs/models.md +39 -1
  65. package/docs/rpc.md +60 -9
  66. package/docs/session.md +7 -1
  67. package/docs/settings.md +33 -1
  68. package/docs/skills.md +38 -0
  69. package/examples/extensions/custom-provider-anthropic/index.ts +7 -3
  70. package/package.json +1 -1
  71. package/skills/model-routing-guide/SKILL.md +182 -0
package/docs/json.md CHANGED
@@ -17,8 +17,12 @@ type AgentSessionEvent =
17
17
  | { type: "auto_compaction_end"; result: CompactionResult | undefined; aborted: boolean; willRetry: boolean; errorMessage?: string }
18
18
  | { type: "auto_retry_start"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
19
19
  | { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
20
- | { type: "background_agent_start"; agentId: string; agentType: string; taskSummary: string }
21
- | { type: "background_agent_end"; agentId: string; agentType: string; success: boolean }
20
+ | { type: "background_agent_start"; agentId: string; agentType: string; taskSummary: string; sessionDir?: string }
21
+ | { type: "subagent_arbitration"; agentId: string; status: "success" | "failure"; proposed: DispatchRoute; final: DispatchRoute | null; changed: ("agent" | "model" | "thinking")[]; step?: number; errorCode?: string; errorMessage?: string }
22
+ | { type: "background_agent_end"; agentId: string; agentType: string; success: boolean; model?: string; thinking?: ThinkingLevel; steps?: SubagentStepMetadata[]; sessionFile?: string }
23
+ | { type: "background_agent_event"; agentId: string; event: Record<string, unknown> }
24
+ | { type: "parent_paused_for_background_agents"; runningAgentCount: number; turnsUsed: number; turnLimit: number }
25
+ | { type: "session_name_changed"; name: string }
22
26
  | { type: "tasks_update"; tasks: readonly SessionTask[] }
23
27
  | { type: "suggest_next"; command: string };
24
28
 
@@ -28,6 +32,20 @@ interface SessionTask {
28
32
  title: string;
29
33
  status: "pending" | "in_progress" | "completed";
30
34
  }
35
+
36
+ interface SubagentStepMetadata {
37
+ step: number;
38
+ agent: string;
39
+ success: boolean;
40
+ model?: string; // canonical provider/model
41
+ thinking?: ThinkingLevel;
42
+ }
43
+
44
+ interface DispatchRoute {
45
+ agent: string;
46
+ model: string; // canonical provider/model
47
+ thinking: ThinkingLevel;
48
+ }
31
49
  ```
32
50
 
33
51
  Base events from [`AgentEvent`](https://github.com/aebrer/dreb/blob/master/packages/agent/src/types.ts):
@@ -35,7 +53,7 @@ Base events from [`AgentEvent`](https://github.com/aebrer/dreb/blob/master/packa
35
53
  ```typescript
36
54
  type AgentEvent =
37
55
  // Agent lifecycle
38
- | { type: "agent_start"; model?: { provider: string; id: string } }
56
+ | { type: "agent_start"; model?: { provider: string; id: string }; thinkingLevel?: ThinkingLevel }
39
57
  | { type: "agent_end"; messages: AgentMessage[] }
40
58
  // Turn lifecycle
41
59
  | { type: "turn_start" }
@@ -75,7 +93,7 @@ Each line is a JSON object. The first line is the session header (`version` is t
75
93
  Followed by events as they occur:
76
94
 
77
95
  ```json
78
- {"type":"agent_start","model":{"provider":"anthropic","id":"claude-sonnet-4-20250514"}}
96
+ {"type":"agent_start","model":{"provider":"anthropic","id":"claude-sonnet-4-20250514"},"thinkingLevel":"high"}
79
97
  {"type":"turn_start"}
80
98
  {"type":"message_start","message":{"role":"assistant","content":[],...}}
81
99
  {"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_delta","delta":"Hello",...}}
@@ -84,6 +102,14 @@ Followed by events as they occur:
84
102
  {"type":"agent_end","messages":[...]}
85
103
  ```
86
104
 
105
+ With global Dispatch Arbiter enabled, each background start is followed before child events/spawn by one safe structured decision. Unchanged decisions use an empty `changed`; failed decisions use `final: null`, prevent spawn, and carry only host-generated errors. Chain decisions also include `step`.
106
+
107
+ ```json
108
+ {"type":"subagent_arbitration","agentId":"a1b2c3","status":"success","proposed":{"agent":"Explore","model":"provider/frontier","thinking":"high"},"final":{"agent":"feature-dev","model":"provider/worker","thinking":"medium"},"changed":["agent","model","thinking"]}
109
+ ```
110
+
111
+ The event never contains the arbiter prompt, response, reasoning, guide, task, or conversation excerpt. The matching parent session persists the same safe fields as a non-context custom JSONL entry.
112
+
87
113
  ## Error handling
88
114
 
89
115
  Errors surface as events, not as broken JSON or exit codes:
@@ -104,7 +130,7 @@ Events are emitted in a predictable sequence:
104
130
 
105
131
  `message_update` events stream as chunks arrive — expect many per message. `tool_execution_update` events are optional (only emitted for tools that report progress).
106
132
 
107
- Auto-compaction and auto-retry events can appear between turns.
133
+ Auto-compaction and auto-retry events can appear between turns. Background lifecycle events are asynchronous: `background_agent_start` is emitted immediately, then an enabled `subagent_arbitration` record appears before that child's first `background_agent_event`; a failed arbitration is followed by `background_agent_end` without any child event.
108
134
 
109
135
  ## Example
110
136
 
package/docs/models.md CHANGED
@@ -110,7 +110,7 @@ Set `api` at provider level (default for all models) or model level (override pe
110
110
  | `api` | API type (see above) |
111
111
  | `apiKey` | API key (see value resolution below) |
112
112
  | `headers` | Custom headers (see value resolution below) |
113
- | `authHeader` | Set `true` to add `Authorization: Bearer <apiKey>` automatically |
113
+ | `authHeader` | Set `true` to use the resolved `apiKey` as `Authorization: Bearer` instead of provider API-key auth |
114
114
  | `models` | Array of model configurations |
115
115
  | `modelOverrides` | Per-model overrides for built-in models on this provider |
116
116
 
@@ -132,6 +132,44 @@ The `apiKey` and `headers` fields support three formats:
132
132
  "apiKey": "sk-..."
133
133
  ```
134
134
 
135
+ ### Bearer Auth for Anthropic-Compatible Providers
136
+
137
+ Third-party Anthropic-compatible endpoints use `x-api-key` by default. If an endpoint instead requires `Authorization: Bearer <key>`, set `authHeader: true`:
138
+
139
+ ```json
140
+ {
141
+ "providers": {
142
+ "company-anthropic": {
143
+ "baseUrl": "https://ai.example.com/anthropic",
144
+ "api": "anthropic-messages",
145
+ "apiKey": "COMPANY_ANTHROPIC_TOKEN",
146
+ "authHeader": true,
147
+ "models": [
148
+ { "id": "company-claude" }
149
+ ]
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ For the built-in `anthropic-messages` implementation, this selects Bearer-only auth: dreb sends the request-time resolved credential as `Authorization` and does not also send `x-api-key`. The credential can use any [value resolution](#value-resolution) format; the environment variable does not need a special Anthropic SDK name.
156
+
157
+ The flag also works when redirecting a built-in provider without redefining its models:
158
+
159
+ ```json
160
+ {
161
+ "providers": {
162
+ "anthropic": {
163
+ "baseUrl": "https://ai.example.com/anthropic",
164
+ "apiKey": "COMPANY_ANTHROPIC_TOKEN",
165
+ "authHeader": true
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ Leave `authHeader` unset or `false` for endpoints that expect `x-api-key`.
172
+
135
173
  ### Custom Headers
136
174
 
137
175
  ```json
package/docs/rpc.md CHANGED
@@ -1243,17 +1243,18 @@ Note: with `summarize: true` the command is LLM-bound and can take a while. `Rpc
1243
1243
 
1244
1244
  ### Settings
1245
1245
 
1246
- Persistent settings, backed by the settings file (see [settings.md](settings.md)). They are normally distinct from live session state, with one security-policy exception:
1246
+ Persistent settings, backed by the settings file (see [settings.md](settings.md)). They are normally distinct from live session state, with global-only control/security-policy exceptions:
1247
1247
 
1248
1248
  - **Persistent defaults** (`get_settings` / `set_settings`): provider/model, thinking level, queue modes, compaction/retry/image/skill/thinking-display/transport toggles, and per-agent model fallback lists seed fresh runtimes. Writing these ordinary defaults does **not** change a running session.
1249
1249
  - **Global nested-context trust policy** (`autoLoadNestedContext`, `trustedContextFolders`, `effectiveTrustedContextRoots`, and the trust commands below): this is read from `~/.dreb/agent/settings.json` only, never project settings. Active main/subagent processes observe it for **future lazy nested/out-of-cwd loads**; it cannot remove content already injected into a conversation. It does not govern the separate initial upward context scan from the launch cwd.
1250
+ - **Global Dispatch Arbiter policy** (`subagentArbiter`): the complete object is read/written globally and project settings cannot shadow it. Enabled runtimes consume it before future subagent spawns; it does not rewrite already-started children.
1250
1251
  - **Runtime state** (`get_state` / `set_model` / `set_thinking_level` / `set_steering_mode` / `set_follow_up_mode` / `set_auto_compaction` / `set_auto_retry`): the state of the live session. Note that the runtime setters also persist their values as new defaults as a side effect.
1251
1252
 
1252
1253
  A dashboard settings tab typically reads `get_state` for what is active now and `get_settings` for persistent defaults plus the current global context-trust policy.
1253
1254
 
1254
1255
  #### get_settings
1255
1256
 
1256
- Get persistent settings. Before replying, RPC flushes pending settings writes, reloads durable global and project settings, and then reads the merged view; reopening dashboard Settings therefore sees external file edits. A pending write failure, unreadable file, parse error, or reload failure returns an explicit RPC error rather than a stale snapshot. Ordinary fields are the merged global + project view; the nested-context trust fields are always global-only.
1257
+ Get persistent settings. Before replying, RPC flushes pending settings writes, reloads durable global and project settings, and then reads the merged view; reopening dashboard Settings therefore sees external file edits. A pending write failure, unreadable file, parse error, or reload failure returns an explicit RPC error rather than a stale snapshot. Ordinary fields are the merged global + project view; nested-context trust and `subagentArbiter` are always global-only.
1257
1258
 
1258
1259
  ```json
1259
1260
  {"type": "get_settings"}
@@ -1283,6 +1284,12 @@ Response:
1283
1284
  "hideThinkingBlock": false,
1284
1285
  "agentModels": {
1285
1286
  "Explore": ["anthropic/sonnet", "openai/gpt-5"]
1287
+ },
1288
+ "subagentArbiter": {
1289
+ "enabled": true,
1290
+ "model": "anthropic/claude-sonnet-4-5",
1291
+ "thinking": "medium",
1292
+ "guidePath": "~/.dreb/agent/model-routing-guide.md"
1286
1293
  }
1287
1294
  }
1288
1295
  }
@@ -1292,6 +1299,8 @@ Response:
1292
1299
 
1293
1300
  `trustedContextFolders` is the raw global configured list, including invalid legacy paths that are ignored fail-closed. `effectiveTrustedContextRoots` is the canonical, existing root set actually enforced after `~` expansion, native `realpath`, deduplication, and ancestor subsumption. `autoLoadNestedContext` defaults to `false`; when `true` it is global expert trust-all for every resolvable target, not a project override. Project `.dreb/settings.json` cannot affect any of these three fields.
1294
1301
 
1302
+ `subagentArbiter` is absent when unconfigured. It is always the global object; project `.dreb/settings.json` cannot enable, disable, or alter it.
1303
+
1295
1304
  #### set_settings
1296
1305
 
1297
1306
  Update persistent default settings. Takes a partial payload — only the supplied keys change. The whole payload is validated before anything is applied: on any invalid field, nothing changes and the response is an explicit error. Writes target the global settings file (same scope as every runtime setter).
@@ -1330,6 +1339,14 @@ Setting per-agent model fallback lists:
1330
1339
 
1331
1340
  For `agentModels`, a non-empty array writes the global fallback list for that agent. An empty array removes the global entry, so that agent uses its agent-definition default unless a project-level override exists.
1332
1341
 
1342
+ Replace the complete global-only Dispatch Arbiter policy (exact model is validated; explicit thinking is capability-validated):
1343
+
1344
+ ```json
1345
+ {"type":"set_settings","settings":{"subagentArbiter":{"enabled":true,"model":"anthropic/claude-sonnet-4-5","thinking":"medium","guidePath":"~/.dreb/agent/model-routing-guide.md"}}}
1346
+ ```
1347
+
1348
+ Set `subagentArbiter: null` to remove the global policy. Enabling requires `model`; `guidePath` defaults to the standard guide path and omitted thinking runs the arbiter call with thinking off. Runtime guide/scope validation still occurs at each spawn because the live explicit scope can change.
1349
+
1333
1350
  Response is the full settings snapshot after the write (same shape as `get_settings`), plus `warnings` when the write was accepted but a project-level override shadows part of it:
1334
1351
 
1335
1352
  ```json
@@ -1406,6 +1423,7 @@ Valid keys and values:
1406
1423
  | `transport` | `"sse"`, `"websocket"`, `"auto"` |
1407
1424
  | `hideThinkingBlock` | boolean |
1408
1425
  | `agentModels` | Plain object mapping agent names to arrays of non-empty model id strings; empty arrays remove the global entry for that agent |
1426
+ | `subagentArbiter` | Complete global-only object or `null`. Keys: `enabled` boolean, exact available `model`, optional valid/capability-supported `thinking`, non-empty `guidePath`. Enabling requires `model`. Unknown nested keys are rejected. |
1409
1427
 
1410
1428
  Errors are explicit `success: false` responses (nothing is applied on any of them):
1411
1429
 
@@ -1419,6 +1437,7 @@ Errors are explicit `success: false` responses (nothing is applied on any of the
1419
1437
  - Invalid trusted-root list: `trustedContextFolders must be an array of non-empty path strings` or `Invalid trustedContextFolders[0]: path must be absolute after ~ expansion` / `path must be an existing directory`
1420
1438
  - Provider without model (or vice versa): `defaultProvider and defaultModel must be set together`
1421
1439
  - Unavailable model: `Model not found: provider/model-id`
1440
+ - Invalid arbiter policy: `Enabling subagentArbiter requires an exact provider/model`, `Arbiter model not found: ...`, or a nested-key/type/thinking capability error
1422
1441
  - Corrupt settings file: `Cannot write settings: the global settings file failed to load (fix or remove the corrupt settings.json first)` — without this guard the write would silently no-op
1423
1442
  - Write failure (I/O error): `Failed to persist settings: ...`
1424
1443
 
@@ -1584,7 +1603,7 @@ Response:
1584
1603
 
1585
1604
  | Event | Description |
1586
1605
  |-------|-------------|
1587
- | `agent_start` | Agent begins processing |
1606
+ | `agent_start` | Agent begins processing (resolved model and effective thinking level) |
1588
1607
  | `agent_end` | Agent completes (includes all generated messages) |
1589
1608
  | `turn_start` | New turn begins |
1590
1609
  | `turn_end` | Turn completes (includes assistant message and tool results) |
@@ -1601,7 +1620,7 @@ Response:
1601
1620
  | `auto_retry_start` | Auto-retry begins (after transient error) |
1602
1621
  | `auto_retry_end` | Auto-retry completes (success or final failure) |
1603
1622
  | `background_agent_start` | Background subagent launched (includes `sessionDir`) |
1604
- | `background_agent_end` | Background subagent finished (includes `sessionFile` when known) |
1623
+ | `background_agent_end` | Background subagent finished (canonical model/thinking, per-step chain metadata, and `sessionFile` when known) |
1605
1624
  | `background_agent_event` | Relayed event from a background subagent's own stream |
1606
1625
  | `parent_paused_for_background_agents` | Parent paused waiting on background agents |
1607
1626
  | `session_name_changed` | Session display name changed (manual rename, extension rename, or auto-title) |
@@ -1615,10 +1634,10 @@ rather than validating against a closed list; new event types may be added.
1615
1634
 
1616
1635
  ### agent_start
1617
1636
 
1618
- Emitted when the agent begins processing a prompt. Includes the resolved model.
1637
+ Emitted when the agent begins processing a prompt. Includes the resolved model and effective thinking level sent to the provider.
1619
1638
 
1620
1639
  ```json
1621
- {"type": "agent_start", "model": {"provider": "anthropic", "id": "claude-sonnet-4-20250514"}}
1640
+ {"type": "agent_start", "model": {"provider": "anthropic", "id": "claude-sonnet-4-20250514"}, "thinkingLevel": "high"}
1622
1641
  ```
1623
1642
 
1624
1643
  ### agent_end
@@ -1806,9 +1825,9 @@ On final failure (max retries exceeded):
1806
1825
  }
1807
1826
  ```
1808
1827
 
1809
- ### background_agent_start / background_agent_end / background_agent_event
1828
+ ### background_agent_start / subagent_arbitration / background_agent_end / background_agent_event
1810
1829
 
1811
- Lifecycle and live-observability events for background subagents (the `subagent` tool's background mode).
1830
+ Lifecycle, pre-spawn routing, and live-observability events for background subagents (the `subagent` tool's background mode).
1812
1831
 
1813
1832
  `background_agent_start` fires at launch. `sessionDir` is the directory the child will write its session JSONL into (per-launch, known before spawn):
1814
1833
 
@@ -1822,7 +1841,22 @@ Lifecycle and live-observability events for background subagents (the `subagent`
1822
1841
  }
1823
1842
  ```
1824
1843
 
1825
- `background_agent_end` fires after the result is delivered to the parent agent. `sessionFile` is the child's session JSONL path when one was written:
1844
+ When the global Dispatch Arbiter is enabled, `subagent_arbitration` fires after the requested route is made concrete and before child spawn/events. It appears for changed and unchanged successful decisions, and for failures that prevent spawn. Chain records include `step`; failures have `final: null` and bounded host-generated `errorCode`/`errorMessage`.
1845
+
1846
+ ```json
1847
+ {
1848
+ "type": "subagent_arbitration",
1849
+ "agentId": "a1b2c3d4e5f6",
1850
+ "status": "success",
1851
+ "proposed": {"agent": "Explore", "model": "provider/frontier", "thinking": "high"},
1852
+ "final": {"agent": "feature-dev", "model": "provider/worker", "thinking": "medium"},
1853
+ "changed": ["agent", "model", "thinking"]
1854
+ }
1855
+ ```
1856
+
1857
+ The event is deliberately safe and programmatic: it never contains the task, guide, conversation context, prompt, raw response, or model reasoning. The parent session persists the same fields as a non-context `custom` entry. Consumers should update displayed background-agent identity from `final.agent` before child events arrive.
1858
+
1859
+ `background_agent_end` fires after the result is delivered to the parent agent. For a single child it includes the canonical resolved `provider/model` and effective thinking level when reported; `sessionFile` is the child's session JSONL path when one was written:
1826
1860
 
1827
1861
  ```json
1828
1862
  {
@@ -1830,10 +1864,27 @@ Lifecycle and live-observability events for background subagents (the `subagent`
1830
1864
  "agentId": "a1b2c3d4e5f6",
1831
1865
  "agentType": "Explore",
1832
1866
  "success": true,
1867
+ "model": "anthropic/claude-sonnet-4-20250514",
1868
+ "thinking": "medium",
1833
1869
  "sessionFile": "/home/user/.dreb/agent/subagent-sessions/a1b2c3d4e5f6/2026-07-07T12-00-00-000Z_uuid.jsonl"
1834
1870
  }
1835
1871
  ```
1836
1872
 
1873
+ Chain completions omit ambiguous scalar model/thinking fields and instead include ordered per-step metadata, since steps may use different agents, providers, models, or thinking levels:
1874
+
1875
+ ```json
1876
+ {
1877
+ "type": "background_agent_end",
1878
+ "agentId": "a1b2c3d4e5f6",
1879
+ "agentType": "Explore",
1880
+ "success": true,
1881
+ "steps": [
1882
+ {"step": 1, "agent": "Explore", "success": true, "model": "anthropic/claude-sonnet-4-6", "thinking": "low"},
1883
+ {"step": 2, "agent": "feature-dev", "success": true, "model": "openai/gpt-5.6-sol", "thinking": "high"}
1884
+ ]
1885
+ }
1886
+ ```
1887
+
1837
1888
  `background_agent_event` relays every JSONL event the child process emits (the same event union documented here, plus the initial session header), verbatim, tagged with the child's `agentId`. This is the live-transcript transport for observers like the dashboard — no session-file tailing needed. Streaming children emit `message_update` deltas at high frequency; consumers that fan events out further (e.g. over a network) should batch or throttle:
1838
1889
 
1839
1890
  ```json
package/docs/session.md CHANGED
@@ -261,7 +261,13 @@ Extension state persistence. Does NOT participate in LLM context.
261
261
  {"type":"custom","id":"h8i9j0k1","parentId":"g7h8i9j0","timestamp":"2024-12-03T14:20:00.000Z","customType":"my-extension","data":{"count":42}}
262
262
  ```
263
263
 
264
- Use `customType` to identify your extension's entries on reload.
264
+ Use `customType` to identify your extension's entries on reload. Core host features can use the same non-context channel. When the Dispatch Arbiter is enabled, every attempted pre-spawn decision is stored as `customType: "subagent_arbitration"` with only safe host-validated metadata:
265
+
266
+ ```json
267
+ {"type":"custom","customType":"subagent_arbitration","data":{"type":"subagent_arbitration","agentId":"a1b2c3","status":"success","proposed":{"agent":"Explore","model":"provider/frontier","thinking":"high"},"final":{"agent":"feature-dev","model":"provider/worker","thinking":"medium"},"changed":["agent","model","thinking"]}}
268
+ ```
269
+
270
+ Failure records have `final: null` plus bounded host-generated `errorCode`/`errorMessage`; chain records include `step`. Arbiter prompts, raw responses, and reasoning are never stored. Because this is `custom`, replay/build-context skips it and neither the parent nor child model receives the record.
265
271
 
266
272
  ### CustomMessageEntry
267
273
 
package/docs/settings.md CHANGED
@@ -224,6 +224,38 @@ Set `parentTurnGuardrail` to `false` to let the parent keep running with no turn
224
224
  }
225
225
  ```
226
226
 
227
+ ### Dispatch Arbiter
228
+
229
+ The optional Dispatch Arbiter is a fully headless, tool-less model call in the subagent control path. It is disabled by default and can be configured **only** in global `~/.dreb/agent/settings.json` (or the global RPC settings API). A project `.dreb/settings.json` cannot enable, disable, or reconfigure it.
230
+
231
+ | Setting | Type | Default | Description |
232
+ |---------|------|---------|-------------|
233
+ | `subagentArbiter.enabled` | boolean | `false` | Run fail-closed arbitration before every actual child spawn |
234
+ | `subagentArbiter.model` | string | - | Required when enabled; exact canonical `provider/model` used for the direct arbiter call |
235
+ | `subagentArbiter.thinking` | string | `off` | Optional arbiter-call thinking: `off`, `minimal`, `low`, `medium`, `high`, or `xhigh`; explicit values are capability-validated |
236
+ | `subagentArbiter.guidePath` | string | `~/.dreb/agent/model-routing-guide.md` | Routing guide generated by `/skill:model-routing-guide`; `~` expands normally and relative paths resolve against the child cwd |
237
+
238
+ ```json
239
+ {
240
+ "subagentArbiter": {
241
+ "enabled": true,
242
+ "model": "provider/router-model",
243
+ "thinking": "medium",
244
+ "guidePath": "~/.dreb/agent/model-routing-guide.md"
245
+ }
246
+ }
247
+ ```
248
+
249
+ First-class controls are available in both interactive `/settings` and the web dashboard Settings screen. Each exposes enable/disable, an authenticated exact-model picker, thinking level, and guide path. The TUI validates current live scope and guide coverage before accepting enablement; the dashboard prevents model-less enablement, validates model/thinking through RPC, shows readiness guidance, and the runtime still revalidates live scope/guide before every dispatch. Validation errors are loud and do not silently persist an unusable enabled policy.
250
+
251
+ Enabling also requires a non-empty **live explicit session model scope** from `--models` or `enabledModels`, plus a schema-valid guide whose canonical covered IDs and `## Model:` sections exactly match that live scope. The research skill cannot discover runtime `--models`; generate its guide with matching explicit skill arguments when needed.
252
+
253
+ For each single child, parallel item, and post-substitution chain step, the arbiter may return only an existing agent name, an exact model in the live scope, and a thinking level supported by that model. Missing/invalid settings, auth, guide, scope, timeout/provider errors, malformed output, unknown agents, out-of-scope models, and unsupported thinking all stop the affected spawn. There is no fallback to the proposed route or parent model after arbitration is enabled.
254
+
255
+ The arbiter receives the immutable child task/cwd, proposed route, available agent names/descriptions/effective tools/model defaults, validated guide, canonical live candidates, bounded first/latest user intent and recent labeled parent activity—including bounded tool outputs—parent model/session title, repository/cwd/branch/dirty-count metadata, and lineage identifiers where available. Following the title setter's rolling-context pattern, ordinary file contents, diffs, command output, and other useful tool-result content are intentional routing context rather than a separate security boundary; the package receives the existing secret scrubbing before inference. The arbiter itself receives no tools. Guide files are capped at 128 KiB; the complete serialized package is capped at 180,000 characters. Individual intent/description/activity fields also have fixed bounds. Required task/guide/scope/agent data is never silently truncated—exceeding the package cap stops inference. The real child's task and cwd are not modified by scrubbing or arbitration.
256
+
257
+ Only host-validated decision metadata is persisted/emitted. Raw arbiter prompts, responses, and reasoning never enter the parent transcript, child context, session history, JSON/RPC events, or dashboard. See [Agent Model Settings](agent-models.md#dispatch-arbiter).
258
+
227
259
  ### Message Delivery
228
260
 
229
261
  | Setting | Type | Default | Description |
@@ -385,7 +417,7 @@ See [packages.md](packages.md) for package management details.
385
417
 
386
418
  ## Project Overrides
387
419
 
388
- Project settings (`.dreb/settings.json`) override global settings. Nested objects are merged. **Exception:** `context.trustedFolders` and `context.autoLoadNested` are global-only security policy: project settings cannot add, replace, override, or enable either one. Nested context from the initial startup upward scan remains separate from this lazy-load policy.
420
+ Project settings (`.dreb/settings.json`) override global settings. Nested objects are merged. **Exceptions:** `context.trustedFolders`, `context.autoLoadNested`, and the complete `subagentArbiter` policy are global-only security/control-path settings. Project settings cannot add, replace, override, enable, or disable them. Nested context from the initial startup upward scan remains separate from the lazy-load policy.
389
421
 
390
422
  ```json
391
423
  // ~/.dreb/agent/settings.json (global)
package/docs/skills.md CHANGED
@@ -285,11 +285,49 @@ dreb ships with **mach6**, a development workflow that orchestrates the full iss
285
285
  | `mach6-review` | Explicitly user-triggered multi-agent review with scope-aware independent assessment |
286
286
  | `mach6-implement` | Implement plans, fix review findings, or fix CI failures |
287
287
  | `mach6-publish` | Pre-merge checks, docs update, merge, tag, release |
288
+ | `model-routing-guide` | Research scoped models and sanitized local subagent evidence into a validated routing guide |
288
289
 
289
290
  Built-in skills are always available and can be overridden by placing a skill with the same name in any [user or project location](#locations). `mach6-review` is model-invocable when the user directly asks an agent to run it, as well as user-invocable through its slash command. Agents must never start formal review autonomously; implementation must first be committed and pushed.
290
291
 
291
292
  See [docs/mach6.md](mach6.md) for full documentation.
292
293
 
294
+ ### model-routing-guide
295
+
296
+ `model-routing-guide` is an explicit, potentially expensive research workflow with exactly two supported scope sources.
297
+
298
+ Pass comma-separated model patterns directly to make them authoritative:
299
+
300
+ ```text
301
+ /skill:model-routing-guide anthropic/claude-*,openai/gpt-5.6-sol
302
+ ```
303
+
304
+ Or invoke it without arguments to use the effective non-empty `enabledModels` array:
305
+
306
+ ```text
307
+ /skill:model-routing-guide
308
+ ```
309
+
310
+ When model scope rotates, update the existing guide incrementally instead of regenerating every retained entry:
311
+
312
+ ```text
313
+ /skill:model-routing-guide update
314
+ /skill:model-routing-guide update anthropic/claude-*,openai/gpt-5.6-sol
315
+ ```
316
+
317
+ `update` must be the first argument. The skill validates the existing guide against its own coverage, diffs that coverage against the newly resolved authoritative scope, preserves retained model sections, removes unscoped sections and summary references, and researches only newly added canonical models. It refreshes scope/local-evidence metadata and performs the same complete final validation before atomically replacing the guide. A missing or malformed existing guide fails loudly and requires normal generation.
318
+
319
+ Model-pattern arguments after the optional `update` keyword take precedence over `enabledModels`; the skill selects one source and does not search for any other runtime or session scope. Because this Stage 1 workflow is implemented only as a skill, it cannot discover the current session's `--models` value or later in-session scope changes. To research that runtime scope, pass the same comma-separated patterns as skill arguments.
320
+
321
+ The skill refuses missing/empty and effectively all-model scopes. It obtains available candidates with `dreb --list-models`, resolves the selected patterns to canonical provider/model IDs, snapshots existing files under `~/.dreb/agent/subagent-sessions/`, and combines sanitized aggregate local observations with official documentation, model cards, benchmarks, issue trackers, forums, and practitioner reports. Existing unreadable or malformed child logs fail the run; a genuinely empty history is labeled cold-start.
322
+
323
+ The generated `~/.dreb/agent/model-routing-guide.md` is human-readable Markdown with schema-versioned YAML frontmatter and one validated section per canonical candidate. Evidence is labeled as vendor claims, measured benchmarks, community reports, or local observations, with dates, confidence, sample counts, contrary findings, and explicit unknowns. The workflow prohibits copied prompts, outputs, tool arguments, secrets, paths, and identifying project details.
324
+
325
+ Semantic local-evidence assessment uses normal dreb tools, so inspected session content is processed by the active research model's configured provider. The persisted guide is sanitized and generalized, but invoking the skill is still a decision to send the inspected evidence to that provider.
326
+
327
+ Its primary routing safeguards are practical: `Explore` is for factual collection and navigation, not planning or implementation; routine lookup, extraction, repetitive file inspection, and straightforward summarization should use the least expensive scoped model demonstrated adequate by the evidence.
328
+
329
+ The optional global-only [Dispatch Arbiter](agent-models.md#dispatch-arbiter) now consumes this file before every subagent spawn. Its live scope is the current session's exact explicit candidate set, so guide frontmatter and model headings must match that set exactly. A guide generated from `enabledModels` will work when the session uses the same resolved scope; for runtime `--models`, pass those patterns to the skill. Missing/stale/malformed guide coverage fails the child launch rather than bypassing arbitration.
330
+
293
331
  ## Skill Repositories
294
332
 
295
333
  - [Anthropic Skills](https://github.com/anthropics/skills) - Document processing (docx, pdf, pptx, xlsx), web development
@@ -6,6 +6,7 @@
6
6
  * - Custom streamSimple implementation
7
7
  * - OAuth support for /login
8
8
  * - API key support via environment variable
9
+ * - Explicit SDK API-key versus Bearer auth selection
9
10
  * - Two model definitions
10
11
  *
11
12
  * Usage:
@@ -359,9 +360,11 @@ function streamCustomAnthropic(
359
360
 
360
361
  try {
361
362
  const apiKey = options?.apiKey ?? "";
362
- const isOAuth = isOAuthToken(apiKey);
363
+ const configuredBearer = model.authMode === "bearer";
364
+ const isOAuth = !configuredBearer && isOAuthToken(apiKey);
363
365
 
364
- // Configure client based on auth type
366
+ // Configure exactly one SDK auth channel. Explicitly nulling the other
367
+ // prevents the SDK from injecting ANTHROPIC_AUTH_TOKEN from the environment.
365
368
  const betaFeatures = ["fine-grained-tool-streaming-2025-05-14", "interleaved-thinking-2025-05-14"];
366
369
  const clientOptions: any = {
367
370
  baseURL: model.baseUrl,
@@ -379,7 +382,8 @@ function streamCustomAnthropic(
379
382
  "x-app": "cli",
380
383
  };
381
384
  } else {
382
- clientOptions.apiKey = apiKey;
385
+ clientOptions.apiKey = configuredBearer ? null : apiKey;
386
+ clientOptions.authToken = configuredBearer ? apiKey : null;
383
387
  clientOptions.defaultHeaders = {
384
388
  accept: "application/json",
385
389
  "anthropic-dangerous-direct-browser-access": "true",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreb/coding-agent",
3
- "version": "2.45.3",
3
+ "version": "2.46.0",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "drebConfig": {