A Taskfile v3 runner for builds that need deterministic fingerprints, shared caches, and cross-machine locking.
This repository is the WALLIX fork of Task, reimplemented in Rust and distributed as a single self-contained binary. It is intended for teams that already use Taskfiles but need stronger guarantees around incremental builds and CI reuse.
The Rust rewrite preserves the Taskfile v3 schema, CLI flags, exit codes, and
observable behaviour of the previous Go implementation. Its black-box test
suite ports the Go test corpus, and its fingerprint checksums are
byte-compatible with the pre-rewrite WALLIX fork, so existing .task state
remains valid.
This is not upstream Task. The fork deliberately removes a few features and changes some semantics; review Compatibility and differences before replacing an upstream installation.
Create Taskfile.yml:
version: '3'
templater: jinja
tasks:
test:
desc: Run the test suite
cmds:
- go test ./...
build:
desc: Build the application
sources:
- '**/*.go'
- go.mod
- go.sum
generates:
- bin/app
cmds:
- go build -o bin/app ./cmd/appThen run:
$ task --list
$ task buildThe second task build is skipped when the inputs, commands, variables, and
generated output still match the saved fingerprint.
Start with the getting-started guide, then use the user guide for Taskfile discovery, variables, includes, and command-line usage. The full accepted shape is covered by the schema reference.
Download the archive for your platform from
GitHub Releases, extract task,
or task.exe on Windows, and place it on your PATH. Archives are published
for Linux, macOS, and Windows on x86-64 and ARM64, with a SHA-256 sidecar for
each archive.
An installed binary can update itself:
task --update # latest release
task --update=4.3.0 # a specific release
task --update --check # check without installingThe updater verifies the published checksum and runs the downloaded binary to
confirm its version before replacing the current executable. It asks for
confirmation unless --yes is supplied.
To build from source, use the toolchain pinned in rust-toolchain.toml:
cargo install --path crates/taskThe installation guide also covers shell completions, download verification, and reproducible builds.
Taskfiles are useful as a readable, repository-local interface to development and CI commands. The difficult part is deciding when work can safely be skipped and making that decision hold when several machines build the same revision. This fork concentrates on that problem.
A task fingerprint covers its sources, generated files, compiled commands, and
variable data. Source and output staleness are reported separately, and
task --status exposes the decision without executing the task:
task --status build
task --status --json buildOnly checksum-based fingerprinting is supported. Timestamp and none methods
were removed because they weaken the relationship between declared inputs and
the result.
A task can restore its generated files instead of running. Cache URLs are templates, so the source checksum can be part of the key:
version: '3'
templater: jinja
tasks:
build:
sources:
- src/**/*.ts
- package.json
- yarn.lock
generates:
- dist/**/*
cache:
url: 'file:///var/cache/task/build-{{ CHECKSUM }}.zip'
cmds:
- yarn buildTwo storage backends are available:
file://stores a ZIP archive on a local or mounted filesystem.oci://stores content-defined, zstd-compressed chunks in an OCI registry. Unchanged chunks are reused across cache entries, and a local content store makes repeated restores incremental.
For CI systems that move state as an artifact rather than expose a shared cache service, fingerprint state and generated files can be exported together:
task --export-cache state.zip build test
task --import-cache state.zipSee Setting up a cache server for an OCI registry deployment and credential configuration.
Tasks with both sources and generates are protected by a local advisory file
lock. The lock includes the task name and source hash, so equivalent builds are
serialized while different inputs remain independent.
Set cache.lock to coordinate across machines:
redis://uses a renewable Redis lease.vk://andvks://use the vk-registry lock API; usevks://when credentials cross an untrusted network.file://places the lock in an explicitly selected shared directory.
If a distributed lock cannot be acquired because its service is unavailable, Task warns and falls back to a local lock. If a held lease is lost, it does not publish the resulting fingerprint or cache entry.
setup is for preparation that must happen before the parent task is checked.
Setup tasks run sequentially and unconditionally, even when the parent is
already up to date. They do not become part of the parent's fingerprint; use
run: once for setup shared by several tasks.
version: '3'
templater: jinja
tasks:
version-file:
run: once
cmds:
- git describe --always > version.txt
build:
setup: [version-file]
sources:
- version.txt
- src/**/*.go
generates:
- bin/app
cmds:
- go build -ldflags "-X main.version=$(cat version.txt)" -o bin/app .Hashing every file in a large output directory can cost more than the staleness
check is worth. A generates entry may name one representative fingerprint
file while retaining the full glob for cache save and restore:
generates:
- glob: node_modules/**/*
fingerprint: node_modules/.yarn-state.ymlsources and generates may also inherit entries from direct dependencies or
task calls. This keeps wrapper tasks aligned with the work they aggregate:
tasks:
all:
deps: [frontend, backend]
sources:
- from: deps
generates:
- from: depsUse from: cmds instead when the related tasks are invoked through cmds.
Literal globs and inherited entries can be combined, and duplicates are removed
automatically.
New Taskfiles should use the native Jinja dialect explicitly:
version: '3'
templater: jinja
vars:
OUTPUT: dist/{{ OS() }}/app
tasks:
build:
cmds:
- '{% if CI %}echo building in CI{% endif %}'
- go build -o {{ OUTPUT }} .Jinja mode supports expressions, conditionals, loops, filters, and normal function-call syntax through minijinja.
The legacy Go text/template dialect remains available for compatibility but
is deprecated. Files without an explicit templater are auto-detected per
file. Convert them before Go rendering is removed:
task --migrate # preview on stdout
task --migrate --write # rewrite the Taskfile in placeSee the templating reference for dialect selection, supported functions, and migration limitations.
The compatibility target is Taskfile v3, including its command-line surface and observable runner behaviour. The following differences from upstream Task v3 are intentional.
- Remote
http://andgit://Taskfile includes and their CLI flags. - Timestamp fingerprinting and the task-level
methodfield. - The
nonefingerprint method.
- Unconditional, sequential
setuptasks. - File and OCI build-cache backends with local or distributed locking.
- Representative fingerprint files for large
sourcesorgeneratesglobs. from: depsandfrom: cmdsinheritance for sources and generated files.--status,--export-cache,--import-cache, and self-update commands.- Native Jinja templating and an automated migration path from Go templates.
- Duplicate YAML task keys are errors instead of last-definition-wins.
- Task-defined
envandvarsoverride the inherited process environment by default. SetTASK_X_ENV_PRECEDENCE=0to restore process-environment precedence. --forceapplies only to tasks named on the command line. Use--force-allto force their dependencies as well.- Dependency cycles fail with the cycle path instead of recursing until the process exhausts its stack. Self-calls with a different compiled body remain valid; recursion driven only by external state is rejected.
- Ctrl-C is escalated through running commands.
SIGTERMstops the run immediately and exits with status1. - Fingerprints include commands and variables as well as file contents, and report source and generated-output staleness independently.
For release-specific compatibility notes, including migration fixes and known gaps, read the changelog.
Linux release binaries are built as static musl executables from pinned inputs and are reproducible from their tagged source. Each Linux release includes a build manifest containing the binary digest. macOS and Windows binaries are reproducible only on the same pinned runner image.
The exact guarantees and verification commands are documented in Reproducible builds.
The workspace contains the runner library (taskcore), the CLI (task), and
the OCI content-addressed store (ocicas). A normal edit loop uses the pinned
Rust toolchain:
cargo check -p taskcore
cargo test -p taskcore --lib
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warningsRun the complete compatibility suite before submitting a change:
cargo test --workspaceChanges to Taskfile behaviour must preserve upstream compatibility or document an intentional divergence. See AGENTS.md for the architecture, development workflow, and review constraints.