@aragon-agent/cli 0.6.21 → 0.6.22

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
@@ -1148,15 +1148,34 @@ than a fact: the file list is derived from `write_file` / `edit_file`, so a
1148
1148
  write made through `bash` is invisible to it.
1149
1149
 
1150
1150
  **The dispatch supervisor.** A time ceiling on a subagent is an inspection
1151
- trigger, not a death sentence — as long as the fast tier is enabled. Two soft
1152
- timers per child (event silence and a wall clock) hand a bounded snapshot to the
1153
- fast model, which decides: keep waiting, steer a nudge in, rebuild the child
1154
- with an amended brief, or abandon it with a recorded reason. The budgets are
1155
- structural, not settings — 4 inspections and 1 replacement per child per
1156
- dispatch, after which the child runs under its own hard ceilings and the
1157
- supervisor goes quiet. Every applied decision is recorded in the report's
1158
- Supervisor section; `/team overseer off` (or no fast tier) restores the
1159
- pre-supervisor regime exactly.
1151
+ trigger, not a death sentence. Every dispatch gets its own supervisor on the
1152
+ fast model: a per-child silence window for suspected stalls, plus a periodic
1153
+ cadence check over the WHOLE roster — one bounded call that carries every live
1154
+ subagent and returns one decision per child: keep waiting, steer a nudge in,
1155
+ rebuild the child with an amended brief, or abandon it with a recorded reason.
1156
+ The cadence grows geometrically (5 min base, ×1.6, capped at 15 min), so a
1157
+ healthy slow subagent is checked logarithmically in its run time rather than
1158
+ every five minutes forever. The budgets are structural, not settings — 12
1159
+ looks, 3 nudges, 1 replacement and 1 abandon per child per dispatch. When the
1160
+ look budget is spent the supervisor says so once (`quiet` in the report) and
1161
+ stops waking that child; failed inspection calls cost a look but never an
1162
+ action. Every applied decision is recorded in the report's Supervisor section
1163
+ with the supervisor's own fast-tier spend, and replace/abandon also surface as
1164
+ a transcript notice while the dispatch runs.
1165
+
1166
+ **No kill by default.** While `team.overseer` is on (the default),
1167
+ `team.subagentTimeoutMs` never aborts anything — a positive value is only the
1168
+ supervisor's first cadence check. If the fast tier is missing (no key,
1169
+ `/fast off`), a due check degrades to an announced *unassisted wait*: the
1170
+ children keep running, the report notes how many checks ran degraded, and
1171
+ nothing is killed. A subagent still ends on the user's Esc, the explicit
1172
+ `team.dispatchTimeoutMs` / `team.maxTurnsPerSubagent` ceilings, its own idle
1173
+ watchdog (lengthened 4× while supervised), or the supervisor's own
1174
+ replace/abandon verdict. One boundary to know: a session with NO fast wiring
1175
+ at all and `team.overseer: true` runs children with no wall clock whatsoever
1176
+ — they finish, or die on their own un-lengthened watchdog. `/team overseer
1177
+ off` is the escape hatch back to the legacy regime where
1178
+ `team.subagentTimeoutMs` is a hard abort again.
1160
1179
 
1161
1180
  **Talking to each other.** Subagents get two extra tools, `team_send` and
1162
1181
  `team_wait`. Messages are delivered by attaching them to the recipient's next
@@ -2001,10 +2020,11 @@ env / `.env` → CLI flags**.
2001
2020
  | `team.enabled` | `true` | Master switch for team subagents. `false` means the `task` tool is never registered — `/team on` in such a session saves the setting for next launch and says so, rather than advertising a tool that is not there. |
2002
2021
  | `team.maxSubagents` | `5` | Subagents per dispatch, clamped to `[1, 10]`. The 10 is the hard ceiling and is enforced twice — on the config value and again on what the model asks for — so hand-editing this file cannot raise it. |
2003
2022
  | `team.maxConcurrent` | `3` | Subagents in flight at once, clamped to `[1, 10]` and capped at `maxSubagents`. A separate knob because provider rate limits are a different constraint from context economics. |
