run
A simple scripting language for CLI automation. Define functions in a Runfile (or ~/.runfile) and call them from the command line to streamline your development workflow.
Why use run?
It hits a common sweet spot — lightweight, readable, and shell-native for quick CLI automation without the overhead of heavier task systems.
- Simple, familiar syntax for shell users and low onboarding cost.
- Nested names, positional args (
$1,$@) and default-value support cover most everyday tasks. - Multi-line commands, variables, and REPL make iterative development fast.
- Global (
~/.runfile) and project-specific (./Runfile) scopes.
What are the alternatives?
make: More about dependency tracking and rebuilding; heavyweight for simple command orchestration.runis easier for linear scripts and ad-hoc tasks.just: Closer in spirit (task runner with recipes).justhas richer features (recipe interpolation, shebangs, some safety) whilerunis simpler and more shell-native.- Plain shell scripts: More flexible but less discoverable and reusable.
runprovides a structured, listable command surface. - Language-based task runners (e.g., npm scripts, Mage): Offer ecosystem hooks and richer logic;
runis lighter and language-agnostic.
Prerequisites
- Rust toolchain with Cargo
- Windows users: PowerShell is used by default (pwsh or powershell). You can override this by setting the
RUN_SHELLenvironment variable to use other shells like Git Bash, WSL, or MSYS2.
Installation
Install via crates.io with Cargo:
Tab Completions
After installation, enable tab completions for your shell:
Or generate completion scripts manually:
Features
- Simple Function Definitions: Define reusable functions in a
Runfilewith clean syntax - Nested Functions: Organise related commands with colon notation (e.g.,
docker:shell,python:test) - Argument Passing: Pass arguments to functions using
$1,$2,$@, etc. - Default Values: Set fallback values using bash-style syntax (e.g.,
${2:-default}) - Multi-line Commands: Chain commands with
&&and split across lines with\ - Variable Support: Define and use variables in your scripts
- Interactive REPL: Start an interactive shell for testing commands
- List Functions: Quickly view all available functions with
--list - Global or Project-Specific: Use
~/.runfilefor global commands or./Runfilefor project-specific ones
Quick Start
Create a Runfile in your project root:
# Build and run commands
build() cargo build --release
test() cargo test
dev() cargo run
# Docker commands with arguments
docker:shell() docker compose exec $1 bash
docker:logs() docker compose logs -f $1
# Git helpers with multiple arguments
git:commit() git add . && git commit -m "$1" && echo "${2:-Done}"
Run your functions:
Usage
Basic Commands
Call a function from your Runfile:
Passing Arguments
Functions can accept arguments which are available as $1, $2, $@, etc:
Nested Functions
Organise related commands with colon notation and call them with spaces:
List Available Functions
View all functions defined in your Runfile:
Run a Script File
Execute a standalone script file:
Interactive Mode
Start a REPL to test commands interactively:
Runfile Examples
Python (with uv)
python:install() uv venv && uv pip install -r requirements.txt
python:test() uv run pytest
python:lint() uv run ruff check .
python:format() uv run black .
Node.js
node:install() npm install
node:dev() npm run dev
node:build() npm run build
node:lint() npm run lint
node:test() npm test
Docker
docker:build() docker build -t myapp .
docker:run() docker run -it --rm myapp
docker:shell() docker compose exec $1 bash
docker:logs() docker compose logs -f $1
docker:up() docker compose up -d
docker:down() docker compose down
Git Helpers
git:commit() git add . && git commit -m "$1" && echo "${2:-Done}"
git:amend() git commit --amend --no-edit
git:push() git push origin $(git branch --show-current)
Multi-line Functions
deploy() echo "Deploying to $1..." \
&& cargo build --release \
&& scp target/release/app server:/app/ \
&& echo "Deploy complete!"
Using All Arguments
echo_all() echo "All args: $@"
forward() docker exec myapp $@
Runfile Syntax
- Function Definition:
name() commandorname() command1 && command2 - Nested Functions:
category:name() command - Arguments: Access with
$1,$2,$3, etc. or$@for all arguments - Default Values: Use bash syntax like
${1:-default_value} - Multi-line: End lines with
\to continue on the next line - Comments: Lines starting with
#are comments - Variables: Define with
name=valueand use with$name
Configuration
Place your Runfile in one of these locations:
./Runfile- Project-specific commands (checked first)~/.runfile- Global commands available everywhere
Functions are executed in the underlying shell, so you can use any standard shell syntax, pipes, redirects, etc.
Shell Selection
By default, run uses:
- Windows: PowerShell (
pwshif available, otherwisepowershell) - Unix-like systems:
sh
You can override this by setting the RUN_SHELL environment variable:
# Use a different shell temporarily
RUN_SHELL=zsh
# Set it for your session (bash/zsh)
# Set it for your session (PowerShell)
# Windows users can use other shells like Git Bash
# Or use cmd (syntax in Runfile must be cmd-compatible)
This allows you to use any shell you prefer, as long as it supports the -c flag for executing commands.
License
MIT