Skip to main content
A workflow that drafts content, iterates through review cycles, then gates deployment behind human approval.

review-loop.toon

name: review-and-publish
agents:
  writer:
    type: claude-code
    model: claude-opus-4-6
    subscription: true
    instructions: You are a technical writer.
  reviewer:
    type: claude-code
    model: claude-opus-4-6
    subscription: true
    instructions: You are a thorough technical reviewer.

input:
  topic: string
  targetAudience: string

steps[4]:
  - id: draft
    agent: writer
    prompt: "Write a technical article about {input.topic}\nfor {input.targetAudience}.\n\nInclude:\n- Introduction\n- Key concepts\n- Practical examples\n- Conclusion"
    output:
      title: string
      content: string

  - kind: loop
    id: review-cycle
    maxIterations: 3
    until: "{review.approved} == true"
    onMaxReached: return-last
    children[2]:
      - id: review
        agent: reviewer
        prompt: "Review the following article for accuracy, clarity, and completeness.\n\nTitle: {draft.title}\nContent: {draft.content}\n\n{loop.iteration > 1 ? 'Previous feedback was: ' + review.feedback + '\nCheck if the issues were addressed.\n' : ''}Respond with whether the article is approved and any remaining feedback."
        output:
          approved: boolean
          feedback: string
          score: number

      - id: revise
        agent: writer
        prompt: "Revise this article based on the review feedback.\n\nOriginal: {draft.content}\nFeedback: {review.feedback}\nScore: {review.score}/10"
        output:
          title: string
          content: string
        skipIf: "{review.approved}"

  - kind: approval
    id: publish-gate
    request:
      title: "Publish '{draft.title}'?"
      summary: "Review score: {review.score}/10\nIterations: {loop.iteration}"
    onDeny: fail

  - id: publish
    needs[1]: publish-gate
    run: "return {\n  url: `https://blog.example.com/${draft.title.toLowerCase().replace(/ /g, '-')}`,\n  publishedAt: new Date().toISOString(),\n};"
    output:
      url: string
      publishedAt: string

Run It

smithers run review-loop.toon --input '{"topic": "Effect in TypeScript", "targetAudience": "backend engineers"}'
The workflow will pause at the publish-gate approval. Approve it with:
smithers approve review-loop.toon --execution-id <id> --gate publish-gate --note "Looks good"

Key Patterns

  • kind: loop repeats the review/revise cycle up to 3 times
  • until: stops the loop when the reviewer approves
  • skipIf: skips revision when the review is already approved
  • Ternary expression conditionally adds previous feedback on subsequent iterations
  • kind: approval suspends execution for human review
  • onDeny: fail causes the workflow to fail if the approval is denied
  • Durable state: if the process restarts during the loop or while waiting for approval, Smithers resumes from persisted state