Skip to content

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.

# 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 = 50
keep_for = "30d"
[tasks.backup-db]
group = "Backups"
description = "Nightly database backup"
cron = "0 2 * * *"
timeout = "30m"
on_overlap = "skip"
keep_runs = 30
run = "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 = 3
retry_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 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.

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.