Skip to content

CLI reference

runwisp is one binary with a handful of subcommands. Run it with no subcommand and it does the friendly thing — attaches to a running daemon, or scaffolds a config and starts one. Everything else is a verb: validate, reload, exec, import, and so on. This page is the full list; each command also prints its own --help.

These apply to every subcommand. They decide which config gets read, where state lives, where the HTTP server listens, and how the daemon logs.

FlagDefaultWhat it does
--config, -crunwisp.tomlPath to the TOML config file, resolved against the working directory.
--data.runwispDirectory for all persistent state — SQLite DB, per-task logs, PID file, Unix socket.
--port, -p9477TCP port for the HTTP server (REST API, SSE log stream, Web UI).
--host127.0.0.1Bind address. Use 0.0.0.0 to listen on every interface.
--log-levelinfoVerbosity: debug, info, warn, error. Env: RUNWISP_LOG_LEVEL.
--log-formatautoLog shape: auto, text, json. Env: RUNWISP_LOG_FORMAT.

--data is the one to pick once and keep: the database (runwisp.db), the socket (runwisp.sock), and every task’s logs all live under it, so moving it later is a plain directory move, not a config change. The two logging flags get the full treatment in Logging.

Terminal window
runwisp # attach a TUI to a running daemon, or scaffold + start one
runwisp daemon # start headless (no TUI) — for Docker, systemd, cron
runwisp tui # attach a TUI to a local daemon over its socket
runwisp tui --url <URL> # attach a TUI to a remote daemon over HTTP

Bare runwisp is the everyday entry point. If a daemon already owns this data dir, it opens the TUI against it. Otherwise — and if there’s no runwisp.toml yet — it offers to scaffold a starter config, spawns the daemon in the background, and attaches.

If the port is already taken by another RunWisp daemon — one started from a different data directory — runwisp tells you which datadir and config that daemon is using and offers to connect to it, or to stop it and launch here instead. (Pick a different port any time with --port.) When the port belongs to something that isn’t RunWisp, you get the plain “port in use” error with hints for finding the culprit.

runwisp daemon is the headless variant for boxes with no terminal: it starts the scheduler, REST API, and Web UI without the TUI, and exits non-zero if there’s no config rather than hanging on a prompt nobody can answer. runwisp tui connects a fresh TUI to a daemon that’s already up, over the local socket — no password needed. Add --url (or set RUNWISP_URL) to attach to a daemon over HTTP — a remote host or a container — logging in with its password; the TUI tour covers how that password is read and cached.

Terminal window
runwisp validate # parse + validate runwisp.toml without starting anything
runwisp list # show configured tasks and their schedules
runwisp status # is the daemon alive right now?

runwisp validate is the CI-and-pre-commit friend: it loads the config, prints a short summary (task and service counts, the resolved timezone), and surfaces the same advisory warnings the daemon would log at boot — all without touching anything live. runwisp list renders the configured tasks as a table. runwisp status pings the daemon over its local socket and prints a short health summary; it also flags when runwisp.toml has changed on disk since the daemon started.

Terminal window
runwisp exec <task> # run a task, stream its output, exit with its code
runwisp exec <task> --daemon # require a running daemon (fail fast if none)
runwisp exec <task> --standalone # require in-process (refuse if a daemon owns the dir)

runwisp exec runs one task and streams its stdout/stderr straight to your terminal, exiting with the run’s own exit code — so it slots cleanly into a script. By default it auto-detects: if a daemon owns this data dir, the run is dispatched through its REST API and followed live; otherwise the task runs in this process from runwisp.toml. --daemon and --standalone pin the choice and are mutually exclusive.

Terminal window
runwisp reload # re-read runwisp.toml and reconcile the live task set
runwisp restart # stop and start fresh (restart-only settings, run_on_start, catch-up)
runwisp stop # shut the daemon down

For the everyday edits — adding, changing, or removing tasks and services, or tweaking [defaults]runwisp reload (the same thing as sending SIGHUP) re-reads the file and reconciles the running task set in place. It’s validate-first: a config that won’t parse, fails validation, or touches a restart-only setting is rejected and your running daemon keeps going untouched. In-flight runs finish under the definition they started with. The Reload page has the full rules.

