See what ran, why it failed, and what it printed.
RunWisp is one small Go binary that replaces crond and supervisord. List your jobs and services in a runwisp.toml. It runs the jobs on schedule, keeps the services alive, and captures every line of stdout and stderr. See it all from a terminal TUI or a web dashboard. No database, no agent, no sidecar.
curl -fsSL https://get.runwisp.com | sh No Node, no Python, no Docker required. Or grab a release binary.
Plain cron is invisible.
crond runs your job, dumps stderr somewhere you'll never read, and forgets about it. No exit-code history. No "did the last run finish?" No notification when it didn't.
RunWisp captures every run (stdout, stderr, exit code, duration) and keeps the last N per task in embedded SQLite. Stream the output live in your browser. Re-trigger with one click. SSH at 3 AM is optional now.
Not a DAG engine. If you need workflows with dependencies, reach for Dagu or Airflow. RunWisp does one machine, well.
Running your stack in Docker? Four ways to add cron to a docker-compose.yml — and the one that gives you a dashboard.
# did this run? find out tomorrow.
0 3 * * * /usr/local/bin/backup.sh [tasks.backup]
cron = "0 3 * * *"
notify_on_failure = ["slack-ops"]
keep_runs = 60
run = "/usr/local/bin/backup.sh" Same data, two surfaces.
A Svelte dashboard ships inside the binary; a TUI for SSH sessions. No extra installs, no separate server.
Up and running in three commands.
From curl to "my backups have a dashboard." No package-manager wrangling, no runtime to install.
Install the binary
One curl. A single static Go binary lands on your PATH.
Write runwisp.toml
Tasks and services in one file, checked into your repo. The schema is the source of truth.
cron = "0 2 * * *"
retry_attempts = 2
keep_runs = 30
run = "pg_dump db | gzip > dump.gz"
[services.worker]
instances = 3
run = "./bin/worker"
Run runwisp
Schedules fire, services supervise, logs persist. Open the dashboard on :9477, or stay in the terminal.
# → dashboard at http://localhost:9477
Doesn't survive a reboot on its own — runwisp service install wires it into systemd or launchd so it comes back automatically.
Predictable, observable, scriptable.
The stuff a solo dev or a small ops team actually needs, without standing up Airflow.
Every run, every detail
Exit code, duration, stdout, stderr, timestamps: captured for every firing, browsable in the UI, queryable over REST. A paper trail for every run.
One binary, zero deps
Static Go binary. No Python, no Node, no external database. Embedded SQLite, embedded dashboard. Runs on a Raspberry Pi.
TOML is the source of truth
Schedules, retries, services, notifiers, all in runwisp.toml. The dashboard reads and triggers; it never edits your config.
Never let runs stack up
Per-task on_overlap: skip, queue, or terminate. Per-service instance counts. Restart backoff that resets on stability.
Notify the way you want
Slack, Telegram, Discord, email, webhook, or an in-app bell. Per-task overrides. Flapping coalesces into one alert, not a storm.
Works without internet
Everything runs with the network unplugged. No phone-home, no account, no dependency on anyone's servers to fire a job.
What it replaces, and what it doesn't.
RunWisp sits between "edit crontab over SSH" and "stand up Airflow." Here's the honest yes/no against the tools you're probably running today.
| Capability | cron | systemd timers | supervisord | PM2 | RunWisp |
|---|---|---|---|---|---|
| Run history per firing | ✗ | journal | ✗ | limited | ✓ |
| Captured stdout / stderr | ✗ | journal | ✓ | ✓ | ✓ |
| Retries with backoff | ✗ | unit | ✗ | restarts | ✓ |
| Failure notifications | ✗ | ✗ | ✗ | ✗ | ✓ |
| Catch-up after downtime | ✗ | persistent | ✗ | ✗ | ✓ |
| Scheduling + supervision in one | ✗ | two units | ✗ | conflated | ✓ |
| Built-in web dashboard | ✗ | ✗ | basic | paid | ✓ |
| Single static binary, no runtime | ✓ | ✓ | Python | Node | ✓ |
| Same on macOS / WSL / Docker | varies | Linux | ✓ | ✓ | ✓ |
| Pre-installed on the box | ✓ | ✓ | ✗ | ✗ | ✗ |
FAQ
Does RunWisp need to run as root?
user = "deploy" per task or service to drop privileges. Otherwise every task runs as the daemon's user.Can it run alongside my existing crontab while I migrate?
/etc/crontab or anyone's user crontab. Move one job at a time. runwisp import cron reads an existing crontab and emits an annotated runwisp.toml with # TODO markers where a human decision is needed.What does it cost? What's the license?
Which platforms does it run on?
Is it a workflow / DAG engine?
How does it handle timezones and DST?
Is it production-ready? How mature is it?
What happens if RunWisp itself crashes?
kill -9 and power loss are recoverable: on restart, any run that was in flight is marked interrupted (never silently lost), though it isn't resumed. runwisp service install wires the daemon into systemd or launchd, so the OS brings it back and scheduling resumes. RunWisp supervises your jobs; the init system supervises RunWisp.How hard is it to uninstall or move away?
runwisp.toml you can version-control, and the dashboard and API never rewrite it. runwisp service uninstall removes the autostart unit and leaves your data alone (add --purge, and type delete, to wipe it too). If you took over an existing crontab, uninstall hands it right back. The whole footprint is one binary, one TOML file, one data directory.Is curl | sh safe to run?
runwisp.toml, or calls systemctl. Rather not pipe to a shell? Read the script first, grab a release binary and check the checksum yourself, or use bun, npm, or Docker. More in security.Start in 30 seconds. Ship on your terms.
A single Go binary. If it doesn't earn the disk space, rm it. No account, no signup, no catch.
curl -fsSL https://get.runwisp.com | sh