@crewhaus/ir 0.3.2 → 0.4.2

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/dist/index.d.ts CHANGED
@@ -14,6 +14,18 @@ export type IrPermissionRule = {
14
14
  export type IrPermissions = {
15
15
  readonly mode?: "default" | "plan" | "auto";
16
16
  readonly rules: readonly IrPermissionRule[];
17
+ /**
18
+ * Loop contract 0.4 (Batch C, G11) — what an `ask` permission does on a
19
+ * NON-interactive surface: `"pause"` parks the turn as a `PendingApproval`
20
+ * (the SAFE default), `"deny"` collapses the ask to a denial in place (the
21
+ * pre-0.4 behaviour). ABSENT MEANS `"pause"` — the runtime resolves the
22
+ * default with `permissions.askMode ?? "pause"`, so the safe direction
23
+ * holds even when no `permissions:` block is declared. Carried only when
24
+ * the spec sets it explicitly (mirrors `mode`), keeping the IR minimal and
25
+ * byte-stable for the emitters that don't read it. NOT optimizer-reachable
26
+ * (a safety control — excluded from `OPTIMIZABLE_PATHS`).
27
+ */
28
+ readonly askMode?: "pause" | "deny";
17
29
  };
18
30
  /**
19
31
  * MCP server configs carried through to codegen (Section 9). Lower-time
@@ -58,6 +70,16 @@ export type IrSubAgentDefinition = {
58
70
  readonly deny: readonly string[];
59
71
  };
60
72
  readonly inheritBypass: boolean;
73
+ /**
74
+ * Item 2 (G31 — A2A federation) — present when the spec wires this
75
+ * sub-agent to a REMOTE peer (`sub_agents.<name>.federation.url`). The
76
+ * spawner routes the Task call through `@crewhaus/federation-router` to the
77
+ * peer's inbound A2A handler instead of spawning locally. Absent → the
78
+ * sub-agent is spawned in-process as before.
79
+ */
80
+ readonly federation?: {
81
+ readonly url: string;
82
+ };
61
83
  };
62
84
  /**
63
85
  * Section 14 — per-tool runtime config carried verbatim from the spec to
@@ -76,6 +98,18 @@ export type IrToolConfigs = Readonly<Record<string, unknown>>;
76
98
  */