runwisp restart is the heavier hammer: it stops the daemon and starts a new one, which is what you need for the restart-only settings ([daemon], the scheduler timezone, [storage], [notify], the bind host/port) and when you want a fresh boot to re-fire run_on_start and missed-run catch-up. runwisp stop takes the daemon down without starting a new one. When the daemon is managed by systemd or launchd (via runwisp service install), both restart and stop delegate to the service manager so its view of the unit stays in sync.

Terminal window
runwisp import cron [FILE] # convert a crontab to runwisp.toml
runwisp import supervisord [FILE...] # convert a supervisord config to runwisp.toml

Both read from a file or from stdin, print the generated TOML to stdout so you can review it, and write a # TODO comment for anything that doesn’t map cleanly — nothing is silently dropped. Shared flags:

FlagWhat it does
--output, -oWrite the TOML to this file instead of stdout.
--writeWrite to the --config path (default runwisp.toml).
--forceOverwrite the target file without prompting.
--quietSuppress the summary on stderr.
--system(cron only) Force system-crontab parsing (the user column).

System crontabs (/etc/crontab, /etc/cron.d/*) carry a user column; runwisp import cron detects that from the path or header and maps it to a per-task user. The Migrating from cron and Migrating from supervisord recipes walk through the whole flow.

Terminal window
runwisp service install # wire up systemd (Linux/WSL) or launchd (macOS)
runwisp service uninstall # remove the unit/plist (data dir is preserved)
runwisp service status # is autostart wired up, and has anything drifted?

These wire the daemon into the host init system so it survives a reboot — OS plumbing only, never touching runwisp.toml. install takes --yes (-y), --print (render the unit to stdout), --dry-run, --force (overwrite a hand-edited unit), --system (a system-wide unit on Linux), and --binary <path> (override the baked-in binary path). uninstall takes --yes, --force, and --purge (also delete the data dir — which makes you type the literal word delete to confirm). It’s all covered in depth on the Autostart page.

Don’t confuse runwisp service status (“will the daemon come back after a reboot?”) with runwisp status (“is it alive right now?”).

Terminal window
runwisp password # print the daemon's ephemeral password (local socket only)
runwisp openapi # print the OpenAPI 3.1 spec (JSON) to stdout

runwisp password fetches the in-memory ephemeral password over the local socket — handy when you want to log in from another device. It prints in plaintext, so pipe it to a clipboard tool (runwisp password | wl-copy) to keep it out of your scrollback. If the daemon uses a fixed RUNWISP_PASSWORD it refuses (that value is never disclosed); if it runs with RUNWISP_NO_AUTH there’s no password at all and the command exits with a distinct code.

runwisp openapi dumps the OpenAPI 3.1 schema to stdout for feeding into code generators — the same schema a running daemon serves at /openapi.json.

Terminal window
runwisp cloud # connect to the optional control plane instead of scheduling locally
runwisp demo # boot a throwaway, fully-populated instance to explore

runwisp cloud starts the daemon connected to the optional control plane; it needs RUNWISP_CLOUD_TOKEN (via env, .env, or --token) and takes --url and --env-file (default .env), plus --no-tui for headless. runwisp demo boots RunWisp against a temporary config and data dir pre-seeded with hundreds of historical runs, so you can poke around the TUI and Web UI without writing a config — everything lives in a temp directory that’s deleted when the daemon stops. It takes --cloud (and the same --token / --url / --env-file) to point at the control plane instead of seeding local history. Pass --no-tui to leave the daemon running in the background and print its Web UI password to stdout instead of opening the TUI — handy over SSH or in a script where you just want to open the Web UI in a browser; stop it later with runwisp stop --data <dir> (the demo prints the exact data dir alongside the password).

VariableWhat it does
RUNWISP_PASSWORDSets the daemon password in memory. Unset, a fresh ephemeral one is minted every boot. See Auth.
RUNWISP_NO_AUTH1 or true disables authentication entirely — local dev / trusted networks only. Mutually exclusive with RUNWISP_PASSWORD. See Auth.
RUNWISP_TRUST_PROXYComma-separated CIDR list of reverse proxies whose X-Forwarded-* headers the daemon may honor.
RUNWISP_CLOUD_TOKENToken for runwisp cloud. Ignored in standalone mode.
RUNWISP_CLOUD_URLControl-plane URL for runwisp cloud (overrides the built-in default).
RUNWISP_LOG_LEVELFallback for --log-level (debug/info/warn/error). The flag wins when both are set.
RUNWISP_LOG_FORMATFallback for --log-format (auto/text/json). The flag wins when both are set.