How Rotor works.
Durable step execution, secrets at runtime, and approvals before anything sends.
Every step runs once.
Rotor memoizes each step. If your workflow crashes at step 4 of 12, it resumes from step 4 — not from the beginning. No re-charged API calls. No duplicate sends. The completed steps are checkpointed and skipped on retry.
Pause without occupying a slot.
step.sleep suspends the workflow until a time. step.waitForSignal pauses until an external event unblocks it — a webhook, a CLI command, or a Slack approval. Neither consumes a worker slot while waiting.
await step.sleep("wait-24h", "24h")
const signal = await step.waitForSignal("approval", { timeout: "72h" })
if (signal.approved) {
await step.run("send-email", () => sendEmail(draft))
}Secrets resolve when the step runs.
You write ${{ secrets.HUBSPOT_API_KEY }} in your config. The vault resolves it at dispatch time — not when you deploy. Rotate the key in the vault; the next run picks it up automatically. No redeploy. No SSH.
// workflow.ts
const config = {
apiKey: "${{ secrets.HUBSPOT_API_KEY }}",
endpoint: "https://api.hubapi.com/crm/v3/objects/contacts",
}
// At dispatch time, Rotor resolves:
// apiKey → "pat-na1-..." (actual key from vault)AI drafts it. You approve it. It sends.
Set approvalRequired: true on any queue. The workflow pauses after the draft step. You approve in Slack or your terminal. The workflow resumes and sends. Timeout policies auto-reject stale approvals.
// rotor.config.ts
export default {
queues: {
outbound: {
approvalRequired: true,
timeout: "24h",
surface: "slack",
},
},
}Every action logged.
Every step run, approval decision, secret access, and guardrail evaluation is logged with actor, timestamp, input, and output. Filter by time range, actor, or event type. Export to CSV or Snowflake.
Stop babysitting cron. Start shipping.
Your workflows retry themselves. Your pipeline runs unattended. You sleep.