← all releases

v0.13.0

pre-release on GitHub

Not the newest. v1.5.1 is out →

Release notes

Added

  • --json output for runwisp status, list, and validate. A schema-versioned, machine-readable document on stdout for headless and agent-driven use; failures still exit non-zero and emit JSON. See CLI.
  • JSON Schema for runwisp.toml. runwisp schema prints it (also published at https://docs.runwisp.com/config.schema.json); scaffolded and imported configs carry a #:schema line so editors validate and autocomplete them. See Driving with an AI agent.
  • runwisp exec --json prints a run’s outcome (run id, status, exit code, duration, failed) as one JSON document on stdout, diverting log lines to stderr; a run that can’t start (unknown task, unreachable daemon) emits an error document instead of nothing. See CLI.
  • runwisp agent-guide prints a paste-ready snippet for your project’s AGENTS.md/CLAUDE.md so an AI coding agent knows how to drive RunWisp. See Driving with an AI agent.

Changed

  • runwisp validate --json errors now carry a structured location (key, line, column) for parse-time failures, so tooling can point at the offending site without parsing the message. See CLI.
  • Readable daemon logs. Log lines now render as 2026-05-27 14:03:01 [INFO] message key=value — colored on an interactive terminal, plain otherwise — instead of Go’s terse level=INFO msg=… logfmt. --log-format=json is unchanged for pipelines. See Logging.
  • Colored, readable --help and errors. Help pages are styled in the RunWisp brand palette, and every error — a typo like runwisp install, a bad config, a failed runwisp password — shares one branded ERROR block instead of a raw log line; plain text when piped or under NO_COLOR. See CLI.
  • runwisp service install --data . installs into the current directory. A relative --data is resolved to its absolute path and baked into the unit instead of being rejected, and declining the suggested data location now offers the current directory rather than erroring out. See Autostart.

Fixed

  • Deep-linking to a deleted or unknown run now shows a “Run not found” state instead of silently displaying a different run under the dead URL. See Web UI tour.
  • The Web UI header no longer pushes the theme toggle and notification bell off-screen on phone-width viewports; informational chips collapse and the controls stay reachable. See Web UI tour.
  • The login screen distinguishes rate-limiting from a wrong password — after too many attempts it tells you to wait instead of reporting “Invalid password”. See Auth.
  • The TUI’s quick status filter (f) now also reaches Skipped and Stopped, matching the Web UI’s status buckets. See the TUI tour.
  • runwisp demo rejects --config/--data it can’t honor instead of silently discarding them; use --seed-only to seed your own paths. See CLI.
  • Task run-parameter form labels are wired to their inputs, so clicking a label focuses its field and screen readers associate the two. See Parameters.
  • runwisp exec no longer exits before a just-triggered run’s output appears. A freshly triggered run is handed back before its record is durably persisted, so the log stream could momentarily find no run and close empty; exec treated that as “the run produced nothing” and exited without printing its output. It now retries until the run becomes streamable.
  • A plain runwisp daemon is no longer misreported as service-managed. Detection dropped the unreliable systemd INVOCATION_ID heuristic (inherited by every process in a desktop terminal) and keys solely on the marker our generated units set, so the TUI quit dialog and cloud self-restart no longer treat a hand-launched daemon as init-managed. See Autostart.
  • A cloud service:apply can no longer overwrite a non-service task’s command, and its instance count is capped like a TOML service — the control plane can’t rewrite what a cron or one-shot task runs, nor start an unbounded fleet.
  • Cloud-dispatched runs and services are cleaned up once they finish. Ad-hoc executions are reaped after they retire, and a new service:remove tears down a cloud-declared service, instead of stranding a supervisor goroutine per dispatched name.
  • Container tasks honor graceful_stop and stop_signal on stop. A stopping container is sent its configured signal and given the grace window before being force-killed, matching shell and compose tasks. See Tasks.
  • Reloading to drop then re-add a task while a run is still draining no longer deletes the revived task or stalls its queue. See Reload.
  • Untrusted values in the daemon log can’t inject terminal escape sequences — control bytes in a logged field (e.g. a task name from an HTTP body) render as visible escapes rather than raw bytes. See Logging.
  • A coalesced notification that fails at its window-close flush now raises an in-app alert, matching uncoalesced failures, instead of failing silently. See Notifications.
  • The failed-run summary no longer omits start_failed runs, so the metrics counter and the TUI “Failed” tally agree. See Metrics.
  • Opening a data directory written by a newer RunWisp fails with a clear error instead of silently running an older binary against a schema it doesn’t understand.
  • runwisp validate --json reports every configuration problem in one pass, each with its own location, instead of stopping at the first. See CLI.
  • runwisp list --json emits tasks: [] (never null) on a config-load error, matching status and validate. See CLI.
  • runwisp exec --json keeps a run’s real exit code when the trailing status fetch fails — the outcome captured during the follow is reused instead of being masked as a failure. See CLI.
All releases