Configuration overview
Everything RunWisp does is configured in one file: runwisp.toml. It’s
the sole source of truth for what runs and how — the REST API and Web
UI can read and trigger, but they never touch your task definitions.
Edited the file? Run runwisp reload (or send SIGHUP) to pick it up;
a few daemon-wide settings need a full restart.
The file breaks into a handful of sections, and most of them are
optional. You’ll usually want at least one [tasks.*] or [services.*]
table with a run key — otherwise there’s nothing for the daemon to
run.
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"Run runwisp in a directory that doesn’t have a runwisp.toml yet and
it’ll offer to write a minimal starter for you — the
Quick start walks through that.
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] |
[daemon] |
Daemon-wide settings — shutdown budget, public URL for notification links, the metrics endpoint, extra config files (include), and real crontabs read as live tasks (include_cron). |
[daemon] |
[scheduler] |
Scheduler-wide settings — the default timezone every cron expression is evaluated in. | Timezone |
[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, per-execution parameters. | [tasks.*] |
[services.<name>] |
Always-on processes. One or more instances, exponential restart backoff, graceful shutdown. |
[services.*] |
[compose.<alias>] |
Imports services from an existing docker-compose.yml so each becomes an observable RunWisp service. |
[compose.*] |
[notifiers.<id>] |
Declares one outbound channel. One table per channel, keyed by id. | Notifications model |
[[route]] |
Sends events (run.failed, run.timeout, …) to one or more channels. One rule, many tasks. |
Notification rules |
[notify] |
Global notification settings — bell channels, retry budget, history retention, coalescing. | Global settings |
notify_on_failure |
Sets the channels to notify when one specific task ends failed, timeout, or crashed. |
Per-task notifications |
One rule cuts across every section: any string value can pull from an
env var or a file with ${VAR} / ${file:path} —
${...} substitution has the details.
Reload semantics
Section titled “Reload semantics”Edit runwisp.toml, then run runwisp reload (or send SIGHUP) to pick up the
change without bouncing the process. RunWisp never watches the file — reload is
always something you ask for.
Most of this file reloads live: tasks and services get added, changed, and
removed, and [defaults] re-applies. A handful of daemon-wide settings don’t,
and need a full runwisp restart instead:
[daemon][scheduler] timezone[storage][notify]- the bind host/port
Reload is validate-first and all-or-nothing, so a typo — or a change to one of those restart-only settings — is rejected and the running task set is left exactly as it was. Reload covers the guarantee, what a reload reports, and how in-flight runs behave.
One thing to watch that reload can’t protect you from: a parse error at
startup stops the boot cold. The daemon exits non-zero before it ever opens
its port. Run runwisp validate against the file before you deploy it.
What the schema considers a breaking change
Section titled “What the schema considers a breaking change”This is pre-1.0, so any release might change the TOML schema, the REST API, or the on-disk layout — and an upgrade may wipe run history. Anything like that gets flagged in the CHANGELOG; the semver guarantees kick in at 1.0.