Cron job manager + process supervisor

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.

Install in 30 seconds
curl -fsSL https://get.runwisp.com | sh

GPL-3.0 daemon · no locked features · no license key

Tasks & services

Same cron line. Different afterlife.

Keep the schedule you already have. Each extra key is something you'd otherwise script around cron yourself.

crontab fire & forget
# did it run? check tomorrow.
0 3 * * * /usr/local/bin/backup.sh
runwisp.toml every run recorded
[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 missed alert with the count.
kill -9 mid-run
On restart the run is marked crashed, exit -2. Never stuck on "running".
today and hope
nohup ./bin/worker &
runwisp.toml supervised
[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.

Alerts

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.

runwisp.toml
[notifiers.phone]
type  = "ntfy"
topic = "${NTFY_TOPIC}"

[tasks.backup]
# ...
notify = ["phone"]
ntfy 03:04

❌ 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]] with kinds = ["succeeded"].
Moving off cron

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.

shell
$ 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 -e keeps 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 uninstall unmasks cron and starts it again.
  • One job at a time, or on macOS? crontab -l | runwisp import cron prints TOML with # TODO where a human has to decide. supervisord configs and systemd units import the same way.
  • Takeover needs Linux, systemd and root. Cron's MAILTO mail stops, so point notify somewhere first. Full walkthrough.
Or poke at a throwaway copy first: sample jobs, hundreds of past runs, deleted when you quit
bunx runwisp demo
Cron alternative · supervisord alternative · systemd-timer alternative

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 mailedjournal✓✓ ✓
Retries with backoff ✗unitstartup onlyrestarts ✓
Failure notifications mail onlyOnFailure=✗✗ ✓
Catch-up after downtime anacronpersistent✗✗ ✓
Scheduling + supervision in one ✗two units✗conflated ✓
Built-in web dashboard ✗Cockpitbasichosted, paid ✓
Single static binary, no runtime ✓✓PythonNode ✓
Same on macOS / WSL / Docker variesLinux✓✓ ✓
Pre-installed on the box most servers✓✗✗ ✗
Questions operators actually ask

FAQ

Does RunWisp need to run as root?
No. Run it as whoever owns the work. When the daemon does run as root, set 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?
Yes. RunWisp doesn't touch /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?
The daemon is GPL-3.0 and free to self-host: no account, no license key, no feature locked behind a paid tier. The Web UI and TUI ship in the same binary.
Which platforms does it run on?
One Go binary on Linux, macOS, WSL, and Docker, x86_64 or arm64, about 35 MB of RAM idle. Same TOML, same SQLite conventions, same dashboard port everywhere. The only platform-specific piece is the autostart wrapper (systemd unit, launchd plist, or container init), documented per OS.
Is it a workflow / DAG engine?
No, and proudly so. RunWisp runs independent tasks and services on one machine. If you need multi-step pipelines with dependencies and conditionals, use Dagu or Airflow. RunWisp is the layer below that, and most boxes never need more.
How does it handle timezones and DST?
Cron expressions evaluate in a configured timezone, per-task if you want. Fall-back fires once (the suppressed firing is still recorded in history); spring-forward fires once, right after the jump (a 02:00 job runs at 03:00) instead of waiting a day. DST is named, auditable behaviour, not an annual silent bug.
Is it production-ready? How mature is it?
Honest answer: 1.0 is stable, but RunWisp is still young. Within the 1.x line, breaking changes wait for a new major version. Pin a version, keep backups of anything you'd hate to lose, and skim the CHANGELOG before upgrading. What's already solid: it's crash-safe, developed in the open, and GPL-3.0, so it can't be pulled out from under you.
What happens if RunWisp itself crashes?
Your state survives. 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?
Easy, by design. Your config is one plain 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?
The installer does one job: download the release tarball for your OS, verify its SHA-256 against the release's checksums, and drop the binary on your PATH. It never reads a crontab, writes 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.
Get started
GPL 3.0 · no accounts · free to self-host

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.

Install in 30 seconds
curl -fsSL https://get.runwisp.com | sh