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.
- 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
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]
}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 }
}
}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 · channelChat, with the tools and subagents you declared
Workflows
workflow · trigger · scheduleDurable runs with timers, retries, and review gates
Data
database · stream · view · diskPostgres we provision, plus streams, views, and disks
Interfaces
app · form · webhookWebhook endpoints, forms, and a generated app
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.
| You'd wire this up | You write |
|---|---|
| 01An agent framework | agent · skill · mcp |
| 02A workflow engine | workflow · trigger |
| 03Integrations and credentials | connection · action · auth · secret |
| 04A database | database · migration · postgres |
| 05Somewhere to approve a step | review on any node |
| 06Run history and traces | event log · spans · OTLP |
| 07A way to ship all of it | swirls deploy |
None of it goes away. It just stops being seven things you have to keep in sync by hand.
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.
- 01
Author
Your editor type-checks the TypeScript, SQL, and Prisma inside your blocks. swirls doctor runs the same checks in CI.
diagnostics - 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 - 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 - 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 - 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
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.
Immutable deployments
Redeploy and the new snapshot takes over. Runs already going finish on the definition they started with.
Bound identity
The person, webhook, or schedule that starts a run is stamped on it and travels with it.
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.
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.
Deny by default
Declare a policy and the whole deployment flips to deny-by-default. A missing grant is a refusal, not a warning.
Declared secret access
A node sees the secrets and connections it declared, and nothing else.
Durable review gates
A workflow can stop and wait for a person, for hours or days, and pick up exactly where it left off.
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.
One system, every client.
A project is a client. The system stays one set of files, and everything a client touches is theirs alone.
Their own connections
OAuth for each client’s Slack, Microsoft, GitHub, and the rest, connected to their project and nobody else’s.
Their own encryption keys
Every project gets its own key set the moment it’s created. Client separation is cryptographic, not a filter.
Their own audit trail
Every run, deploy, and credential in a client’s project lands in that client’s record.
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 modelWrite one and see.
Install the CLI, write an agent and a workflow, deploy. About five minutes.
curl -fsSL https://swirls.ai/install | bash