/** * Frozen Workflow v2 definition schema retained only for offline migration * and archive verification. It is not executable after the v2 retirement. * Canonical JSON shape for historical v0/v0.2 workflows * (see /tmp/wf-ui-v0.md §3 for the spec). * * Two node types: * - subagent — runtime spawns the bot's worker, feeds `prompt`, * collects `output` JSON. * - hostExecutor — runtime calls the executor registered by `executor`. * * The schema enforces shape; cross-field invariants (deps reachability, * no cycles) are checked by `parseWorkflowDefinition`. The `revisionId` * helper computes a content hash over canonical JSON so semantically * equal definitions get identical ids regardless of key ordering. */ import { z } from 'zod'; export { canonicalJsonStringify } from '../utils/canonical-json.js'; export declare const ParamDefSchema: z.ZodObject<{ type: z.ZodEnum<["string", "number", "boolean", "object", "array"]>; format: z.ZodOptional; required: z.ZodOptional; default: z.ZodOptional; description: z.ZodOptional; }, "strip", z.ZodTypeAny, { type: "string" | "number" | "boolean" | "object" | "array"; default?: unknown; required?: boolean | undefined; description?: string | undefined; format?: string | undefined; }, { type: "string" | "number" | "boolean" | "object" | "array"; default?: unknown; required?: boolean | undefined; description?: string | undefined; format?: string | undefined; }>; export type ParamDef = z.infer; export declare const RetryPolicySchema: z.ZodObject<{ maxAttempts: z.ZodNumber; backoff: z.ZodEnum<["fixed", "exponential"]>; baseMs: z.ZodNumber; factor: z.ZodOptional; jitter: z.ZodOptional; }, "strip", z.ZodTypeAny, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }>; export type RetryPolicy = z.infer; /** * Output binding — `{ "$ref": ".output." }` references the * `output` of another node's most recent successful work activity. * * Hard constraints (all enforced at parse time): * - Object MUST be exactly one key (`$ref`), strict — no extra fields. * Half-parsed mixed objects are a footgun: callers might forget the * `$ref` key and silently get a literal object instead of resolved data. * - `$ref` must be a non-empty string; runtime `resolveRef` then enforces * the `.output.` separator + path-segment safety (no `__proto__` etc). */ export declare const OutputRefSpecSchema: z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>; export type OutputRefSpec = z.infer; /** A string field that may either be a literal or a single `$ref`. */ export declare const BoundStringSchema: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; export type BoundString = z.infer; /** * Recursive JSON allowing `OutputRefSpec` to appear at any leaf or sub-tree. * * Refusal rule for non-strict `$ref`-bearing objects: an object that has a * `$ref` key MUST be an exact strict `OutputRefSpec`. Mixing `$ref` with * other keys is rejected at parse time to keep `$ref` a reserved form. */ export declare const BoundJsonValueSchema: z.ZodType; export declare const HumanGateSchema: z.ZodObject<{ stage: z.ZodLiteral<"before">; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>; export type HumanGate = z.infer; export declare const OutputSchemaSchema: z.ZodRecord; export declare const SubagentNodeSchema: z.ZodObject<{ type: z.ZodLiteral<"subagent">; bot: z.ZodString; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; workingDir: z.ZodOptional; modelOverrides: z.ZodOptional; reasoningEffort: z.ZodOptional; }, "strip", z.ZodTypeAny, { model?: string | undefined; reasoningEffort?: string | undefined; }, { model?: string | undefined; reasoningEffort?: string | undefined; }>>; toolPolicy: z.ZodOptional>; deny: z.ZodOptional>; }, "strip", z.ZodTypeAny, { deny?: string[] | undefined; allow?: string[] | undefined; }, { deny?: string[] | undefined; allow?: string[] | undefined; }>>; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodOptional; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>>; retryPolicy: z.ZodOptional; baseMs: z.ZodNumber; factor: z.ZodOptional; jitter: z.ZodOptional; }, "strip", z.ZodTypeAny, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }>>; timeoutMs: z.ZodOptional; maxOutputBytes: z.ZodOptional; outputSchema: z.ZodOptional>; /** * Opt-in escape hatch for a side-effect hostExecutor node that *must* run * without a humanGate (e.g. a system-internal cron tick, an explicitly * batched send-all script). Default is unset / false → validator rejects * ungated side-effect executors at parse time (`SIDE_EFFECT_EXECUTORS`). * * Setting this to `true` is the workflow author's audit-trail: "I know * this node sends a message / writes to repo / schedules a cron with no * human approval — accept the risk." Prefer `humanGate` whenever the * intent is "let an operator confirm before this fires." */ unsafeAllowUngated: z.ZodOptional; }, "strip", z.ZodTypeAny, { type: "subagent"; prompt: string | { $ref: string; }; bot: string; workingDir?: string | undefined; description?: string | undefined; timeoutMs?: number | undefined; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; modelOverrides?: { model?: string | undefined; reasoningEffort?: string | undefined; } | undefined; toolPolicy?: { deny?: string[] | undefined; allow?: string[] | undefined; } | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }, { type: "subagent"; prompt: string | { $ref: string; }; bot: string; workingDir?: string | undefined; description?: string | undefined; timeoutMs?: number | undefined; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; modelOverrides?: { model?: string | undefined; reasoningEffort?: string | undefined; } | undefined; toolPolicy?: { deny?: string[] | undefined; allow?: string[] | undefined; } | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }>; export type SubagentNode = z.infer; export declare const HostExecutorNodeSchema: z.ZodObject<{ type: z.ZodLiteral<"hostExecutor">; executor: z.ZodString; input: z.ZodType; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodOptional; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>>; retryPolicy: z.ZodOptional; baseMs: z.ZodNumber; factor: z.ZodOptional; jitter: z.ZodOptional; }, "strip", z.ZodTypeAny, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }>>; timeoutMs: z.ZodOptional; maxOutputBytes: z.ZodOptional; outputSchema: z.ZodOptional>; /** * Opt-in escape hatch for a side-effect hostExecutor node that *must* run * without a humanGate (e.g. a system-internal cron tick, an explicitly * batched send-all script). Default is unset / false → validator rejects * ungated side-effect executors at parse time (`SIDE_EFFECT_EXECUTORS`). * * Setting this to `true` is the workflow author's audit-trail: "I know * this node sends a message / writes to repo / schedules a cron with no * human approval — accept the risk." Prefer `humanGate` whenever the * intent is "let an operator confirm before this fires." */ unsafeAllowUngated: z.ZodOptional; }, "strip", z.ZodTypeAny, { type: "hostExecutor"; executor: string; description?: string | undefined; timeoutMs?: number | undefined; input?: unknown; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }, { type: "hostExecutor"; executor: string; description?: string | undefined; timeoutMs?: number | undefined; input?: unknown; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }>; export type HostExecutorNode = z.infer; /** * Executors that produce externally-visible side effects: sending a Feishu * message, scheduling a botmux cron task, etc. Validator requires a * `humanGate.stage='before'` on any node using one of these executors, or * an explicit `unsafeAllowUngated: true` opt-in (see NodeBaseShape). * * Add new executors here as they're registered with the dispatch table — * keep this list in lockstep with `runtime.ts`'s side-effect executor * registrations. Read-only / pure-computation executors do NOT belong * here; only ones whose execution is observable outside the workflow. */ export declare const SIDE_EFFECT_EXECUTORS: ReadonlySet; export declare function isSideEffectExecutor(executor: string): boolean; export declare const LoopOutputProjectionSchema: z.ZodObject<{ from: z.ZodString; }, "strict", z.ZodTypeAny, { from: string; }, { from: string; }>; export type LoopOutputProjection = z.infer; export declare const LoopNodeSchema: z.ZodObject<{ type: z.ZodLiteral<"loop">; description: z.ZodOptional; depends: z.ZodOptional>; maxIterations: z.ZodNumber; body: z.ZodArray; terminate: z.ZodObject<{ node: z.ZodString; via: z.ZodLiteral<"humanGate">; }, "strict", z.ZodTypeAny, { node: string; via: "humanGate"; }, { node: string; via: "humanGate"; }>; output: z.ZodOptional>; }, "strict", z.ZodTypeAny, { type: "loop"; body: string[]; maxIterations: number; terminate: { node: string; via: "humanGate"; }; output?: { from: string; } | undefined; description?: string | undefined; depends?: string[] | undefined; }, { type: "loop"; body: string[]; maxIterations: number; terminate: { node: string; via: "humanGate"; }; output?: { from: string; } | undefined; description?: string | undefined; depends?: string[] | undefined; }>; export type LoopNode = z.infer; export declare const DecisionNodeSchema: z.ZodObject<{ type: z.ZodLiteral<"decision">; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodObject<{ stage: z.ZodLiteral<"before">; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>; }, "strict", z.ZodTypeAny, { type: "decision"; humanGate: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }; description?: string | undefined; depends?: string[] | undefined; }, { type: "decision"; humanGate: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }; description?: string | undefined; depends?: string[] | undefined; }>; export type DecisionNode = z.infer; export declare const WorkflowNodeSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{ type: z.ZodLiteral<"subagent">; bot: z.ZodString; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; workingDir: z.ZodOptional; modelOverrides: z.ZodOptional; reasoningEffort: z.ZodOptional; }, "strip", z.ZodTypeAny, { model?: string | undefined; reasoningEffort?: string | undefined; }, { model?: string | undefined; reasoningEffort?: string | undefined; }>>; toolPolicy: z.ZodOptional>; deny: z.ZodOptional>; }, "strip", z.ZodTypeAny, { deny?: string[] | undefined; allow?: string[] | undefined; }, { deny?: string[] | undefined; allow?: string[] | undefined; }>>; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodOptional; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>>; retryPolicy: z.ZodOptional; baseMs: z.ZodNumber; factor: z.ZodOptional; jitter: z.ZodOptional; }, "strip", z.ZodTypeAny, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }>>; timeoutMs: z.ZodOptional; maxOutputBytes: z.ZodOptional; outputSchema: z.ZodOptional>; /** * Opt-in escape hatch for a side-effect hostExecutor node that *must* run * without a humanGate (e.g. a system-internal cron tick, an explicitly * batched send-all script). Default is unset / false → validator rejects * ungated side-effect executors at parse time (`SIDE_EFFECT_EXECUTORS`). * * Setting this to `true` is the workflow author's audit-trail: "I know * this node sends a message / writes to repo / schedules a cron with no * human approval — accept the risk." Prefer `humanGate` whenever the * intent is "let an operator confirm before this fires." */ unsafeAllowUngated: z.ZodOptional; }, "strip", z.ZodTypeAny, { type: "subagent"; prompt: string | { $ref: string; }; bot: string; workingDir?: string | undefined; description?: string | undefined; timeoutMs?: number | undefined; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; modelOverrides?: { model?: string | undefined; reasoningEffort?: string | undefined; } | undefined; toolPolicy?: { deny?: string[] | undefined; allow?: string[] | undefined; } | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }, { type: "subagent"; prompt: string | { $ref: string; }; bot: string; workingDir?: string | undefined; description?: string | undefined; timeoutMs?: number | undefined; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; modelOverrides?: { model?: string | undefined; reasoningEffort?: string | undefined; } | undefined; toolPolicy?: { deny?: string[] | undefined; allow?: string[] | undefined; } | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }>, z.ZodObject<{ type: z.ZodLiteral<"hostExecutor">; executor: z.ZodString; input: z.ZodType; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodOptional; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>>; retryPolicy: z.ZodOptional; baseMs: z.ZodNumber; factor: z.ZodOptional; jitter: z.ZodOptional; }, "strip", z.ZodTypeAny, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }>>; timeoutMs: z.ZodOptional; maxOutputBytes: z.ZodOptional; outputSchema: z.ZodOptional>; /** * Opt-in escape hatch for a side-effect hostExecutor node that *must* run * without a humanGate (e.g. a system-internal cron tick, an explicitly * batched send-all script). Default is unset / false → validator rejects * ungated side-effect executors at parse time (`SIDE_EFFECT_EXECUTORS`). * * Setting this to `true` is the workflow author's audit-trail: "I know * this node sends a message / writes to repo / schedules a cron with no * human approval — accept the risk." Prefer `humanGate` whenever the * intent is "let an operator confirm before this fires." */ unsafeAllowUngated: z.ZodOptional; }, "strip", z.ZodTypeAny, { type: "hostExecutor"; executor: string; description?: string | undefined; timeoutMs?: number | undefined; input?: unknown; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }, { type: "hostExecutor"; executor: string; description?: string | undefined; timeoutMs?: number | undefined; input?: unknown; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }>, z.ZodObject<{ type: z.ZodLiteral<"loop">; description: z.ZodOptional; depends: z.ZodOptional>; maxIterations: z.ZodNumber; body: z.ZodArray; terminate: z.ZodObject<{ node: z.ZodString; via: z.ZodLiteral<"humanGate">; }, "strict", z.ZodTypeAny, { node: string; via: "humanGate"; }, { node: string; via: "humanGate"; }>; output: z.ZodOptional>; }, "strict", z.ZodTypeAny, { type: "loop"; body: string[]; maxIterations: number; terminate: { node: string; via: "humanGate"; }; output?: { from: string; } | undefined; description?: string | undefined; depends?: string[] | undefined; }, { type: "loop"; body: string[]; maxIterations: number; terminate: { node: string; via: "humanGate"; }; output?: { from: string; } | undefined; description?: string | undefined; depends?: string[] | undefined; }>, z.ZodObject<{ type: z.ZodLiteral<"decision">; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodObject<{ stage: z.ZodLiteral<"before">; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>; }, "strict", z.ZodTypeAny, { type: "decision"; humanGate: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }; description?: string | undefined; depends?: string[] | undefined; }, { type: "decision"; humanGate: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }; description?: string | undefined; depends?: string[] | undefined; }>]>; export type WorkflowNode = z.infer; /** * Node id constraint: safe path segment for use in activityId and the * artifact sidecar path (UI doc §A: `runs//attempts//...`). * Disallow `/`, `..`, whitespace, etc. so a maliciously authored or * imported workflow cannot escape the run directory. */ export declare const NODE_ID_PATTERN: RegExp; export declare const WorkflowDefinitionSchema: z.ZodObject<{ workflowId: z.ZodString; version: z.ZodNumber; params: z.ZodOptional; format: z.ZodOptional; required: z.ZodOptional; default: z.ZodOptional; description: z.ZodOptional; }, "strip", z.ZodTypeAny, { type: "string" | "number" | "boolean" | "object" | "array"; default?: unknown; required?: boolean | undefined; description?: string | undefined; format?: string | undefined; }, { type: "string" | "number" | "boolean" | "object" | "array"; default?: unknown; required?: boolean | undefined; description?: string | undefined; format?: string | undefined; }>>>; defaults: z.ZodOptional; baseMs: z.ZodNumber; factor: z.ZodOptional; jitter: z.ZodOptional; }, "strip", z.ZodTypeAny, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }>>; timeoutMs: z.ZodOptional; maxOutputBytes: z.ZodOptional; /** * Cap on concurrent dispatch actions (dispatchGate + dispatchWork) * within a single runLoop tick. v0.1.3 first-cut parallelism defaults * to 4 — small enough that a wide fan-out won't immediately exhaust * worker / OOM headroom, large enough that ~typical 2-3 branch DAGs * fully parallelize. Set higher on workflows that want more throughput. * * Per-bot serialization is independent of this cap; same-bot siblings * still get dispatched one-per-tick regardless of the limit. */ maxConcurrency: z.ZodOptional; }, "strip", z.ZodTypeAny, { timeoutMs?: number | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; maxConcurrency?: number | undefined; }, { timeoutMs?: number | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; maxConcurrency?: number | undefined; }>>; nodes: z.ZodRecord; bot: z.ZodString; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; workingDir: z.ZodOptional; modelOverrides: z.ZodOptional; reasoningEffort: z.ZodOptional; }, "strip", z.ZodTypeAny, { model?: string | undefined; reasoningEffort?: string | undefined; }, { model?: string | undefined; reasoningEffort?: string | undefined; }>>; toolPolicy: z.ZodOptional>; deny: z.ZodOptional>; }, "strip", z.ZodTypeAny, { deny?: string[] | undefined; allow?: string[] | undefined; }, { deny?: string[] | undefined; allow?: string[] | undefined; }>>; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodOptional; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>>; retryPolicy: z.ZodOptional; baseMs: z.ZodNumber; factor: z.ZodOptional; jitter: z.ZodOptional; }, "strip", z.ZodTypeAny, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }>>; timeoutMs: z.ZodOptional; maxOutputBytes: z.ZodOptional; outputSchema: z.ZodOptional>; /** * Opt-in escape hatch for a side-effect hostExecutor node that *must* run * without a humanGate (e.g. a system-internal cron tick, an explicitly * batched send-all script). Default is unset / false → validator rejects * ungated side-effect executors at parse time (`SIDE_EFFECT_EXECUTORS`). * * Setting this to `true` is the workflow author's audit-trail: "I know * this node sends a message / writes to repo / schedules a cron with no * human approval — accept the risk." Prefer `humanGate` whenever the * intent is "let an operator confirm before this fires." */ unsafeAllowUngated: z.ZodOptional; }, "strip", z.ZodTypeAny, { type: "subagent"; prompt: string | { $ref: string; }; bot: string; workingDir?: string | undefined; description?: string | undefined; timeoutMs?: number | undefined; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; modelOverrides?: { model?: string | undefined; reasoningEffort?: string | undefined; } | undefined; toolPolicy?: { deny?: string[] | undefined; allow?: string[] | undefined; } | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }, { type: "subagent"; prompt: string | { $ref: string; }; bot: string; workingDir?: string | undefined; description?: string | undefined; timeoutMs?: number | undefined; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; modelOverrides?: { model?: string | undefined; reasoningEffort?: string | undefined; } | undefined; toolPolicy?: { deny?: string[] | undefined; allow?: string[] | undefined; } | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }>, z.ZodObject<{ type: z.ZodLiteral<"hostExecutor">; executor: z.ZodString; input: z.ZodType; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodOptional; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>>; retryPolicy: z.ZodOptional; baseMs: z.ZodNumber; factor: z.ZodOptional; jitter: z.ZodOptional; }, "strip", z.ZodTypeAny, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }, { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; }>>; timeoutMs: z.ZodOptional; maxOutputBytes: z.ZodOptional; outputSchema: z.ZodOptional>; /** * Opt-in escape hatch for a side-effect hostExecutor node that *must* run * without a humanGate (e.g. a system-internal cron tick, an explicitly * batched send-all script). Default is unset / false → validator rejects * ungated side-effect executors at parse time (`SIDE_EFFECT_EXECUTORS`). * * Setting this to `true` is the workflow author's audit-trail: "I know * this node sends a message / writes to repo / schedules a cron with no * human approval — accept the risk." Prefer `humanGate` whenever the * intent is "let an operator confirm before this fires." */ unsafeAllowUngated: z.ZodOptional; }, "strip", z.ZodTypeAny, { type: "hostExecutor"; executor: string; description?: string | undefined; timeoutMs?: number | undefined; input?: unknown; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }, { type: "hostExecutor"; executor: string; description?: string | undefined; timeoutMs?: number | undefined; input?: unknown; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; }>, z.ZodObject<{ type: z.ZodLiteral<"loop">; description: z.ZodOptional; depends: z.ZodOptional>; maxIterations: z.ZodNumber; body: z.ZodArray; terminate: z.ZodObject<{ node: z.ZodString; via: z.ZodLiteral<"humanGate">; }, "strict", z.ZodTypeAny, { node: string; via: "humanGate"; }, { node: string; via: "humanGate"; }>; output: z.ZodOptional>; }, "strict", z.ZodTypeAny, { type: "loop"; body: string[]; maxIterations: number; terminate: { node: string; via: "humanGate"; }; output?: { from: string; } | undefined; description?: string | undefined; depends?: string[] | undefined; }, { type: "loop"; body: string[]; maxIterations: number; terminate: { node: string; via: "humanGate"; }; output?: { from: string; } | undefined; description?: string | undefined; depends?: string[] | undefined; }>, z.ZodObject<{ type: z.ZodLiteral<"decision">; description: z.ZodOptional; depends: z.ZodOptional>; humanGate: z.ZodObject<{ stage: z.ZodLiteral<"before">; prompt: z.ZodUnion<[z.ZodString, z.ZodObject<{ $ref: z.ZodString; }, "strict", z.ZodTypeAny, { $ref: string; }, { $ref: string; }>]>; approvers: z.ZodOptional>; deadlineMs: z.ZodOptional; onTimeout: z.ZodOptional>; }, "strip", z.ZodTypeAny, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }, { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }>; }, "strict", z.ZodTypeAny, { type: "decision"; humanGate: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }; description?: string | undefined; depends?: string[] | undefined; }, { type: "decision"; humanGate: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }; description?: string | undefined; depends?: string[] | undefined; }>]>>; }, "strip", z.ZodTypeAny, { version: number; nodes: Record | undefined; maxOutputBytes?: number | undefined; modelOverrides?: { model?: string | undefined; reasoningEffort?: string | undefined; } | undefined; toolPolicy?: { deny?: string[] | undefined; allow?: string[] | undefined; } | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; } | { type: "hostExecutor"; executor: string; description?: string | undefined; timeoutMs?: number | undefined; input?: unknown; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; } | { type: "loop"; body: string[]; maxIterations: number; terminate: { node: string; via: "humanGate"; }; output?: { from: string; } | undefined; description?: string | undefined; depends?: string[] | undefined; } | { type: "decision"; humanGate: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }; description?: string | undefined; depends?: string[] | undefined; }>; workflowId: string; params?: Record | undefined; defaults?: { timeoutMs?: number | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; maxConcurrency?: number | undefined; } | undefined; }, { version: number; nodes: Record | undefined; maxOutputBytes?: number | undefined; modelOverrides?: { model?: string | undefined; reasoningEffort?: string | undefined; } | undefined; toolPolicy?: { deny?: string[] | undefined; allow?: string[] | undefined; } | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; } | { type: "hostExecutor"; executor: string; description?: string | undefined; timeoutMs?: number | undefined; input?: unknown; depends?: string[] | undefined; humanGate?: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; } | undefined; outputSchema?: Record | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; unsafeAllowUngated?: boolean | undefined; } | { type: "loop"; body: string[]; maxIterations: number; terminate: { node: string; via: "humanGate"; }; output?: { from: string; } | undefined; description?: string | undefined; depends?: string[] | undefined; } | { type: "decision"; humanGate: { stage: "before"; prompt: string | { $ref: string; }; approvers?: string[] | undefined; onTimeout?: "fail" | "success" | undefined; deadlineMs?: number | undefined; }; description?: string | undefined; depends?: string[] | undefined; }>; workflowId: string; params?: Record | undefined; defaults?: { timeoutMs?: number | undefined; maxOutputBytes?: number | undefined; retryPolicy?: { backoff: "fixed" | "exponential"; baseMs: number; maxAttempts: number; factor?: number | undefined; jitter?: boolean | undefined; } | undefined; maxConcurrency?: number | undefined; } | undefined; }>; export type WorkflowDefinition = z.infer; /** * revisionId = sha256(canonicalJsonStringify(def)). * Use the `version` field for human-readable semantic versions. */ export declare function computeRevisionId(def: WorkflowDefinition): string; /** * Schema parse + cross-field invariants: * 1. every `depends` entry references an existing node * 2. graph is acyclic * 3. at least one root node (no deps) among scheduler-visible nodes * (loop body nodes are excluded from this check — they're scheduled * by their owning loop block, not the top-level orchestrator) * 4. loop / decision cross-field invariants (see `validateLoopBlocks`) * * Throws on any failure. Use `WorkflowDefinitionSchema.safeParse(...)` * directly if you only need shape checks (no graph validation). */ export declare function parseWorkflowDefinition(raw: unknown): WorkflowDefinition; /** * Loop / decision cross-field validation (v0.2; see /tmp/wf-loop-v02.md §3.4). * * Returns the set of node ids that belong to some loop's body, so the * caller (`validateGraph`) can scope the root-existence check to * scheduler-visible nodes only. * * Throws on any rule violation. Error messages always include the * offending loopId + nodeId so workflow-create skills and authors can * self-correct without re-reading the spec. */ export declare function validateLoopBlocks(def: WorkflowDefinition): Set; /** * Kahn's algorithm. Returns nodeIds in dispatch-safe order (deps before * dependents). Ties broken by `Object.keys(nodes)` insertion order so * the result is deterministic for a given workflow JSON. * * Assumes the graph is valid (no cycles); call `parseWorkflowDefinition` * first or pass a definition that already came from there. */ export declare function topologicalOrder(def: WorkflowDefinition): string[]; //# sourceMappingURL=definition.d.ts.map