Swirl Background - Animated Topographic Lines
Join the waitlist

DEPLOY AGENTIC AI.
ONE FILE. ONE COMMAND.

Write workflows in .swirls files. Run locally with zero config. When it's ready swirls deploy.

A compact workflow language for agents, APIs, forms, email, and human steps—framework-agnostic, diff-friendly, and easy to sketch in plain English before you refine it in code.

Unlimited local executionsGit-nativeCloud starts at $30/mo
contact-form.swirls
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: email
    label: "Send confirmation"
  }

  flow {
    root -> summarize
    summarize -> notify
  }
}

trigger on_contact {
  form:contact -> process_contact
  enabled: true
}
Three ways in

DESCRIBE IT. BUILD IT. SHIP IT.

You don't need to be a developer to create a Swirls workflow. Describe what you want and get working code back.

Write it yourself

.swirls files have full LSP support: IntelliSense, error checking, go-to-definition in VS Code. 12 node types, 3 resource types, one flow block.

swirls worker start

Let an LLM write it

Describe your workflow in plain English. Claude, GPT, or any LLM can generate a valid .swirls file. The format is small, declarative, and well-documented. Ideal for AI code generation.

"Enrich leads and score them with AI"

Start from a cookbook

Copy a working example (lead enrichment, support triage, content pipelines, blog generation) and customize it.

Browse 4+ ready-to-run examples
The .swirls file

THREE CONCEPTS. ONE FILE.
FULL WORKFLOWS.

Every .swirls file is made of resources, graphs, and triggers. One file, three concepts.

Resources

Your workflow entry points

Forms, webhooks, and schedules. Each one generates a UI in the Portal and an API endpoint automatically.

example.swirls
form contact {
  label: "Contact Form"
  enabled: true
  schema: @json {
    { "type": "object", "additionalProperties": true }
  }
}

webhook inbound {
  label: "Inbound Webhook"
  enabled: true
}

schedule daily_report {
  cron: "0 9 * * *"
  timezone: "America/New_York"
}
Graphs

DAGs of typed nodes

Code, AI, HTTP, email, switch, human review. 12 node types connected by explicit edges. Every input and output is typed.

example.swirls
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"
    prompt: @ts {
      const { message } = context.nodes.root.output
      return `Summarize this inquiry in two sentences for the team. Message: ${message}`
    }
  }

  node notify {
    type: email
    label: "Send confirmation"
  }

  flow {
    root -> summarize
    summarize -> notify
  }
}
Triggers

Connect a resource to a graph

One line. When the resource fires, the graph runs.

example.swirls
trigger on_contact {
  form:contact -> process_contact
  enabled: true
}

trigger on_webhook {
  webhook:inbound -> enrich_lead
  enabled: true
}

trigger daily {
  schedule:daily_report -> generate_report
  enabled: true
}
Node Types

12 PRIMITIVES. INFINITE WORKFLOWS.

Every node in a graph has a type. Each type does one thing well. Combine them to build anything.

code

Run TypeScript

ai

LLMs, structured output, images, embeddings

http

Call any API

email

Send email

switch

Route by condition

stream

Persist to queryable storage

graph

Call another graph

scrape

Extract web content

wait

Pause for a duration

bucket

File storage

document

Process documents

If your workflow needs it, there's a node for it.

Human-in-the-Loop

PAUSE. REVIEW. RESUME.

Any node can require human approval before continuing. The workflow serializes its state, shuts down, and resumes exactly where it stopped when approved. Built into the language, not bolted on.

1
Workflow reaches a review nodeExecution pauses. State is serialized.
2
Human reviews in the PortalApprove, reject, or edit the output.
3
Execution resumes or stopsPick up where you left off. The state persists indefinitely.
review syntax
node draft_email {
  type: ai
  label: "Draft Email"
  model: "anthropic/claude-sonnet-4-20250514"
  kind: object
  prompt: @ts {
    return `Draft a response to: ${context.nodes.root.output.message}`
  }
  schema: @json {
    {
      "type": "object",
      "required": ["subject", "body"],
      "properties": {
        "subject": { "type": "string" },
        "body": { "type": "string" }
      }
    }
  }
  review: {
    enabled: true
    label: "Review draft before sending"
  }
}
Full Observability

