See what ran, why it failed, and what it printed.
RunWisp replaces crond and supervisord with one small Go binary. List your jobs and services in a runwisp.toml. It runs the jobs on schedule, restarts the services when they crash, and keeps every line they print. Browse it all in a web dashboard or a terminal UI. No database, no agent, no sidecar.
curl -fsSL https://get.runwisp.com | sh GPL-3.0 daemon · no locked features · no license key
The dashboard ships inside the binary.
No Node, no separate server. It listens on 127.0.0.1:9477 behind a password (runwisp password prints it).
- Overview What's running, what's next, what failed, and the box's CPU and RAM.
- Run now Tasks with params get a form generated from the TOML: choices, defaults, required fields.
- Live log Output streams as it prints, colours intact. Progress bars redraw in place instead of flooding the log.
- Why it failed Exit code, end reason, stderr, and CPU/RAM next to what the task usually uses.
- Search Full text across every run a task ever printed. Re-run, cancel or delete in bulk.
- Read-only config The UI shows your TOML and never edits it. Changed the file? A banner offers Reload.
- On a phone Tap a run and the log fills the screen. Good enough for 3 AM.
Same runs, over SSH.
Type runwisp on the box. Or stay on your laptop: runwisp tui --url https://box:9477 pins the cert on first connect, like SSH. Quitting never stops a remote daemon.
- f
- filter runs: failed, running, succeeded…
- /
- search every run's log (tab toggles regex)
- r
- run now, with a form if the task has params
- p
- pause or resume the schedule
- spacee
- select runs, rerun them
- []
- step back through a progress bar's redraws
- R
- reload runwisp.toml
- n
- notifications
- ?
- every other key
Sidebar marks: ● running · ✗ last run failed · ‖ paused · ⏸ held while cron still runs. The home screen opens the Web UI already signed in. CLI reference.
Same cron line. Different afterlife.
Keep the schedule you already have. Each extra key is something you'd otherwise script around cron yourself.
# did it run? check tomorrow.
0 3 * * * /usr/local/bin/backup.sh [tasks.backup]
cron = "0 3 * * *"
run = "/usr/local/bin/backup.sh"
timeout = "30m" # a hung pg_dump gets killed
on_overlap = "skip" # still running? don't stack
failures = ['+output:(?i)error'] # printed ERROR, exited 0: still red
notify = ["phone"] - Clocks go back an hour
- It runs once. The repeat is logged as
dst_skipped. - The box was off at 03:00
-
One catch-up run when it's back, and a
missedalert with the count. kill -9mid-run-
On restart the run is marked
crashed, exit -2. Never stuck on "running".
nohup ./bin/worker & [services.worker]
run = "./bin/worker"
instances = 3
[services.worker.health_check]
run = "curl -fsS http://127.0.0.1:8080/healthz"
A crashed instance restarts with backoff, and only that one. A health check that keeps
failing stops it as unhealthy and the restart policy takes over. If it never
comes back, you get a "gave up restarting" alert instead of a quiet process list.
What lands on your phone.
The exit code and the last lines the job printed, right in the notification. Tap it and the run opens in the Web UI.
[notifiers.phone]
type = "ntfy"
topic = "${NTFY_TOPIC}"
[tasks.backup]
# ...
notify = ["phone"] ❌ backup failed
Exited with code 1 after 4m 12s.
Scheduled run · 14 Oct, 03:00.
pg_dump: error: connection to server at "db" (10.0.0.5), port 5432 failed: FATAL: sorry, too many clients already
from runwisp · vps-1
- Same event, other places. Slack, Discord, Telegram, Gotify, Pushover, email or a webhook. The bell in the UI needs no setup at all.
- A job failing every minute sends one alert, then check-ins: "×10 — earlier repeats coalesced into this alert."
- Silence by default on success. Want a ping when the deploy goes through? One
[[route]]withkinds = ["succeeded"].
Leave your crontab where it is.
sudo runwisp takeover reads your crontabs in place and swaps the cron service for RunWisp. It shows the plan and asks once before it touches anything.
$ sudo runwisp takeover
Found 12 cron jobs on this box:
/etc/crontab, /etc/cron.d
1. Write /etc/runwisp/runwisp.toml
reads /etc/crontab, /etc/cron.d live via [daemon] include_cron
2. Install RunWisp as a system service and retire cron.service
stop cron.service
mask cron.service
systemctl enable --now runwisp.service
Take over from cron.service? [Y/n] - Your crontabs are never rewritten. RunWisp reads them live, so
crontab -ekeeps working. - Nothing runs twice. While cron is still up, its jobs show as held: listed, not started.
runwisp run <job>tries one under RunWisp first. - Changed your mind?
runwisp service uninstallunmasks cron and starts it again. - One job at a time, or on macOS?
crontab -l | runwisp import cronprints TOML with# TODOwhere a human has to decide. supervisord configs and systemd units import the same way. -
Takeover needs Linux, systemd and root. Cron's
MAILTOmail stops, so pointnotifysomewhere first. Full walkthrough.
bunx runwisp demo What it replaces, and what it doesn't.
RunWisp sits between "edit crontab over SSH" and "stand up Airflow". First, what it won't do for you:
- Not a DAG engine. Tasks are independent. Need pipelines? Dagu or Airflow.
- One box, one daemon. No clustering, no failover.
- One password. No SSO, no roles.
- No native Windows. WSL works.
| Capability | cron | systemd timers | supervisord | PM2 | RunWisp |
|---|---|---|---|---|---|
| Run history per firing | ✗ | journal | ✗ | counter only | ✓ |
| Captured stdout / stderr | mailed | journal | ✓ | ✓ | ✓ |
| Retries with backoff | ✗ | unit | startup only | restarts | ✓ |
| Failure notifications | mail only | OnFailure= | ✗ | ✗ | ✓ |
| Catch-up after downtime | anacron | persistent | ✗ | ✗ | ✓ |
| Scheduling + supervision in one | ✗ | two units | ✗ | conflated | ✓ |
| Built-in web dashboard | ✗ | Cockpit | basic | hosted, paid | ✓ |
| Single static binary, no runtime | ✓ | ✓ | Python | Node | ✓ |
| Same on macOS / WSL / Docker | varies | Linux | ✓ | ✓ | ✓ |
| Pre-installed on the box | most servers | ✓ | ✗ | ✗ | ✗ |
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 crashed with exit code -2 (never left stuck on "running"), 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