Skip to content

Step Types

Tomas Pflanzer edited this page Feb 27, 2026 · 1 revision

Step Types

Sandcastle supports 15 step types organized in three phases. Each phase added capabilities without breaking existing workflows.

Phase 1 - Core (7 types)

standard

The default step type. Runs an AI agent in a sandbox with the given prompt. The agent can use tools, write code, browse the web, and produce structured output.

- id: analyze
  prompt: |
    Analyze the competitive landscape for {input.company_name}.
    Focus on pricing, features, and market positioning.
  model: sonnet
  max_turns: 10

llm

Direct LLM call without sandbox overhead. Faster and cheaper for pure text generation tasks where tool use isn't needed.

- id: summarize
  type: llm
  prompt: Summarize this in 3 bullet points: {steps.research.output}
  model: haiku

http

Make HTTP requests to external APIs. Supports GET, POST, PUT, DELETE with headers, body, and response parsing.

- id: fetch-data
  type: http
  method: GET
  url: https://api.example.com/data
  headers:
    Authorization: "Bearer {input.api_token}"

code

Execute code in a sandboxed environment. Supports Python and JavaScript. Access to previous step outputs.

- id: process
  type: code
  language: python
  code: |
    import json
    data = json.loads(context['steps']['fetch-data']['output'])
    result = [item for item in data if item['score'] > 0.8]
    print(json.dumps(result))

condition

Branch workflow execution based on a condition. Routes to different downstream steps based on evaluation.

- id: check-quality
  type: condition
  condition: "{steps.analyze.output.score} > 0.7"
  if_true: publish
  if_false: review

classify

Classify input text into predefined categories using an LLM. Returns the category label and confidence.

- id: triage
  type: classify
  input: "{steps.intake.output}"
  categories:
    - urgent
    - normal
    - low-priority
  model: haiku

loop

Iterate over a list, executing a sub-prompt for each item. Results are collected into an array.

- id: process-each
  type: loop
  over: "{steps.split.output}"
  prompt: |
    Process this item: {item}
    Extract key metrics and format as JSON.
  model: haiku

Phase 2 - Power (3 types)

race

Execute multiple branches in parallel. First branch to complete wins; others are cancelled. Ideal for redundancy, speed optimization, or trying multiple approaches simultaneously.

- id: fastest-answer
  type: race
  branches:
    - prompt: "Research via web search: {input.question}"
      model: sonnet
    - prompt: "Answer from knowledge: {input.question}"
      model: opus
  timeout: 60

sensor

Poll an external URL or wait for a webhook callback. Useful for monitoring external systems, waiting for approvals, or triggering on events.

- id: wait-for-deploy
  type: sensor
  url: "https://api.example.com/deploy/{steps.trigger.output.deploy_id}/status"
  poll_interval: 30
  timeout: 600
  success_condition: "response.status == 'complete'"

gate

Multi-strategy approval gate. Supports manual approval, automatic timeout, and quorum-based decisions.

- id: approval-gate
  type: gate
  strategy: manual
  approvers: ["team-lead", "qa"]
  timeout: 3600
  on_timeout: auto_approve

Phase 3 - Zero-cost (3 types)

These step types don't make API calls, so they add zero cost to your workflow.

transform

Render Jinja2 templates to transform data between steps. No API calls - runs locally.

- id: format-email
  type: transform
  template: |
    Subject: Weekly Report - {{ steps.analyze.output.date }}

    Hi {{ input.recipient }},

    Here are this week's highlights:
    {% for item in steps.analyze.output.highlights %}
    - {{ item }}
    {% endfor %}

notify

Send notifications to Slack, email, webhooks, or other services. Lightweight alert step.

- id: alert-team
  type: notify
  channel: slack
  webhook: "{env.SLACK_WEBHOOK_URL}"
  message: |
    Workflow complete! Results: {steps.compile.output.summary}

delegate

Spawn a sub-workflow as a child execution. The parent workflow waits for the child to complete and receives its output.

- id: run-sub-analysis
  type: delegate
  workflow: detailed-analysis.yaml
  input:
    data: "{steps.preliminary.output}"
    depth: "deep"

Additional types

approval

Pause execution and wait for human approval. The approval appears in the dashboard queue and can be managed via CLI.

- id: human-review
  type: approval
  message: "Please review the generated contract before sending."
  timeout: 86400

sub_workflow

Execute another workflow file inline. Similar to delegate but with tighter integration.

- id: enrich
  type: sub_workflow
  workflow: lead-enrichment.yaml
  input:
    company: "{steps.intake.output.company}"

Combining step types

The real power comes from combining step types in a single workflow:

steps:
  - id: research          # standard - AI agent research
    prompt: "Research {input.topic}"

  - id: parallel-write    # race - fastest writer wins
    type: race
    depends_on: [research]
    branches:
      - prompt: "Write blog post from: {steps.research.output}"
      - prompt: "Write article from: {steps.research.output}"

  - id: quality-check     # classify - auto-triage quality
    type: classify
    depends_on: [parallel-write]
    categories: [publish, revise, reject]

  - id: format            # transform - zero-cost formatting
    type: transform
    depends_on: [quality-check]
    condition: "{steps.quality-check.output} == 'publish'"
    template: "..."

  - id: notify-team       # notify - zero-cost alert
    type: notify
    depends_on: [format]
    channel: slack

Clone this wiki locally