Workflow Recipes

Five copy-pasteable patterns. Each card shows the JSON, the pattern in one line, and why it matters. Click Open in builder to load it into /workflow, or grab the JSON for workflow-cli / POST /api/workflow/run.

Fan-out / synthesise

Open in builder

N independent LLM calls run concurrently, then one synthesiser sees them all.

Multi-agent specialist + lead pattern. Three different angles on the same input in roughly the time of one — the parallel batch in v0.4 makes wall-clock latency ≈ max(child latencies) instead of their sum.

Show workflow JSON (4 steps)
{
  "id": "fanout-synth",
  "name": "Fan-out then synthesise",
  "description": "Three independent reviewers run in parallel, then a lead synthesises a single verdict.",
  "inputs": {
    "input": "(your topic / code / text here)"
  },
  "steps": [
    {
      "id": "a",
      "label": "Angle A",
      "type": "llm",
      "prompt": "Analyse {{input.input}} from angle A (e.g. correctness). 3 bullets.",
      "maxTokens": 200
    },
    {
      "id": "b",
      "label": "Angle B",
      "type": "llm",
      "parallel": true,
      "prompt": "Analyse {{input.input}} from angle B (e.g. security). 3 bullets.",
      "maxTokens": 200
    },
    {
      "id": "c",
      "label": "Angle C",
      "type": "llm",
      "parallel": true,
      "prompt": "Analyse {{input.input}} from angle C (e.g. style). 3 bullets.",
      "maxTokens": 200
    },
    {
      "id": "synth",
      "label": "Synthesise",
      "type": "llm",
      "prompt": "Combine the three analyses below into a single verdict.\n\nA:\n{{a.output}}\n\nB:\n{{b.output}}\n\nC:\n{{c.output}}",
      "maxTokens": 350
    }
  ]
}

Classify → branch

Open in builder

One step labels the input, then mutually-exclusive `runIf` conditions route to the right downstream step.

A switch statement for LLMs. Cleaner than asking one prompt to handle every possible input — each branch can specialise. Combined with v0.4 parallel, three branches that don't depend on each other can fan out too.

Show workflow JSON (4 steps)
{
  "id": "classify-branch",
  "name": "Classify then branch",
  "description": "Labels input as one of three categories, runs only the matching downstream drafter.",
  "inputs": {
    "text": "(input to classify)"
  },
  "steps": [
    {
      "id": "label",
      "label": "Classify",
      "type": "llm",
      "prompt": "Classify the following as EXACTLY ONE label on one line: A, B, C.\n\n{{input.text}}",
      "temperature": 0,
      "maxTokens": 5
    },
    {
      "id": "handle-a",
      "label": "Handle case A",
      "type": "llm",
      "runIf": {
        "source": "{{label.output}}",
        "type": "contains",
        "value": "A"
      },
      "prompt": "Write a response appropriate for case A:\n{{input.text}}",
      "maxTokens": 250
    },
    {
      "id": "handle-b",
      "label": "Handle case B",
      "type": "llm",
      "runIf": {
        "source": "{{label.output}}",
        "type": "contains",
        "value": "B"
      },
      "prompt": "Write a response appropriate for case B:\n{{input.text}}",
      "maxTokens": 250
    },
    {
      "id": "handle-c",
      "label": "Handle case C",
      "type": "llm",
      "runIf": {
        "source": "{{label.output}}",
        "type": "contains",
        "value": "C"
      },
      "prompt": "Write a response appropriate for case C:\n{{input.text}}",
      "maxTokens": 250
    }
  ]
}

Fetch → summarise → verify

Open in builder

Pull external data, summarise it, assert the summary meets a contract.

Closes the loop on RAG-lite workflows. The `assert` step turns the workflow into a CI test: if the LLM hallucinates and drops a required keyword, the workflow exits non-zero.

Show workflow JSON (3 steps)
{
  "id": "fetch-summarise",
  "name": "Fetch a URL, summarise it, verify the summary",
  "description": "Fetch any HTTPS endpoint, summarise via LLM, fail if the summary doesn't contain the required keyword.",
  "inputs": {
    "url": "https://jsonplaceholder.typicode.com/posts/1",
    "keyword": "sunt"
  },
  "steps": [
    {
      "id": "page",
      "label": "Fetch URL",
      "type": "fetch",
      "url": "{{input.url}}"
    },
    {
      "id": "summary",
      "label": "Summarise",
      "type": "llm",
      "prompt": "Summarise the response below in 1-2 sentences. Preserve key words from the body.\n\n{{page.output}}",
      "maxTokens": 200
    },
    {
      "id": "verify",
      "label": "Verify",
      "type": "assert",
      "input": "{{summary.output}}",
      "assertions": [
        {
          "type": "contains",
          "value": "{{input.keyword}}"
        }
      ]
    }
  ]
}

Generate → critique → refine

Open in builder

Two-pass quality lift: a writer drafts, a critic flags issues, the writer rewrites.

Often beats a single big prompt with all the requirements stuffed in. The critic step is doing real work — it has the draft + the original requirements in context, with no obligation to defend the first attempt.

Show workflow JSON (3 steps)
{
  "id": "refine",
  "name": "Generate then refine",
  "description": "Writer produces a draft, critic flags issues, writer produces a refined v2.",
  "inputs": {
    "task": "Write a tweet announcing a new browser-side RAG feature."
  },
  "steps": [
    {
      "id": "draft",
      "label": "First draft",
      "type": "llm",
      "prompt": "Task: {{input.task}}\n\nWrite a first draft. No commentary.",
      "maxTokens": 250
    },
    {
      "id": "critique",
      "label": "Critique",
      "type": "llm",
      "prompt": "Be a brutally honest critic. List 3 specific weaknesses of the draft below given the original task.\n\nTask: {{input.task}}\n\nDraft:\n{{draft.output}}",
      "maxTokens": 250
    },
    {
      "id": "refine",
      "label": "Refined v2",
      "type": "llm",
      "prompt": "Rewrite the draft to address every critique. Output ONLY the rewritten text.\n\nTask: {{input.task}}\n\nDraft:\n{{draft.output}}\n\nCritique:\n{{critique.output}}",
      "maxTokens": 250
    }
  ]
}

Self-check via llm-judge

Open in builder

An LLM-as-judge assertion grades the previous step's output against a rubric.

Lets you fail a workflow on quality dimensions that mechanical asserts (contains/regex) can't capture — e.g. "is the tone empathetic?" or "does the answer cite the source?". Powers the auto-eval loop.

Show workflow JSON (2 steps)
{
  "id": "judge",
  "name": "LLM-as-judge gate",
  "description": "Generate an answer, then a judge asserts it satisfies a quality rubric.",
  "inputs": {
    "question": "Explain TCP slow start to a beginner in 3 sentences."
  },
  "steps": [
    {
      "id": "answer",
      "label": "Answer",
      "type": "llm",
      "prompt": "{{input.question}}",
      "maxTokens": 200
    },
    {
      "id": "judge",
      "label": "Judge",
      "type": "assert",
      "input": "{{answer.output}}",
      "assertions": [
        {
          "type": "llm-judge",
          "rubric": "Is the answer accurate, friendly, and under ~4 sentences?"
        }
      ]
    }
  ]
}

Same JSON, three runtimes.

/workflow·workflow-cli·POST /api/workflow/run