Skip to main content
This guide builds a two-step workflow that researches a topic and then writes a report once the research output exists.

Step 1: Create the Workflow

Create workflow.tsx:
/** @jsxImportSource smithers-orchestrator */
import { createSmithers, Sequence, Task } from "smithers-orchestrator";
import { ToolLoopAgent as Agent } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";

const { Workflow, smithers, outputs } = createSmithers({
  research: z.object({
    summary: z.string(),
    keyPoints: z.array(z.string()),
  }),
  report: z.object({
    title: z.string(),
    body: z.string(),
  }),
});

const researcher = new Agent({
  model: anthropic("claude-sonnet-4-20250514"),
  instructions: "You are an expert research assistant.",
});

const writer = new Agent({
  model: anthropic("claude-sonnet-4-20250514"),
  instructions: "You are a concise technical writer.",
});

export default smithers((ctx) => {
  const research = ctx.outputMaybe(outputs.research, { nodeId: "research" });

  return (
    <Workflow name="research-report">
      <Sequence>
        <Task id="research" output={outputs.research} agent={researcher}>
          {`Research the following topic and return a summary with key points.\n\nTopic: ${ctx.input.topic}`}
        </Task>

        {research ? (
          <Task id="report" output={outputs.report} agent={writer}>
            {`Write a concise report.\n\nSummary: ${research.summary}\nKey points: ${research.keyPoints.join(", ")}`}
          </Task>
        ) : null}
      </Sequence>
    </Workflow>
  );
});
Two JSX-specific details matter here:
  • ctx.outputMaybe(...) is how the second render discovers that research has finished.
  • the report task only mounts once the research output exists.

Step 2: Run It

Create main.ts:
import { runWorkflow } from "smithers-orchestrator";
import workflow from "./workflow";

const result = await runWorkflow(workflow, {
  input: { topic: "The history of the Zig programming language" },
});

console.log(result.status);
console.log(JSON.stringify(result.output, null, 2));
Run it:
bun run main.ts

What Happened

  1. Smithers rendered the JSX tree. Only research was mounted.
  2. The research task ran, validated its output against the Zod schema, and persisted it.
  3. Smithers rendered again with that stored output available through ctx.outputMaybe(...).
  4. The report task mounted on the second render and used the research output in its prompt.

Next Steps