2004
- | `team.subagentTimeoutMs` | `0` | One subagent's wall clock, clamped to `[0, 1800000]`. With the supervisor off it is a hard abort; with it on (the default) a positive value is the **first wall-clock inspection** — the supervisor looks and decides instead of killing. `0` (the default) = no ceiling — a wedged subagent still dies on its own idle watchdog, exactly like the lead. |
2023
+ | `team.subagentTimeoutMs` | `0` | One subagent's wall clock, clamped to `[0, 1800000]`. With `team.overseer: false` it is a hard abort (the legacy regime). With the supervisor on (the default) it **never aborts anything** — a positive value is only a compatibility source for the supervisor's first cadence check. `0` (the default) = use `team.overseerIntervalMs` / the structural 5 min instead. |
2005
2024
  | `team.dispatchTimeoutMs` | `0` | The whole dispatch's wall clock (and the `task` tool timeout), clamped to `[0, 3600000]`. `0` (the default) = no ceiling; only Esc ends a dispatch early. |
2006
2025
  | `team.maxTurnsPerSubagent` | `0` | Runaway-loop cap, clamped to `[0, 100]`. `0` (the default) = no cap, matching the lead. A subagent stopped at a positive cap is reported as `stopped: turn cap reached`, with whatever it had produced. |
2007
- | `team.overseer` | `true` | The dispatch supervisor: time ceilings on subagents become inspection triggers for a fast-tier supervisor that decides wait / nudge / replace / abandon instead of aborting. Needs the fast tier (`fast.enabled`); with the tier off or this `false`, children run under the legacy hard ceilings exactly. `/team overseer on\|off` flips it live, and it is read per dispatch. |
2026
+ | `team.overseer` | `true` | The dispatch supervisor: one per dispatch on the fast model, ticking on a geometric cadence over every live subagent and deciding wait / nudge / replace / abandon. With the fast tier missing a tick degrades to an announced unassisted wait — never a kill; with this `false`, children run under the legacy hard ceilings exactly. `/team overseer on\|off` flips it live, and it is read per dispatch. |
2027
+ | `team.overseerIntervalMs` | `0` | Supervisor cadence base, clamped to `[0, 3600000]`. `0` (the default) = the structural 300 s; a positive `team.subagentTimeoutMs` is honoured first when this is `0` (compat). Later checks grow ×1.6, clamped to `[60 s, 900 s]`; any nudge/replace/abandon resets that child's cadence to the base. Only meaningful while `team.overseer` is true. |
2008
2028
  | `todo.enabled` | `true` | Master switch for todo planning. `false` means the `todo_write` tool is never registered — `/todo on` in such a session saves the setting for next launch and says so, rather than advertising a tool that is not there. |
2009
2029
  | `todo.panel` | `true` | Render the right-hand rail. Independent of `todo.enabled` on purpose: a screen-reader user wants the planning discipline without the column, and the system prompt varies one sentence accordingly. |
2010
2030
  | `todo.followThrough` | `"notify"` | What happens when a run ends with steps left. `notify` says so and stops; `auto` continues the plan after a 3-second grace window, bounded by two structural limits (one fruitless attempt, 25 continuations per plan) that are deliberately **not** settings; `off` is silent. An unrecognized value falls back to `notify`. |
@@ -2015,7 +2035,7 @@ env / `.env` → CLI flags**.
2015
2035
  | `retry.multiplier` | `2` | Growth factor, clamped to `[1, 5]`. The one **float** key in this section: `2.5` is a legitimate factor and is stored as typed. |
2016
2036
  | `retry.jitter` | `true` | Equal jitter (`d/2 + rand·d/2`), which de-correlates concurrent subagents hitting the same 429 while keeping the announced countdown within a factor of two of the truth. Full jitter can fire 40 ms after announcing 30 s, which reads as a bug. |
2017
2037
  | `retry.respectRetryAfter` | `true` | Honour `Retry-After` (and the provider rate-limit reset headers) as a **floor**, never a replacement — a `Retry-After: 1` on the ninth retry does not undo eight retries of backoff. A stated wait above 60 s is surfaced immediately instead of waited out. |
2018
- | `retry.maxElapsedMs` | `240000` | Wall-clock budget from the first failure, clamped to `[10000, 1800000]`. When `team.subagentTimeoutMs` is positive, keep this below it: an equal budget means a subagent is killed at the same instant its ladder ends, and the user is then told "subagent timed out" for what was a provider outage. |
2038
+ | `retry.maxElapsedMs` | `240000` | Wall-clock budget from the first failure, clamped to `[10000, 1800000]`. Under the legacy regime (`team.overseer: false`) with `team.subagentTimeoutMs` positive, keep this below it: an equal budget means a subagent is killed at the same instant its ladder ends, and the user is then told "subagent timed out" for what was a provider outage. |
2019
2039
  | `retry.onPartialStream` | `true` | Allow a restart after content has already streamed to the transcript. The view is rewound and the discarded tool cards removed; engine history is provably clean at that point, because it is only written on a completed turn. `false` refuses the whole path. |
