Agents write it. Swizzle
runs it.

A self-hosted runtime for automations written as ordinary code. Your agent writes the Python or TypeScript. Swizzle brings triggers, secrets, OAuth, retries, approvals and logs. No canvas, no nodes, no pager at 3 a.m.

Get started →
  • Cron
  • Webhooks
  • Secrets
  • Sandboxes
  • Retries
  • Logs

$ swizzle apply automations/invoice-chaser

Code, not spaghetti.

Node editors were built for humans holding a mouse. Your agent has no mouse. It has a compiler, a test runner and git, and it is very good with them.

  • Review it like a PR. A diff, not a screenshot of boxes.
  • Real languages, real libraries. Python, JavaScript or TypeScript, with the packages you already use.
  • Lives in git. Branch it, revert it, blame it.
automations/invoice-chaserwritten by agent

config.yaml

name: invoice-chaser
version: "1.0.0"
entrypoint: main.ts
trigger:
  type: cron
  schedule: "0 9 * * MON"
secrets: [STRIPE_API_KEY, SLACK_WEBHOOK_URL]
runtime:
  retry: { max_attempts: 3, backoff: exponential }
api_check: { mode: passive }

main.ts

// Every Monday, nudge customers with open invoices.
import { logStep, runAutomation, runStep } from "./swizzle-sdk.ts";
import { nudge, openInvoices } from "./billing.ts";

await runAutomation(async () => {
  const invoices = await runStep("open-invoices", openInvoices);

  for (const inv of invoices) {
    // a retry skips the nudges that already went out
    await runStep(`nudge:${inv.id}`, () => nudge(inv));
  }
  logStep("chased invoices", { count: invoices.length });
  return { chased: invoices.length };
});
47 boxes, 112 wires, one webhook. Nobody can review this.

One, two, stir.

Three moves from an idea in a chat to an automation that runs every Monday at nine.

  1. 1{ts}

    Your agent writes the automation.

    Claude Code, Codex or any agent that can write a file. The workspace comes with an AGENTS.md and a builder skill, so the agent knows the SDK, the config and the checks. Python, JavaScript or TypeScript.

    swizzle workspace init
  2. 2

    Swizzle checks it and deploys it.

    Validate runs every deploy check without changing anything. Apply creates a numbered deployment, binds its secrets and connections, and switches the trigger on. A rollback is one command.

    swizzle apply
  3. 3

    It runs. You sleep.

    Every run in a locked-down container, retried with backoff, logged step by step. When a run finally fails, Telegram tells you, and Hand to agent turns it into a brief for the fix.

    swizzle logs

Every run takes the same track.

Trigger, sandbox, secrets, your code, done. When a call fails, the run loops back and tries again with backoff. Every lap is in the log, for you and for your agent.

RUN 4812waiting for cue
TriggerA cron schedule or an interval, a signed webhook, the result of another automation, or a manual run.
SandboxAn unprivileged process in a restricted Docker container, with a time limit and resource limits.
SecretsEncrypted at rest and injected as environment variables. Never in the repo or the prompt, and redacted from the logs.
Retry loopFixed or exponential backoff up to your limit. Finished steps return their stored result instead of running again.
DoneResult, logs and step timings for every run. A run that runs out of attempts lands in the dead letters and messages you.

Everything around the code.

Your agent writes the interesting part. Swizzle handles the parts that make automations fail at 3 a.m.

Secrets

Encrypted at rest, write-only through the API, redacted from every log and result.

secrets: [STRIPE_API_KEY]

OAuth

Google, Microsoft, GitHub, ClickUp or any OAuth2 provider. Swizzle refreshes the token, the run gets a fresh one.

connections: [google]

Cron

Cron expressions or plain intervals like 5m. An overlapping tick is skipped or queued, your choice.

schedule: "0 9 * * MON"

Webhooks

A path with a random token, an HMAC signature check and a JSON Schema, all before your code runs.

type: webhook

Sandboxes

Each deployed run in a restricted container as an unprivileged user, with resource limits.

timeout: 5m

Retries

Backoff, dead letters and durable steps. A retry never repeats work that already finished.

runStep("charge", …)

Approvals

Pause for a person, an event or a date. The run gives its worker back and resumes where it stopped.

requestApproval("refund")

Deployments

Every apply is a numbered deployment with its own logs. Staging and production stay apart.

swizzle rollback

Hand your agent the keys.

Swizzle is open source under Apache 2.0. One Docker Compose stack on your laptop, a home server or a VPS. Your code, your data and your secrets stay on your machine.

Get started on GitHub →