@crewhaus/ir 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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,52 @@ 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;
473
820
  };
474
821
  /**
475
822
  * Track F (Section 57) — typed message schemas (Σ) for multi-agent
@@ -512,8 +859,6 @@ export type IrCliBanner = {
512
859
  };
513
860
  export type IrCliOptions = {
514
861
  readonly banner?: IrCliBanner;
515
- /** Phase 2 M2.2 — TUI mode gate. */
516
- readonly tui?: "basic" | "rich";
517
862
  };
518
863
  export type IrV0 = {
519
864
  readonly version: 0;
@@ -525,6 +870,16 @@ export type IrV0 = {
525
870
  /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
526
871
  * Optional; when absent the runtime default applies. */
527
872
  readonly maxTokens?: number;
873
+ /** Loop contract 0.4 (Batch A) — extended-thinking selector (spec
874
+ * `agent.thinking`). Absent when the spec omits the block. */
875
+ readonly thinking?: IrThinking;
876
+ /** Loop contract 0.4 (Batch A) — stream partial output tokens (spec
877
+ * `agent.streaming`, cli shape only). Carried verbatim only when
878
+ * declared; absent means false. */
879
+ readonly streaming?: boolean;
880
+ /** Loop contract 0.4 (Batch A) — per-tool rate limits (spec
881
+ * `agent.rate_limits`). Absent when the spec omits the block. */
882
+ readonly rateLimits?: IrRateLimits;
528
883
  /** Item 22 — ordered failover models (spec `agent.model_fallbacks`).
529
884
  * Absent when the spec omits the block; the runtime then keeps its
530
885
  * single-adapter path. */
@@ -547,6 +902,15 @@ export type IrV0 = {
547
902
  readonly failureTaxonomy?: IrFailureTaxonomy;
548
903
  /** Item 27 — run-level spend cap + degradation ladder. Optional. */
549
904
  readonly budget?: IrBudget;
905
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional; absent
906
+ * when the spec omits the `limits` block. */
907
+ readonly limits?: IrLimits;
908
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional;
909
+ * absent when the spec omits the `hooks` block. */
910
+ readonly hooks?: readonly IrHook[];
911
+ /** Loop contract 0.4 (Batch B, G02) — in-loop output evaluation.
912
+ * Optional; absent when the spec omits the `evaluation` block. */
913
+ readonly evaluation?: IrEvaluation;
550
914
  /** Pillar 3 (FR-004) — security fabric config (intent-gate judge
551
915
  * selection). Optional; absent when the spec omits the `security`
552
916
  * block. */
@@ -555,6 +919,9 @@ export type IrV0 = {
555
919
  readonly feedback?: IrFeedback;
556
920
  /** #53 cross-session memory config. Optional; absent when the spec omits `memory`. */
557
921
  readonly memory?: IrMemory;
922
+ /** Loop contract 0.4 (Batch E, G22) — agent-shape RAG config. Present when
923
+ * the spec declares `knowledge:`; absent otherwise. */
924
+ readonly knowledge?: IrKnowledge;
558
925
  /** v0.3.0 Goal 1 — continuity config. DEFAULT-ON: present unless the spec
559
926
  * opted out with `continuity: false`. */
560
927
  readonly continuity?: IrContinuity;
@@ -567,6 +934,12 @@ export type IrV0 = {
567
934
  /** Ops item 37 — SLO targets + mitigation ladder. Optional; absent when the
568
935
  * spec omits the `observability` block. */
569
936
  readonly observability?: IrObservability;
937
+ /** Item 1 (G30) — MCP-server projection config. Present when the spec
938
+ * declares `expose.mcp`; absent otherwise. */
939
+ readonly expose?: IrExpose;
940
+ /** Item 3 (G32) — marketplace plugin names loaded at boot (`plugins:`).
941
+ * Present (non-empty) only when the spec declares them; load order. */
942
+ readonly plugins?: readonly string[];
570
943
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
571
944
  readonly chains?: readonly IrChainBinding[];
572
945
  readonly wallets?: readonly IrWalletBinding[];
@@ -576,13 +949,44 @@ export type IrV0 = {
576
949
  /**
577
950
  * One step in a workflow IR. `model` is resolved at lower-time
578
951
  * (`step.model ?? workflow.model`) so codegen can read it directly.
952
+ *
953
+ * Loop contract 0.4 (Batch B, G02) — a step may be a JUDGE GATE
954
+ * (`kind: "judge"`) over the previous step's output. Judge steps keep the
955
+ * full step shape so every existing consumer compiles and iterates
956
+ * unchanged: `instructions` carries the judge `criteria` verbatim, `model`
957
+ * is the resolved judge model (`judge.model ?? workflow.model`), and
958
+ * `tools`/`toolConfigs` are empty. Emitters/interpreters branch on
959
+ * `kind === "judge"` and read the gate config from `judge`.
579
960
  */
580
961
  export type IrWorkflowStep = {
581
962
  readonly name: string;
582
963
  readonly instructions: string;
583
964
  readonly model: string;
965
+ /** Model max OUTPUT tokens for this step's turn (spec `steps[].max_tokens`).
966
+ * Optional; when absent the runtime default applies. */
967
+ readonly maxTokens?: number;
968
+ /** Loop contract 0.4 (Batch A) — per-step extended-thinking selector
969
+ * (spec `steps[].thinking`). Absent when the spec omits the block. */
970
+ readonly thinking?: IrThinking;
584
971
  readonly tools: readonly string[];
585
972
  readonly toolConfigs: IrToolConfigs;
973
+ /** Item 9 (G37) — per-step ordered failover models (spec
974
+ * `steps[].model_fallbacks`). Absent → single-model. */
975
+ readonly modelFallbacks?: readonly string[];
976
+ /** Item 9 (G37) — per-step breaker tuning (spec `steps[].circuit_breaker`). */
977
+ readonly circuitBreaker?: IrCircuitBreaker;
978
+ /** Item 9 (G37) — per-step two-tier turn-difficulty router. Absent →
979
+ * single-model. */
980
+ readonly modelTiers?: IrModelTiers;
981
+ /** Item 9 (G37) — per-step N-candidate pool with a selection policy (a
982
+ * PolicyRouter decides per step against the shared routing-store
983
+ * scoreboard). Absent → single-model. */
984
+ readonly modelPool?: IrModelPool;
985
+ /** Loop contract 0.4 (Batch B, G02) — `"judge"` marks a gate step over
986
+ * the previous step's output. ABSENT on regular agent steps. */
987
+ readonly kind?: "judge";
988
+ /** Present iff `kind === "judge"` — the resolved gate config. */
989
+ readonly judge?: IrJudge;
586
990
  };
587
991
  /**
588
992
  * Workflow IR — a sequence of steps. Each step runs as one user→assistant
@@ -604,6 +1008,13 @@ export type IrWorkflowV0 = {
604
1008
  readonly compaction: IrCompaction;
605
1009
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
606
1010
  readonly failureTaxonomy?: IrFailureTaxonomy;
1011
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1012
+ * to this shape). Optional. */
1013
+ readonly budget?: IrBudget;
1014
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1015
+ readonly limits?: IrLimits;
1016
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1017
+ readonly hooks?: readonly IrHook[];
607
1018
  /** v0.3.0 — carried when the spec declares `continuity:` (NOT default-on
608
1019
  * here); target-workflow prints the ignored-note comment. */
609
1020
  readonly continuity?: IrContinuity;
@@ -787,6 +1198,33 @@ export type IrHeartbeat = {
787
1198
  readonly everyMs: number;
788
1199
  readonly instructions: string;
789
1200
  };
1201
+ /**
1202
+ * Loop contract 0.4 (Batch F, temporal contract / G84 schedule half) — a
1203
+ * cron OR interval wake trigger carried into the IR for the daemon-able
1204
+ * shapes (IrChannelV0, IrManagedV0, IrBatchV0). The temporal downstream
1205
+ * lowers this into the emitted daemon's wake loop; `runs resume` rehydrates
1206
+ * an interrupted scheduled run. Durations (`jitter`, interval `every`) are
1207
+ * normalized to milliseconds at lower time so codegen reads literal numbers,
1208
+ * while `cron` is carried verbatim for the daemon's cron parser. Exactly one
1209
+ * `kind` — the discriminated union mirrors the spec's `schedule:` block.
1210
+ */
1211
+ export type IrSchedule = {
1212
+ readonly kind: "cron";
1213
+ /** A 5- or 6-field cron expression, carried verbatim. */
1214
+ readonly cron: string;
1215
+ /** IANA tz the cron evaluates in; absent → the daemon's default (UTC). */
1216
+ readonly timezone?: string;
1217
+ /** Random +/- delay per wake, normalized to ms. Absent → no jitter. */
1218
+ readonly jitterMs?: number;
1219
+ /** Synthetic prompt each wake runs. Absent → the daemon's default tick. */
1220
+ readonly instructions?: string;
1221
+ } | {
1222
+ readonly kind: "interval";
1223
+ /** Wake cadence in ms (spec `every` duration, normalized at lower time). */
1224
+ readonly everyMs: number;
1225
+ readonly jitterMs?: number;
1226
+ readonly instructions?: string;
1227
+ };
790
1228
  /**
791
1229
  * Phase 3 §3.4 — channel daemon control-UI gateway config.
792
1230
  */
@@ -801,6 +1239,15 @@ export type IrChannelV0 = {
801
1239
  readonly agent: {
802
1240
  readonly model: string;
803
1241
  readonly instructions: string;
1242
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1243
+ * Optional; when absent the runtime default applies. */
1244
+ readonly maxTokens?: number;
1245
+ /** Loop contract 0.4 (Batch A) — extended-thinking selector (spec
1246
+ * `agent.thinking`). Absent when the spec omits the block. */
1247
+ readonly thinking?: IrThinking;
1248
+ /** Loop contract 0.4 (Batch A) — per-tool rate limits (spec
1249
+ * `agent.rate_limits`). Absent when the spec omits the block. */
1250
+ readonly rateLimits?: IrRateLimits;
804
1251
  /** Item 22 — ordered failover models (spec `agent.model_fallbacks`). */
805
1252
  readonly modelFallbacks?: readonly string[];
806
1253
  /** Item 22 — breaker tuning (spec `agent.circuit_breaker`). */
@@ -819,16 +1266,29 @@ export type IrChannelV0 = {
819
1266
  readonly subAgents: readonly IrSubAgentDefinition[];
820
1267
  readonly compaction: IrCompaction;
821
1268
  readonly heartbeat?: IrHeartbeat;
1269
+ /** Loop contract 0.4 (Batch F) — cron/interval wake trigger. Optional;
1270
+ * absent when the spec omits `schedule:`. */
1271
+ readonly schedule?: IrSchedule;
822
1272
  readonly gateway?: IrChannelGateway;
823
1273
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
824
1274
  readonly failureTaxonomy?: IrFailureTaxonomy;
825
1275
  /** Item 27 — run-level spend cap + degradation ladder. Optional. */
826
1276
  readonly budget?: IrBudget;
1277
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1278
+ readonly limits?: IrLimits;
1279
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1280
+ readonly hooks?: readonly IrHook[];
1281
+ /** Loop contract 0.4 (Batch B, G02) — in-loop output evaluation.
1282
+ * Optional; absent when the spec omits the `evaluation` block. */
1283
+ readonly evaluation?: IrEvaluation;
827
1284
  /** Response-feedback config. `feedback.channelReactions` gates Slack 👍/👎
828
1285
  * → user_feedback codegen in this target. Absent when spec omits it. */
829
1286
  readonly feedback?: IrFeedback;
830
1287
  /** #53 cross-session memory config. Optional; absent when the spec omits `memory`. */
831
1288
  readonly memory?: IrMemory;
1289
+ /** Loop contract 0.4 (Batch E, G22) — agent-shape RAG config. Present when
1290
+ * the spec declares `knowledge:`; absent otherwise. */
1291
+ readonly knowledge?: IrKnowledge;
832
1292
  /** v0.3.0 Goal 1 — continuity config. DEFAULT-ON: present unless the spec
833
1293
  * opted out with `continuity: false`. `scope` resolves to `session` here
834
1294
  * (per-conversation stores riding the session router's sessionId, §14.5). */
@@ -842,6 +1302,12 @@ export type IrChannelV0 = {
842
1302
  /** Ops item 37 — SLO targets + mitigation ladder. Optional; absent when the
843
1303
  * spec omits the `observability` block. */
844
1304
  readonly observability?: IrObservability;
1305
+ /** Item 1 (G30) — MCP-server projection config. Present when the spec
1306
+ * declares `expose.mcp`; absent otherwise. */
1307
+ readonly expose?: IrExpose;
1308
+ /** Item 3 (G32) — marketplace plugin names loaded at boot (`plugins:`).
1309
+ * Present (non-empty) only when the spec declares them; load order. */
1310
+ readonly plugins?: readonly string[];
845
1311
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
846
1312
  readonly chains?: readonly IrChainBinding[];
847
1313
  readonly wallets?: readonly IrWalletBinding[];
@@ -868,6 +1334,15 @@ export type IrManagedV0 = {
868
1334
  readonly agent: {
869
1335
  readonly model: string;
870
1336
  readonly instructions: string;
1337
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1338
+ * Optional; when absent the runtime default applies. */
1339
+ readonly maxTokens?: number;
1340
+ /** Loop contract 0.4 (Batch A) — extended-thinking selector (spec
1341
+ * `agent.thinking`). Absent when the spec omits the block. */
1342
+ readonly thinking?: IrThinking;
1343
+ /** Loop contract 0.4 (Batch A) — per-tool rate limits (spec
1344
+ * `agent.rate_limits`). Absent when the spec omits the block. */
1345
+ readonly rateLimits?: IrRateLimits;
871
1346
  /** Item 22 — ordered failover models (spec `agent.model_fallbacks`). */
872
1347
  readonly modelFallbacks?: readonly string[];
873
1348
  /** Item 22 — breaker tuning (spec `agent.circuit_breaker`). */
@@ -878,14 +1353,34 @@ export type IrManagedV0 = {
878
1353
  readonly modelPool?: IrModelPool;
879
1354
  };
880
1355
  readonly tenants: readonly IrManagedTenant[];
1356
+ /** Loop contract 0.4 (Batch F, G81) — tool catalog for the managed daemon.
1357
+ * Optional (absent when the spec omits `agent.tools`); the emitter reads
1358
+ * `ir.tools ?? []`. Per-tenant tool_config overlays apply at runtime via the
1359
+ * policy-engine's tenant context. */
1360
+ readonly tools?: readonly string[];
1361
+ /** Loop contract 0.4 (Batch F, G81) — builtin tool config blobs (spec
1362
+ * `agent.tool_config`). Optional; absent when the spec omits it. */
1363
+ readonly toolConfigs?: IrToolConfigs;
881
1364
  readonly permissions: IrPermissions;
882
1365
  readonly compaction: IrCompaction;
883
1366
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
884
1367
  readonly failureTaxonomy?: IrFailureTaxonomy;
885
1368
  /** Item 27 — run-level spend cap + degradation ladder. Optional. */
886
1369
  readonly budget?: IrBudget;
1370
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1371
+ readonly limits?: IrLimits;
1372
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1373
+ readonly hooks?: readonly IrHook[];
1374
+ /** Loop contract 0.4 (Batch F) — cron/interval wake trigger. Optional. */
1375
+ readonly schedule?: IrSchedule;
1376
+ /** Loop contract 0.4 (Batch B, G02) — in-loop output evaluation.
1377
+ * Optional; absent when the spec omits the `evaluation` block. */
1378
+ readonly evaluation?: IrEvaluation;
887
1379
  /** #53 cross-session memory config. Optional; absent when the spec omits `memory`. */
888
1380
  readonly memory?: IrMemory;
1381
+ /** Loop contract 0.4 (Batch E, G22) — agent-shape RAG config. Present when
1382
+ * the spec declares `knowledge:`; absent otherwise. */
1383
+ readonly knowledge?: IrKnowledge;
889
1384
  /** v0.3.0 Goal 1 — continuity config. DEFAULT-ON: present unless the spec
890
1385
  * opted out with `continuity: false`. `scope` resolves to `spec` here;
891
1386
  * every store is tenant-fenced at boot (deps carry the tenant, §2.7). */
@@ -900,6 +1395,10 @@ export type IrManagedV0 = {
900
1395
  * spec omits the `observability` block. The managed daemon's `pause-intake`
901
1396
  * rung reuses its `budget_exceeded` 429 path. */
902
1397
  readonly observability?: IrObservability;
1398
+ /** Item 1 (G30) — MCP-server projection config. Present when the spec
1399
+ * declares `expose.mcp`; absent otherwise. SSE-backed exposure rides this
1400
+ * shape's gateway-server tenancy/budgets. */
1401
+ readonly expose?: IrExpose;
903
1402
  };
904
1403
  /**
905
1404
  * Section 19 — Graph IR. A `target: "graph"` spec lowers into a fixed
@@ -910,6 +1409,12 @@ export type IrGraphNode = {
910
1409
  readonly instructions: string;
911
1410
  /** Resolved at lower-time (node.model ?? graph.model). */
912
1411
  readonly model: string;
1412
+ /** Model max OUTPUT tokens for this node's turn (spec
1413
+ * `nodes.<n>.max_tokens`). Optional; runtime default when absent. */
1414
+ readonly maxTokens?: number;
1415
+ /** Loop contract 0.4 (Batch A) — per-node extended-thinking selector
1416
+ * (spec `nodes.<n>.thinking`). Absent when the spec omits the block. */
1417
+ readonly thinking?: IrThinking;
913
1418
  readonly tools: readonly string[];
914
1419
  readonly toolConfigs: IrToolConfigs;
915
1420
  /**
@@ -917,10 +1422,36 @@ export type IrGraphNode = {
917
1422
  * LLM turn and pauses the graph until `resume(checkpointId, decision)`.
918
1423
  */
919
1424
  readonly hitlPrompt?: string;
1425
+ /** Loop contract 0.4 (Batch B, G02) — `"judge"` marks a gate node over
1426
+ * its upstream node's output. ABSENT on regular LLM nodes. Judge nodes
1427
+ * keep the full node shape (`instructions` = the judge criteria, `model`
1428
+ * = resolved `judge.model ?? graph.model`, empty `tools`) so existing
1429
+ * consumers compile unchanged; branch on `kind` and read `judge`. */
1430
+ readonly kind?: "judge";
1431
+ /** Present iff `kind === "judge"` — the resolved gate config. */
1432
+ readonly judge?: IrJudge;
1433
+ };
1434
+ /**
1435
+ * Loop contract 0.4 (Batch A) — declarative edge predicate over the graph's
1436
+ * shared state, lowered 1:1 from `edges[].when`. `key` names an upstream
1437
+ * NODE whose recorded output (`state["<nodeName>"]`) the predicate reads
1438
+ * (parse-validated; the ir-passes wellformedness check re-verifies for
1439
+ * direct-IR builders). Exactly one of `equals`/`exists` is ever present.
1440
+ * Emitters lower it onto a graph-engine `EdgeCondition`:
1441
+ * `(state) => state[key] === equals` / `(state) => state[key] !== undefined`.
1442
+ */
1443
+ export type IrGraphEdgeWhen = {
1444
+ readonly key: string;
1445
+ readonly equals?: string | number | boolean;
1446
+ readonly exists?: true;
920
1447
  };
921
1448
  export type IrGraphEdge = {
922
1449
  readonly from: string;
923
1450
  readonly to: string;
1451
+ /** Loop contract 0.4 (Batch A) — declarative predicate gating this edge.
1452
+ * Absent means the edge matches unconditionally (the engine takes the
1453
+ * first matching edge in declaration order). */
1454
+ readonly when?: IrGraphEdgeWhen;
924
1455
  /** Track F (Section 57) — typed message schema carried by this edge.
925
1456
  * Defaults to `{ kind: "untyped" }` (any payload) when absent. The
926
1457
  * ir-passes wellformedness check verifies named refs resolve. */
@@ -933,6 +1464,12 @@ export type IrGraphV0 = {
933
1464
  readonly entry: string;
934
1465
  readonly nodes: readonly IrGraphNode[];
935
1466
  readonly edges: readonly IrGraphEdge[];
1467
+ /** Loop contract 0.4 (Batch A) — parallel barrier groups (>= 2 node names
1468
+ * each), lowered verbatim from the spec's `parallel` and emitted as
1469
+ * graph-engine `addParallel` calls. A group executes concurrently when
1470
+ * the cursor reaches its FIRST member; execution continues from the LAST
1471
+ * member's outgoing edge. Absent when the spec omits the block. */
1472
+ readonly parallel?: ReadonlyArray<ReadonlyArray<string>>;
936
1473
  /** Track F (Section 57) — named message schemas referenced by edges.
937
1474
  * Absent means no typed edges (all `untyped` by default). */
938
1475
  readonly messageSchemas?: readonly IrMessageSchema[];
@@ -940,6 +1477,13 @@ export type IrGraphV0 = {
940
1477
  readonly compaction: IrCompaction;
941
1478
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
942
1479
  readonly failureTaxonomy?: IrFailureTaxonomy;
1480
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1481
+ * to this shape). Optional. */
1482
+ readonly budget?: IrBudget;
1483
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1484
+ readonly limits?: IrLimits;
1485
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1486
+ readonly hooks?: readonly IrHook[];
943
1487
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
944
1488
  readonly chains?: readonly IrChainBinding[];
945
1489
  readonly wallets?: readonly IrWalletBinding[];
@@ -1016,9 +1560,27 @@ export type IrCrewRole = {
1016
1560
  /** Resolved at lower-time (`role.model ?? crew.model`). */
1017
1561
  readonly model: string;
1018
1562
  readonly instructions: string;
1563
+ /** Model max OUTPUT tokens for this role's turns (spec
1564
+ * `roles.<r>.max_tokens`). Optional; runtime default when absent. */
1565
+ readonly maxTokens?: number;
1566
+ /** Loop contract 0.4 (Batch A) — per-role extended-thinking selector
1567
+ * (spec `roles.<r>.thinking`). Absent when the spec omits the block. */
1568
+ readonly thinking?: IrThinking;
1019
1569
  readonly tools: readonly string[];
1020
1570
  readonly toolConfigs: IrToolConfigs;
1021
1571
  readonly subAgents: readonly IrSubAgentDefinition[];
1572
+ /** Item 9 (G37) — per-role ordered failover models (spec
1573
+ * `roles.<r>.model_fallbacks`). Absent → single-model. */
1574
+ readonly modelFallbacks?: readonly string[];
1575
+ /** Item 9 (G37) — per-role breaker tuning (spec `roles.<r>.circuit_breaker`). */
1576
+ readonly circuitBreaker?: IrCircuitBreaker;
1577
+ /** Item 9 (G37) — per-role two-tier turn-difficulty router. Absent →
1578
+ * single-model. */
1579
+ readonly modelTiers?: IrModelTiers;
1580
+ /** Item 9 (G37) — per-role N-candidate pool with a selection policy (a
1581
+ * PolicyRouter decides per role against the shared routing-store
1582
+ * scoreboard). Absent → single-model. */
1583
+ readonly modelPool?: IrModelPool;
1022
1584
  };
1023
1585
  export type IrCrewRoutingKind = "match" | "llm";
1024
1586
  export type IrCrewRouting = {
@@ -1048,6 +1610,15 @@ export type IrCrewV0 = {
1048
1610
  readonly compaction: IrCompaction;
1049
1611
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
1050
1612
  readonly failureTaxonomy?: IrFailureTaxonomy;
1613
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1614
+ * to this shape). Optional. */
1615
+ readonly budget?: IrBudget;
1616
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. The crew shape is
1617
+ * the one place `limits.crew` (orchestration ceilings) can be populated.
1618
+ * Optional. */
1619
+ readonly limits?: IrLimits;
1620
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1621
+ readonly hooks?: readonly IrHook[];
1051
1622
  /** #53/v0.3.0 — cross-session memory config (crew joins the carrying
1052
1623
  * shapes in 0.3.0; roles share the spec-scoped store). Optional. */
1053
1624
  readonly memory?: IrMemory;
@@ -1061,6 +1632,10 @@ export type IrCrewV0 = {
1061
1632
  /** v0.3.0 Goal 2 — continual-learning config (§3.3, PR 17). Present
1062
1633
  * when the spec declares an enabled `learning:` block. */
1063
1634
  readonly learning?: IrLearning;
1635
+ /** Loop contract 0.4 (Batch C, G26) — observability subscriber/exporter
1636
+ * controls (+ item-37 SLO targets). Optional; absent when the spec omits
1637
+ * the `observability` block. */
1638
+ readonly observability?: IrObservability;
1064
1639
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
1065
1640
  readonly chains?: readonly IrChainBinding[];
1066
1641
  readonly wallets?: readonly IrWalletBinding[];
@@ -1082,6 +1657,9 @@ export type IrResearchV0 = {
1082
1657
  readonly agent: {
1083
1658
  readonly model: string;
1084
1659
  readonly instructions: string;
1660
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1661
+ * Optional; when absent the runtime default applies. */
1662
+ readonly maxTokens?: number;
1085
1663
  /** Adaptive model routing — N-candidate pool. Absent → single-model. */
1086
1664
  readonly modelPool?: IrModelPool;
1087
1665
  };
@@ -1106,6 +1684,13 @@ export type IrResearchV0 = {
1106
1684
  readonly compaction: IrCompaction;
1107
1685
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
1108
1686
  readonly failureTaxonomy?: IrFailureTaxonomy;
1687
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1688
+ * to this shape). Optional. */
1689
+ readonly budget?: IrBudget;
1690
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1691
+ readonly limits?: IrLimits;
1692
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1693
+ readonly hooks?: readonly IrHook[];
1109
1694
  /** #53 cross-session memory config. Optional; absent when the spec omits `memory`. */
1110
1695
  readonly memory?: IrMemory;
1111
1696
  /** v0.3.0 Goal 1 — continuity config. DEFAULT-ON: present unless the spec
@@ -1138,6 +1723,9 @@ export type IrBatchV0 = {
1138
1723
  readonly agent: {
1139
1724
  readonly model: string;
1140
1725
  readonly instructions: string;
1726
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1727
+ * Optional; when absent the runtime default applies. */
1728
+ readonly maxTokens?: number;
1141
1729
  /** Adaptive model routing — N-candidate pool. Absent → single-model. */
1142
1730
  readonly modelPool?: IrModelPool;
1143
1731
  };
@@ -1161,9 +1749,19 @@ export type IrBatchV0 = {
1161
1749
  readonly compaction: IrCompaction;
1162
1750
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
1163
1751
  readonly failureTaxonomy?: IrFailureTaxonomy;
1752
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1753
+ * to this shape). Optional. */
1754
+ readonly budget?: IrBudget;
1755
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1756
+ readonly limits?: IrLimits;
1757
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1758
+ readonly hooks?: readonly IrHook[];
1164
1759
  /** v0.3.0 — carried when the spec declares `continuity:` (NOT default-on
1165
1760
  * here); target-batch-worker prints the ignored-note comment. */
1166
1761
  readonly continuity?: IrContinuity;
1762
+ /** Loop contract 0.4 (Batch F) — cron/interval wake trigger for the queue
1763
+ * worker daemon. Optional. */
1764
+ readonly schedule?: IrSchedule;
1167
1765
  /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
1168
1766
  readonly chains?: readonly IrChainBinding[];
1169
1767
  readonly wallets?: readonly IrWalletBinding[];
@@ -1226,6 +1824,9 @@ export type IrBrowserV0 = {
1226
1824
  readonly agent: {
1227
1825
  readonly model: string;
1228
1826
  readonly instructions: string;
1827
+ /** Model max OUTPUT tokens for one turn (spec `agent.max_tokens`).
1828
+ * Optional; when absent the runtime default applies. */
1829
+ readonly maxTokens?: number;
1229
1830
  /** Adaptive model routing — N-candidate pool. Absent → single-model. */
1230
1831
  readonly modelPool?: IrModelPool;
1231
1832
  };
@@ -1247,6 +1848,13 @@ export type IrBrowserV0 = {
1247
1848
  readonly compaction: IrCompaction;
1248
1849
  /** Section 55 (Track A) — named failure taxonomy. Optional. */
1249
1850
  readonly failureTaxonomy?: IrFailureTaxonomy;
1851
+ /** Item 27 — run-level spend cap + degradation ladder (Batch A extends it
1852
+ * to this shape). Optional. */
1853
+ readonly budget?: IrBudget;
1854
+ /** Loop contract 0.4 (Batch A) — hard runtime ceilings. Optional. */
1855
+ readonly limits?: IrLimits;
1856
+ /** Loop contract 0.4 (Batch A) — spec-declared lifecycle hooks. Optional. */
1857
+ readonly hooks?: readonly IrHook[];
1250
1858
  /** v0.3.0 — carried when the spec declares `continuity:` (NOT default-on
1251
1859
  * here); target-browser-driver prints the ignored-note comment. */
1252
1860
  readonly continuity?: IrContinuity;
@@ -1400,3 +2008,4 @@ export type Bundle = {
1400
2008
  }>;
1401
2009
  };
1402
2010
  export { type BundleReadmeOptions, type BundleReadmeSection, type CollectedSecretRefs, type EmitReadmeOptions, GENERATED_README_MARKER, collectSecretRefs, renderBundleReadme, } from "./readme";
2011
+ 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";