2020
2040
  | `skills.enabled` | `true` | Master switch for the skill system. |
2021
2041
  | `skills.requireApproval` | `true` | Require a human to approve `skill_install` / `skill_create`. |
@@ -519,6 +519,19 @@ export class AgentController {
519
519
  // Every child runs the lead's own model, so the lead's cost table
520
520
  // is the one honest price for the dispatch total.
521
521
  modelCost: () => this.getModelInfo().cost,
522
+ // The FAST table for the supervisor's own spend line
523
+ // (subagent-overseer-v2 D-7 / R-P1-2). Reuses the tier
524
+ // resolution and the unknown-pricing predicate the fast
525
+ // reviewer already uses: undefined prices as `pricing
526
+ // unknown`, never as $0.00 (C-11 / RV-4).
527
+ fastModelCost: () => {
528
+ const tier = this.fast?.getTier();
529
+ if (!tier || !tier.ok)
530
+ return undefined;
531
+ return this.isPricedModel(tier.ref)
532
+ ? this.getModelInfoFor(tier.ref).cost
533
+ : undefined;
534
+ },
522
535
  withPausedWatchdog: (fn) => this.withPausedWatchdog(fn),
523
536
  }),
524
537
  ]
@@ -294,7 +294,8 @@ const COMMANDS = [
294
294
  ? `\nRunning: ${snapshot.runs.map((r) => `${r.label} (${r.phase})`).join(', ')}`
295
295
  : '';
296
296
  ctx.notify('info', `Team mode: ${state}. Max subagents: ${cfg.maxSubagents}, ` +
297
- `concurrent: ${cfg.maxConcurrent}, supervisor: ${cfg.overseer ? 'on' : 'off'} (needs the fast tier).${roster}`);
297
+ `concurrent: ${cfg.maxConcurrent}, supervisor: ${cfg.overseer ? 'on' : 'off'}` +
298
+ `${cfg.overseer ? ' (never kills; checks the fast tier each tick)' : ' (legacy hard timeouts)'}.${roster}`);
298
299
  return;
299
300
  }
