One binary · Linux · macOS · WSL · 25 MB RAM idle

Schedule,
supervise,
observe.
One binary.

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.

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

No Node, no Python, no Docker required. Or grab a release binary.

trigger a run · stream the log · see why it failed
The 3 AM problem

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.

crontab fire & forget
# did this run? find out tomorrow.
0 3 * * * /usr/local/bin/backup.sh
runwisp.toml every fire, recorded
[tasks.backup]
cron              = "0 3 * * *"
notify_on_failure = ["slack-ops"]
keep_runs         = 60
run               = "/usr/local/bin/backup.sh"
Observe

Same data, two surfaces.

A Svelte dashboard ships inside the binary; a TUI for SSH sessions. No extra installs, no separate server.

localhost:9477
trigger runs · stream logs live
RunWisp web dashboard: tasks overview with health status, run history, and live metrics
runwisp tui
the same view, over SSH
RunWisp terminal UI: task list with statuses, running dashboard with live updates
Setup

Up and running in three commands.

From curl to "my backups have a dashboard." No package-manager wrangling, no runtime to install.

1/3

Install the binary

One curl. A single static Go binary lands on your PATH.

$ curl -fsSL https://get.runwisp.com | sh
2/3

Write runwisp.toml

Tasks and services in one file, checked into your repo. The schema is the source of truth.

[tasks.backup-db]
cron = "0 2 * * *"
retry_attempts = 2
keep_runs = 30
run = "pg_dump db | gzip > dump.gz"

[services.worker]
instances = 3
run = "./bin/worker"
3/3

Run runwisp

Schedules fire, services supervise, logs persist. Open the dashboard on :9477, or stay in the terminal.

$ runwisp
# → 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.

Run those three commands
What it runs

Two kinds of job. Plus whatever's already in your compose file.

Does the command exit on its own? It's a task. Does it stay up? It's a service. That's the whole taxonomy, and it lives in one runwisp.toml run by one daemon.

Tasks exit

Cron expressions with a real execution history behind them. This one is a health check — retry_attempts is what keeps a dropped packet quiet and a genuine outage loud: every attempt has to fail before it pages you.

tasks exits
[tasks.healthcheck]
cron           = "*/5 * * * *"
on_overlap     = "skip"
timeout        = "30s"
retry_attempts = 2
run            = "curl -fsS $URL/up"

Services stay up

Restart policies, replica counts, graceful-stop windows. Each replica is its own supervised run — worker#1 through worker#3 — and when one dies, only that one comes back.

services stays up
[services.worker]
instances     = 3
healthy_after = "5s"
start_retries = 2
restart_delay = "2s"
run           = "node ./worker.js"

Compose stacks come as they are

One line next to your docker-compose.yml and every service in it becomes a supervised RunWisp service — logs, restarts, notifications, trigger and stop. You don't rewrite the compose file.

compose already yours
# beside your compose file
[compose.myapp]

# optional per-service knobs
[compose.myapp.worker]
instances = 3

Tasks vs. services → Compose reference →

Built for the operator who reads journalctl

Predictable, observable, scriptable.

The stuff a solo dev or a small ops team actually needs, without standing up Airflow.

history

Every run, every detail

Exit code, duration, stdout, stderr, timestamps: captured for every firing, browsable in the UI, queryable over REST. No silent failures.

binary

One binary, zero deps

Static Go binary. No Python, no Node, no external database. Embedded SQLite, embedded dashboard. Runs on a Raspberry Pi.

toml

TOML is the source of truth

Schedules, retries, services, notifiers, all in runwisp.toml. The dashboard reads and triggers; it never edits your config.

on_overlap

Never let runs stack up

Per-task on_overlap: skip, queue, or terminate. Per-service instance counts. Restart backoff that resets on stability.

catch_up

Reboots don't drop runs

Boot the machine, start RunWisp, and missed firings replay, bounded by max_catch_up_runs. No quiet gaps in your history.

notify

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.

ui

Web + terminal UI

A Svelte dashboard ships inside the binary. A Bubbletea TUI for SSH sessions. Same data, two surfaces, no extra installs.

logs

Live log streaming

Watch a task's output as it happens, in the browser or over SSH. Tail historic logs without grepping through files.

offline

Works without internet

Everything runs with the network unplugged. No phone-home, no account, no dependency on anyone's servers to fire a job.

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." Here's the honest yes/no against the tools you're probably running today.

Capability cronsystemd timerssupervisordPM2 RunWisp
Run history per firing journallimited
Captured stdout / stderr journal
Retries with backoff unitrestarts
Failure notifications
Catch-up after downtime persistent
Scheduling + supervision in one two unitsconflated
Built-in web dashboard basicpaid
Single static binary, no runtime PythonNode
Same on macOS / WSL / Docker variesLinux
Pre-installed on the box
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 open-source, free to self-host, forever. No telemetry, no account, no paid tier gating any feature. The Web UI and TUI ship in the binary.
Which platforms does it run on?
One Go binary on Linux, macOS, WSL, and Docker, about 25 MB 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 at the next valid minute. DST is named, auditable behaviour, not an annual silent bug.
Get started
gpl-3.0-or-later · no telemetry · 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