Spindle DocsStart a trial

Features

What Spindle actually does

No feature here exists because a competitor has it. Each one came out of a support ticket where somebody's nightly run went wrong in a way their crontab could not have told them about.


Scheduling

A workflow is triggered by a cron expression, a fixed interval, an inbound event, or by hand. The expression is standard five-field cron — there is nothing new to learn, and a crontab line can be pasted in unchanged.

Schedules are evaluated in a timezone you name, not in UTC and not in whatever the host happens to be set to. Daylight-saving transitions are handled explicitly: a run scheduled inside a skipped hour is moved forward, and a run inside a repeated hour fires once.

Trigger types
TriggerWritten asNotes
Cron"20 2 * * *"five fields, with a named timezone
Intervalevery: 15mmeasured from the end of the last run
Eventon: webhooksigned POST to a per-workflow URL
Manualspindle runCLI or console, with optional parameters
Chainedafter: other-wfstarts when a named workflow passes

Overlap policy

The question a crontab cannot answer: what if the previous run has not finished? Choose per workflow — skip (the default), queue up to a depth you set, cancel_previous, or allow for jobs that genuinely parallelise.

Most incidents we see in migrated crontabs are two copies of the same job writing to the same table.

One scheduler, one decision. Even when the control plane fails over, a scheduled run is claimed exactly once. Agents hold a lease on the run and a lease cannot be granted twice for the same slot.

Dependency graphs

Steps declare needs, and Spindle derives the execution order. Independent steps run in parallel up to the concurrency you allow; a step whose dependency failed is reported as skipped, not failed, so the failure count in your history stays honest.

Fan-out and fan-in

A matrix step expands over a list — one region, one tenant, one shard per instance — and a downstream step can wait for all of them or for the first success.

Conditional steps

A step may be gated on an expression over previous outputs, so a cleanup step runs only when the import actually wrote something.

Cycle detection

A definition with a cycle is rejected when it is loaded, with the offending path named. It never reaches the scheduler.

Retries that mean something

Retry policy belongs to the step, because the right answer differs per step. An HTTP fetch should retry quickly and often; a migration should not retry at all; a charge should retry only with the same idempotency key.

retries:
  max: 5
  backoff: 20s
  multiplier: 2.0        # 20s, 40s, 80s, 160s, 320s
  jitter: 0.3
  retry_on: [exit:75, timeout]
  idempotency_key: "$SPINDLE_RUN_ID/$SPINDLE_STEP"

Exit codes can be classified: some mean "try again", some mean "this will never work", and some mean "the input was bad, skip it and carry on". A step that exits with a code you did not classify is treated as a hard failure.

Timeouts

Each step has a timeout, and the workflow has a wall-clock budget. On timeout the agent sends SIGTERM, waits a grace period you set, then SIGKILL — and records which of the two ended the process.

A step killed by timeout is retried only if timeout is in its retry_on list.

Late runs

Separate from failure. late_after is a budget for the whole workflow, and missing it pages even while every step is still green. This is the alert that catches a gradually slowing job before it collides with the next morning.

Observability

Agents and networking

The agent is a single static binary. It polls the control plane over outbound HTTPS, claims work, runs it as a local user you choose, and streams results back. There is no inbound connection to your network and no port to open.

Agent requirements
ItemRequirement
PlatformsLinux x86-64 and arm64, FreeBSD 14, macOS 14+ (development only)
Resident memory~40 MB idle, plus whatever your steps use
Outbound accessHTTPS to the control plane; no other egress required
Privilegesruns unprivileged; a system unit file is provided
Credentialsstay on the agent host; Spindle stores step names and exit codes

Access control

Workflows belong to projects, and roles are granted on a project. The four roles are deliberately few: viewer reads history, operator may trigger and cancel runs, maintainer may change definitions, owner may change membership and billing.

Single sign-on through SAML or OIDC is available on the Scale plan, including group mapping onto project roles so access follows your directory rather than a separate list.

Secrets are references, not values. A step refers to a secret by name; the agent resolves it from your own store — environment file, Vault, systemd credentials — at run time. Spindle has no field that can hold a secret value, which removes the question of how well we would have protected it.

Limits

Per plan
LimitSoloTeamScale
Workflows10150unlimited
Steps per workflow20100400
Concurrent steps440negotiated
Agents225unlimited
Log retention7 days30 days180 days
Run history90 days1 year3 years
Minimum interval5 min1 min15 sec
Artifact size per run10 MB100 MB1 GB

Hitting a limit never silently drops a run: the run is queued and the project owner is notified. Details on the pricing page.