300
301
  if (verb === 'on' || verb === 'off') {
@@ -20,7 +20,7 @@ export declare const LOG_CONFIG_SET_KEYS: readonly ["log.level", "log.toFile", "
20
20
  * switch falls through every case, writes nothing, and still prints
21
21
  * `Set team.enabled = false`.
22
22
  */
23
- export declare const TEAM_CONFIG_SET_KEYS: readonly ["team.enabled", "team.maxSubagents", "team.maxConcurrent", "team.subagentTimeoutMs", "team.dispatchTimeoutMs", "team.maxTurnsPerSubagent", "team.overseer"];
23
+ export declare const TEAM_CONFIG_SET_KEYS: readonly ["team.enabled", "team.maxSubagents", "team.maxConcurrent", "team.subagentTimeoutMs", "team.dispatchTimeoutMs", "team.maxTurnsPerSubagent", "team.overseer", "team.overseerIntervalMs"];
24
24
  /**
25
25
  * Config keys under `retry.` that `aragon config set` accepts
26
26
  * (llm-api-retry-backoff §8.2).
@@ -44,6 +44,7 @@ export const TEAM_CONFIG_SET_KEYS = [
44
44
  'team.dispatchTimeoutMs',
45
45
  'team.maxTurnsPerSubagent',
46
46
  'team.overseer',
47
+ 'team.overseerIntervalMs',
47
48
  ];
48
49
  /**
49
50
  * Config keys under `retry.` that `aragon config set` accepts
@@ -202,6 +203,8 @@ export function applyTeamConfigSet(key, value) {
202
203
  return patch(clampOne('maxTurnsPerSubagent'));
203
204
  case 'team.overseer':
204
205
  return patch({ overseer: isTrue(value) });
206
+ case 'team.overseerIntervalMs':
207
+ return patch(clampOne('overseerIntervalMs'));
205
208
  default:
206
209
  return null;
207
210
  }
@@ -309,10 +309,11 @@ export interface TeamConfig {
309
309
  * the lead, whose only in-run ceiling is the event-silence idle watchdog
310
310
  * a child already keeps. A wedged child still dies on its OWN watchdog.
311
311
  *
312
- * WITH `team.overseer` ON (the default) this is the FIRST wall-clock
313
- * INSPECTION point, not a hard abort: the supervisor looks and decides
314
- * (wait / nudge / replace / abandon), so a slow-but-healthy child is no
315
- * longer killed at an arbitrary wall clock.
312
+ * WITH `team.overseer` ON (the default) this NEVER aborts anything
313
+ * (subagent-overseer-v2 D-4): a positive value is only a COMPATIBILITY
314
+ * SOURCE for the supervisor's first cadence check, honouring users who
315
+ * already treated it as a trigger point. The only hard abort left is
316
+ * the legacy regime (`team.overseer: false`).
316
317
  */
317
318
  subagentTimeoutMs: number;
318
319
  /**
@@ -329,17 +330,32 @@ export interface TeamConfig {
329
330
  */
330
331
  maxTurnsPerSubagent: number;
331
332
  /**
332
- * The dispatch supervisor (team-overseer): time ceilings on children
333
- * become inspection triggers for a fast-tier supervisor that decides
334
- * wait / nudge / replace / abandon, instead of aborts. Default TRUE.
333
+ * The dispatch supervisor (team-overseer / subagent-overseer-v2): time
334
+ * ceilings on children become inspection triggers for a fast-tier
335
+ * supervisor that decides wait / nudge / replace / abandon, instead of
336
+ * aborts. Default TRUE.
335
337
  *
336
- * READ PER DISPATCH. With the supervisor off (or no fast tier), children
337
- * run exactly the pre-feature regime: `subagentTimeoutMs` is a hard abort
338
- * and silence is the child's own watchdog. With it ON,
339
- * `subagentTimeoutMs > 0` is the FIRST wall-clock inspection point, not
340
- * a death sentence.
338
+ * READ PER DISPATCH. The supervisor ticks on a cadence ladder over every
339
+ * live child, and NO timeout is a death sentence while this is on: with
340
+ * the fast tier missing a tick degrades to an announced unassisted wait,
341
+ * never a kill. With this FALSE, children run exactly the pre-feature
342
+ * legacy regime: `subagentTimeoutMs` is a hard abort and silence is the
343
+ * child's own watchdog.
341
344
  */
342
345
  overseer: boolean;
346
+ /**
347
+ * Supervisor cadence BASE, in milliseconds (subagent-overseer-v2 D-8).
348
+ * `0` (the default) = the structural default
349
+ * (`TEAM_LIMITS.overseerDefaultCheckMs`, 300 s).
350
+ *
351
+ * EFFECTIVE FIRST CHECK, derived read-only and never written back:
352
+ * `overseerIntervalMs > 0` wins; otherwise a positive
353
+ * `subagentTimeoutMs` is honoured (users who already treated it as a
354
+ * trigger point); otherwise the structural default. Later checks grow
355
+ * by `overseerCadenceRatio` (1.6), clamped to [60 s, 900 s]. Only
356
+ * meaningful while `team.overseer` is true.
357
+ */
358
+ overseerIntervalMs: number;
343
359
  }
344
360
  /**
345
361
  * The requirement's ceiling on the fan-out (R-g).
@@ -455,6 +455,8 @@ export const DEFAULT_TEAM_CONFIG = {
455
455
  // The dispatch supervisor, default ON (team-overseer): ceilings become
456
456
  // inspections; the fast-tier supervisor decides what to do.
457
457
  overseer: true,
458
+ // 0 = the structural cadence default (300 s). See the field docstring.
459
+ overseerIntervalMs: 0,
458
460
  };
459
461
  const SUBAGENTS_RANGE = { min: 1, max: HARD_MAX_SUBAGENTS };
460
462
  const CONCURRENT_RANGE = { min: 1, max: HARD_MAX_SUBAGENTS };
@@ -463,6 +465,7 @@ const CONCURRENT_RANGE = { min: 1, max: HARD_MAX_SUBAGENTS };
463
465
  // ("my setting won't stick"), the exact trap `scrollResumeMs` records above.
464
466
  const SUBAGENT_TIMEOUT_RANGE = { min: 0, max: 1_800_000 };
465
467
  const DISPATCH_TIMEOUT_RANGE = { min: 0, max: 3_600_000 };
468
+ const OVERSEER_INTERVAL_RANGE = { min: 0, max: 3_600_000 };
466
469
  const TURNS_RANGE = { min: 0, max: 100 };
467
470
  /**
468
471
  * THE single gate for every team-config read AND write, mirroring
@@ -486,6 +489,7 @@ export function clampTeamConfig(raw) {
486
489
  dispatchTimeoutMs: clampIntAllowingZero(src.dispatchTimeoutMs, DEFAULT_TEAM_CONFIG.dispatchTimeoutMs, DISPATCH_TIMEOUT_RANGE),
487
490
  maxTurnsPerSubagent: clampIntAllowingZero(src.maxTurnsPerSubagent, DEFAULT_TEAM_CONFIG.maxTurnsPerSubagent, TURNS_RANGE),
488
491
  overseer: bool(src.overseer, DEFAULT_TEAM_CONFIG.overseer),
492
+ overseerIntervalMs: clampIntAllowingZero(src.overseerIntervalMs, DEFAULT_TEAM_CONFIG.overseerIntervalMs, OVERSEER_INTERVAL_RANGE),
489
493
  };
490
494
  }
491
495
  export const DEFAULT_TODO_CONFIG = {
@@ -102,11 +102,12 @@ export declare const TEAM_LIMITS: {
102
102
  readonly maxColdStartRetries: 1;
103
103
  readonly retryBackoffMs: 2000;
104
104
  /**
105
- * Wall-clock budget of everything one inspection may carry. The digest holds
106
- * run facts, the supervisor's own memory and the tail of the child's live
107
- * history; unbounded, one look at a child that read five big files would
108
- * make the "cheap" supervision call cost more than the child (the argument
109
- * FAST_LIMITS.digestMaxChars makes, one level up).
105
+ * Wall-clock budget of everything one SINGLE inspection may carry (the
106
+ * silence-triggered path). The digest holds run facts, the supervisor's own
107
+ * memory and the tail of the child's live history; unbounded, one look at a
108
+ * child that read five big files would make the "cheap" supervision call
109
+ * cost more than the child (the argument FAST_LIMITS.digestMaxChars makes,
110
+ * one level up).
110
111
  */
111
112
  readonly overseerDigestBytes: 8000;
112
113
  /** Clamp on a `nudge` guidance text. Advice, not a second brief. */
@@ -114,11 +115,48 @@ export declare const TEAM_LIMITS: {
114
115
  /** Clamp on the decision `reason` recorded in the report. */
115
116
  readonly overseerReasonChars: 200;
116
117
  /**
117
- * Inspections PER CHILD per dispatch. An indecisive supervisor must stop
118
- * burning fast-tier calls; past the budget the child simply runs under its
119
- * hard ceilings and the supervisor goes quiet.
118
+ * Per-child slice of a BATCH digest (D-3 / R-P2-5). 6.7x tighter than the
119
+ * single-inspection budget above: a batch carries up to ten children in one
120
+ * call, and memory plus the history tail are the first to give way (the
121
+ * facts-first assembly order already puts them last).
120
122
  */
121
- readonly overseerMaxInspectionsPerChild: 4;
123
+ readonly overseerPerChildDigestBytes: 1200;
124
+ /** Whole-batch digest ceiling (D-3): 10 children x 1 200 B fits exactly. */
125
+ readonly overseerBatchDigestBytes: 12000;
126
+ /**
127
+ * Output budget of ONE batch inspection (R-P0-1). The single-inspection path
128
+ * keeps `FAST_LIMITS.reviewOutputTokens` (512); a batch must return up to
129
+ * ten decision objects, and 512 tokens cannot physically hold ten x
130
+ * (reason <= 200 + guidance <= 1200). A truncated batch reply fails
131
+ * "first `[` to last `]`" parsing and degrades to all-wait - exactly the
132
+ * failure this separate, larger budget exists to prevent.
133
+ */
134
+ readonly overseerBatchOutputTokens: 2048;
135
+ /** Tighter `reason` clamp inside the batch protocol (R-P0-1). */
136
+ readonly overseerBatchReasonChars: 80;
137
+ /** Tighter `guidance` clamp inside the batch protocol (R-P0-1). */
138
+ readonly overseerBatchGuidanceChars: 400;
139
+ /**
140
+ * LOOKS per child per dispatch (D-5). A look is cost, not mutation: every
141
+ * inspection of a child - silence-triggered, cadence tick or post-mortem -
142
+ * spends one, including a call that failed softly. Twelve with the cadence
143
+ * ladder covers hours of healthy slow work; past the budget the supervisor
144
+ * says so once (`trigger: 'quiet'`) and stops waking that child up.
145
+ */
146
+ readonly overseerMaxLooksPerChild: 12;
147
+ /**
148
+ * LOOKS per dispatch, the fool-proof total (R-P1-6):
149
+ * hardMaxSubagents x overseerMaxLooksPerChild = 120. A mathematical upper
150
+ * bound, not a tuning knob - the per-child budget always binds first; this
151
+ * one exists so a bug cannot loop calls forever. When it trips, the whole
152
+ * MonitorLoop stops with one aggregate notice.
153
+ */
154
+ readonly overseerMaxLooksPerDispatch: number;
155
+ /**
156
+ * NUDGES per child per dispatch (D-5). Advice is cheap but not free: a
157
+ * supervisor that steers the same child forever is one that never decided.
158
+ */
159
+ readonly overseerMaxNudgesPerChild: 3;
122
160
  /**
123
161
  * Rebuilds PER CHILD per dispatch. One: a replacement that also stalls dies
124
162
  * on its own watchdog rather than ping-ponging fresh children at a task the
@@ -126,13 +164,25 @@ export declare const TEAM_LIMITS: {
126
164
  */
127
165
  readonly overseerMaxReplacementsPerChild: 1;
128
166
  /**
129
- * First wall-clock check when `team.subagentTimeoutMs === 0` (the shipped
130
- * default): the supervisor still looks even when no ceiling was configured.
167
+ * Abandons PER CHILD per dispatch (D-5). One, so a supervisor that has
168
+ * already given up on a brief cannot keep re-killing bodies of it.
169
+ */
170
+ readonly overseerMaxAbandonsPerChild: 1;
171
+ /**
172
+ * Cadence ladder growth factor (D-2). Each no-action inspection schedules
173
+ * the next `previous * ratio` out, so a healthy slow child is looked at
174
+ * logarithmically in its run time rather than every five minutes.
175
+ */
176
+ readonly overseerCadenceRatio: 1.6;
177
+ /**
178
+ * First cadence check when neither `team.overseerIntervalMs` nor
179
+ * `team.subagentTimeoutMs` names one (the shipped defaults): the supervisor
180
+ * still looks even when no ceiling was configured.
131
181
  */
132
182
  readonly overseerDefaultCheckMs: 300000;
133
- /** Clamp on the model-chosen `nextCheckMs`, lower bound. */
183
+ /** Clamp on a ladder step / model-chosen `nextCheckMs`, lower bound. */
134
184
  readonly overseerNextCheckMinMs: 60000;
135
- /** Clamp on the model-chosen `nextCheckMs`, upper bound. */
185
+ /** Clamp on a ladder step / model-chosen `nextCheckMs`, upper bound. */
136
186
  readonly overseerNextCheckMaxMs: 900000;
137
187
  /**
138
188
  * A child's OWN idle watchdog, multiplied by this while the supervisor is
@@ -142,6 +192,16 @@ export declare const TEAM_LIMITS: {
142
192
  */
143
193
  readonly overseerWatchdogFactor: 4;
144
194
  };
195
+ /**
196
+ * The pseudo-label the runtime's AGGREGATE supervisor notices travel under
197
+ * (subagent-overseer-v2 D-5 / R-P1-6): the dispatch-total look-budget notice
198
+ * is one fact about the whole roster, not a row any child owns. RESERVED at
199
+ * normalization (`normalizeSubagentSpecs` seeds `dedupeLabel` with it), so a
200
+ * spec asking for the bare label `team` is handed `team-2` instead - the
201
+ * report ledger and the exec stream can then never attribute an aggregate
202
+ * notice to a real child, or swallow that child's own quiet note.
203
+ */
204
+ export declare const TEAM_AGGREGATE_LABEL = "team";
145
205
  /**
146
206
  * The two comm tools, which are POLICY-EXEMPT inside a child (§3.11).
147
207
  *
@@ -24,13 +24,20 @@
24
24
  * is 72 000 bytes, so a character-denominated cap would let the executor chop
25
25
  * the report mid-section and take the failure count with it.
26
26
  */
27
+ /**
28
+ * The two factors of the dispatch-total look budget (R-P1-6), hoisted only so
29
+ * `TEAM_LIMITS.overseerMaxLooksPerDispatch` can state their product without a
30
+ * second copy of either number. Not for export: the authority is TEAM_LIMITS.
31
+ */
32
+ const HARD_MAX_SUBAGENTS = 10;
33
+ const OVERSEER_MAX_LOOKS_PER_CHILD = 12;
27
34
  export const TEAM_LIMITS = {
28
35
  /**
29
36
  * The requirement's ceiling (R-g). Enforced in `clampTeamConfig` AND in
30
37
  * `normalizeSubagentSpecs`, so neither a hand-edited file nor a model asking
31
38
  * for thirty can exceed it.
32
39
  */
33
- hardMaxSubagents: 10,
40
+ hardMaxSubagents: HARD_MAX_SUBAGENTS,
34
41
  // --- Spec normalization (§3.3.1) ---
35
42
  /** `SubagentSpec.description`, clamped (never rejected). */
36
43
  descriptionChars: 60,
@@ -106,13 +113,14 @@ export const TEAM_LIMITS = {
106
113
  * nothing a re-dispatch by the lead would not buy better. */
107
114
  maxColdStartRetries: 1,
108
115
  retryBackoffMs: 2_000,
109
- // --- The dispatch supervisor (team-overseer) ---
116
+ // --- The dispatch supervisor (team-overseer / subagent-overseer-v2) ---
110
117
  /**
111
- * Wall-clock budget of everything one inspection may carry. The digest holds
112
- * run facts, the supervisor's own memory and the tail of the child's live
113
- * history; unbounded, one look at a child that read five big files would
114
- * make the "cheap" supervision call cost more than the child (the argument
115
- * FAST_LIMITS.digestMaxChars makes, one level up).
118
+ * Wall-clock budget of everything one SINGLE inspection may carry (the
119
+ * silence-triggered path). The digest holds run facts, the supervisor's own
120
+ * memory and the tail of the child's live history; unbounded, one look at a
121
+ * child that read five big files would make the "cheap" supervision call
122
+ * cost more than the child (the argument FAST_LIMITS.digestMaxChars makes,
123
+ * one level up).
116
124
  */
117
125
  overseerDigestBytes: 8_000,
118
126
  /** Clamp on a `nudge` guidance text. Advice, not a second brief. */
@@ -120,11 +128,48 @@ export const TEAM_LIMITS = {
120
128
  /** Clamp on the decision `reason` recorded in the report. */
121
129
  overseerReasonChars: 200,
122
130
  /**
123
- * Inspections PER CHILD per dispatch. An indecisive supervisor must stop
124
- * burning fast-tier calls; past the budget the child simply runs under its
125
- * hard ceilings and the supervisor goes quiet.
131
+ * Per-child slice of a BATCH digest (D-3 / R-P2-5). 6.7x tighter than the
132
+ * single-inspection budget above: a batch carries up to ten children in one
133
+ * call, and memory plus the history tail are the first to give way (the
134
+ * facts-first assembly order already puts them last).
135
+ */
136
+ overseerPerChildDigestBytes: 1_200,
137
+ /** Whole-batch digest ceiling (D-3): 10 children x 1 200 B fits exactly. */
138
+ overseerBatchDigestBytes: 12_000,
139
+ /**
140
+ * Output budget of ONE batch inspection (R-P0-1). The single-inspection path
141
+ * keeps `FAST_LIMITS.reviewOutputTokens` (512); a batch must return up to
142
+ * ten decision objects, and 512 tokens cannot physically hold ten x
143
+ * (reason <= 200 + guidance <= 1200). A truncated batch reply fails
144
+ * "first `[` to last `]`" parsing and degrades to all-wait - exactly the
145
+ * failure this separate, larger budget exists to prevent.
146
+ */
147
+ overseerBatchOutputTokens: 2_048,
148
+ /** Tighter `reason` clamp inside the batch protocol (R-P0-1). */
149
+ overseerBatchReasonChars: 80,
150
+ /** Tighter `guidance` clamp inside the batch protocol (R-P0-1). */
151
+ overseerBatchGuidanceChars: 400,
152
+ /**
153
+ * LOOKS per child per dispatch (D-5). A look is cost, not mutation: every
154
+ * inspection of a child - silence-triggered, cadence tick or post-mortem -
155
+ * spends one, including a call that failed softly. Twelve with the cadence
156
+ * ladder covers hours of healthy slow work; past the budget the supervisor
157
+ * says so once (`trigger: 'quiet'`) and stops waking that child up.
158
+ */
159
+ overseerMaxLooksPerChild: 12,
160
+ /**
161
+ * LOOKS per dispatch, the fool-proof total (R-P1-6):
162
+ * hardMaxSubagents x overseerMaxLooksPerChild = 120. A mathematical upper
163
+ * bound, not a tuning knob - the per-child budget always binds first; this
164
+ * one exists so a bug cannot loop calls forever. When it trips, the whole
165
+ * MonitorLoop stops with one aggregate notice.
126
166
  */
127
- overseerMaxInspectionsPerChild: 4,
167
+ overseerMaxLooksPerDispatch: HARD_MAX_SUBAGENTS * OVERSEER_MAX_LOOKS_PER_CHILD,
168
+ /**
169
+ * NUDGES per child per dispatch (D-5). Advice is cheap but not free: a
170
+ * supervisor that steers the same child forever is one that never decided.
171
+ */
172
+ overseerMaxNudgesPerChild: 3,
128
173
  /**
129
174
  * Rebuilds PER CHILD per dispatch. One: a replacement that also stalls dies
130
175
  * on its own watchdog rather than ping-ponging fresh children at a task the
@@ -132,13 +177,25 @@ export const TEAM_LIMITS = {
132
177
  */
133
178
  overseerMaxReplacementsPerChild: 1,
134
179
  /**
135
- * First wall-clock check when `team.subagentTimeoutMs === 0` (the shipped
136
- * default): the supervisor still looks even when no ceiling was configured.
180
+ * Abandons PER CHILD per dispatch (D-5). One, so a supervisor that has
181
+ * already given up on a brief cannot keep re-killing bodies of it.
182
+ */
183
+ overseerMaxAbandonsPerChild: 1,
184
+ /**
185
+ * Cadence ladder growth factor (D-2). Each no-action inspection schedules
186
+ * the next `previous * ratio` out, so a healthy slow child is looked at
187
+ * logarithmically in its run time rather than every five minutes.
188
+ */
189
+ overseerCadenceRatio: 1.6,
190
+ /**
191
+ * First cadence check when neither `team.overseerIntervalMs` nor
192
+ * `team.subagentTimeoutMs` names one (the shipped defaults): the supervisor
193
+ * still looks even when no ceiling was configured.
137
194
  */
138
195
  overseerDefaultCheckMs: 300_000,
139
- /** Clamp on the model-chosen `nextCheckMs`, lower bound. */
196
+ /** Clamp on a ladder step / model-chosen `nextCheckMs`, lower bound. */
140
197
  overseerNextCheckMinMs: 60_000,
141
- /** Clamp on the model-chosen `nextCheckMs`, upper bound. */
198
+ /** Clamp on a ladder step / model-chosen `nextCheckMs`, upper bound. */
142
199
  overseerNextCheckMaxMs: 900_000,
143
200
  /**
144
201
  * A child's OWN idle watchdog, multiplied by this while the supervisor is
@@ -148,6 +205,16 @@ export const TEAM_LIMITS = {
148
205
  */
149
206
  overseerWatchdogFactor: 4,
150
207
  };
208
+ /**
209
+ * The pseudo-label the runtime's AGGREGATE supervisor notices travel under
210
+ * (subagent-overseer-v2 D-5 / R-P1-6): the dispatch-total look-budget notice
211
+ * is one fact about the whole roster, not a row any child owns. RESERVED at
212
+ * normalization (`normalizeSubagentSpecs` seeds `dedupeLabel` with it), so a
213
+ * spec asking for the bare label `team` is handed `team-2` instead - the
214
+ * report ledger and the exec stream can then never attribute an aggregate
215
+ * notice to a real child, or swallow that child's own quiet note.
216
+ */
217
+ export const TEAM_AGGREGATE_LABEL = 'team';
151
218
  /**
152
219
  * The two comm tools, which are POLICY-EXEMPT inside a child (§3.11).
153
220
  *
@@ -24,7 +24,7 @@
24
24
  * honest reading of a stale key is silence, not a report line about a
25
25
  * capability that no longer exists.
26
26
  */
27
- import { TEAM_LIMITS } from './limits.js';
27
+ import { TEAM_AGGREGATE_LABEL, TEAM_LIMITS } from './limits.js';
28
28
  function asString(value) {
29
29
  return typeof value === 'string' ? value : '';
30
30
  }
@@ -88,7 +88,12 @@ export function normalizeSubagentSpecs(raw, max) {
88
88
  return { specs: [], requested: 0 };
89
89
  const requested = raw.length;
90
90
  const kept = [];
91
- const taken = new Set();
91
+ // SEEDED WITH THE RESERVED AGGREGATE LABEL (subagent-overseer-v2 D-5 /
92
+ // R-P1-6): the runtime's dispatch-total supervisor notices travel under
93
+ // `TEAM_AGGREGATE_LABEL`, so no child may wear that slug - `dedupeLabel`
94
+ // hands a spec asking for it the suffixed form instead, the same namespace
95
+ // fix it already applies to any other collision.
96
+ const taken = new Set([TEAM_AGGREGATE_LABEL]);
92
97
  for (let i = 0; i < raw.length; i += 1) {
93
98
  const item = raw[i];
94
99
  if (!item || typeof item !== 'object')