-
-
Notifications
You must be signed in to change notification settings - Fork 6
Step Types
Sandcastle supports 15 step types organized in three phases. Each phase added capabilities without breaking existing workflows.
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: 10Direct 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: haikuMake 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}"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))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: reviewClassify 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: haikuIterate 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: haikuExecute 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: 60Poll 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'"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_approveThese step types don't make API calls, so they add zero cost to your workflow.
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 %}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}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"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: 86400Execute 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}"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: slackSandcastle v0.17.0 | BSL-1.1 License | Created by Tomas Pflanzer @gizmax