Skip to main content
renderFrame converts a workflow’s JSX tree into a GraphSnapshot — an XML representation and an ordered task list. It does not execute tasks, call agents, or modify the database.

Usage

import { renderFrame } from "smithers-orchestrator";
import workflow from "./workflow";

const snapshot = await renderFrame(workflow, {
  runId: "preview",
  iteration: 0,
  input: { description: "Fix authentication bug" },
  outputs: {},
});

console.log(snapshot.frameNo);       // 0
console.log(snapshot.tasks.length);  // Number of tasks in the tree
console.log(snapshot.xml);           // XML tree representation

Signature

function renderFrame<Schema>(
  workflow: SmithersWorkflow<Schema>,
  ctx: {
    runId: string;
    iteration: number;
    iterations?: Record<string, number>;
    input: object;
    outputs: object;
  },
  opts?: { baseRootDir?: string },
): Promise<GraphSnapshot>;

Context Object

FieldTypeDescription
runIdstringRun ID for the snapshot. Any string for previews.
iterationnumberCurrent loop iteration (0 for non-looping workflows).
iterationsRecord<string, number>Per-loop iteration counts, keyed by loop ID. Optional.
inputobjectInput data the workflow expects from ctx.input.
outputsobjectPreviously computed outputs by table name. {} for initial state.

Options

FieldTypeDefaultDescription
baseRootDirstringundefinedBase directory for resolving relative paths.

GraphSnapshot

type GraphSnapshot = {
  runId: string;
  frameNo: number;
  xml: XmlNode | null;
  tasks: TaskDescriptor[];
};
FieldTypeDescription
runIdstringRun ID from context.
frameNonumberAlways 0 for renderFrame.
xmlXmlNode | nullRendered XML tree, or null if empty.
tasksTaskDescriptor[]Tasks in execution order.

XmlNode

type XmlNode = XmlElement | XmlText;

type XmlElement = {
  kind: "element";
  tag: string;           // e.g. "smithers:workflow", "smithers:task"
  props: Record<string, string>;
  children: XmlNode[];
};

type XmlText = {
  kind: "text";
  text: string;
};

TaskDescriptor

type TaskDescriptor = {
  nodeId: string;
  ordinal: number;
  iteration: number;
  ralphId?: string;
  dependsOn?: string[];
  needs?: Record<string, string>;
  worktreeId?: string;
  worktreePath?: string;
  worktreeBranch?: string;

  outputTable: Table | null;
  outputTableName: string;
  outputRef?: ZodObject<any>;
  outputSchema?: ZodObject<any>;

  parallelGroupId?: string;
  parallelMaxConcurrency?: number;

  needsApproval: boolean;
  approvalMode?: "gate" | "decision";
  approvalOnDeny?: "fail" | "continue" | "skip";
  skipIf: boolean;
  retries: number;
  retryPolicy?: RetryPolicy;
  timeoutMs: number | null;
  continueOnFail: boolean;
  cachePolicy?: CachePolicy;

  agent?: AgentLike | AgentLike[];
  prompt?: string;
  staticPayload?: unknown;
  computeFn?: () => unknown | Promise<unknown>;

  label?: string;
  meta?: Record<string, unknown>;
};
FieldDescription
nodeIdid prop from <Task>.
ordinalPosition in task list (0-indexed).
iterationLoop iteration this task belongs to.
ralphIdEnclosing <Loop> ID, if any.
dependsOnNode IDs this task depends on.
needsNamed dependencies. Keys are context keys, values are node IDs.
worktreeIdGit worktree ID.
worktreePathFilesystem path to git worktree.
worktreeBranchBranch name for git worktree.
outputTableDrizzle table object for output.
outputTableNameString name of output table.
outputRefZod schema reference from output prop.
outputSchemaZod schema for validating agent output.
parallelGroupIdEnclosing <Parallel> group ID.
parallelMaxConcurrencyPer-group concurrency limit.
needsApprovalWhether task requires human approval.
approvalMode"gate" pauses before execution; "decision" records a decision.
approvalOnDenyBehavior on denial: "fail", "continue", or "skip".
skipIfWhether task is skipped.
retriesRetry attempts on failure.
retryPolicyBackoff config ({ backoff?, initialDelayMs? }).
timeoutMsPer-task timeout in ms, or null for global default.
continueOnFailWhether workflow continues on task failure.
cachePolicyCache config ({ by?, version? }).
agentAI agent(s) assigned to this task.
promptResolved prompt string.
staticPayloadStatic output data (no-agent tasks).
computeFnCallback for compute tasks.
labelHuman-readable label.
metaArbitrary metadata.

Use Cases

Previewing the Execution Graph

const snapshot = await renderFrame(workflow, {
  runId: "dry-run",
  iteration: 0,
  input: { description: "Preview" },
  outputs: {},
});

for (const task of snapshot.tasks) {
  console.log(`${task.ordinal}. [${task.nodeId}] -> ${task.outputTableName}`);
  if (task.needsApproval) console.log("   (requires approval)");
  if (task.skipIf) console.log("   (skipped)");
}

Simulating Completed Outputs

// First render: no outputs
const snap1 = await renderFrame(workflow, {
  runId: "sim",
  iteration: 0,
  input: { description: "Bug" },
  outputs: {},
});

// Second render: simulate "analyze" completing
const snap2 = await renderFrame(workflow, {
  runId: "sim",
  iteration: 0,
  input: { description: "Bug" },
  outputs: {
    analyze: [{ runId: "sim", nodeId: "analyze", iteration: 0, summary: "Found null pointer" }],
  },
});

CLI

smithers graph workflow.tsx --input '{"description": "Fix bug"}'
Prints the GraphSnapshot as JSON to stdout.