EVERY EXECUTION, ON THE RECORD

When a Swirls workflow runs, every node execution is recorded: inputs, outputs, duration, status. Queryable. Replayable.

Debug step-by-step. Roll back to a previous graph version. See exactly which node failed and why.

EXECUTION TRACErun_8f3a · enrich_lead · v2.4.1
1trigger/webhook2ms{ company: "Acme Corp" }
2http/clearbit340ms{ employees: 450, revenue: "$52M" }
3http/builtwith280ms{ stack: ["React", "AWS", "Postgres"] }
4code/extract1ms{ signals: 12, tier: "enterprise" }
5ai/score1.2s{ score: 87, reasoning: "Strong ICP fit..." }
6email/notify150msSMTP timeout, retrying in 30s
Every node tracedInputs, outputs, duration, status
ReplayableRe-run any execution with the same state
Version-awareSee which graph version produced each result

This is what “auditable AI” looks like.

Cryptographic Security

SECRETS GO WHERE THE WORKFLOW SAYS, AND NOWHERE ELSE.

Swirls derives the minimum set of secrets authorized by each node's token. Enforced by the runtime.

The SHA-256 hash of your compiled workflow definition is embedded in every authorization token. Modify the workflow, the token breaks. Permissions stay in sync with the code, always.

Secrets in your graph

Only what you declare on the node enters context.secrets

For any node, the executor merges values from your project vault only for the keys listed in that node's secrets: declaration. Nothing else from the vault is exposed to TypeScript at runtime.

workflow.swirls
// The runtime injects project vault values only for keys listed on this node.
// Anything else in the vault never appears on context.secrets here.

graph call_partner_api {
  label: "Partner API (least-privilege secrets)"

  root {
    type: code
    label: "Fetch with scoped credentials"
    // Only these names are authorized for this node; the executor builds context.secrets from this list alone.
    secrets: [PARTNER_API_KEY, PARTNER_WEBHOOK_SECRET]
    inputSchema: @json {
      {
        "type": "object",
        "required": ["query"],
        "properties": { "query": { "type": "string" } },
        "additionalProperties": false
      }
    }
    code: @ts {
      // PARTNER_API_KEY and PARTNER_WEBHOOK_SECRET are in scope; other vault keys are not.
      const key = context.secrets.PARTNER_API_KEY
      const signingSecret = context.secrets.PARTNER_WEBHOOK_SECRET
      return {
        query: context.nodes.root.input.query,
        ready: Boolean(key && signingSecret),
      }
    }
  }
}
DELEGATION CHAINdelegation · HMAC-SHA256
1 workspace
2deployment
3execution
4node
5tool
Tamper a workflow, break the tokenThe SHA-256 hash of your compiled .swirls definition is a caveat on every token. A modified workflow produces a different hash and can't authorize itself.
Keys derived on demandKeys are derived on demand via HKDF-SHA512 and discarded. There is no KMS database to breach.
Per-node encryption contextEach node gets its own encryption context. The execution engine is the only thing that crosses the boundary.
SEE THE FULL SECURITY MODEL →
Deployment

START LOCAL. DEPLOY WHEN READY.

Develop on your machine with the same execution engine that runs in production. When you're ready, push to the cloud with one command.

Local

swirls worker start
  • SQLite-backed execution
  • Full Portal access
  • Hot reload

Cloud

swirls deploy
  • $30/mo with 50k credits
  • Managed infrastructure
  • Auto-scaling

Self-hosted

Coming soon
  • Your infrastructure
  • Full control
  • Air-gapped support

DEPLOY YOUR FIRST AGENT

Install the CLI, write a .swirls file, and run it locally in under 5 minutes. When it's ready, swirls deploy and it's live.