Configuration overview
RunWisp is configured through a single runwisp.toml file. It is the
sole source of truth for what runs and how — the REST API and Web UI
are read-only and trigger-only, never mutate task definitions. To pick up
edits, restart the daemon.
The file is divided into a handful of sections. Most are optional; the only
thing RunWisp truly needs is at least one [tasks.*] or [services.*]
table with a run key.
A complete example
Section titled “A complete example”# Disk-usage safeguards[storage]max_size = "5gb"min_free_space = "500mb"
# Global defaults applied to every task unless overridden[defaults]timeout = "1h"log_max_size = "100mb"log_on_full = "drop_old"keep_runs = 50keep_for = "30d"
[tasks.backup-db]group = "Backups"description = "Nightly database backup"cron = "0 2 * * *"timeout = "30m"on_overlap = "skip"keep_runs = 30run = "pg_dump mydb | gzip > /backups/mydb-$(date +%F).sql.gz"
[tasks.process-event-queue]description = "Worker that retries with exponential backoff"cron = "*/10 * * * *"on_overlap = "queue"retry_attempts = 3retry_delay = "2s"retry_backoff = "exponential"run = "/usr/local/bin/process-queue"
[services.metrics-daemon]description = "Always-on metrics collector"run = "/usr/local/bin/metrics-agent"If you run runwisp in a directory without a runwisp.toml, it
offers to write a minimal starter for you — see
Your first task.
Section by section
Section titled “Section by section”| Section | Purpose | Reference |
|---|---|---|
[storage] | Disk-usage limits — caps total bytes used and reserves headroom on the data partition. | [storage] |
[defaults] | Defaults inherited by every task and service unless explicitly overridden. | [defaults] |
[tasks.<name>] | Scheduled or manually-triggered units of work. Cron expression, concurrency, retries, timeout, retention. | [tasks.*] |
[services.<name>] | Always-on processes. One or more instances, exponential restart backoff, graceful shutdown. | [services.*] |
[[notifier]] | Declares one outbound channel. Repeated for each channel. | Notifications model |
[[notification_route]] | Sends events (run.failed, run.timeout, …) to one or more channels. One rule, many tasks. | Notification rules |
[notify] | Global notification settings — queue size, retention, in-app toggle. | Global settings |
notify_on_failure | Sets the channels to notify when one specific task ends failed, timeout, or crashed. | Per-task notifications |
Reload semantics
Section titled “Reload semantics”RunWisp does not currently support live reload of runwisp.toml.
There is no file watcher, no SIGHUP handler, and no runwisp reload
subcommand. A running daemon keeps the config it parsed at startup
until you restart it — Ctrl-C the daemon, edit the file, and run
runwisp daemon again (or restart it through whatever supervisor you
have managing the process).
Restart is fast: in-flight runs are cancelled (they record as
stopped if they exit within the [daemon] shutdown_timeout window,
or get reconciled as crashed on next boot if they don’t), the
database is reopened, and the schedule is re-applied from the new
file. See Operations: upgrading for the
current restart-based workflow.
A startup parse error fails the boot — the daemon exits non-zero before
opening its port. Your previous instance has already exited by then, so
the safe pre-flight is runwisp validate against the new file before
you restart.
What the schema considers a breaking change
Section titled “What the schema considers a breaking change”Pre-1.0, any release may ship breaking changes to the TOML schema, REST API, or on-disk data layout, and upgrading may reset run history. Changes are flagged in the CHANGELOG; semver guarantees land with 1.0.