Skip to main content
TOON workflows define their data shapes directly in the file. No Schema.Class or Model.Class boilerplate required.
Examples below omit agents: declarations and agent: fields for brevity — see Nodes for complete step syntax.

Workflow Input

The top-level input: block defines what the workflow accepts:
name: bugfix
input:
  ticketId: string
  description: string
  priority: "low" | "medium" | "high"
This compiles to the same Schema validation as the Effect builder API. Invalid input is rejected before any steps run.

Step Output

Each step declares its output shape inline:
steps[1]:
  - id: analyze
    prompt: "Analyze this bug: {input.description}"
    output:
      summary: string
      severity: "low" | "medium" | "high"
      affectedFiles: "string[]"
Smithers generates a persisted Model from this declaration and manages the SQLite storage automatically.

Field Types

TOON supports these field types:
TypeTOON SyntaxEffect Equivalent
StringstringSchema.String
NumbernumberSchema.Number
BooleanbooleanSchema.Boolean
String literal"value"Schema.Literal("value")
Union literal"a" | "b" | "c"Schema.Literal("a", "b", "c")
Array"string[]"Schema.Array(Schema.String)
Optionalstring?Schema.optional(Schema.String)
Objectnested blocknested Schema.Struct

Nested Objects

Nest objects by indenting:
steps[1]:
  - id: plan
    prompt: "Create a fix plan for: {input.description}"
    output:
      plan:
        steps: "string[]"
        estimatedHours: number
        risk: "low" | "medium" | "high"
      metadata:
        author: string?
        createdAt: string

Optional Fields

Append ? to make a field optional:
input:
  ticketId: string
  description: string
  assignee: string?
  labels: "string[]?"
Optional fields compile to Schema.optional(...) and are undefined when not provided.

Imported Schemas

For complex or shared schemas, import them from TypeScript:
imports:
  schemas[1]{from,use}:
    ./schemas.ts,"TicketInput,AnalysisOutput"

name: bugfix
input: TicketInput

steps[1]:
  - id: analyze
    prompt: "Analyze: {input.description}"
    output: AnalysisOutput
The imported types must be Schema.Class or Model.Class definitions:
// schemas.ts
import { Schema } from "effect";
import { Model } from "@effect/sql";

export class TicketInput extends Schema.Class<TicketInput>("TicketInput")({
  ticketId: Schema.String,
  description: Schema.String,
}) {}

export class AnalysisOutput extends Model.Class<AnalysisOutput>("AnalysisOutput")({
  summary: Schema.String,
  severity: Schema.Literal("low", "medium", "high"),
}) {}

Schema Reuse Across Steps

When multiple steps produce the same shape, define the schema once at the top level:
schemas:
  Review:
    approved: boolean
    feedback: string

steps[2]:
  - id: initial-review
    prompt: "Review the initial draft."
    output: Review

  - id: final-review
    prompt: "Review the final draft."
    output: Review
Smithers tracks step identity separately from model identity, so two steps can share an output schema without conflict.

Arrays of Objects

Use [] suffix on an object type:
steps[1]:
  - id: find-bugs
    prompt: "Find all bugs in {input.repo}."
    output:
      bugs:
        - file: string
          line: number
          description: string
          severity: "low" | "medium" | "high"
The - prefix under bugs: indicates an array of objects.

Validation

TOON schemas are validated at two points:
  1. Build time — the .toon file is parsed and schema definitions are checked for valid types
  2. Runtime — workflow input is validated against the input schema, and step outputs are validated against output schemas before persistence
Invalid data fails fast with clear error messages pointing to the TOON file location.

Next Steps

  • Nodes — Define steps, sequences, parallels, and more.
  • Prompts — Interpolate schema fields into prompts.
  • Imports — Import schemas from TypeScript modules.