Scheduled tasks
Cron expressions with a real execution history. Skip, queue, or terminate overlapping runs. Catch up missed firings after a reboot. Page Slack, Telegram, or email on failure.
It's 3 AM. Your backup didn't run. You won't know until morning. RunWisp fixes that - one static binary that replaces crond, supervisord, and the tab you forgot to open.
curl -fsSL https://get.runwisp.com | sh No Node, no Python, no Docker required. Or grab a release binary.
Example run history: backup-db retried once and recovered, certbot and sync-s3 all green, worker service up 41 days.
Scheduled tasks, long-running services, and health checks, all defined in the same runwisp.toml and run by the same daemon.
Cron expressions with a real execution history. Skip, queue, or terminate overlapping runs. Catch up missed firings after a reboot. Page Slack, Telegram, or email on failure.
Supervise worker processes with restart policies, instance counts, and graceful-stop windows. Same TOML file, same dashboard, same logs.
Hit an endpoint, exit non-zero if it's broken. RunWisp captures the run, keeps the output, and pages you the way you want to be paged.
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.
# did this run? find out tomorrow.
0 3 * * * /usr/local/bin/backup.sh [tasks.backup]
cron = "0 3 * * *"
retry_attempts = 2
notify_on_failure = ["slack-ops"]
keep_runs = 60
run = "/usr/local/bin/backup.sh" A Svelte dashboard ships inside the binary; a TUI for SSH sessions. No extra installs, no separate server.
From curl to "my backups have a dashboard." No package-manager wrangling, no runtime to install.
One curl. A single static Go binary lands on your PATH.
Tasks and services in one file, checked into your repo. The schema is the source of truth.
Schedules fire, services supervise, logs persist. Open the dashboard on :9477, or stay in the terminal.
The stuff a solo dev or a small ops team actually needs, without standing up Airflow.
Exit code, duration, stdout, stderr, timestamps: captured for every firing, browsable in the UI, queryable over REST. No silent failures.
Static Go binary. No Python, no Node, no external database. Embedded SQLite, embedded dashboard. Runs on a Raspberry Pi.
Schedules, retries, services, notifiers, all in runwisp.toml. The dashboard reads and triggers; it never edits your config.
Per-task on_overlap: skip, queue, or terminate. Per-service instance counts. Restart backoff that resets on stability.
Boot the machine, start RunWisp, and missed firings replay, bounded by max_catch_up_runs. No quiet gaps in your history.
Slack, Telegram, Discord, email, webhook, or an in-app bell. Per-task overrides. Flapping coalesces into one alert, not a storm.
A Svelte dashboard ships inside the binary. A Bubbletea TUI for SSH sessions. Same data, two surfaces, no extra installs.
Watch a task's output as it happens, in the browser or over SSH. Tail historic logs without grepping through files.
Everything runs with the network unplugged. No phone-home, no account, no dependency on anyone's servers to fire a job.
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 | ✓ | ✓ | ✗ | ✗ | ✗ |
user = "deploy" per task or service to drop privileges. Otherwise every task runs as the daemon's user./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.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