77
99
  export type IrCompaction = {
78
100
  readonly model?: string;
101
+ /** Loop contract 0.4 (Batch A) — context-window fill fraction that
102
+ * triggers autocompaction (spec `compaction.threshold`, 0.5–0.99).
103
+ * Runtime default applies when absent. */
104
+ readonly threshold?: number;
105
+ /** Loop contract 0.4 (Batch A) — messages preserved verbatim at the
106
+ * transcript HEAD by `compaction-snip` (spec `compaction.snip_keep_head`).
107
+ * Snip package default when absent. */
108
+ readonly snipKeepHead?: number;
109
+ /** Loop contract 0.4 (Batch A) — messages preserved verbatim at the
110
+ * transcript TAIL by `compaction-snip` (spec `compaction.snip_keep_tail`).
111
+ * Snip package default when absent. */
112
+ readonly snipKeepTail?: number;
79
113
  /** Pillar 2 — RESERVED, not yet wired at runtime. Intended to make
80
114
  * target emitters wire `compaction-curator` as a pre-pass before the
81
115
  * autocompact threshold check, but no emitter or runtime-core path
@@ -164,6 +198,99 @@ export type IrModelPool = {
164
198
  readonly bandit?: "epsilon-greedy" | "thompson";
165
199
  };
166
200
  };
201
+ /**
202
+ * Loop contract 0.4 (Batch A) — extended-thinking selector, lowered from
203
+ * the spec's `thinking` block (agent-level on cli/channel/managed;
204
+ * step/node/role-level on workflow/graph/crew). Exactly one variant is ever
205
+ * present (the spec's superRefine enforces the exactly-one rule):
206
+ *
207
+ * - `{ budgetTokens }` — explicit thinking-token budget (>= 1024), passed
208
+ * to the provider verbatim (`ProviderRequest.thinking`).
209
+ * - `{ effort }` — portable preset the adapter layer converts to a
210
+ * provider-appropriate budget (`EFFORT_THINKING_BUDGET_TOKENS` in
211
+ * `@crewhaus/adapter-anthropic`; threads as
212
+ * `ProviderRequest.reasoningEffort`).
213
+ */
214
+ export type IrThinking = {
215
+ readonly budgetTokens: number;
216
+ } | {
217
+ readonly effort: "low" | "medium" | "high";
218
+ };
219
+ /**
220
+ * Loop contract 0.4 (Batch A) — runaway-loop detection tuning inside
221
+ * {@link IrLimits}. Every field carried verbatim only when declared; the
222
+ * runtime owns per-knob defaults. `escalation`: `warn` (trace event only) |
223
+ * `justify` (demand a justification via the intent gate) | `abort` (end the
224
+ * run).
225
+ */
226
+ export type IrLoopDetection = {
227
+ readonly window?: number;
228
+ readonly threshold?: number;
229
+ readonly escalation?: "warn" | "justify" | "abort";
230
+ };
231
+ /**
232
+ * Loop contract 0.4 (Batch A) — crew-only orchestration ceilings, lowered
233
+ * from `limits.crew`. Present ONLY on the `IrCrewV0` variant's limits.
234
+ */
235
+ export type IrCrewLimits = {
236
+ readonly maxActivations?: number;
237
+ readonly refusalDepth?: number;
238
+ readonly maxA2aDepth?: number;
239
+ };
240
+ /**
241
+ * Loop contract 0.4 (Batch A) — hard runtime ceilings for one agent loop,
242
+ * lowered from the top-level `limits:` block. Carried on the loop-running
243
+ * shapes (IrV0/cli, IrChannelV0, IrManagedV0, IrWorkflowV0, IrGraphV0,
244
+ * IrCrewV0, IrResearchV0, IrBatchV0, IrBrowserV0). Absent when the spec
245
+ * omits the block; every field carried verbatim only when declared (the
246
+ * runtime owns per-knob defaults). `crew` is populated only on the crew
247
+ * variant (the spec rejects `limits.crew` elsewhere).
248
+ */
249
+ export type IrLimits = {
250
+ readonly maxToolIterations?: number;
251
+ readonly maxConcurrentTools?: number;
252
+ readonly contextLimit?: number;
253
+ readonly deadlineMs?: number;
254
+ readonly turnTimeoutMs?: number;
255
+ readonly modelCallTimeoutMs?: number;
256
+ readonly loopDetection?: IrLoopDetection;
257
+ readonly crew?: IrCrewLimits;
258
+ };
259
+ /**
260
+ * Loop contract 0.4 (Batch A) — the hook-event names the spec accepts.
261
+ * Mirrors `HookEvent` from `@crewhaus/hooks-engine` — the canonical list —
262
+ * kept inline (exactly as `IrVectorBackend` mirrors vector-store's ids) so
263
+ * the runtime-agnostic IR keeps its zero runtime-package dependencies. The
264
+ * spec's `SPEC_HOOK_EVENTS` const carries the same list with a hooks-engine
265
+ * cross-check test; keep all three in sync.
266
+ */
267
+ export type IrHookEvent = "session-start" | "stop" | "pre-tool" | "post-tool" | "pre-model" | "post-model" | "pre-compact" | "post-compact" | "pre-slash" | "alert";
268
+ /**
269
+ * Loop contract 0.4 (Batch A) — one spec-declared lifecycle hook, lowered
270
+ * from a `hooks:` entry (snake_case `timeout_ms` → `timeoutMs`). Same shape
271
+ * as hooks-engine's `HookDef`, so emitters can concat these with the
272
+ * settings.json-discovered hooks. Carried (as `hooks?: readonly IrHook[]`)
273
+ * on the same shapes as {@link IrLimits}.
274
+ */
275
+ export type IrHook = {
276
+ readonly event: IrHookEvent;
277
+ readonly matcher?: string;
278
+ readonly command: string;
279
+ readonly timeoutMs?: number;
280
+ };
281
+ /** Loop contract 0.4 (Batch A) — one tool's rate-limit tuning (sustained
282
+ * requests-per-minute + optional short-burst allowance). */
283
+ export type IrRateLimit = {
284
+ readonly rpm: number;
285
+ readonly burst?: number;
286
+ };
287
+ /**
288
+ * Loop contract 0.4 (Batch A) — per-tool rate limits, lowered from
289
+ * `agent.rate_limits` on the interactive shapes (IrV0/cli, IrChannelV0,
290
+ * IrManagedV0). Keys are tool names or `"*"` (the catch-all bucket).
291
+ * Absent when the spec omits the block.
292
+ */
293
+ export type IrRateLimits = Readonly<Record<string, IrRateLimit>>;
167
294
  /**
168
295
  * Section 55 (Track A) — named failure taxonomy. Cross-cutting; carried
169
296
  * through to runtime-core so `recovery-engine` can consult the user's
@@ -205,6 +332,85 @@ export type IrBudget = {
205
332
  readonly model: string;
206
333
  };
207
334
  };
335
+ /**
336
+ * Loop contract 0.4 (Batch B, G02) — the grader selector inside
337
+ * {@link IrEvaluation}, lowered 1:1 from `evaluation.grader`:
338
+ *
339
+ * - `llm_judge` — a model scores the final text in [0,1] against
340
+ * `criteria`. `model` is the judge model id; when ABSENT the runtime
341
+ * uses the shape's primary model (the `cheapest` sentinel was already
342
+ * resolved at lower time, like `compaction.model`). Judge calls are
343
+ * METERED into the run budget.
344
+ * - `contains` / `regex` — deterministic pass/fail text checks (score 1
345
+ * on pass, 0 on fail; no model spend).
346
+ */
347
+ export type IrEvaluationGrader = {
348
+ readonly type: "llm_judge";
349
+ readonly criteria: string;
350
+ readonly model?: string;
351
+ } | {
352
+ readonly type: "contains";
353
+ readonly value: string;
354
+ } | {
355
+ readonly type: "regex";
356
+ readonly value: string;
357
+ };
358
+ /**
359
+ * Loop contract 0.4 (Batch B, G02) — in-loop output evaluation, lowered
360
+ * from the top-level `evaluation:` block on the interactive shapes
361
+ * (IrV0/cli, IrChannelV0, IrManagedV0). After each completed assistant
362
+ * turn the runtime scores the final text with `grader`; a score below
363
+ * `threshold` triggers `onFail`:
364
+ *
365
+ * - `retry` — re-prompt with the judge rationale appended as a system
366
+ * nudge, at most `maxRetries` times (retries are hard-capped and the
367
+ * judge/model calls metered into the run budget).
368
+ * - `halt` — abort the turn with a classified `"evaluation"` failure.
369
+ * - `note` — emit the `eval_graded` trace event only.
370
+ *
371
+ * `onFail`/`maxRetries` are RESOLVED at lower time (defaults `"retry"`/1)
372
+ * so emitters and the interpreter read one deterministic shape.
373
+ * `threshold` is present iff `grader.type === "llm_judge"` (RESOLVED
374
+ * default 0.7) — deterministic graders are pass/fail and carry none.
375
+ * Absent from the IR when the spec omits the block.
376
+ */
377
+ export type IrEvaluation = {
378
+ readonly grader: IrEvaluationGrader;
379
+ /** Present iff `grader.type === "llm_judge"` (resolved default 0.7). */
380
+ readonly threshold?: number;
381
+ /** Resolved below-threshold behaviour (spec `on_fail`, default "retry"). */
382
+ readonly onFail: "retry" | "halt" | "note";
383
+ /** Resolved retry hard-cap (spec `max_retries`, default 1). */
384
+ readonly maxRetries: number;
385
+ };
386
+ /**
387
+ * Loop contract 0.4 (Batch B, G02) — the judge gate carried by
388
+ * `kind: "judge"` workflow steps ({@link IrWorkflowStep}) and graph nodes
389
+ * ({@link IrGraphNode}). The judge scores the PREVIOUS step's (workflow) /
390
+ * upstream node's (graph) final output in [0,1] against `criteria`; below
391
+ * `threshold`, `onFail` applies:
392
+ *
393
+ * - `retry_previous` — re-run the gated step/node with the judge
394
+ * rationale appended as a system nudge, at most `maxRetries` times.
395
+ * - `halt` — abort the run with a classified `"evaluation"` failure.
396
+ * - `continue` — record the `judge_verdict` trace event and proceed.
397
+ *
398
+ * All three knobs are RESOLVED at lower time (defaults 0.7 /
399
+ * `"retry_previous"` / 1). The judge MODEL is not carried here: it lives
400
+ * in the step's/node's existing `model` field, resolved at lower time as
401
+ * `judge.model ?? <shape>.model` (exactly how regular steps resolve
402
+ * theirs), so emitters read one model slot per step/node.
403
+ */
404
+ export type IrJudge = {
405
+ readonly criteria: string;
406
+ /** Resolved passing score in [0,1] (spec `threshold`, default 0.7). */
407
+ readonly threshold: number;
408
+ /** Resolved below-threshold behaviour (spec `on_fail`,
409
+ * default "retry_previous"). */
410
+ readonly onFail: "retry_previous" | "halt" | "continue";
411
+ /** Resolved re-run hard-cap (spec `max_retries`, default 1). */
412
+ readonly maxRetries: number;
413
+ };
208
414
  /**
209
415
  * Pillar 3 (FR-004) — per-target security fabric configuration the
210
416
  * compiler lowers from the spec's `security` block. Today it carries the
@@ -316,18 +522,91 @@ export type IrMemoryDream = {
316
522
  * reserved `thredz`), `ttlMs` (explicit fact forgetting — `spec.memory.ttl`
317
523
  * parsed to milliseconds at lower time, >= 1h enforced there), `wiki`
318
524
  * (see {@link IrMemoryWiki}), and `dream` (see {@link IrMemoryDream}).
525
+ *
526
+ * Loop contract 0.4 (Batch E): `autoRecall`/`autoCapture` are now RESOLVED at
527
+ * lower time — with the block present they default to `true` (G46, mildly
528
+ * breaking), so a compiled bundle carries an explicit boolean rather than
529
+ * relying on a runtime default. `recallMode`/`refreshEvery` (G21) carry the
530
+ * per-turn recall cadence; `sessionRecall` (G77) folds session summaries into
531
+ * the recall fusion.
319
532
  */
320
533
  export type IrMemory = {
321
534
  readonly enabled?: boolean;
322
535
  readonly backend?: "file" | "thredz";
536
+ /** Loop contract 0.4 (Batch A) — top-level embedder for the FACT store
537
+ * (`@crewhaus/embedder` factory grammar, spec `memory.embedder`).
538
+ * Runtime fallback order: `embedder` → `wiki.embedder`. */
539
+ readonly embedder?: string;
323
540
  readonly ttlMs?: number;
324
541
  readonly autoCapture?: boolean;
325
542
  readonly autoCaptureThreshold?: number;
326
543
  readonly autoRecall?: boolean;
544
+ /**
545
+ * Loop contract 0.4 (Batch E, G21) — WHEN auto-recall runs, RESOLVED at
546
+ * lower time from `spec.memory.autoRecall`. Carried ONLY when `"per-turn"`
547
+ * (the interactive cadence); `"session-start"` is the implicit default
548
+ * whenever `autoRecall` is true, so the common case stays absent. In
549
+ * `"per-turn"` mode the runtime re-runs the recall closure against the
550
+ * latest user message every `refreshEvery` turns and swaps the volatile
551
+ * recalled TAIL block — it never re-injects into the frozen cache prefix.
552
+ */
553
+ readonly recallMode?: "session-start" | "per-turn";
554
+ /**
555
+ * Loop contract 0.4 (Batch E, G21) — turns between per-turn recall
556
+ * refreshes (`spec.memory.refreshEvery`, int > 0). Meaningful only when
557
+ * `recallMode` is `"per-turn"`; the runtime defaults to 1 when absent.
558
+ */
559
+ readonly refreshEvery?: number;
560
+ /**
561
+ * Loop contract 0.4 (Batch E, G77) — fold session summaries in as a third
562
+ * RRF ranker in the recall fusion (`spec.memory.sessionRecall`). Absent
563
+ * unless the spec opted in (default false).
564
+ */
565
+ readonly sessionRecall?: boolean;
327
566
  readonly recallK?: number;
328
567
  readonly wiki?: IrMemoryWiki;
329
568
  readonly dream?: IrMemoryDream;
330
569
  };
570
+ /**
571
+ * Loop contract 0.4 (Batch E, G22) — one lowered `knowledge.sources[]` entry.
572
+ * A discriminated union so an emitter switches on `kind` without re-deriving
573
+ * which of path/glob/url was set (the spec's exactly-one-of rule already
574
+ * enforced that). Mirrors how {@link IrPipelineDocument} carries the pipeline
575
+ * corpus, but for the agent shapes the corpus is ingested from disk/URL at
576
+ * build/boot rather than inlined.
577
+ */
578
+ export type IrKnowledgeSource = {
579
+ readonly kind: "path";
580
+ readonly path: string;
581
+ } | {
582
+ readonly kind: "glob";
583
+ readonly glob: string;
584
+ } | {
585
+ readonly kind: "url";
586
+ readonly url: string;
587
+ };
588
+ /**
589
+ * Loop contract 0.4 (Batch E, G22) — the agent-shape RAG config, lowered from
590
+ * `spec.knowledge` on cli/channel/managed. Presence registers
591
+ * `@crewhaus/tool-retrieve` as a citation-bearing `Retrieve` tool, ingesting
592
+ * `sources` at build/boot. It REUSES target-pipeline's retrieve engine, so
593
+ * the resolved shape mirrors `IrPipelineV0.retrieve` + `.indexing`:
594
+ * `vectorBackend`/`defaultK`/`chunkSize`/`chunkOverlap` are RESOLVED to the
595
+ * pipeline defaults (`in-memory` / 5 / 400 / 0) at lower time so the engine
596
+ * reads concrete values. `embedder` is carried only when declared;
597
+ * resolution order is `knowledge.embedder → memory.embedder →
598
+ * memory.wiki.embedder → the target's default embedder model` (a vector store
599
+ * needs embeddings — it never degrades to BM25, unlike memory recall).
600
+ * Absent when the spec omits `knowledge`.
601
+ */
602
+ export type IrKnowledge = {
603
+ readonly embedder?: string;
604
+ readonly vectorBackend: IrVectorBackend;
605
+ readonly defaultK: number;
606
+ readonly chunkSize: number;
607
+ readonly chunkOverlap: number;
608
+ readonly sources: readonly IrKnowledgeSource[];
609
+ };
331
610
  /** v0.3.0 §2.7 — the RESOLVED continuity scope. `auto` is a compiler
332
611
  * concern: `lower()` resolves it per shape (cli/research/crew/managed →
333
612
  * `spec`, channel → `session`), so the IR never carries `auto`. */
@@ -394,6 +673,35 @@ export type IrThredz = {
394
673
  /** Register this addressable agent handle at boot (idempotent
395
674
  * `agent_register`). Absent → no registration (the default). */
396
675
  readonly agentName?: string;
676
+ /** Item 5 (G44) — the nine Thredz messaging tools (`message_send` /
677
+ * `inbox_poll` / `message_ack` / `thread_get` / `agent_*`) are registered.
678
+ * Present and `true` ONLY when the spec opts in (`thredz.messaging: true`);
679
+ * ABSENT means the default-off posture (the send-side tools are
680
+ * destructive + justification-gated, so they never register unasked). */
681
+ readonly messaging?: boolean;
682
+ };
683
+ /**
684
+ * Item 1 (G30) — the MCP-server projection config inside {@link IrExpose}.
685
+ * `transport` is `stdio` (spawned stdio MCP server) or `sse` (HTTP+SSE
686
+ * endpoint, riding the gateway-server tenancy/budgets where the shape has
687
+ * them). `tools` is RESOLVED (default `"chat"`): `chat` projects one primary
688
+ * invoke tool (`{ message }` → final assistant text); `per-subagent` adds one
689
+ * tool per declared sub-agent (the spec's cross-field check guarantees at
690
+ * least one exists).
691
+ */
692
+ export type IrExposeMcp = {
693
+ readonly transport: "stdio" | "sse";
694
+ readonly tools: "chat" | "per-subagent";
695
+ };
696
+ /**
697
+ * Item 1 (G30) — the `expose:` config, lowered from the top-level `expose:`
698
+ * block. Carried on the serving shapes (IrV0/cli, IrChannelV0, IrManagedV0).
699
+ * Present ONLY when the spec declares `expose.mcp`; ABSENT → the bundle is not
700
+ * exposed as an MCP server (byte-identical to pre-Batch-G). `mcp` is the one
701
+ * projection kind today; the object leaves room for future exposure targets.
702
+ */
703
+ export type IrExpose = {
704
+ readonly mcp?: IrExposeMcp;
397
705
  };
398
706
  /** v0.3.0 Goal 2 (§3.3, PR 17) — the first-class competency exam: dataset +
399
707
  * graders paths, spec-relative. Whether the files EXIST is a runtime
@@ -463,13 +771,71 @@ export type IrSlo = {
463
771
  readonly mitigation: ReadonlyArray<IrSloMitigation>;
464
772
  };
465
773
  /**
466
- * Ops item 37 cross-cutting observability config, lowered from
467
- * `spec.observability`. Today it carries one sub-block, `slo`. Carried on the
468
- * interactive/daemon shapes that run a chat loop (IrV0/cli, IrChannelV0,
469
- * IrManagedV0). Absent when the spec omits the `observability` block.
774
+ * Loop contract 0.4 (Batch C, G26) trace subscriber level.
775
+ * `off` — no ring buffer, no printer.
776
+ * `ring` — ring buffer only (the DEFAULT), no printer attached.
777
+ * `pretty` ring buffer + colorised stderr printer.
778
+ * `json` — ring buffer + JSON-Lines printer.
779
+ */
780
+ export type IrObservabilityTraceLevel = "off" | "ring" | "pretty" | "json";
781
+ export type IrObservabilityTrace = {
782
+ readonly level: IrObservabilityTraceLevel;
783
+ };
784
+ /** Loop contract 0.4 (Batch C, G26) — a simple on/off subscriber toggle
785
+ * (metrics / cost / alerts / incidents). */
786
+ export type IrObservabilityToggle = {
787
+ readonly enabled: boolean;
788
+ };
789
+ /** Loop contract 0.4 (Batch C, G26) — OTLP exporter config. `endpoint` is
790
+ * carried verbatim (a `$VAR` value is the emitter's to resolve). */
791
+ export type IrObservabilityOtel = {
792
+ readonly endpoint?: string;
793
+ };
794
+ /**
795
+ * Ops item 37 + Loop contract 0.4 (Batch C, G26) — cross-cutting
796
+ * observability config, lowered from `spec.observability`. Carries the `slo`
797
+ * targets (item 37) plus the subscriber/exporter controls (G26). Carried on
798
+ * the shapes that run an agent loop with observability subscribers
799
+ * (IrV0/cli, IrChannelV0, IrManagedV0, IrCrewV0).
800
+ *
801
+ * DEFAULTS SEMANTICS — spec ABSENCE is NOT `off`. The lowering carries ONLY
802
+ * what the spec declares; each key is absent when its sub-block is omitted,
803
+ * and the emitter/runtime applies the default:
804
+ * - `cost` absent ⇒ cost-tracker ON (`ir.observability?.cost?.enabled ?? true`)
805
+ * - `trace` absent ⇒ ring buffer ON, no printer (`?.trace?.level ?? "ring"`)
806
+ * - `metrics`/`alerts`/`incidents` absent ⇒ OFF (opt-in: `?.enabled ?? false`)
807
+ * - `otel` absent ⇒ no OTel export
808
+ * An EXPLICIT `cost: { enabled: false }` / `trace: { level: "off" }` reaches
809
+ * the IR verbatim and wins. Absent from the IR entirely when the spec omits
810
+ * the whole `observability:` block.
470
811
  */
471
812
  export type IrObservability = {
472
813
  readonly slo?: IrSlo;
814
+ readonly trace?: IrObservabilityTrace;
815
+ readonly metrics?: IrObservabilityToggle;
816
+ readonly cost?: IrObservabilityToggle;
817
+ readonly alerts?: IrObservabilityToggle;
818
+ readonly incidents?: IrObservabilityToggle;
819
+ readonly otel?: IrObservabilityOtel;
820
+ };
821
+ /**
822
+ * "Watch me" (design/watch-me.md §4.6) — observe-and-learn config, lowered
823
+ * from `spec.watchme` on the three interactive-loop shapes (IrV0/cli,
824
+ * IrChannelV0, IrManagedV0), carried beside `observability` (a sibling
825
+ * feature, not a telemetry sub-key). Unlike IrObservability's declare-only
826
+ * carriage, every field here is REQUIRED: the lowering resolves all defaults
827
+ * (a bare `watchme: {}` arrives fully populated), so emitters/runtimes never
828
+ * re-derive them. Absent from the IR entirely when the spec omits the block.
829
+ */
830
+ export type IrWatchme = {
831
+ readonly enabled: boolean;
832
+ readonly capture: "full" | "mirrors";
833
+ /** Phase-2 judge model — default resolved at lower time. */
834
+ readonly judgeModel: string;
835
+ readonly judgeSampleRate: number;
836
+ readonly judgeBudgetUsd: number;
837
+ readonly scope: "harness" | "user";
838
+ readonly share: boolean;
473
839
  };
474
840
  /**
475
841
  * Track F (Section 57) — typed message schemas (Σ) for multi-agent
@@ -512,8 +878,6 @@ export type IrCliBanner = {
512
878
  };
513
879
  export type IrCliOptions = {
514
880
  readonly banner?: IrCliBanner;
515
- /** Phase 2 M2.2 — TUI mode gate. */
516
- readonly tui?: "basic" | "rich";
517
881
  };
