Skip to content

Quick start

RunWisp is one small Go binary. You list the shell commands you want to run in a runwisp.toml, and RunWisp takes care of the rest — firing jobs on cron, restarting services when they crash, and capturing every line of stdout and stderr so you can go back and look at what happened. There’s a TUI in your terminal and a Web UI in your browser for poking around. No external database, no agent, no sidecar.

It runs on Linux, macOS, and WSL — on x86_64 or arm64. There’s no native Windows build; if Windows is where you live, run RunWisp inside WSL.

Pick whichever channel feels most natural for how you install software. The binary is statically linked with zero runtime dependencies, so as soon as it lands on your PATH, you’re done.

Figures out your OS and arch, grabs the right release, checks the SHA-256, and puts runwisp on your PATH.

Terminal window
curl -fsSL https://get.runwisp.com | sh

Pick a directory where you’d like your tasks to live — a project root, your home folder, anywhere you’d happily keep a config file — and run:

Terminal window
runwisp

The first time, when there’s no runwisp.toml next to you yet, RunWisp won’t go behind your back. It asks:

No runwisp.toml at /home/user/myproject.
Create a starter with one example task? [Y/n]

Hit Enter. RunWisp writes a starter file, fires up its daemon in the background, and drops you into the TUI. (The screenshot below shows a demo instance with some history; yours will start with just the hello task.)

TUI Home page: sidebar with task groups, right pane showing Open Web UI row, Web UI URL, masked password, and a recent-activity table.

The Home page hands you two things worth remembering: the Web UI URL (http://localhost:9477 out of the box) and an auto-generated password for logging in from the browser. You won’t need the password to open the dashboard from this TUI — it shoves a logged-in session straight at your browser. But if you’ll ever want to hit the dashboard from another machine, or from a fresh browser, highlight the password row now and press

Enter to copy it to the clipboard.

Here’s the runwisp.toml that just got written: one task you can actually run, plus a couple of commented hints showing the most common next steps.

runwisp.toml
# Docs: https://docs.runwisp.com/configuration/overview/
[tasks.hello]
description = "Example task. Trigger it from the TUI (press r) or the Web UI."
run = "echo hello from runwisp"
# Schedule a task with cron:
# [tasks.heartbeat]
# cron = "* * * * *"
# run = "date"
# Long-running service (auto-restart, supports replicas):
# [services.worker]
# instances = 1
# run = "node ./worker.js"

There are three places you can fire off hello. They all hit the same daemon and land in the same history — pick whichever is closest to where your hands already are.

Open the dashboard (step 4 walks through that the first time around), click hello in the sidebar, and hit Run Task. hello from runwisp streams into the log pane live, and the run shows up in the task’s history.

Press Esc to leave the exec view, arrow back up to Home in the sidebar, then highlight ⮕ Open Web UI on the Home page and hit Enter. Your default browser opens the dashboard, already logged in. Behind the scenes, the TUI mints a single-use launch ticket, so your password never travels through the URL. On a host without a browser, the TUI just prints the URL — open it from another machine and sign in with the password you copied in step 2.

Web UI dashboard: sidebar with tasks and services, daemon header with sparklines, recent activity feed below. Web UI dashboard: sidebar with tasks and services, daemon header with sparklines, recent activity feed below.

A few knobs worth knowing while you’re here:

  • Set RUNWISP_PASSWORD to pick your own password instead of the generated one. The daemon reads it in memory only, never writes it to disk, so it plays nicely with Docker secrets and systemd’s LoadCredential.
  • Running purely locally — a dev container, your laptop, an isolated network — and the login wall is just in the way? Set RUNWISP_NO_AUTH=1 to skip it entirely.
  • Use --host and --port to move the dashboard somewhere else. Defaults are 127.0.0.1 and 9477 — loopback only — which is almost always what you want.

That’s the whole loop. Now swap [tasks.hello] out for whatever you actually came here to run. A few patterns to crib from:

[tasks.backup-db]
cron = "0 2 * * *" # nightly at 2 AM
on_overlap = "skip" # don't pile up if a run is still going
keep_runs = 30 # keep the last 30 runs on disk
run = "pg_dump mydb | gzip > /backups/mydb-$(date +%F).sql.gz"
[tasks.health-check]
cron = "*/5 * * * *" # every five minutes
run = "curl -sf https://myapp.example.com/health || exit 1"
[services.worker]
instances = 3 # keep three copies alive at all times
run = "node /app/worker.js"

[tasks.*] run on a cron schedule or on demand and then exit. [services.*] are meant to stay up — when one falls over, RunWisp restarts it, and it keeps instances = N copies running in parallel. And that on_overlap = "skip" up there is one of three concurrency policies for when a run is still going as the next one comes due.

RunWisp doesn’t watch runwisp.toml for changes — you tell it when to pick them up. For the everyday edits — adding, changing, or removing tasks and services, or tweaking [defaults] — run runwisp reload (or send SIGHUP). It re-reads the file and reconciles the running task set in place. Reload is validate-first, so a typo is rejected and the daemon keeps running, and in-flight runs finish under the definition they started with.

Reach for runwisp restart when you’ve changed a restart-only setting ([daemon], the scheduler timezone, [storage], [notify], or the bind host/port), or when you want a fresh boot to re-fire run_on_start and missed-run catch-up. It stops the daemon and starts a new one with your edits loaded. (If you installed RunWisp as a service, it asks systemd or launchd to do the restart so the service manager stays in the loop.) Until you reload or restart, the TUI header, runwisp status, and the Web UI all show a notice that the config on disk no longer matches what the daemon is running. runwisp stop shuts the daemon down without starting a new one.