Single Go binary · Linux · macOS · Windows
Your project's tasks, one line at a time.
One binary. Plain-text .wf files. No YAML. WF runs your build, install and deploy steps from top to bottom, and shows you exactly what ran.
How it works
Write. Run. Read.
Three steps, nothing hidden. Every line of a .wf file is one command, run in the order you wrote it.
1. Write
Group your commands in named sections of a .wf file: [deploy] # Deploy the app, then one command per line.
2. Run
wf deploy reads every .wf file in the current folder and runs the deploy section. wf build inside it calls another section.
3. Read
Each command is printed, its output framed, its duration shown. Sub-workflows are indented like a tree. The first failure stops everything.
Example
The same deploy, four ways.
Check that the tools are installed, install the dependencies, clear the cache, write a secret, start the containers. Read the WF version once and you know what it does.
deploy.wf · WF · 7 lines
[deploy] # Deploy the application require docker composer run composer install --no-dev remove var/cache write .env.local APP_SECRET=${GENERATE_SECRET} docker_compose up -d notify_success "Deployed!"
Makefile · Make · 10 lines
# Deploy the application
.PHONY: deploy
deploy:
@command -v docker >/dev/null || (echo "docker is required" && exit 1)
@command -v composer >/dev/null || (echo "composer is required" && exit 1)
composer install --no-dev
rm -rf var/cache
echo "APP_SECRET=$$(openssl rand -hex 32)" >> .env.local
docker compose up -d
@echo "Deployed!"
To know: tabs only, $$ escaping, .PHONY, shell commands, openssl installed.
justfile · just · 9 lines
# Deploy the application
deploy:
@command -v docker >/dev/null || (echo "docker is required" && exit 1)
@command -v composer >/dev/null || (echo "composer is required" && exit 1)
composer install --no-dev
rm -rf var/cache
echo "APP_SECRET=$(openssl rand -hex 32)" >> .env.local
docker compose up -d
@echo "Deployed!"
To know: recipe syntax, shell commands, openssl installed.
Taskfile.yml · Task · 16 lines
version: '3'
tasks:
deploy:
desc: Deploy the application
preconditions:
- sh: command -v docker
msg: docker is required
- sh: command -v composer
msg: composer is required
cmds:
- composer install --no-dev
- rm -rf var/cache
- echo "APP_SECRET=$(openssl rand -hex 32)" >> .env.local
- docker compose up -d
- echo "Deployed!"
To know: YAML indentation, Task keys, shell commands, openssl installed.
Why WF
Made for the steps you repeat.
Installing, building, deploying: a list of commands in a fixed order. You need them written down and run the same way every time, not a programming language.
Nothing to learn
A section is [name], a command is one line, a comment starts with #. Anyone on your team can read a .wf file.
No shell in between
run composer install runs composer with install. Quotes work like in a terminal; pipes and globs stay plain text. No surprises.
Native file commands
mkdir, write, copy, move, remove and set_permissions are built into WF. They do not depend on the tools of the machine.
Output you can read
A tree of workflows and commands, a timer on each one, and a clear message on the line that failed.
Compare
Like Make or just, without the syntax.
Those tools can do anything, so they need a language. WF only runs commands in order, so it needs none.
| Shell script | Make | just | Task | WF | |
|---|---|---|---|---|---|
| Install | Bash or PowerShell | make | Single binary | Single binary | Single Go binary |
| File | .sh / .ps1 | Makefile | justfile | Taskfile.yml | .wf files |
| Syntax | A programming language | Targets, tabs, make functions | Recipes, parameters, expressions | YAML, Go templates | One command per line |
| Conditions & loops | Yes | Yes | Yes | Yes | No, by design |
| Output | Raw | Raw | Raw | Raw or prefixed | Tree with a timer per command |
Scope
What WF will never do
A single Go file you can read in one sitting stays a tool you can trust. WF will not grow into another scripting language.
- add conditions
- add loops
- add functions
- run steps in parallel
- hide a shell behind your commands
- load plugins
- require a YAML file
Get WF
One download. Five platforms.
Linux x64 and ARM64, macOS Intel and Apple Silicon, Windows x64. Download the binary, put it in your PATH, and you are ready.