518
882
  export type IrV0 = {
519
883
  readonly version: 0;
@@ -525,6 +889,16 @@ export type IrV0 = {
525
889
  /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
526
890
  * Optional; when absent the runtime default applies. */
527
891
  readonly maxTokens?: number;
892
+ /** Loop contract 0.4 (Batch A) — extended-thinking selector (spec
893
+ * `agent.thinking`). Absent when the spec omits the block. */
894
+ readonly thinking?: IrThinking;
895
+ /** Loop contract 0.4 (Batch A) — stream partial output tokens (spec
896
+ * `agent.streaming`, cli shape only). Carried verbatim only when
897
+ * declared; absent means false. */
898
+ readonly streaming?: boolean;
899
+ /** Loop contract 0.4 (Batch A) — per-tool rate limits (spec
900
+ * `agent.rate_limits`). Absent when the spec omits the block. */
901
+ readonly rateLimits?: IrRateLimits;
528
902
  /** Item 22 — ordered failover models (spec `agent.model_fallbacks`).
529
903
  * Absent when the spec omits the block; the runtime then keeps its
530
904
  * single-adapter path. */
@@ -547,6 +921,15 @@ export type IrV0 = {
547
921
  readonly failureTaxonomy?: IrFailureTaxonomy;
548
922
  /** Item 27 — run-level spend cap + degradation ladder. Optional. */
549
923
  readonly budget?: IrBudget;
924
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional; absent
925
+ * when the spec omits the `limits` block. */
926
+ readonly limits?: IrLimits;
927
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional;
928
+ * absent when the spec omits the `hooks` block. */
929
+ readonly hooks?: readonly IrHook[];
930
+ /** Loop contract 0.4 (Batch B, G02) — in-loop output evaluation.
931
+ * Optional; absent when the spec omits the `evaluation` block. */
932
+ readonly evaluation?: IrEvaluation;
550
933
  /** Pillar 3 (FR-004) — security fabric config (intent-gate judge
551
934
  * selection). Optional; absent when the spec omits the `security`
552
935
  * block. */
@@ -555,6 +938,9 @@ export type IrV0 = {
555
938
  readonly feedback?: IrFeedback;
556
939
  /** #53 cross-session memory config. Optional; absent when the spec omits `memory`. */
557
940
  readonly memory?: IrMemory;
941
+ /** Loop contract 0.4 (Batch E, G22) — agent-shape RAG config. Present when
942
+ * the spec declares `knowledge:`; absent otherwise. */
943
+ readonly knowledge?: IrKnowledge;
558
944
  /** v0.3.0 Goal 1 — continuity config. DEFAULT-ON: present unless the spec
559
945
  * opted out with `continuity: false`. */
560
946
  readonly continuity?: IrContinuity;
@@ -567,6 +953,16 @@ export type IrV0 = {
567
953
  /** Ops item 37 — SLO targets + mitigation ladder. Optional; absent when the
568
954
  * spec omits the `observability` block. */
569
955
  readonly observability?: IrObservability;
956
+ /** "Watch me" — observe-and-learn config (design/watch-me.md §4.6).
957
+ * Optional; absent when the spec omits the `watchme` block; all defaults
958
+ * resolved at lower time when present. */
959
+ readonly watchme?: IrWatchme;
960
+ /** Item 1 (G30) — MCP-server projection config. Present when the spec
961
+ * declares `expose.mcp`; absent otherwise. */
962
+ readonly expose?: IrExpose;
963
+ /** Item 3 (G32) — marketplace plugin names loaded at boot (`plugins:`).
964
+ * Present (non-empty) only when the spec declares them; load order. */
965
+ readonly plugins?: readonly string[];
570
966
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
571
967
  readonly chains?: readonly IrChainBinding[];
572
968
  readonly wallets?: readonly IrWalletBinding[];
@@ -576,13 +972,44 @@ export type IrV0 = {
576
972
  /**
577
973
  * One step in a workflow IR. `model` is resolved at lower-time
578
974
  * (`step.model ?? workflow.model`) so codegen can read it directly.
975
+ *
976
+ * Loop contract 0.4 (Batch B, G02) — a step may be a JUDGE GATE
977
+ * (`kind: "judge"`) over the previous step's output. Judge steps keep the
978
+ * full step shape so every existing consumer compiles and iterates
979
+ * unchanged: `instructions` carries the judge `criteria` verbatim, `model`
980
+ * is the resolved judge model (`judge.model ?? workflow.model`), and
981
+ * `tools`/`toolConfigs` are empty. Emitters/interpreters branch on
982
+ * `kind === "judge"` and read the gate config from `judge`.
579
983
  */
580
984
  export type IrWorkflowStep = {
581
985
  readonly name: string;
582
986
  readonly instructions: string;
583
987
  readonly model: string;
988
+ /** Model max OUTPUT tokens for this step's turn (spec `steps[].max_tokens`).
989
+ * Optional; when absent the runtime default applies. */
990
+ readonly maxTokens?: number;
991
+ /** Loop contract 0.4 (Batch A) — per-step extended-thinking selector
992
+ * (spec `steps[].thinking`). Absent when the spec omits the block. */
993
+ readonly thinking?: IrThinking;
584
994
  readonly tools: readonly string[];
585
995
  readonly toolConfigs: IrToolConfigs;
996
+ /** Item 9 (G37) — per-step ordered failover models (spec
997
+ * `steps[].model_fallbacks`). Absent → single-model. */
998
+ readonly modelFallbacks?: readonly string[];
999
+ /** Item 9 (G37) — per-step breaker tuning (spec `steps[].circuit_breaker`). */
1000
+ readonly circuitBreaker?: IrCircuitBreaker;
1001
+ /** Item 9 (G37) — per-step two-tier turn-difficulty router. Absent →
1002
+ * single-model. */
1003
+ readonly modelTiers?: IrModelTiers;
1004
+ /** Item 9 (G37) — per-step N-candidate pool with a selection policy (a
1005
+ * PolicyRouter decides per step against the shared routing-store
1006
+ * scoreboard). Absent → single-model. */
1007
+ readonly modelPool?: IrModelPool;
1008
+ /** Loop contract 0.4 (Batch B, G02) — `"judge"` marks a gate step over
1009
+ * the previous step's output. ABSENT on regular agent steps. */
1010
+ readonly kind?: "judge";
1011
+ /** Present iff `kind === "judge"` — the resolved gate config. */
1012
+ readonly judge?: IrJudge;
586
1013
  };
587
1014
  /**
588
1015
  * Workflow IR — a sequence of steps. Each step runs as one user→assistant
@@ -604,6 +1031,13 @@ export type IrWorkflowV0 = {
604
1031
  readonly compaction: IrCompaction;
605
1032
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
606
1033
  readonly failureTaxonomy?: IrFailureTaxonomy;
1034
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1035
+ * to this shape). Optional. */
1036
+ readonly budget?: IrBudget;
1037
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1038
+ readonly limits?: IrLimits;
1039
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1040
+ readonly hooks?: readonly IrHook[];
607
1041
  /** v0.3.0 — carried when the spec declares `continuity:` (NOT default-on
608
1042
  * here); target-workflow prints the ignored-note comment. */
609
1043
  readonly continuity?: IrContinuity;
@@ -750,6 +1184,12 @@ export type IrWhatsAppConfig = {
750
1184
  readonly phoneNumberId: IrSecretRef;
751
1185
  readonly accessToken: IrSecretRef;
752
1186
  readonly appSecret: IrSecretRef;
1187
+ /**
1188
+ * Shared token echoed back on Meta's unsigned GET callback-URL verification
1189
+ * handshake (`hub.verify_token`). Optional — absent means the daemon fails
1190
+ * that handshake closed and serves only an already-verified subscription.
1191
+ */
1192
+ readonly verifyToken?: IrSecretRef;
753
1193
  };
754
1194
  /**
755
1195
  * Section 33 — iMessage channel config (macOS host-bound). `chatDbPath`
@@ -787,6 +1227,33 @@ export type IrHeartbeat = {
787
1227
  readonly everyMs: number;
788
1228
  readonly instructions: string;
789
1229
  };
1230
+ /**
1231
+ * Loop contract 0.4 (Batch F, temporal contract / G84 schedule half) — a
1232
+ * cron OR interval wake trigger carried into the IR for the daemon-able
1233
+ * shapes (IrChannelV0, IrManagedV0, IrBatchV0). The temporal downstream
1234
+ * lowers this into the emitted daemon's wake loop; `runs resume` rehydrates
1235
+ * an interrupted scheduled run. Durations (`jitter`, interval `every`) are
1236
+ * normalized to milliseconds at lower time so codegen reads literal numbers,
1237
+ * while `cron` is carried verbatim for the daemon's cron parser. Exactly one
1238
+ * `kind` — the discriminated union mirrors the spec's `schedule:` block.
1239
+ */
1240
+ export type IrSchedule = {
1241
+ readonly kind: "cron";
1242
+ /** A 5- or 6-field cron expression, carried verbatim. */
1243
+ readonly cron: string;
1244
+ /** IANA tz the cron evaluates in; absent → the daemon's default (UTC). */
1245
+ readonly timezone?: string;
1246
+ /** Random +/- delay per wake, normalized to ms. Absent → no jitter. */
1247
+ readonly jitterMs?: number;
1248
+ /** Synthetic prompt each wake runs. Absent → the daemon's default tick. */
1249
+ readonly instructions?: string;
1250
+ } | {
1251
+ readonly kind: "interval";
1252
+ /** Wake cadence in ms (spec `every` duration, normalized at lower time). */
1253
+ readonly everyMs: number;
1254
+ readonly jitterMs?: number;
1255
+ readonly instructions?: string;
1256
+ };
790
1257
  /**
791
1258
  * Phase 3 §3.4 — channel daemon control-UI gateway config.
792
1259
  */
@@ -801,6 +1268,15 @@ export type IrChannelV0 = {
801
1268
  readonly agent: {
802
1269
  readonly model: string;
803
1270
  readonly instructions: string;
1271
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1272
+ * Optional; when absent the runtime default applies. */
1273
+ readonly maxTokens?: number;
1274
+ /** Loop contract 0.4 (Batch A) — extended-thinking selector (spec
1275
+ * `agent.thinking`). Absent when the spec omits the block. */
1276
+ readonly thinking?: IrThinking;
1277
+ /** Loop contract 0.4 (Batch A) — per-tool rate limits (spec
1278
+ * `agent.rate_limits`). Absent when the spec omits the block. */
1279
+ readonly rateLimits?: IrRateLimits;
804
1280
  /** Item 22 — ordered failover models (spec `agent.model_fallbacks`). */
805
1281
  readonly modelFallbacks?: readonly string[];
806
1282
  /** Item 22 — breaker tuning (spec `agent.circuit_breaker`). */
@@ -819,16 +1295,29 @@ export type IrChannelV0 = {
819
1295
  readonly subAgents: readonly IrSubAgentDefinition[];
820
1296
  readonly compaction: IrCompaction;
821
1297
  readonly heartbeat?: IrHeartbeat;
1298
+ /** Loop contract 0.4 (Batch F) — cron/interval wake trigger. Optional;
1299
+ * absent when the spec omits `schedule:`. */
1300
+ readonly schedule?: IrSchedule;
822
1301
  readonly gateway?: IrChannelGateway;
823
1302
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
824
1303
  readonly failureTaxonomy?: IrFailureTaxonomy;
825
1304
  /** Item 27 — run-level spend cap + degradation ladder. Optional. */
826
1305
  readonly budget?: IrBudget;
1306
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1307
+ readonly limits?: IrLimits;
1308
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1309
+ readonly hooks?: readonly IrHook[];
1310
+ /** Loop contract 0.4 (Batch B, G02) — in-loop output evaluation.
1311
+ * Optional; absent when the spec omits the `evaluation` block. */
1312
+ readonly evaluation?: IrEvaluation;
827
1313
  /** Response-feedback config. `feedback.channelReactions` gates Slack 👍/👎
828
1314
  * → user_feedback codegen in this target. Absent when spec omits it. */
829
1315
  readonly feedback?: IrFeedback;
830
1316
  /** #53 cross-session memory config. Optional; absent when the spec omits `memory`. */
831
1317
  readonly memory?: IrMemory;
1318
+ /** Loop contract 0.4 (Batch E, G22) — agent-shape RAG config. Present when
1319
+ * the spec declares `knowledge:`; absent otherwise. */
1320
+ readonly knowledge?: IrKnowledge;
832
1321
  /** v0.3.0 Goal 1 — continuity config. DEFAULT-ON: present unless the spec
833
1322
  * opted out with `continuity: false`. `scope` resolves to `session` here
834
1323
  * (per-conversation stores riding the session router's sessionId, §14.5). */
@@ -842,6 +1331,16 @@ export type IrChannelV0 = {
842
1331
  /** Ops item 37 — SLO targets + mitigation ladder. Optional; absent when the
843
1332
  * spec omits the `observability` block. */
844
1333
  readonly observability?: IrObservability;
1334
+ /** "Watch me" — observe-and-learn config (design/watch-me.md §4.6).
1335
+ * Optional; absent when the spec omits the `watchme` block; all defaults
1336
+ * resolved at lower time when present. */
1337
+ readonly watchme?: IrWatchme;
1338
+ /** Item 1 (G30) — MCP-server projection config. Present when the spec
1339
+ * declares `expose.mcp`; absent otherwise. */
1340
+ readonly expose?: IrExpose;
1341
+ /** Item 3 (G32) — marketplace plugin names loaded at boot (`plugins:`).
1342
+ * Present (non-empty) only when the spec declares them; load order. */
1343
+ readonly plugins?: readonly string[];
845
1344
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
846
1345
  readonly chains?: readonly IrChainBinding[];
847
1346
  readonly wallets?: readonly IrWalletBinding[];
@@ -868,6 +1367,15 @@ export type IrManagedV0 = {
868
1367
  readonly agent: {
869
1368
  readonly model: string;
870
1369
  readonly instructions: string;
1370
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1371
+ * Optional; when absent the runtime default applies. */
1372
+ readonly maxTokens?: number;
1373
+ /** Loop contract 0.4 (Batch A) — extended-thinking selector (spec
1374
+ * `agent.thinking`). Absent when the spec omits the block. */
1375
+ readonly thinking?: IrThinking;
1376
+ /** Loop contract 0.4 (Batch A) — per-tool rate limits (spec
1377
+ * `agent.rate_limits`). Absent when the spec omits the block. */
1378
+ readonly rateLimits?: IrRateLimits;
871
1379
  /** Item 22 — ordered failover models (spec `agent.model_fallbacks`). */
872
1380
  readonly modelFallbacks?: readonly string[];
873
1381
  /** Item 22 — breaker tuning (spec `agent.circuit_breaker`). */
@@ -878,14 +1386,38 @@ export type IrManagedV0 = {
878
1386
  readonly modelPool?: IrModelPool;
879
1387
  };
880
1388
  readonly tenants: readonly IrManagedTenant[];
1389
+ /** Loop contract 0.4 (Batch F, G81) — tool catalog for the managed daemon.
1390
+ * Optional (absent when the spec omits `agent.tools`); the emitter reads
1391
+ * `ir.tools ?? []`. Per-tenant tool_config overlays apply at runtime via the
1392
+ * policy-engine's tenant context. */
1393
+ readonly tools?: readonly string[];
1394
+ /** Loop contract 0.4 (Batch F, G81) — builtin tool config blobs (spec
1395
+ * `agent.tool_config`). Optional; absent when the spec omits it. */
1396
+ readonly toolConfigs?: IrToolConfigs;
881
1397
  readonly permissions: IrPermissions;
882
1398
  readonly compaction: IrCompaction;
883
1399
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
884
1400
  readonly failureTaxonomy?: IrFailureTaxonomy;
885
1401
  /** Item 27 — run-level spend cap + degradation ladder. Optional. */
886
1402
  readonly budget?: IrBudget;
1403
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1404
+ readonly limits?: IrLimits;
1405
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1406
+ readonly hooks?: readonly IrHook[];
1407
+ /** Loop contract 0.4 (Batch F) — cron/interval wake trigger. Optional. */
1408
+ readonly schedule?: IrSchedule;
1409
+ /** Loop contract 0.4 (Batch B, G02) — in-loop output evaluation.
1410
+ * Optional; absent when the spec omits the `evaluation` block. */
1411
+ readonly evaluation?: IrEvaluation;
1412
+ /** NEW-inloop-coverage — response-feedback config. Gates the gateway's
1413
+ * `feedback.submit` rating route and (with `autoDistill`) the daemon's
1414
+ * distill janitor step. Absent when the spec omits the block. */
1415
+ readonly feedback?: IrFeedback;
887
1416
  /** #53 cross-session memory config. Optional; absent when the spec omits `memory`. */
888
1417
  readonly memory?: IrMemory;
1418
+ /** Loop contract 0.4 (Batch E, G22) — agent-shape RAG config. Present when
1419
+ * the spec declares `knowledge:`; absent otherwise. */
1420
+ readonly knowledge?: IrKnowledge;
889
1421
  /** v0.3.0 Goal 1 — continuity config. DEFAULT-ON: present unless the spec
890
1422
  * opted out with `continuity: false`. `scope` resolves to `spec` here;
891
1423
  * every store is tenant-fenced at boot (deps carry the tenant, §2.7). */
@@ -900,6 +1432,16 @@ export type IrManagedV0 = {
900
1432
  * spec omits the `observability` block. The managed daemon's `pause-intake`
901
1433
  * rung reuses its `budget_exceeded` 429 path. */
902
1434
  readonly observability?: IrObservability;
1435
+ /** "Watch me" — observe-and-learn config (design/watch-me.md §4.6).
1436
+ * Optional; absent when the spec omits the `watchme` block; all defaults
1437
+ * resolved at lower time when present. CARRIED but not runtime-wired on
1438
+ * this shape in v1 — `compile()` emits the accepted-but-unwired warning
1439
+ * (design/watch-me.md §6.3 names the target-managed stamp seam). */
1440
+ readonly watchme?: IrWatchme;
1441
+ /** Item 1 (G30) — MCP-server projection config. Present when the spec
1442
+ * declares `expose.mcp`; absent otherwise. SSE-backed exposure rides this
1443
+ * shape's gateway-server tenancy/budgets. */
1444
+ readonly expose?: IrExpose;
903
1445
  };
904
1446
  /**
905
1447
  * Section 19 — Graph IR. A `target: "graph"` spec lowers into a fixed
@@ -910,17 +1452,53 @@ export type IrGraphNode = {
910
1452
  readonly instructions: string;
911
1453
  /** Resolved at lower-time (node.model ?? graph.model). */
912
1454
  readonly model: string;
1455
+ /** Model max OUTPUT tokens for this node's turn (spec
1456
+ * `nodes.<n>.max_tokens`). Optional; runtime default when absent. */
1457
+ readonly maxTokens?: number;
1458
+ /** Loop contract 0.4 (Batch A) — per-node extended-thinking selector
1459
+ * (spec `nodes.<n>.thinking`). Absent when the spec omits the block. */
1460
+ readonly thinking?: IrThinking;
913
1461
  readonly tools: readonly string[];
914
1462
  readonly toolConfigs: IrToolConfigs;
915
1463
  /**
916
- * When set, the node calls `ctx.requestApproval(prompt)` after the
917
- * LLM turn and pauses the graph until `resume(checkpointId, decision)`.
1464
+ * When set, the node calls `ctx.requestApproval(prompt)` BEFORE its LLM
1465
+ * turn and pauses the graph until `resume(checkpointId, decision)`. The
1466
+ * gate is a pre-condition: at the pause the node has spent nothing, the
1467
+ * `hitl_pause` event carries the upstream state the approver is deciding
1468
+ * on, and a rejecting decision cancels the turn (the node records only
1469
+ * `state["<name>_decision"]`).
918
1470
  */
919
1471
  readonly hitlPrompt?: string;
1472
+ /** Loop contract 0.4 (Batch B, G02) — `"judge"` marks a gate node over
1473
+ * its upstream node's output. ABSENT on regular LLM nodes. Judge nodes
1474
+ * keep the full node shape (`instructions` = the judge criteria, `model`
1475
+ * = resolved `judge.model ?? graph.model`, empty `tools`) so existing
1476
+ * consumers compile unchanged; branch on `kind` and read `judge`. */
1477
+ readonly kind?: "judge";
1478
+ /** Present iff `kind === "judge"` — the resolved gate config. */
1479
+ readonly judge?: IrJudge;
1480
+ };
1481
+ /**
1482
+ * Loop contract 0.4 (Batch A) — declarative edge predicate over the graph's
1483
+ * shared state, lowered 1:1 from `edges[].when`. `key` names an upstream
1484
+ * NODE whose recorded output (`state["<nodeName>"]`) the predicate reads
1485
+ * (parse-validated; the ir-passes wellformedness check re-verifies for
1486
+ * direct-IR builders). Exactly one of `equals`/`exists` is ever present.
1487
+ * Emitters lower it onto a graph-engine `EdgeCondition`:
1488
+ * `(state) => state[key] === equals` / `(state) => state[key] !== undefined`.
1489
+ */
1490
+ export type IrGraphEdgeWhen = {
1491
+ readonly key: string;
1492
+ readonly equals?: string | number | boolean;
1493
+ readonly exists?: true;
920
1494
  };
921
1495
  export type IrGraphEdge = {
922
1496
  readonly from: string;
923
1497
  readonly to: string;
1498
+ /** Loop contract 0.4 (Batch A) — declarative predicate gating this edge.
1499
+ * Absent means the edge matches unconditionally (the engine takes the
1500
+ * first matching edge in declaration order). */
1501
+ readonly when?: IrGraphEdgeWhen;
924
1502
  /** Track F (Section 57) — typed message schema carried by this edge.
925
1503
  * Defaults to `{ kind: "untyped" }` (any payload) when absent. The
926
1504
  * ir-passes wellformedness check verifies named refs resolve. */
@@ -933,6 +1511,12 @@ export type IrGraphV0 = {
933
1511
  readonly entry: string;
934
1512
  readonly nodes: readonly IrGraphNode[];
935
1513
  readonly edges: readonly IrGraphEdge[];
1514
+ /** Loop contract 0.4 (Batch A) — parallel barrier groups (>= 2 node names
1515
+ * each), lowered verbatim from the spec's `parallel` and emitted as
1516
+ * graph-engine `addParallel` calls. A group executes concurrently when
1517
+ * the cursor reaches its FIRST member; execution continues from the LAST
1518
+ * member's outgoing edge. Absent when the spec omits the block. */
1519
+ readonly parallel?: ReadonlyArray<ReadonlyArray<string>>;
936
1520
  /** Track F (Section 57) — named message schemas referenced by edges.
937
1521
  * Absent means no typed edges (all `untyped` by default). */
938
1522
  readonly messageSchemas?: readonly IrMessageSchema[];
@@ -940,6 +1524,13 @@ export type IrGraphV0 = {
940
1524
  readonly compaction: IrCompaction;
941
1525
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
942
1526
  readonly failureTaxonomy?: IrFailureTaxonomy;
1527
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1528
+ * to this shape). Optional. */
1529
+ readonly budget?: IrBudget;
1530
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1531
+ readonly limits?: IrLimits;
1532
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1533
+ readonly hooks?: readonly IrHook[];
943
1534
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
944
1535
  readonly chains?: readonly IrChainBinding[];
945
1536
  readonly wallets?: readonly IrWalletBinding[];
@@ -1016,9 +1607,27 @@ export type IrCrewRole = {
1016
1607
  /** Resolved at lower-time (`role.model ?? crew.model`). */
1017
1608
  readonly model: string;
1018
1609
  readonly instructions: string;
1610
+ /** Model max OUTPUT tokens for this role's turns (spec
1611
+ * `roles.<r>.max_tokens`). Optional; runtime default when absent. */
1612
+ readonly maxTokens?: number;
1613
+ /** Loop contract 0.4 (Batch A) — per-role extended-thinking selector
1614
+ * (spec `roles.<r>.thinking`). Absent when the spec omits the block. */
1615
+ readonly thinking?: IrThinking;
1019
1616
  readonly tools: readonly string[];
1020
1617
  readonly toolConfigs: IrToolConfigs;
1021
1618
  readonly subAgents: readonly IrSubAgentDefinition[];
1619
+ /** Item 9 (G37) — per-role ordered failover models (spec
1620
+ * `roles.<r>.model_fallbacks`). Absent → single-model. */
1621
+ readonly modelFallbacks?: readonly string[];
1622
+ /** Item 9 (G37) — per-role breaker tuning (spec `roles.<r>.circuit_breaker`). */
1623
+ readonly circuitBreaker?: IrCircuitBreaker;
1624
+ /** Item 9 (G37) — per-role two-tier turn-difficulty router. Absent →
1625
+ * single-model. */
1626
+ readonly modelTiers?: IrModelTiers;
1627
+ /** Item 9 (G37) — per-role N-candidate pool with a selection policy (a
1628
+ * PolicyRouter decides per role against the shared routing-store
1629
+ * scoreboard). Absent → single-model. */
1630
+ readonly modelPool?: IrModelPool;
1022
1631
  };
1023
1632
  export type IrCrewRoutingKind = "match" | "llm";
1024
1633
  export type IrCrewRouting = {
@@ -1048,6 +1657,15 @@ export type IrCrewV0 = {
1048
1657
  readonly compaction: IrCompaction;
1049
1658
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
1050
1659
  readonly failureTaxonomy?: IrFailureTaxonomy;
1660
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1661
+ * to this shape). Optional. */
1662
+ readonly budget?: IrBudget;
1663
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. The crew shape is
1664
+ * the one place `limits.crew` (orchestration ceilings) can be populated.
1665
+ * Optional. */
1666
+ readonly limits?: IrLimits;
1667
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1668
+ readonly hooks?: readonly IrHook[];
1051
1669
  /** #53/v0.3.0 — cross-session memory config (crew joins the carrying
1052
1670
  * shapes in 0.3.0; roles share the spec-scoped store). Optional. */
1053
1671
  readonly memory?: IrMemory;
@@ -1061,6 +1679,10 @@ export type IrCrewV0 = {
1061
1679
  /** v0.3.0 Goal 2 — continual-learning config (§3.3, PR 17). Present
1062
1680
  * when the spec declares an enabled `learning:` block. */
1063
1681
  readonly learning?: IrLearning;
1682
+ /** Loop contract 0.4 (Batch C, G26) — observability subscriber/exporter
1683
+ * controls (+ item-37 SLO targets). Optional; absent when the spec omits
1684
+ * the `observability` block. */
1685
+ readonly observability?: IrObservability;
1064
1686
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
1065
1687
  readonly chains?: readonly IrChainBinding[];
1066
1688
  readonly wallets?: readonly IrWalletBinding[];
@@ -1082,6 +1704,9 @@ export type IrResearchV0 = {
1082
1704
  readonly agent: {
1083
1705
  readonly model: string;
1084
1706
  readonly instructions: string;
1707
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1708
+ * Optional; when absent the runtime default applies. */
1709
+ readonly maxTokens?: number;
1085
1710
  /** Adaptive model routing — N-candidate pool. Absent → single-model. */
1086
1711
  readonly modelPool?: IrModelPool;
1087
1712
  };
@@ -1106,6 +1731,13 @@ export type IrResearchV0 = {
1106
1731
  readonly compaction: IrCompaction;
1107
1732
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
1108
1733
  readonly failureTaxonomy?: IrFailureTaxonomy;
1734
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1735
+ * to this shape). Optional. */
1736
+ readonly budget?: IrBudget;
1737
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1738
+ readonly limits?: IrLimits;
1739
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1740
+ readonly hooks?: readonly IrHook[];
1109
1741
  /** #53 cross-session memory config. Optional; absent when the spec omits `memory`. */
1110
1742
  readonly memory?: IrMemory;
1111
1743
  /** v0.3.0 Goal 1 — continuity config. DEFAULT-ON: present unless the spec
@@ -1138,6 +1770,9 @@ export type IrBatchV0 = {
1138
1770
  readonly agent: {
1139
1771
  readonly model: string;
1140
1772
  readonly instructions: string;
1773
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1774
+ * Optional; when absent the runtime default applies. */
1775
+ readonly maxTokens?: number;
1141
1776
  /** Adaptive model routing — N-candidate pool. Absent → single-model. */
1142
1777
  readonly modelPool?: IrModelPool;
1143
1778
  };
@@ -1161,9 +1796,19 @@ export type IrBatchV0 = {
1161
1796
  readonly compaction: IrCompaction;
1162
1797
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
1163
1798
  readonly failureTaxonomy?: IrFailureTaxonomy;
1799
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1800
+ * to this shape). Optional. */
1801
+ readonly budget?: IrBudget;
1802
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1803
+ readonly limits?: IrLimits;
1804
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1805
+ readonly hooks?: readonly IrHook[];
1164
1806
  /** v0.3.0 — carried when the spec declares `continuity:` (NOT default-on
1165
1807
  * here); target-batch-worker prints the ignored-note comment. */
1166
1808
  readonly continuity?: IrContinuity;
1809
+ /** Loop contract 0.4 (Batch F) — cron/interval wake trigger for the queue
1810
+ * worker daemon. Optional. */
1811
+ readonly schedule?: IrSchedule;
1167
1812
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
1168
1813
  readonly chains?: readonly IrChainBinding[];
1169
1814
  readonly wallets?: readonly IrWalletBinding[];
@@ -1226,6 +1871,9 @@ export type IrBrowserV0 = {
1226
1871
  readonly agent: {
1227
1872
  readonly model: string;
1228
1873
  readonly instructions: string;
1874
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1875
+ * Optional; when absent the runtime default applies. */
1876
+ readonly maxTokens?: number;
1229
1877
  /** Adaptive model routing — N-candidate pool. Absent → single-model. */
1230
1878
  readonly modelPool?: IrModelPool;
1231
1879
  };
@@ -1237,6 +1885,14 @@ export type IrBrowserV0 = {
1237
1885
  };
1238
1886
  /** Optional initial URL; daemon calls driver.goto() before runChatLoop. */
1239
1887
  readonly startUrl?: string;
1888
+ /**
1889
+ * SECURITY — the spec opted in to private/loopback navigation targets
1890
+ * (`driver.allowPrivateTargets: true`). Relaxes BOTH the Navigate
1891
+ * pre-goto guard and the chromium DNS-pinning proxy for this harness,
1892
+ * never the http/https scheme allowlist. Carried only when true, so a
1893
+ * bundle that leaves it at the default stays byte-identical.
1894
+ */
1895
+ readonly allowPrivateTargets?: boolean;
1240
1896
  };
1241
1897
  /** Vision-grounding model. Defaults at lower-time to agent.model. */
1242
1898
  readonly groundingModel: string;
@@ -1247,6 +1903,13 @@ export type IrBrowserV0 = {
1247
1903
  readonly compaction: IrCompaction;
1248
1904
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
1249
1905
  readonly failureTaxonomy?: IrFailureTaxonomy;
1906
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1907
+ * to this shape). Optional. */
1908
+ readonly budget?: IrBudget;
1909
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1910
+ readonly limits?: IrLimits;
1911
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1912
+ readonly hooks?: readonly IrHook[];
1250
1913
  /** v0.3.0 — carried when the spec declares `continuity:` (NOT default-on
1251
1914
  * here); target-browser-driver prints the ignored-note comment. */
1252
1915
  readonly continuity?: IrContinuity;
@@ -1400,3 +2063,4 @@ export type Bundle = {
1400
2063
  }>;
1401
2064
  };
1402
2065
  export { type BundleReadmeOptions, type BundleReadmeSection, type CollectedSecretRefs, type EmitReadmeOptions, GENERATED_README_MARKER, collectSecretRefs, renderBundleReadme, } from "./readme";
2066
+ export { CANVAS_TARGETS, type LoopCanvas, type LoopEdge, type LoopNode, type LoopNodeKind, type LoopProjection, type LoopRing, type LoopSegment, type LoopSegmentId, NO_BUDGET_WARNING, PERCEIVE_TOOL_RE, RING_TARGETS, SEGMENT_ORDER, projectLoop, } from "./loop";