CLI reference
The runwisp binary is the daemon, the TUI launcher, the config
scaffolder, and a small handful of one-shot helpers. Run it with no
arguments to start the daemon and attach an interactive TUI; pass a
subcommand for everything else.
All subcommands share the same set of global flags and honour the same environment variables.
Subcommands at a glance
Section titled “Subcommands at a glance”The two-verb model: exec runs a task in this CLI process (no daemon
needed); run-task asks a running daemon to start one. They never
collide — exec refuses if a daemon is already attached to the data
dir, and run-task requires one.
| Command | What it does |
|---|---|
runwisp (no args) | Spawn the daemon if not running and attach the TUI. The everyday command. |
runwisp daemon | Headless start for systemd / Docker. |
runwisp cloud | Headless start in cloud mode. Requires RUNWISP_CLOUD_TOKEN. |
runwisp tui | Attach a fresh TUI to an already-running daemon. |
runwisp exec <task> | Run a task in this process (no daemon), stream its output. |
runwisp run-task <task> | Trigger a run via the running daemon’s REST API. |
runwisp list | Print configured tasks as a table. Reads runwisp.toml only. |
runwisp status | Hit the daemon’s /health endpoint. Exit 0 = alive. |
runwisp init | Scaffold an annotated runwisp.toml and a random password. |
runwisp validate | Parse and check runwisp.toml without starting anything. |
runwisp openapi | Print the OpenAPI 3.1 spec for the daemon’s REST API to stdout. |
There is no runwisp reload. To pick up changes to runwisp.toml,
restart the daemon. The reload-without-restart story is on the roadmap;
today it is restart-only.
Default — runwisp with no args
Section titled “Default — runwisp with no args”runwispWhat it does, in order:
- Resolves the password —
RUNWISP_PASSWORDenv var, thendata/password, else generates one and writes it todata/password. - Pings
http://<host>:<port>/health.- Already running: connects and attaches the TUI.
- Port held by something else: prints what’s holding it and exits 1.
- Port free: spawns a background daemon, waits up to 10s for it to become healthy, then attaches the TUI.
Quitting the TUI does not stop the daemon — the daemon was spawned in
the background and keeps running. Use Ctrl+C while the daemon is
attached inline (i.e., the spawn fell back to inline mode) or kill it
explicitly. The TUI’s own status footer tells you which mode you’re in.
runwisp daemon
Section titled “runwisp daemon”Headless start. Runs the scheduler, REST API, and Web UI without an
attached TUI — the right verb for systemd ExecStart, Docker CMD, and
anywhere else stdin isn’t a terminal. For an attached TUI, run runwisp
with no subcommand instead.
ExecStart=/usr/local/bin/runwisp daemon --config /etc/runwisp/runwisp.toml --data /var/lib/runwispExits with status 1 on startup error (port in use, invalid config,
unwritable data dir). Otherwise runs until SIGTERM / SIGINT.
runwisp cloud
Section titled “runwisp cloud”Headless start in cloud mode — the daemon connects outbound to a RunWisp cloud control plane (or any peer that speaks the AsyncAPI protocol) for observability push and ad-hoc dispatch. The local cron scheduler is not started; scheduling is owned by the peer.
runwisp cloud [--token <token>] [--url <url>] [--env-file <path>] [--no-tui]| Flag | Type | Default | What it does |
|---|---|---|---|
--token | string | (env) | Cloud token (overrides RUNWISP_CLOUD_TOKEN). |
--url | string | (env) | Cloud API URL (overrides RUNWISP_CLOUD_URL). Defaults to the production endpoint. |
--env-file | string | .env | Path to a dotenv file. Loaded into the process environment before flag resolution. |
--no-tui | bool | false | Run headless. Logs to stderr instead of attaching a UI. |
Refuses to start if RUNWISP_CLOUD_TOKEN is unset after env-file load.
The cloud connection retries with backoff on transport failure and
never blocks task execution — see Prime Directive #4 (offline-complete).
runwisp tui
Section titled “runwisp tui”Attach a fresh TUI to a daemon that’s already running on --host:--port.
Useful when SSHing in to inspect a daemon started by systemd /
docker run -d.
runwisp tui [--password <password>]| Flag | Type | Default | What it does |
|---|---|---|---|
--password | string | (empty) | CHAP password. Falls back to RUNWISP_PASSWORD, then data/password. |
Exits 1 if the daemon is unreachable, the password is wrong, or auth is rate-limited.
runwisp exec <task>
Section titled “runwisp exec <task>”runwisp exec <task-name>Runs the task inside the CLI process — not against the running daemon. The CLI:
- loads
runwisp.toml, - instantiates an in-process executor and task manager,
- triggers the task,
- streams stdout/stderr line by line to your terminal,
- exits with the task’s exit code.
This makes exec the right command for one-off testing and CI smoke
runs.
runwisp exec opens the local SQLite store directly. If a daemon is
already running on the same data dir, the command refuses with an
error — two writers on one SQLite file silently corrupts state, so
the daemon’s PID file is checked before anything else happens. If you
need to fire a task at the running daemon, use
runwisp run-task instead.
runwisp run-task <task>
Section titled “runwisp run-task <task>”runwisp run-task <task-name>Asks the running daemon to start a fresh run for <task-name> via the
REST API. The CLI authenticates with the resolved password
(RUNWISP_PASSWORD → data/password), POSTs the trigger, and prints
the new run’s ULID. It does not stream output — for that, attach
the TUI (runwisp tui) or open the Web UI.
The complement to runwisp exec: exec runs
in-process and refuses when a daemon is up; run-task requires a
daemon to be reachable.
runwisp list
Section titled “runwisp list”runwisp listLoads runwisp.toml (no daemon required) and prints a table:
NAME SCHEDULE CONCURRENCY POLICY API DESCRIPTIONbackup-postgres 0 3 * * * 1 queue yes Nightly logical dumpapi-worker (service x3) 1 skip yes Three workers consuming the job queuedeploy-hook (manual) 1 skip yes Triggered after each releaseSCHEDULEshows the cron expression for tasks,(service xN)for services withinstances = N, or(manual)for tasks without acron.APIreflectsapi_trigger—nomeans the task can only fire on its cron, never from CLI/UI/REST.DESCRIPTIONis truncated to 50 characters.
Exit 0 on success, 1 if the file can’t be parsed.
runwisp status
Section titled “runwisp status”Pings /health first; on success, fetches /api/system for the version,
uptime, host, and CPU summary.
runwisp statusRunWisp is healthy at :9477 Version: 0.4.0 Uptime: 3h 12m CPU: 4 cores Host: builder-01Exit 0 if the daemon answers 200 OK on /health, 1 otherwise. The
extra metadata is best-effort — if /api/system is unreachable or
unauthorised, only the first line prints. Useful in shell scripts and
Docker HEALTHCHECK lines:
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD runwisp status || exit 1runwisp init
Section titled “runwisp init”Scaffold a runwisp.toml with worked examples and generate a one-time
random password.
runwisp init [--force]| Flag | Short | Type | Default | What it does |
|---|---|---|---|---|
--force | -f | bool | false | Overwrite an existing runwisp.toml. |
Refuses to clobber an existing file without --force. The generated
password is printed once on stdout — copy it somewhere safe; the daemon
also writes it to data/password on first run.
runwisp validate
Section titled “runwisp validate”runwisp validateParses runwisp.toml, runs the full schema validation, and exits. Does
not start the daemon, touch the database, or open ports. Pair it
with a pre-commit hook or CI job:
runwisp validate --config ./runwisp.tomlExit 0 if valid, 1 on parse or schema error. The error message names
the offending key.
runwisp openapi
Section titled “runwisp openapi”Pretty-prints the OpenAPI 3.1 spec for the daemon’s REST API to stdout.
The same file is committed at apps/runwisp/openapi.json;
this command is useful for producing it fresh from a development build.
runwisp openapi > openapi.jsonPipe it into a code generator (openapi-typescript, oapi-codegen, etc.)
to drive a typed client.
Global flags
Section titled “Global flags”Every subcommand accepts these — they bind on rootCmd and persist.
| Flag | Short | Type | Default | What it does |
|---|---|---|---|---|
--config | -c | string | runwisp.toml | Path to the TOML config file. |
--data | string | data | Data directory — SQLite, log files, JWT secret, password file, PID file. | |
--port | -p | int | 9477 | HTTP port for REST API + Web UI + SSE log streams. |
--host | string | 127.0.0.1 | Bind address. Use 0.0.0.0 to expose on the LAN; pair with a reverse proxy. |
Both --config and --data accept relative or absolute paths. Relative
paths are resolved against the current working directory at startup
— not the binary’s location, and not the directory holding
runwisp.toml.
Environment variables
Section titled “Environment variables”| Variable | What it overrides | Notes |
|---|---|---|
RUNWISP_PASSWORD | The login password used by Web UI / TUI / API. | Highest precedence: env > data/password > generated. |
RUNWISP_FINGERPRINT | The daemon’s instance fingerprint. | Otherwise read from SQLite, then computed from machine-id + cwd. |
RUNWISP_TRUST_PROXY | Trust X-Forwarded-Proto from a reverse proxy. | Comma-separated CIDR list (e.g. 127.0.0.1/32,::1/128). 0.0.0.0/0 rejected. |
GOMEMLIMIT | Go runtime soft heap limit. | Defaults to 128MiB to keep the daemon RAM-frugal on small VPSes. |
Exit codes
Section titled “Exit codes”RunWisp follows POSIX convention.
| Code | Meaning |
|---|---|
0 | Success. |
1 | Generic CLI error — config invalid, daemon unreachable, password wrong, etc. |
| N | runwisp exec only: returns the underlying task’s exit code on failure. |
The TUI propagates exit codes from the daemon process when running in-line.
Worked example: a CI smoke test
Section titled “Worked example: a CI smoke test”#!/usr/bin/env bashset -euo pipefail
runwisp validate --config ./runwisp.tomlrunwisp exec smoke-test --config ./runwisp.tomlvalidate ensures the file parses, then exec runs the task
in-process and the script exits with the task’s exit code — useful for
catching shell errors in run = """…""" blocks before deploying the
file to a running daemon.
Where to next
Section titled “Where to next”- Configuration reference — every key in
runwisp.toml. - Operations: data directory — what
--dataactually contains. - Operations: auth (CHAP + JWT) — how
--passwordflows into the login model.