AGENTIC WORKFLOWS.
SECURE BY CONSTRUCTION.
Durable execution for AI workflows. Agents only access what the workflow authorizes. Define it in one .swirls file. Deploy it in one command.
The workflow definition IS the security policy. 13 node types. Resumable steps. Auditable execution. Free to run locally.
form contact {
label: "Contact Form"
enabled: true
schema: @json {
{
"type": "object",
"required": ["name", "email", "message"],
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"message": { "type": "string" }
}
}
}
}
graph process_contact {
label: "Process Contact"
root {
type: code
label: "Normalize"
code: @ts {
const { name, email, message } = context.nodes.root.input
return {
name: String(name ?? "").trim(),
email: String(email ?? "").toLowerCase().trim(),
message: String(message ?? "").trim(),
}
}
}
node summarize {
type: ai
label: "Summarize"
model: "google/gemini-2.5-flash"
}
node notify {
type: resend
label: "Send confirmation"
}
flow {
root -> summarize
summarize -> notify
}
}
trigger on_contact {
form:contact -> process_contact
enabled: true
}AGENTS ACT ON YOUR BEHALF. WHO CONTROLS WHAT THEY CAN DO?
AI agents call APIs, move data, and spend money. Most runtimes give every agent full access to everything. Swirls scopes permissions automatically from your workflow definition. Each agent only reaches the secrets, tools, and endpoints you authorize. Nothing more.
Flat token. Every node gets access to every secret and every endpoint.
Permissions narrow at every step. The workflow definition controls it all.
DURABLE. REVIEWABLE. AUDITABLE.
Workflows survive failures, pause for human review, and produce tamper-evident execution logs. Three properties of one runtime. Watch one workflow flow through all three.
Durable Execution
Every step is saved. Workflows resume exactly where they stopped. No re-execution. No lost state.
Human-in-the-Loop
Workflows pause for human review when stakes are high. Approve, reject, or edit. Built into the language.
Tamper-Evident Logs
Every execution is recorded and verifiable. If an agent did it, you can prove it.
THREE WAYS IN.
Write workflows by hand, generate them with an LLM, or fork a recipe from the cookbook. Every path gets you to a running workflow.
Full LSP support in VS Code
- IntelliSense and error checking as you type
- 13 node types, 3 resource types
- Run locally with swirls worker start
- Hot reload on save
/**
* Scores incoming leads and persists results for reporting.
* High-scoring leads trigger an alert to the sales team.
*/
webhook new_lead {
label: "New Lead Webhook"
schema: @json {
{
"type": "object",
"required": ["email", "company", "source"],
"properties": {
"email": { "type": "string", "format": "email" },
"company": { "type": "string" },
"source": { "type": "string" }
}
}
}
}
graph score_lead {
label: "Score Lead"
root {
type: code
label: "Extract lead"
code: @ts { return context.nodes.root.input }
}
node score {
type: ai
label: "Score the lead"
kind: object
model: "google/gemini-2.5-flash"
prompt: @ts {
const lead = context.nodes.root.output
return "Score this B2B lead 0-100.\n\nEmail: "
+ lead.email + "\nCompany: " + lead.company
}
schema: @json {
{
"type": "object",
"required": ["score", "reasoning"],
"properties": {
"score": { "type": "number" },
"reasoning": { "type": "string" },
"tier": { "type": "string", "enum": ["hot", "warm", "cold"] }
}
}
}
}
node route {
type: switch
label: "Route by score"
cases: ["hot", "other"]
router: @ts {
if (context.nodes.score.output.tier === "hot") return "hot"
return "other"
}
}
node alert_sales {
type: resend
label: "Alert sales team"
from: @ts { return "[email protected]" }
to: @ts { return "[email protected]" }
subject: @ts {
return "Hot lead: " + context.nodes.root.output.company
+ " (Score: " + context.nodes.score.output.score + ")"
}
text: @ts {
const lead = context.nodes.root.output
const result = context.nodes.score.output
return "New hot lead!\n\nCompany: " + lead.company
+ "\nScore: " + result.score
+ "\nReason: " + result.reasoning
}
}
flow {
root -> score
score -> route
route -["hot"]-> alert_sales
}
}
stream scored_leads {
label: "Scored leads"
graph: score_lead
schema: @json {
{
"type": "object",
"required": ["score", "reasoning", "tier"],
"properties": {
"score": { "type": "number" },
"reasoning": { "type": "string" },
"tier": { "type": "string" }
}
}
}
condition: @ts { return true }
prepare: @ts {
return context.nodes.score.output
}
}
trigger on_lead {
webhook:new_lead -> score_lead
enabled: true
}DEPLOY YOUR FIRST AGENTIC WORKFLOW
Install the CLI. Write a .swirls file. Run it locally in under five minutes. When it's ready, swirls cloud deploy.
Shape the future of Swirls by joining our community.
JOIN THE DISCORD