A cross-platform task runner and build orchestration tool. Define tasks once, run them anywhere.
If you've ever wanted npm run scripts but for Go, Rust, C++, or any other language—Pace is for you. Unlike Make (which has limited Windows support) or language-specific runners, Pace works the same on Windows, Linux, and macOS with an intuitive configuration syntax.
- Cross-platform - Works on Windows, Linux, and macOS
- Simple syntax - Human-readable
.paceconfiguration files - Task dependencies - Chain tasks together with automatic ordering
- File watching - Re-run tasks when source files change
- Smart caching - Skip unchanged tasks based on file hashes
- Hooks - Run setup/cleanup commands before and after tasks
- Arguments - Pass parameters to tasks with positional or named args
- Retry logic - Automatically retry failed tasks
- Parallel execution - Run independent tasks concurrently
iwr -useb https://raw.githubusercontent.com/Azuyamat/pace/refs/heads/master/install.ps1 | iexwinget install Azuyamat.Pacecurl -sSL https://raw.githubusercontent.com/Azuyamat/pace/refs/heads/master/install.sh | shDownload the .deb package from releases:
sudo dpkg -i pace_<version>_amd64.debgo install github.com/azuyamat/pace/cmd/pace@latestDownload the appropriate binary for your platform from the releases page.
Let Pace automatically generate a configuration for your project:
cd your-project
pace initPace will detect your project type (Go, Node.js, Python, Rust) and create an optimized config.pace with appropriate tasks, caching, and file patterns.
Alternatively, create a config.pace file in your project root:
default build
task build [b] {
description "Build the project"
command "go build -o bin/app main.go"
requires [test]
inputs [**/*.go]
outputs [bin/app]
cache true
}
hook test {
description "Run tests"
command "go test ./..."
}
Run your default task:
pace runOr run a specific task:
pace run buildDefine reusable values:
var output = "bin/myapp"
var version = "1.0.0"
task build {
command "go build -ldflags '-X main.Version=${version}' -o ${output} ."
}
Create shortcuts for tasks using inline syntax:
task build [b] {
description "Build the application"
command "go build -o bin/app main.go"
}
task test [t] {
description "Run tests"
command "go test ./..."
}
task dev [d] {
description "Start development server"
command "go run main.go"
}
Or use standalone alias statements:
alias b build
alias t test
alias d dev
Now you can run:
pace run b # same as: pace run buildtask example [ex] {
description "Example task with all properties"
command "echo 'Hello World'"
# Dependencies and hooks
depends-on [other-task] # Tasks that must complete before this one
requires [setup] # Hooks to run before task
triggers [cleanup] # Hooks to run after task
on_success [notify] # Hooks to run on success
on_failure [alert] # Hooks to run on failure
# File tracking for caching
inputs [src/**/*.go, go.mod]
outputs [bin/app]
# Performance and behavior
cache true # Enable smart caching
timeout "10m" # Maximum execution time
retry 3 # Number of retry attempts
retry_delay "5s" # Delay between retries
# Execution environment
working_dir "src" # Working directory for command
env {
NODE_ENV = production
DEBUG = false
}
# Conditional execution
when "platform == linux" # Only run on Linux
# Flags
silent false # Suppress output
parallel false # Run dependencies in parallel
continue_on_error false # Continue if task fails
watch false # Enable file watching
}
Property Defaults:
cache: falseparallel: falsesilent: falsecontinue_on_error: falsewatch: falseretry: 0
Note: You can use identifiers or strings in arrays. Arrays support both [item1, item2] and ["item1", "item2"] syntax.
Pass arguments to tasks:
task greet {
args {
required ["name"]
}
command "echo 'Hello, $name!'"
}
pace run greet --name=WorldOr use positional arguments:
task echo {
command "echo $1 $2"
}
pace run echo hello worldHooks are lightweight tasks for setup/cleanup:
hook "format" {
description "Format code"
command "gofmt -s -w ."
}
pace run [task] # Run a task (or default task)
pace watch [task] # Watch inputs and re-run on changes
pace list # List all tasks and hooks
pace list --tree # List with dependency tree
pace help [command] # Show help--dry-run- Show what would run without executing--force- Ignore cache and force execution
Watch task inputs and automatically re-run:
pace watch buildThis monitors all files matching the task's inputs patterns and re-executes when changes are detected.
When cache true is set, Pace tracks:
- Input file hashes
- Output file hashes
- Command string
- Dependency results
If nothing has changed since the last run, the task is skipped. Cache data is stored in .pace-cache/.
Syntax highlighting for .pace files is available. Check the vscode-pace directory for the extension.
default all
task all {
description "Build all components"
depends-on [backend, frontend]
command "echo 'Build complete'"
}
task backend [be] {
description "Build Go backend"
command "go build -o bin/server cmd/server/main.go"
inputs [cmd/**/*.go, internal/**/*.go]
outputs [bin/server]
cache true
}
task frontend [fe] {
description "Build React frontend"
command "npm run build"
working_dir "frontend"
inputs [frontend/src/**/*]
outputs [frontend/dist/**/*]
cache true
}
var app_name = "myapp"
task dev [d] {
description "Start development server with hot reload"
requires [generate]
command "go run cmd/server/main.go"
watch true
inputs [**/*.go]
}
hook generate {
description "Generate code"
command "go generate ./..."
}
task test [t] {
description "Run all tests"
command "go test -v ./..."
inputs [**/*.go]
cache true
}
task lint [l] {
description "Lint Go code"
command "golangci-lint run"
inputs [**/*.go]
cache true
}
task build [b] {
description "Build production binary"
command "go build -o bin/${app_name} cmd/server/main.go"
requires [test, lint]
inputs [**/*.go]
outputs [bin/${app_name}]
cache true
}
Contributions are welcome! This is a passion project, so new ideas and improvements are always appreciated.
MIT
