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 (live reload is on the roadmap, not yet
implemented).
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"The fully annotated reference lives next to the binary at
apps/runwisp/runwisp.example.toml
— or run runwisp init to drop it into your working directory.
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 manual jobs. Cron expression, concurrency policy, retries, timeout, retention. | [tasks.*] |
[services.<name>] | Always-on processes. One or more instances, exponential restart backoff, graceful shutdown. | [services.*] |
[[notifier]] | Outbound channels (Slack, Telegram, more on the way). Repeated for each channel. | Providers overview |
[[notification_route]] | Routes events (run.failed, run.timeout, …) to one or more notifiers. | [[notification_route]] |
[notify] | Global notification settings — queue size, retention, in-app toggle. | [notify] |
notify_on_failure (sugar) | Per-task shorthand that desugars to a synthetic notification route. | Per-task sugar |
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:
# systemdsudo systemctl restart runwisp
# Dockerdocker restart runwisp
# Manual (foreground)# Ctrl-C the daemon, edit the file, run `runwisp daemon` again.Restart is fast — it cancels in-flight runs (which record as stopped
if they exit within the daemon’s 3-second graceful-shutdown window, or
get reconciled as crashed on next boot if they don’t), reopens the
database, and re-applies the schedule from the new file. Live reload is
on the roadmap; 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, the TOML schema may receive breaking changes — they are flagged in
the CHANGELOG.
The Go schema in
apps/runwisp/internal/config/schema.go
is the authoritative spec; these docs are the on-ramp.