Simple task runner.
keepup runs YAML-declared groups of commands composed into named flows.
Groups are atomic and reusable; flows decide how they run — either as ordered
parallel waves (step mode) or scheduled automatically from the data
dependencies between them (dag mode). Data flows between groups through
{{ output "name" }} references — rendered by a Go-template + sprig engine, and
validated up front. A single binary, no runtime, safe-by-default execution (no
shell unless you ask for it), and incremental re-runs via content-based caching.
| Feature | What it gives you |
|---|---|
| Groups + flows | Reusable command units composed into many named pipelines in one file — no duplication. |
| Two scheduling modes | step (explicit parallel waves with barriers) or dag (topological, inferred from {{ output.X }} data deps). |
| Output piping | Pass one group's captured stdout into another via {{ output "name" }}, validated at load time. |
| Structured outputs | {{ out "name" }} returns a structured value (stdout, stderr, exit code, duration, status) for richer when: predicates. output "name" is unchanged. |
| Templating | command/params are Go templates with sprig: {{ output "sha" | trunc 7 }}, {{ env "CI" | default "local" }}. Legacy {{ output.X }} still works. |
| Caching | Per-group cache: { reads, writes } fingerprints inputs (hash or mtime) and skips unchanged work, replaying stored output. |
| Watch mode | keepup watch re-runs a flow on file changes (using each group's cache.reads); caching makes unaffected groups no-ops. |
| Gating | require: (must pass) and skip-if: (skip when already done) predicates short-circuit a group before it runs. |
| Conditionals | when: skips a step (step mode) or a single dag-mode group (dag mode); skipping a dag group cascades to all its dependents. |
| Timeouts & retries | Per-step / per-flow timeout and retries envelope around each command attempt, with backoff. |
| Safe execution | Commands run as real argv by default (no shell injection); opt into a shell per group with shell:. |
| Env layering | Global env: plus per-group overrides, merged over the process environment. |
| Discoverability | keepup list, keepup validate, and keepup graph (Mermaid or Graphviz diagram: step waves, conditional and cacheable groups). run/watch/graph tab-complete flow names, with descriptions, from the config on the command line. |
| JSON events | keepup run --events and keepup watch --events emit a newline-delimited JSON stream for CI tooling. watch adds a watch.trigger {"files":[...]} event before each debounced re-run; the banner writes to stderr so --events - yields pure JSON on stdout. |
| Migration | keepup migrate converts legacy v1 configs to v2 and validates the result. |
Download an archive for your platform from the latest release — builds are published for macOS, Linux, and Windows on both amd64 and arm64:
VERSION=1.27.0
curl -sSLO "https://github.com/quike/keepup/releases/download/v$VERSION/keepup_${VERSION}_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz"
tar xzf keepup_${VERSION}_*.tar.gz
sudo install keepup /usr/local/bin/Each release ships a checksums.txt; verify with
sha256sum -c checksums.txt --ignore-missing.
From source:
go install github.com/quike/keepup@latestkeepup init # scaffold a starter keepup.yml
keepup run # run the default flow
keepup run ci # run a named flow
keepup watch dev # re-run on file changes
keepup list # show flows; `list groups` shows groups
keepup graph ci # diagram the flow (waves, conditionals, caches)
keepup run <TAB> # complete flow names from the current config- Index
- Usage — quick tour of the CLI
- Configuration — full schema reference
- FAQ — flows, modes, caching, migration