00The Swirls platform

Your agent is
the easy part.

The rest is where the weeks go.

So write the rest down too. Agents, workflows, triggers, data, who's allowed in, the app on top: all of it in .swirls files you review like any other code, and deploy in one shot.

platformthe short version
You write
.swirls files, in your repo
You deploy
one snapshot; nothing else runs
It runs on
Temporal, managed for you
You get
agents, runs, data, an app
acme/system.swirlswhat it does
connection slack {
  provider: slack
}

secret ai_keys {
  vars: [ OPENROUTER_API_KEY, WEBHOOK_SECRET ]
}

database tickets {
  label: "Tickets"
  schema: @prisma {
    model Ticket {
      id      Int    @id @default(autoincrement())
      email   String
      summary String
    }
  }
}

workflow triage_ticket {
  label: "Triage ticket"
  description: "Create a ticket from a support request."

  root {
    type: database
    database: tickets
    operation: insert
    inputSchema: @json {
      {
        "type": "object",
        "required": ["email", "summary"],
        "properties": {
          "email": { "type": "string" },
          "summary": { "type": "string" }
        }
      }
    }
    outputSchema: @json {
      {
        "type": "object",
        "required": ["id", "email", "summary"],
        "properties": {
          "id": { "type": "number" },
          "email": { "type": "string" },
          "summary": { "type": "string" }
        }
      }
    }
    run: @ts {
      return context.db.tickets.ticket.create({
        data: context.nodes.root.input,
      })
    }
  }
}

agent concierge {
  label: "Concierge"
  secrets: ai_keys
  provider: openrouter
  model: "openai/gpt-4o-mini"
  tools: [triage_ticket]
}
connection · secret · database · workflow · agent
acme/access.swirlswho can use it
webhook inbound {
  label: "Inbound support"
  secret: ai_keys.WEBHOOK_SECRET
  header: "X-Swirls-Secret"
}

trigger on_support {
  webhook:inbound -> triage_ticket
  enabled: true
}

role support {
  match {
    department: "support"
  }
}

policy {
  allow support -> agent concierge
}

app support_desk {
  description "Support desk for the account
    team: chat with the concierge and read
    the ticket table."

  expose {
    agent    concierge
    database tickets { access read }
  }
}
webhook · trigger · role · policy · app

Two files. Names resolve across all of them, so the trigger finds the workflow and the app finds the agent. Get a name wrong and the deploy fails, not the run. Your editor knows the whole system too: the TypeScript inside every block is typed from the graph around it, down to a database client that only offers what the node declared.

  • Agents

    agent · skill · mcp · channel

    Chat, with the tools and subagents you declared

  • Workflows

    workflow · trigger · schedule

    Durable runs with timers, retries, and review gates

  • Data

    database · stream · view · disk

    Postgres we provision, plus streams, views, and disks

  • Interfaces

    app · form · webhook

    Webhook endpoints, forms, and a generated app

01The stack

Where the weeks go.

Ship one agent and you end up standing up six more things around it. Each one is a dependency, a deploy, and another place where what you wrote stops matching what's running.

What teams usually wire together, and what you write in Swirls instead
You'd wire this upYou write
01An agent frameworkagent · skill · mcp
02A workflow engineworkflow · trigger
03Integrations and credentialsconnection · action · auth · secret
04A databasedatabase · migration · postgres
05Somewhere to approve a stepreview on any node
06Run history and tracesevent log · spans · OTLP
07A way to ship all of itswirls deploy

None of it goes away. It just stops being seven things you have to keep in sync by hand.

02Deploy

It compiles, then it runs.

The runtime never reads raw .swirls source. swirls deploy compiles your files, checks them, and writes a snapshot. That snapshot is what runs.

  1. 01

    Author

    Your editor type-checks the TypeScript, SQL, and Prisma inside your blocks. swirls doctor runs the same checks in CI.

    diagnostics
  2. 02

    Compile

    Every .swirls file in the workspace is parsed together, so a name that doesn't resolve breaks the deploy instead of the run.

    validated project
  3. 03

    Snapshot

    The deploy writes fresh snapshot rows and a source archive. Nothing is edited in place, and a pointer decides which snapshot is live.

    deployment snapshot
  4. 04

    Execute

    Temporal runs it. Timers, retries, child runs, and a step waiting on a person all survive a restart or a redeploy.

    durable run
  5. 05

    Observe

    Every step lands in the event log and opens a span. Traces export over OTLP to a backend you own.

    events · traces

Redeploy and the new snapshot takes over. Runs already going finish on the definition they started with. A push that changed nothing deploys nothing: the compiler fingerprints the system itself, so identical source is a green check instead of a churned release. And every deployment keeps its exact source, so what was running on Tuesday always has an answer.

top-level declarations
24top-level declarations
workflow node types
20workflow node types
typed provider actions
185typed provider actions
brokered OAuth providers
8brokered OAuth providers
03Governance

What the runtime enforces.

The authority lives in the files you reviewed, and the runtime holds you to them. The compiler checks the system before it ships; these hold while it runs.

01

Immutable deployments

Redeploy and the new snapshot takes over. Runs already going finish on the definition they started with.

02

Bound identity

The person, webhook, or schedule that starts a run is stamped on it and travels with it.

03

Run-scoped credentials

Every run carries a credential naming the organization, project, providers, and approved agents behind it. It expires in an hour and can be revoked.

04

Workflow-bound authority

The credential is bound to a fingerprint of the workflow it was approved for. If what’s deployed stops matching what was reviewed, the run refuses to start.

05

Deny by default

Declare a policy and the whole deployment flips to deny-by-default. A missing grant is a refusal, not a warning.

06

Declared secret access

A node sees the secrets and connections it declared, and nothing else.

07

Durable review gates

A workflow can stop and wait for a person, for hours or days, and pick up exactly where it left off.

08

Append-only audit events

Operational audit events land in an append-only log you can export.

Swirls is alpha, and some of this is newer than the rest. Generated apps are the youngest piece. Access grants are enforced when an agent is invoked, and the security page says exactly where that line sits today.

04Clients

One system, every client.

A project is a client. The system stays one set of files, and everything a client touches is theirs alone.

01

Their own connections

OAuth for each client’s Slack, Microsoft, GitHub, and the rest, connected to their project and nobody else’s.

02

Their own encryption keys

Every project gets its own key set the moment it’s created. Client separation is cryptographic, not a filter.

03

Their own audit trail

Every run, deploy, and credential in a client’s project lands in that client’s record.

04

Their own bill

Client workspaces are priced when they’re active. The first two are included, and idle clients cost nothing.

Winning the next client means creating a project and deploying. Losing an engineer means the next one reads the files.

See the operating model

Write one and see.

Install the CLI, write an agent and a workflow, deploy. About five minutes.

installmacos · linux
curl -fsSL https://swirls.ai/install | bash
Next: where Swirls fits among the alternatives