@crewhaus/ir 0.1.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/src/index.ts ADDED
@@ -0,0 +1,937 @@
1
+ /**
2
+ * v0 IR — runtime-agnostic representation, target-tagged.
3
+ * In the slice, IR shape mirrors the spec; later passes (ir-passes module)
4
+ * will perform optimization and target-specific lowering.
5
+ */
6
+ export type IrPermissionRule = {
7
+ readonly type: "alwaysAllow" | "alwaysDeny" | "alwaysAsk";
8
+ readonly pattern: string;
9
+ };
10
+
11
+ /**
12
+ * Permissions config carried through to codegen. The mode here cannot be
13
+ * "bypass" — that's enforced by the spec parser. Bypass enters via CLI flag.
14
+ */
15
+ export type IrPermissions = {
16
+ readonly mode?: "default" | "plan" | "auto";
17
+ readonly rules: readonly IrPermissionRule[];
18
+ };
19
+
20
+ /**
21
+ * MCP server configs carried through to codegen (Section 9). Lower-time
22
+ * normalisation: optional spec fields become required IR fields with
23
+ * empty defaults, so target codegen doesn't need `?? []` guards.
24
+ */
25
+ export type IrMcpStdioConfig = {
26
+ readonly transport: "stdio";
27
+ readonly command: string;
28
+ readonly args: readonly string[];
29
+ readonly env?: Readonly<Record<string, string>>;
30
+ };
31
+
32
+ export type IrMcpSseConfig = {
33
+ readonly transport: "sse";
34
+ readonly url: string;
35
+ readonly headers?: Readonly<Record<string, string>>;
36
+ };
37
+
38
+ export type IrMcpServerConfig = IrMcpStdioConfig | IrMcpSseConfig;
39
+ export type IrMcpServers = Readonly<Record<string, IrMcpServerConfig>>;
40
+
41
+ /**
42
+ * Section 13 — a sub-agent definition lowered from spec form. The map's key
43
+ * is hoisted to a `name` field for ergonomics. `tools: readonly string[]`
44
+ * mirrors `IrV0.tools`; codegen filters the parent catalog to this
45
+ * allowlist when building the child catalog. `permissions` defaults to
46
+ * `"inherit"` at lower-time when undefined; `inheritBypass` to false.
47
+ */
48
+ export type IrSubAgentDefinition = {
49
+ readonly name: string;
50
+ readonly description: string;
51
+ readonly instructions: string;
52
+ readonly tools: readonly string[];
53
+ readonly model?: string;
54
+ readonly permissions:
55
+ | "inherit"
56
+ | "scoped"
57
+ | { readonly allow: readonly string[]; readonly deny: readonly string[] };
58
+ readonly inheritBypass: boolean;
59
+ };
60
+
61
+ /**
62
+ * Section 14 — per-tool runtime config carried verbatim from the spec to
63
+ * codegen. Keys are tool names (lowercase variable name as used in
64
+ * `BUILTIN_TOOL_MAP`); values are tool-specific config blobs whose schemas
65
+ * live inside each tool package. Empty-default at lower-time so codegen
66
+ * never has to `?? {}`.
67
+ */
68
+ export type IrToolConfigs = Readonly<Record<string, unknown>>;
69
+
70
+ /**
71
+ * Section 17 — optional per-target compaction config. `model` overrides
72
+ * the model used by `compaction-autocompact` for summarisation; when
73
+ * undefined (or the whole block is undefined) the runtime defaults to
74
+ * the agent's primary model. Lower-time the spec block is normalised to
75
+ * an object so codegen never has to `?? {}`.
76
+ */
77
+ export type IrCompaction = {
78
+ readonly model?: string;
79
+ /** Pillar 2 — when true, target emitters wire `compaction-curator`
80
+ * as a pre-pass before the autocompact threshold check. The spec
81
+ * layer accepts this verbatim (validated in `packages/spec`); the
82
+ * IR holds it as an opt-in flag with no default so emitters can
83
+ * distinguish "user said false" from "user didn't say". */
84
+ readonly curate?: boolean;
85
+ /** Cosine threshold for the curator's dedupe pass. Curator's own
86
+ * default (0.92, `DEFAULT_DEDUPE_THRESHOLD` in
87
+ * `@crewhaus/compaction-curator`) applies when undefined. */
88
+ readonly dedupeThreshold?: number;
89
+ /** Top-K cap for the curator's relevance reorder. Undefined means
90
+ * reorder without trimming. */
91
+ readonly relevanceTopK?: number;
92
+ };
93
+
94
+ /**
95
+ * Section 55 (Track A) — named failure taxonomy. Cross-cutting; carried
96
+ * through to runtime-core so `recovery-engine` can consult the user's
97
+ * named classes before falling back to its built-in taxonomy.
98
+ *
99
+ * `pattern` is a substring (case-insensitive) of the error.message OR a
100
+ * `/regex/` literal — the recovery engine compiles each form once at
101
+ * spec-load time. `recovery` names which `RecoveryAction` to take.
102
+ * `hint`, when present, is what `runtime-core` appends as a synthetic
103
+ * system message on `retry`/`continue` recoveries so the model gets
104
+ * named-class self-correction guidance.
105
+ *
106
+ * Source: Natural-Language Agent Harnesses (arxiv 2603.25723).
107
+ */
108
+ export type IrFailureTaxonomyEntry = {
109
+ readonly class: string;
110
+ readonly pattern: string;
111
+ readonly recovery: "retry" | "compact" | "continue" | "tombstone" | "fail";
112
+ readonly hint?: string;
113
+ };
114
+
115
+ export type IrFailureTaxonomy = readonly IrFailureTaxonomyEntry[];
116
+
117
+ /**
118
+ * Track F (Section 57) — typed message schemas (Σ) for multi-agent
119
+ * communication. Source: AgentFlow (arxiv 2604.20801). A typed graph
120
+ * DSL with well-formedness checking makes searching the full multi-
121
+ * agent design space tractable: structurally broken candidates are
122
+ * eliminated cheaply, so the search budget goes to well-formed
123
+ * harnesses only.
124
+ *
125
+ * An IrMessageSchema is a named JSON-Schema shape describing what a
126
+ * given edge in the crew/graph carries. The well-formedness pass in
127
+ * `@crewhaus/ir-passes` checks that every edge in the graph references
128
+ * either a declared schema or `untyped` (the legacy default).
129
+ */
130
+ export type IrMessageSchema = {
131
+ readonly name: string;
132
+ /** JSON Schema describing the message payload. v0 keeps it as `unknown`
133
+ * rather than typed-importing zod-to-json-schema — the wellformedness
134
+ * pass only checks that the schema is an object; full validation
135
+ * happens at runtime in `@crewhaus/runtime-core`. */
136
+ readonly schema: Readonly<Record<string, unknown>>;
137
+ };
138
+
139
+ /**
140
+ * Per-edge schema reference. `untyped` means "any payload" (the v0
141
+ * default that preserves backwards compatibility). Named references
142
+ * must match one of the variant's `messageSchemas` entries.
143
+ */
144
+ export type IrSchemaRef =
145
+ | { readonly kind: "untyped" }
146
+ | { readonly kind: "named"; readonly name: string };
147
+
148
+ /**
149
+ * Phase 3 §3.3 — CLI banner config carried into IR for codegen.
150
+ */
151
+ export type IrCliBanner = {
152
+ readonly taglineMode: "static" | "random";
153
+ readonly taglines: readonly string[];
154
+ };
155
+
156
+ export type IrCliOptions = {
157
+ readonly banner?: IrCliBanner;
158
+ /** Phase 2 M2.2 — TUI mode gate. */
159
+ readonly tui?: "basic" | "rich";
160
+ };
161
+
162
+ export type IrV0 = {
163
+ readonly version: 0;
164
+ readonly name: string;
165
+ readonly target: "cli";
166
+ readonly agent: {
167
+ readonly model: string;
168
+ readonly instructions: string;
169
+ };
170
+ readonly tools: readonly string[];
171
+ readonly toolConfigs: IrToolConfigs;
172
+ readonly mcp_servers: IrMcpServers;
173
+ readonly permissions: IrPermissions;
174
+ readonly subAgents: readonly IrSubAgentDefinition[];
175
+ readonly compaction: IrCompaction;
176
+ readonly cli?: IrCliOptions;
177
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
178
+ readonly failureTaxonomy?: IrFailureTaxonomy;
179
+ /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
180
+ readonly chains?: readonly IrChainBinding[];
181
+ readonly wallets?: readonly IrWalletBinding[];
182
+ readonly contracts?: readonly IrContractBinding[];
183
+ readonly transactionPolicy?: IrTransactionPolicy;
184
+ };
185
+
186
+ /**
187
+ * One step in a workflow IR. `model` is resolved at lower-time
188
+ * (`step.model ?? workflow.model`) so codegen can read it directly.
189
+ */
190
+ export type IrWorkflowStep = {
191
+ readonly name: string;
192
+ readonly instructions: string;
193
+ readonly model: string;
194
+ readonly tools: readonly string[];
195
+ readonly toolConfigs: IrToolConfigs;
196
+ };
197
+
198
+ /**
199
+ * Workflow IR — a sequence of steps. Each step runs as one user→assistant
200
+ * turn; the prior step's terminal assistant text is threaded into the next
201
+ * step's user message by the generated runtime (target-workflow).
202
+ */
203
+ export type IrWorkflowV0 = {
204
+ readonly version: 0;
205
+ readonly name: string;
206
+ readonly target: "workflow";
207
+ readonly steps: readonly IrWorkflowStep[];
208
+ readonly mcp_servers: IrMcpServers;
209
+ readonly permissions: IrPermissions;
210
+ /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
211
+ readonly chains?: readonly IrChainBinding[];
212
+ readonly wallets?: readonly IrWalletBinding[];
213
+ readonly contracts?: readonly IrContractBinding[];
214
+ readonly transactionPolicy?: IrTransactionPolicy;
215
+ readonly compaction: IrCompaction;
216
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
217
+ readonly failureTaxonomy?: IrFailureTaxonomy;
218
+ };
219
+
220
+ /**
221
+ * A secret value referenced by a channel config (Section 12). Lower-time
222
+ * normalisation: spec strings starting with `$VAR_NAME` (where VAR_NAME
223
+ * matches `[A-Z_][A-Z0-9_]*`) become `{ kind: "env", name }`, anything else
224
+ * becomes `{ kind: "literal", value }`. Codegen emits literals as quoted
225
+ * strings and env-refs as `process.env.VAR_NAME`, plus a startup check
226
+ * that exits non-zero when a referenced env var is unset.
227
+ */
228
+ export type IrSecretRef =
229
+ | { readonly kind: "literal"; readonly value: string }
230
+ | { readonly kind: "env"; readonly name: string };
231
+
232
+ /**
233
+ * Section 47 — Blockchain primitives (cross-cutting subsystem).
234
+ *
235
+ * These types are shared across shapes that interact with chain state.
236
+ * Any shape may declare optional `chains` / `wallets` / `contracts` /
237
+ * `transactionPolicy` blocks; the §47 `onchain` and `onchain-game`
238
+ * target variants additionally require `triggers` and a `game` block
239
+ * respectively (those types land with slice 2).
240
+ *
241
+ * Finality policy is encoded explicitly because reorg tolerance and
242
+ * confirmation counts are quality knobs (Pillar 2: optimizable) and
243
+ * security boundaries (Pillar 3: a wrong finality choice lets an
244
+ * attacker present a reorged log as real). See [recipes/47-onchain-daemon-and-game.md](https://github.com/crewhaus/demos/blob/main/walkthroughs/47-onchain-daemon-and-game.md).
245
+ */
246
+ export type IrChainFinality =
247
+ | { readonly kind: "confirmations"; readonly count: number }
248
+ | { readonly kind: "finalized" }
249
+ | { readonly kind: "safe" };
250
+
251
+ /**
252
+ * Resolved chain config. `kind: "evm"` is the only supported family in
253
+ * slice 0/1/2 — Solana, Cosmos, and Bitcoin are deferred. `rpcUrls` is
254
+ * an array of `IrSecretRef` so URLs that carry API keys (Alchemy,
255
+ * Infura) can be loaded from env at runtime. `rpcPolicy` controls how
256
+ * multiple URLs are used: `single` picks the first, `fallback` retries
257
+ * the next on error, `quorum` requires N/M agreement on critical reads.
258
+ */
259
+ export type IrChainBinding = {
260
+ readonly id: string;
261
+ readonly kind: "evm";
262
+ readonly rpcUrls: readonly IrSecretRef[];
263
+ readonly rpcPolicy: "single" | "quorum" | "fallback";
264
+ readonly finality: IrChainFinality;
265
+ readonly reorgTolerant: boolean;
266
+ };
267
+
268
+ /**
269
+ * Wallet binding — how the runtime signs transactions for `chainId`.
270
+ * `custody` declares where the key lives; `signingPolicy` declares how
271
+ * each sign request is gated. The default for any `destructive: true`
272
+ * tool that uses this wallet is `explicit-user-approval`; `policy-gated`
273
+ * defers to the §47 `transaction_policy` block; `automated` is only
274
+ * permitted when the wallet is also marked `kms` or `hsm` custody.
275
+ * `keyRef` is required for `kms` / `hsm` / `local` custody; for
276
+ * `user-controlled` (WalletConnect, MetaMask, etc.) the signing happens
277
+ * externally and `keyRef` is omitted.
278
+ */
279
+ export type IrWalletBinding = {
280
+ readonly id: string;
281
+ readonly chainId: string;
282
+ readonly custody: "user-controlled" | "kms" | "hsm" | "local";
283
+ readonly signingPolicy: "explicit-user-approval" | "policy-gated" | "automated";
284
+ readonly keyRef?: IrSecretRef;
285
+ };
286
+
287
+ /**
288
+ * Smart-contract binding. `abiRef` is a string the
289
+ * `tool-contract-gateway` (slice 1) resolves into a typed-tool set;
290
+ * supported schemes are `abi://erc20`, `abi://erc721`, `abi://erc1155`,
291
+ * and `file://path/to/abi.json`. Reads against this contract become
292
+ * `readOnly: true` tools; writes become `destructive: true` and gate
293
+ * approval automatically via `permission-engine`.
294
+ */
295
+ export type IrContractBinding = {
296
+ readonly id: string;
297
+ readonly chainId: string;
298
+ readonly address: string;
299
+ readonly abiRef: string;
300
+ };
301
+
302
+ /**
303
+ * Transaction policy — the safety floor for any tool that signs and
304
+ * broadcasts a transaction. `defaultWriteApproval: "required"` is the
305
+ * default; setting it to `"none"` is only valid when every wallet is
306
+ * `automated` custody, which the §47 IR pass enforces. `maxValueUsd`
307
+ * is an upper bound on native-token transfers (in USD, evaluated at
308
+ * sign-time via the configured price oracle); transactions exceeding
309
+ * the cap are rejected pre-broadcast. `allowedContracts` is a list of
310
+ * `IrContractBinding.id` values — destructive calls to any other
311
+ * contract are rejected. `simulationRequired: true` forces every
312
+ * destructive call through a fork-simulator before approval.
313
+ */
314
+ export type IrTransactionPolicy = {
315
+ readonly defaultWriteApproval: "required" | "policy" | "none";
316
+ readonly maxValueUsd?: number;
317
+ readonly allowedContracts: readonly string[];
318
+ readonly simulationRequired: boolean;
319
+ };
320
+
321
+ export type IrSlackConfig = {
322
+ readonly botToken: IrSecretRef;
323
+ readonly signingSecret: IrSecretRef;
324
+ readonly appToken?: IrSecretRef;
325
+ };
326
+
327
+ /**
328
+ * Section 33 — Telegram channel config. `secretToken` is the value passed
329
+ * to `setWebhook(secret_token=...)` and verified on every inbound POST
330
+ * via the `X-Telegram-Bot-Api-Secret-Token` header.
331
+ */
332
+ export type IrTelegramConfig = {
333
+ readonly botToken: IrSecretRef;
334
+ readonly secretToken: IrSecretRef;
335
+ };
336
+
337
+ /**
338
+ * Section 33 — Discord channel config. `publicKeyHex` is the bot
339
+ * application's public key (hex, 64 chars) used for Ed25519 verification
340
+ * of inbound interaction webhooks.
341
+ */
342
+ export type IrDiscordConfig = {
343
+ readonly applicationId: IrSecretRef;
344
+ readonly botToken: IrSecretRef;
345
+ readonly publicKeyHex: IrSecretRef;
346
+ };
347
+
348
+ /**
349
+ * Section 33 — WhatsApp Business Cloud API channel config.
350
+ * `phoneNumberId` is the Meta-issued phone-number id (numeric,
351
+ * stringified) the bot sends messages from. `accessToken` is the
352
+ * system-user token authorising sends. `appSecret` is the Meta app
353
+ * secret used to verify the `X-Hub-Signature-256` HMAC.
354
+ */
355
+ export type IrWhatsAppConfig = {
356
+ readonly phoneNumberId: IrSecretRef;
357
+ readonly accessToken: IrSecretRef;
358
+ readonly appSecret: IrSecretRef;
359
+ };
360
+
361
+ /**
362
+ * Section 33 — iMessage channel config (macOS host-bound). `chatDbPath`
363
+ * defaults to `~/Library/Messages/chat.db`; `cursorPath` defaults to
364
+ * `.crewhaus/imessage-cursor.json`. Both can be overridden in spec for
365
+ * tests. The adapter requires `CREWHAUS_IMESSAGE_HOST_ENABLED=1` at
366
+ * boot, so no IR-level secret is needed.
367
+ */
368
+ export type IrIMessageConfig = {
369
+ readonly chatDbPath?: IrSecretRef;
370
+ readonly cursorPath?: IrSecretRef;
371
+ };
372
+
373
+ export type IrChannels = {
374
+ readonly slack?: IrSlackConfig;
375
+ readonly telegram?: IrTelegramConfig;
376
+ readonly discord?: IrDiscordConfig;
377
+ readonly whatsapp?: IrWhatsAppConfig;
378
+ readonly imessage?: IrIMessageConfig;
379
+ };
380
+
381
+ export type IrRouting = {
382
+ readonly sessionKey: "thread" | "user" | "channel";
383
+ };
384
+
385
+ /**
386
+ * Channel IR — a long-running daemon that listens for inbound webhook events
387
+ * and runs one agent turn per inbound message. The daemon resumes per-thread
388
+ * sessions (keyed by `routing.sessionKey`) via session-store + event-log,
389
+ * appends the new message, and runs one `runChatLoop` turn.
390
+ */
391
+ /**
392
+ * Phase 3 §3.1 — heartbeat config carried into IR. `everyMs` is
393
+ * normalized from the duration-string in the spec to milliseconds at
394
+ * lower time so codegen can emit a literal numeric setInterval arg.
395
+ */
396
+ export type IrHeartbeat = {
397
+ readonly everyMs: number;
398
+ readonly instructions: string;
399
+ };
400
+
401
+ /**
402
+ * Phase 3 §3.4 — channel daemon control-UI gateway config.
403
+ */
404
+ export type IrChannelGateway = {
405
+ readonly port: number;
406
+ readonly ui: boolean;
407
+ };
408
+
409
+ export type IrChannelV0 = {
410
+ readonly version: 0;
411
+ readonly name: string;
412
+ readonly target: "channel";
413
+ readonly agent: {
414
+ readonly model: string;
415
+ readonly instructions: string;
416
+ };
417
+ readonly tools: readonly string[];
418
+ readonly toolConfigs: IrToolConfigs;
419
+ readonly channels: IrChannels;
420
+ readonly routing: IrRouting;
421
+ readonly mcp_servers: IrMcpServers;
422
+ readonly permissions: IrPermissions;
423
+ readonly subAgents: readonly IrSubAgentDefinition[];
424
+ readonly compaction: IrCompaction;
425
+ readonly heartbeat?: IrHeartbeat;
426
+ readonly gateway?: IrChannelGateway;
427
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
428
+ readonly failureTaxonomy?: IrFailureTaxonomy;
429
+ /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
430
+ readonly chains?: readonly IrChainBinding[];
431
+ readonly wallets?: readonly IrWalletBinding[];
432
+ readonly contracts?: readonly IrContractBinding[];
433
+ readonly transactionPolicy?: IrTransactionPolicy;
434
+ };
435
+
436
+ /**
437
+ * Section 20 — Managed daemon IR. Carries the agent block, the
438
+ * tenant table, and any per-tenant policy / budget overrides. The
439
+ * `target-managed` codegen consumes this to emit `daemon.ts` +
440
+ * `agent.ts` files.
441
+ */
442
+ export type IrManagedTenant = {
443
+ readonly id: string;
444
+ readonly budget: {
445
+ readonly maxInputTokens: number;
446
+ readonly maxOutputTokens: number;
447
+ };
448
+ };
449
+
450
+ export type IrManagedV0 = {
451
+ readonly version: 0;
452
+ readonly name: string;
453
+ readonly target: "managed";
454
+ readonly agent: {
455
+ readonly model: string;
456
+ readonly instructions: string;
457
+ };
458
+ readonly tenants: readonly IrManagedTenant[];
459
+ readonly permissions: IrPermissions;
460
+ readonly compaction: IrCompaction;
461
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
462
+ readonly failureTaxonomy?: IrFailureTaxonomy;
463
+ };
464
+
465
+ /**
466
+ * Section 19 — Graph IR. A `target: "graph"` spec lowers into a fixed
467
+ * set of LLM-backed nodes plus the edges that connect them.
468
+ */
469
+ export type IrGraphNode = {
470
+ readonly name: string;
471
+ readonly instructions: string;
472
+ /** Resolved at lower-time (node.model ?? graph.model). */
473
+ readonly model: string;
474
+ readonly tools: readonly string[];
475
+ readonly toolConfigs: IrToolConfigs;
476
+ /**
477
+ * When set, the node calls `ctx.requestApproval(prompt)` after the
478
+ * LLM turn and pauses the graph until `resume(checkpointId, decision)`.
479
+ */
480
+ readonly hitlPrompt?: string;
481
+ };
482
+
483
+ export type IrGraphEdge = {
484
+ readonly from: string;
485
+ readonly to: string;
486
+ /** Track F (Section 57) — typed message schema carried by this edge.
487
+ * Defaults to `{ kind: "untyped" }` (any payload) when absent. The
488
+ * ir-passes wellformedness check verifies named refs resolve. */
489
+ readonly schema?: IrSchemaRef;
490
+ };
491
+
492
+ export type IrGraphV0 = {
493
+ readonly version: 0;
494
+ readonly name: string;
495
+ readonly target: "graph";
496
+ readonly entry: string;
497
+ readonly nodes: readonly IrGraphNode[];
498
+ readonly edges: readonly IrGraphEdge[];
499
+ /** Track F (Section 57) — named message schemas referenced by edges.
500
+ * Absent means no typed edges (all `untyped` by default). */
501
+ readonly messageSchemas?: readonly IrMessageSchema[];
502
+ readonly permissions: IrPermissions;
503
+ readonly compaction: IrCompaction;
504
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
505
+ readonly failureTaxonomy?: IrFailureTaxonomy;
506
+ /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
507
+ readonly chains?: readonly IrChainBinding[];
508
+ readonly wallets?: readonly IrWalletBinding[];
509
+ readonly contracts?: readonly IrContractBinding[];
510
+ readonly transactionPolicy?: IrTransactionPolicy;
511
+ };
512
+
513
+ /**
514
+ * Section 21 — Pipeline / RAG IR. Carries the embedder + vector-store
515
+ * config + an indexing pipeline (chunker → embed → store) + the agent
516
+ * block that uses the Retrieve tool.
517
+ */
518
+ export type IrPipelineDocument = {
519
+ readonly id: string;
520
+ readonly text: string;
521
+ readonly metadata?: Readonly<Record<string, unknown>>;
522
+ };
523
+
524
+ export type IrPipelineV0 = {
525
+ readonly version: 0;
526
+ readonly name: string;
527
+ readonly target: "pipeline";
528
+ readonly agent: {
529
+ readonly model: string;
530
+ readonly instructions: string;
531
+ };
532
+ readonly retrieve: {
533
+ readonly embedderModel: string;
534
+ readonly vectorBackend: "in-memory";
535
+ readonly defaultK: number;
536
+ };
537
+ readonly indexing: {
538
+ readonly chunkStrategy: "fixed" | "semantic" | "markdown";
539
+ readonly chunkSize: number;
540
+ readonly chunkOverlap: number;
541
+ readonly documents: readonly IrPipelineDocument[];
542
+ };
543
+ readonly permissions: IrPermissions;
544
+ readonly compaction: IrCompaction;
545
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
546
+ readonly failureTaxonomy?: IrFailureTaxonomy;
547
+ };
548
+
549
+ /**
550
+ * Section 22 — CRW (multi-agent crew) IR. One role definition per entry;
551
+ * `entry` names the role that runs first; optional `routing` block carries
552
+ * either a `match` map (predicate-driven) or `llm` directive (use a model
553
+ * to pick the next role) — both lower-time placeholders today, with the
554
+ * built-in default-router behaviour preserved when both are absent.
555
+ */
556
+ export type IrCrewRole = {
557
+ readonly name: string;
558
+ /** Resolved at lower-time (`role.model ?? crew.model`). */
559
+ readonly model: string;
560
+ readonly instructions: string;
561
+ readonly tools: readonly string[];
562
+ readonly toolConfigs: IrToolConfigs;
563
+ readonly subAgents: readonly IrSubAgentDefinition[];
564
+ };
565
+
566
+ export type IrCrewRoutingKind = "match" | "llm";
567
+
568
+ export type IrCrewRouting = {
569
+ readonly kind: IrCrewRoutingKind;
570
+ /**
571
+ * Per-role match table. Only set when `kind === "match"`. Keys are
572
+ * source role names; values are simple substring matchers tested
573
+ * against the source role's terminal output to pick the next role.
574
+ */
575
+ readonly match?: Readonly<
576
+ Record<string, ReadonlyArray<{ readonly contains: string; readonly to: string }>>
577
+ >;
578
+ };
579
+
580
+ export type IrCrewV0 = {
581
+ readonly version: 0;
582
+ readonly name: string;
583
+ readonly target: "crew";
584
+ readonly entry: string;
585
+ readonly roles: readonly IrCrewRole[];
586
+ readonly routing?: IrCrewRouting;
587
+ /** Track F (Section 57) — named message schemas referenced by handoffs.
588
+ * Absent means no typed handoffs (all `untyped` by default). */
589
+ readonly messageSchemas?: readonly IrMessageSchema[];
590
+ readonly mcp_servers: IrMcpServers;
591
+ readonly permissions: IrPermissions;
592
+ readonly compaction: IrCompaction;
593
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
594
+ readonly failureTaxonomy?: IrFailureTaxonomy;
595
+ /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
596
+ readonly chains?: readonly IrChainBinding[];
597
+ readonly wallets?: readonly IrWalletBinding[];
598
+ readonly contracts?: readonly IrContractBinding[];
599
+ readonly transactionPolicy?: IrTransactionPolicy;
600
+ };
601
+
602
+ /**
603
+ * Section 23 — RES (autonomous research) IR. The compiled daemon
604
+ * decomposes `goal` into `branchingFactor` sub-questions, runs each
605
+ * branch as a single-turn agent loop, and writes a numbered-citation
606
+ * report. The agent in each branch has the standard tool catalog plus
607
+ * the auto-injected `Source(uri)` and `CiteFact(uri, snippet, ...)`
608
+ * tools from `@crewhaus/crawler` + `@crewhaus/citation-tracker`.
609
+ */
610
+ export type IrResearchV0 = {
611
+ readonly version: 0;
612
+ readonly name: string;
613
+ readonly target: "research";
614
+ readonly agent: {
615
+ readonly model: string;
616
+ readonly instructions: string;
617
+ };
618
+ /** Default research goal. The daemon's `--goal "..."` flag overrides. */
619
+ readonly goal: string;
620
+ /** How many sub-questions the planner decomposes into per run. */
621
+ readonly branchingFactor: number;
622
+ /** Soft per-run wall-clock cap. The daemon emits `[budget exceeded]` and writes a partial report. */
623
+ readonly maxDurationMs: number;
624
+ readonly retrieve: {
625
+ /** http(s) origins the crawler may fetch. Empty array denies all https. */
626
+ readonly allowedOrigins: readonly string[];
627
+ /** Absolute file:// roots the crawler may read from. Empty denies all file://. */
628
+ readonly allowedFileRoots: readonly string[];
629
+ /** Optional vector backend hint for future RAG-augmented research. */
630
+ readonly vectorBackend?: "in-memory";
631
+ };
632
+ readonly tools: readonly string[];
633
+ readonly toolConfigs: IrToolConfigs;
634
+ readonly mcp_servers: IrMcpServers;
635
+ readonly permissions: IrPermissions;
636
+ readonly compaction: IrCompaction;
637
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
638
+ readonly failureTaxonomy?: IrFailureTaxonomy;
639
+ /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
640
+ readonly chains?: readonly IrChainBinding[];
641
+ readonly wallets?: readonly IrWalletBinding[];
642
+ readonly contracts?: readonly IrContractBinding[];
643
+ readonly transactionPolicy?: IrTransactionPolicy;
644
+ };
645
+
646
+ /**
647
+ * Section 23 BATCH — queue-worker IR. The compiled daemon pulls jobs
648
+ * from the configured queue, runs the user's handler with `concurrency`
649
+ * bounded parallelism, wraps each invocation in an idempotency-key
650
+ * cache, and acks/nacks based on outcome. The handler runs the agent
651
+ * (single-turn `runChatLoop`) with the job's input as the user message.
652
+ */
653
+ export type IrBatchQueueAdapter = "in-memory" | "sqs" | "redis-streams" | "postgres";
654
+
655
+ export type IrBatchV0 = {
656
+ readonly version: 0;
657
+ readonly name: string;
658
+ readonly target: "batch";
659
+ readonly agent: {
660
+ readonly model: string;
661
+ readonly instructions: string;
662
+ };
663
+ readonly queue: {
664
+ readonly adapter: IrBatchQueueAdapter;
665
+ /** Per-domain rate-limit ms; >= 0. */
666
+ readonly visibilityTimeoutMs: number;
667
+ /** Stop renew sidecar past this; ack/nack by then. */
668
+ readonly visibilityRenewIntervalMs?: number;
669
+ /** Cap on attempts before DLQ. Default 3. */
670
+ readonly maxRetries: number;
671
+ /** When `adapter === "in-memory"`, optional seed jobs (mostly tests + smoke). */
672
+ readonly seedJobs?: readonly string[];
673
+ };
674
+ readonly concurrency: number;
675
+ readonly idempotencyWindowMs: number;
676
+ readonly tools: readonly string[];
677
+ readonly toolConfigs: IrToolConfigs;
678
+ readonly mcp_servers: IrMcpServers;
679
+ readonly permissions: IrPermissions;
680
+ readonly compaction: IrCompaction;
681
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
682
+ readonly failureTaxonomy?: IrFailureTaxonomy;
683
+ /** §47 cross-cutting blockchain subsystem (slice 0). All optional. */
684
+ readonly chains?: readonly IrChainBinding[];
685
+ readonly wallets?: readonly IrWalletBinding[];
686
+ readonly contracts?: readonly IrContractBinding[];
687
+ readonly transactionPolicy?: IrTransactionPolicy;
688
+ };
689
+
690
+ /**
691
+ * Section 24 — VOICE (realtime audio agent) IR. The compiled daemon
692
+ * opens a realtime adapter (OpenAI Realtime by default), hosts a
693
+ * call-session state machine, and runs a barge-in controller over
694
+ * inbound audio frames.
695
+ */
696
+ export type IrVoiceProvider = "openai" | "vapi";
697
+ export type IrVoiceTelephony = "twilio" | "livekit-sip" | "in-memory";
698
+
699
+ export type IrVoiceV0 = {
700
+ readonly version: 0;
701
+ readonly name: string;
702
+ readonly target: "voice";
703
+ readonly agent: {
704
+ readonly model: string;
705
+ readonly instructions: string;
706
+ };
707
+ readonly voice: {
708
+ readonly provider: IrVoiceProvider;
709
+ /** Provider-specific voice id (OpenAI: alloy, echo, …). */
710
+ readonly voiceId: string;
711
+ /** Server VAD vs caller-driven. v0 defaults to "server". */
712
+ readonly vad: "server" | "none";
713
+ /** Barge-in trigger frame count (consecutive speech frames). */
714
+ readonly bargeInTriggerFrames: number;
715
+ /** Barge-in window ms — sliding window for the trigger count. */
716
+ readonly bargeInWindowMs: number;
717
+ };
718
+ /** Optional telephony adapter wiring (Twilio, LiveKit, in-memory for the smoke). */
719
+ readonly telephony?: {
720
+ readonly provider: IrVoiceTelephony;
721
+ };
722
+ readonly tools: readonly string[];
723
+ readonly toolConfigs: IrToolConfigs;
724
+ readonly mcp_servers: IrMcpServers;
725
+ readonly permissions: IrPermissions;
726
+ readonly compaction: IrCompaction;
727
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
728
+ readonly failureTaxonomy?: IrFailureTaxonomy;
729
+ };
730
+
731
+ /**
732
+ * Section 25 — BROW (computer-use / browser driver) IR. The compiled
733
+ * daemon launches a chromium driver, registers Screenshot + Click /
734
+ * Type / Key / Scroll + FindElement tools, optionally navigates to
735
+ * `startUrl`, and runs `runChatLoop` against the user's prompt.
736
+ */
737
+ export type IrBrowserBackend = "host" | "chromium" | "remote";
738
+
739
+ export type IrBrowserV0 = {
740
+ readonly version: 0;
741
+ readonly name: string;
742
+ readonly target: "browser";
743
+ readonly agent: {
744
+ readonly model: string;
745
+ readonly instructions: string;
746
+ };
747
+ readonly driver: {
748
+ readonly backend: IrBrowserBackend;
749
+ readonly viewport: {
750
+ readonly width: number;
751
+ readonly height: number;
752
+ };
753
+ /** Optional initial URL; daemon calls driver.goto() before runChatLoop. */
754
+ readonly startUrl?: string;
755
+ };
756
+ /** Vision-grounding model. Defaults at lower-time to agent.model. */
757
+ readonly groundingModel: string;
758
+ readonly tools: readonly string[];
759
+ readonly toolConfigs: IrToolConfigs;
760
+ readonly mcp_servers: IrMcpServers;
761
+ readonly permissions: IrPermissions;
762
+ readonly compaction: IrCompaction;
763
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
764
+ readonly failureTaxonomy?: IrFailureTaxonomy;
765
+ };
766
+
767
+ /** Discriminated union over every supported target IR. */
768
+ /**
769
+ * Section 29 — IR for the EVAL target shape. Lowered from the spec's
770
+ * dataset/graders/concurrency/seed; codegen writes a single-file
771
+ * `agent.ts` that boots dataset-registry + grader-registry + eval-runner.
772
+ */
773
+ export type IrEvalV0 = {
774
+ readonly version: 0;
775
+ readonly name: string;
776
+ readonly target: "eval";
777
+ readonly agent: {
778
+ readonly model: string;
779
+ readonly instructions: string;
780
+ readonly tools: readonly string[];
781
+ };
782
+ readonly dataset: {
783
+ readonly name: string;
784
+ readonly version: string;
785
+ readonly split: "train" | "dev" | "test";
786
+ };
787
+ readonly graders: readonly {
788
+ readonly name: string;
789
+ readonly opts?: Readonly<Record<string, unknown>>;
790
+ }[];
791
+ readonly concurrency: number;
792
+ readonly seed?: number;
793
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
794
+ readonly failureTaxonomy?: IrFailureTaxonomy;
795
+ };
796
+
797
+ /**
798
+ * Section 47 — `onchain` daemon trigger. The compiled daemon listens
799
+ * for one of three trigger kinds and runs one agent turn per inbound
800
+ * event:
801
+ * - `event`: subscribe to a contract event (topic[0] = keccak of the
802
+ * event signature). The daemon decodes the event using the
803
+ * declared contract ABI and threads the decoded payload into the
804
+ * agent's user message.
805
+ * - `block`: scan new blocks at `scanIntervalMs` cadence, running
806
+ * the agent against block-level summaries. Used by treasury
807
+ * monitors and reorg detectors.
808
+ * - `address`: watch transfers/calls to or from a watched address.
809
+ * `direction` ("in" | "out" | "both") filters which side of the
810
+ * transfer fires the trigger.
811
+ */
812
+ export type IrChainTrigger =
813
+ | {
814
+ readonly kind: "event";
815
+ readonly chainId: string;
816
+ readonly contract: string;
817
+ readonly event: string;
818
+ readonly filter?: Readonly<Record<string, unknown>>;
819
+ }
820
+ | {
821
+ readonly kind: "block";
822
+ readonly chainId: string;
823
+ readonly scanIntervalMs: number;
824
+ }
825
+ | {
826
+ readonly kind: "address";
827
+ readonly chainId: string;
828
+ readonly address: string;
829
+ readonly direction: "in" | "out" | "both";
830
+ };
831
+
832
+ /**
833
+ * Section 47 — IR for the `onchain` target shape. The compiled daemon
834
+ * subscribes to the configured triggers, dedupes events by `(txHash,
835
+ * logIndex)` within `idempotencyWindowMs`, and runs one
836
+ * `runChatLoop({singleTurn: true})` per inbound trigger with the
837
+ * decoded payload as the user message. The agent has access to the
838
+ * standard tool catalog (including §47 `tool-evm` + `tool-evm-tx`) so
839
+ * it can respond with transactions, alerts, or notifications.
840
+ */
841
+ export type IrChainV0 = {
842
+ readonly version: 0;
843
+ readonly name: string;
844
+ readonly target: "onchain";
845
+ readonly agent: {
846
+ readonly model: string;
847
+ readonly instructions: string;
848
+ };
849
+ readonly chains: readonly IrChainBinding[];
850
+ readonly wallets: readonly IrWalletBinding[];
851
+ readonly contracts: readonly IrContractBinding[];
852
+ readonly transactionPolicy: IrTransactionPolicy;
853
+ readonly triggers: readonly IrChainTrigger[];
854
+ /** Dedup window for `(txHash, logIndex)` (or block height for block triggers). */
855
+ readonly idempotencyWindowMs: number;
856
+ readonly tools: readonly string[];
857
+ readonly toolConfigs: IrToolConfigs;
858
+ readonly mcp_servers: IrMcpServers;
859
+ readonly permissions: IrPermissions;
860
+ readonly compaction: IrCompaction;
861
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
862
+ readonly failureTaxonomy?: IrFailureTaxonomy;
863
+ };
864
+
865
+ /**
866
+ * Section 47 — IR for the `onchain-game` target. Models a perceive-act
867
+ * loop against a game contract: the daemon reads game state via the
868
+ * configured `stateReader` view function, runs the agent to propose a
869
+ * move, broadcasts the move as a transaction, waits for confirmation,
870
+ * and re-reads the new state. Closest analogues are `voice` (realtime
871
+ * perceive-act loop with barge-in) and `browser` (perceive-act loop
872
+ * with vision grounding). The chain-specific concerns are turn
873
+ * semantics (sync/realtime/async) and move-confirmation finality.
874
+ */
875
+ export type IrChainGameTurnSemantics = "turn-based" | "real-time" | "async";
876
+
877
+ export type IrChainGameV0 = {
878
+ readonly version: 0;
879
+ readonly name: string;
880
+ readonly target: "onchain-game";
881
+ readonly agent: {
882
+ readonly model: string;
883
+ readonly instructions: string;
884
+ };
885
+ /** Games are bound to one chain at a time; multi-chain games are rare. */
886
+ readonly chain: IrChainBinding;
887
+ /** Single player wallet. */
888
+ readonly wallet: IrWalletBinding;
889
+ readonly game: {
890
+ /** Game contract binding. */
891
+ readonly contract: IrContractBinding;
892
+ /** ABI method name for reading the full game state (a view fn). */
893
+ readonly stateReader: string;
894
+ /** Optional separate actions contract; defaults to game.contract. */
895
+ readonly actionsContract?: string;
896
+ readonly turnSemantics: IrChainGameTurnSemantics;
897
+ /** Hard cap on a move's wall-clock spend for real-time games. */
898
+ readonly moveTimeoutMs?: number;
899
+ /** Natural-language win condition the model uses to evaluate state. */
900
+ readonly objective?: string;
901
+ };
902
+ readonly transactionPolicy: IrTransactionPolicy;
903
+ readonly tools: readonly string[];
904
+ readonly toolConfigs: IrToolConfigs;
905
+ readonly mcp_servers: IrMcpServers;
906
+ readonly permissions: IrPermissions;
907
+ readonly compaction: IrCompaction;
908
+ /** Section 55 (Track A) — named failure taxonomy. Optional. */
909
+ readonly failureTaxonomy?: IrFailureTaxonomy;
910
+ };
911
+
912
+ export type IrNode =
913
+ | IrV0
914
+ | IrWorkflowV0
915
+ | IrChannelV0
916
+ | IrGraphV0
917
+ | IrManagedV0
918
+ | IrPipelineV0
919
+ | IrCrewV0
920
+ | IrResearchV0
921
+ | IrBatchV0
922
+ | IrVoiceV0
923
+ | IrBrowserV0
924
+ | IrEvalV0
925
+ | IrChainV0
926
+ | IrChainGameV0;
927
+
928
+ /**
929
+ * The output of compilation: a set of files to be written to disk by the
930
+ * bundle-packager (slice: written directly by the CLI app).
931
+ */
932
+ export type Bundle = {
933
+ readonly files: ReadonlyArray<{
934
+ readonly path: string;
935
+ readonly content: string;
936
+ }>;
937
+ };