Getting started
Install the spool CLI, run a workflow, then watch one survive a crash.
Everything here runs on your own machine - no server to stand up, no
account to create.
Install
Section titled “Install”curl -fsSL https://hyperspool.com/install.sh | shThat drops a single static spool binary on your PATH. Check it:
spool --versionRun your first workflow
Section titled “Run your first workflow”A workflow can be a plain script. Write one and run it:
echo 'echo "hello from Hyperspool"' > hello.shspool run ./hello.shspool run spins up a throwaway in-memory instance, executes the file,
streams its output, and exits with the run’s status. Nothing persists:
when the command returns, the instance and its history are gone. It’s
the fastest way to try something out.
YAML pipelines run the same way:
spool run ./pipeline.yamlAgainst a persistent instance, spool submit --follow does the same and
opens the run’s live view - each step checked off as it lands:

Watch a run survive a crash
Section titled “Watch a run survive a crash”The reason to reach for Hyperspool is that a run outlives the process
executing it: kill the engine mid-run and the run picks up from its last
checkpoint. spool run is in-memory, so it can’t show that. A persistent
instance can.
spool init writes a few starter workflows into the current directory:
spool initOne of them, durable.sh, is a checkpointed bash workflow. It draws a
random number, sleeps, and then does arithmetic on the number it drew:
#!/usr/bin/env bashset -e
# Drawn once, ever. From here on the number lives in the run's log.n="$(spool step "pick" -- bash -c 'echo $(( RANDOM % 100 ))')"echo "picked $n"
# The script exits here. When the timer fires the run is dispatched# again, to whichever agent is free - which need not be this one - and# the script starts over from the top.spool sleep 5s
# `pick` does not draw a new number on that second pass. It replays the# recorded one, so $n is what it was before the sleep: new process, new# machine, five seconds or thirty days later, same value.m="$(spool step "add" -- expr "$n" + 1)"echo "$n + 1 = $m"Run it as-is first, before any crash test:
spool run ./durable.sh run: dev:default:run-2qyEKiaS7pTtkkZipicked 74spool: script suspended for 5000ms; agent re-dispatch on wakeup
- replaying from checkpoint (completed steps are cached, not re-run)picked 7474 + 1 = 75 dev:default:run-2qyEKiaS7pTtkkZi completedThe text above is the whole of it, but the timing is the part that reads better moving — the pause is the process being gone:

Two things to read off that. picked 74 appears twice because the whole
script really did run twice - spool sleep ends the process rather than
pausing inside it, and the wake-up starts the script again from the
first line. And it says 74 both times, because pick was recorded on
the first pass and replayed on the second.
A random number is the easiest thing to catch lying. Had the second pass
re-run pick you would be looking at a different number, and $n would
be useless to everything after the sleep. It doesn’t, so $n is
ordinary state that survives an arbitrary gap, and the arithmetic on the
far side is arithmetic on the number you actually drew.
None of that depends on staying put. agent re-dispatch on wakeup is
the run being handed back out for anyone to claim, and the claim can go
to a different agent on a different machine: the workflow log carries
the recorded value, so any agent that picks the run up can serve it.
Make the sleep 30d and the run is rows in a database for a month;
whoever resumes it in September gets 74.
(The generated file sleeps for 5s. Widen it to 60s for the crash
test below, so you have room to interrupt it.)
Start a persistent instance, pointed at a database file you name:
spool dev --db ./cryo-demo.dbThis one process is the server, an agent, and the web UI at
http://localhost:18753. Leave it running. In a second terminal, submit
the script - other spool commands find the running instance on their
own, no flags needed:
spool submit ./durable.sh --followpick runs and prints its number, then the run parks on spool sleep.
Note the number down. While it’s parked, kill the instance - hard, so
there’s no doubt it’s a real crash:
kill -9 "$(pgrep -f 'spool dev')"(That targets the spool dev you just started. If you happen to be running
more than one instance, kill the specific process id instead.)
The run’s state lives in ./cryo-demo.db, not in the process you just
killed. Start the instance again against the same file:
spool dev --db ./cryo-demo.dbOn startup it says resumed 1 in-flight run(s) from storage and the run
finishes. spool logs <run-id> shows the completed pass:
picked 7474 + 1 = 75The same number you noted down before the kill. pick was not re-run
- its checkpoint came out of
./cryo-demo.db, which is the one thing thekill -9couldn’t touch. Openhttp://localhost:18753to see the timeline.
(The log holds the last pass, so picked 74 appears once here. Live, as
in the spool run transcript above, you watch both passes stream by.)
The whole test, recorded — start, submit, park, kill, restart, and the run finishing on the number it drew before the process died:
That crash test is the durable model in one move: kill the engine
mid-run, restart it, and the run resumes with its recorded values
intact. It behaves the same whether the interruption is a kill -9, a
deploy, a reboot, or a thirty-day sleep that outlives the machine
entirely.
In-memory vs persistent
Section titled “In-memory vs persistent”Durability needs a database. Without one, a run lives only as long as its process.
spool run <file>is in-memory by default - nothing survives the command.spool run --db <path> <file>persists to a sqlite file, so the same crash test works for a one-shot run.spool devkeeps state in sqlite and survives restarts. With no--dbit uses a default file under your state directory;--db <path>names the file;--db :memory:makes it ephemeral.
On the server, in three steps
Section titled “On the server, in three steps”Everything above runs on your own machine and needs no account. If you have been invited to a Hyperspool org, the same workflows run there, with one difference to state plainly: jobs execute on machines you provide. With no agent running, a submitted run waits for a machine that never arrives.
1. Point the CLI at the server. Sign in at hyperspool.dev/workflows, mint a personal access token under Settings -> Tokens, then:
spool login https://api.hyperspool.devIt verifies the token, resolves your org and project, and writes
~/.config/spool/config.toml.
2. Start an agent. Mint a token for it, then install it on a machine that should run your jobs:
spool agents issue my-runner --project acme/web --cap shell --cap polyglotcurl -fsSL https://hyperspool.com/install.sh | sh -s -- \ --service --server https://api.hyperspool.dev \ --id my-runner --token csat_... --caps shell,polyglotThe token prints once. An agent claims only jobs whose requires: its
capabilities cover. spool agents ls lists it as soon as the token is
minted, with last=never until the process connects, which is how to
tell a token nothing ever used from an agent that is running.
See Deploying agents for systemd, macOS, containers and self-update.
3. Submit.
spool submit pipeline.yaml --followA run that stops with nothing to say is usually the missing agent: the
CLI reports what it is waiting for, and spool agents ls shows what the
fleet advertises.
Where to go next
Section titled “Where to go next”- Tour - thirty minutes through steps, timers, approvals, signals, events, and child workflows, all locally.
- Concepts - the vocabulary in nine terms.
- The authoring model - the checkpoint/replay rules; read once before writing a real workflow.
- Workflows in your language - the same primitives in Python, TypeScript, Go, and Rust.
- Deploying agents - run agents where your work needs to happen.
- Local and the server - how far
spool devtakes you, and what the server adds when the work outgrows one machine.