runner is for people who bounce between codebases and refuse to memorize each repo’s private little task-running religion.
Instead of guessing whether this one wants npm run, pnpm exec, bunx,
cargo, uv run, deno task, turbo, make, just, etc. type:
run <TAB>run ran in this very project
❯ run
run 0.12.2
Package Managers bun, cargo
Task Runners just
Node 24.14.1
Monorepo yes
just build-packages
just default
just gen-schema Drift guard: just gen-schema && git diff --exit-code schemas/
just install
just ls
just run
just runner
just test-release Build release bin and verify the facade shims spawn the native binary.
cargo b build
cargo bb build --bin run --bin runner
cargo bbr build --bin run --bin runner --release
cargo bin-run run --quiet --bin run
cargo bin-runner run --quiet --bin runner
cargo c check
cargo cl clippy --all-targets --all-features
cargo comp run --quiet --bin runner -- completions
cargo d doc
cargo f run --quiet --bin run -- --pm npm dprint fmt
cargo format run --quiet --bin run -- --pm npm dprint fmt
cargo i install --path .
cargo l clippy --all-targets --all-features -- -D warnings -D clippy::all
cargo lint clippy --all-targets --all-features -- -D warnings -D clippy::all
cargo man run --quiet --features man -- man
cargo meta metadata --format-version 1
cargo r run
cargo rbin-run run --quiet --bin run --release
cargo rbin-runner run --quiet --bin runner --release
cargo rm remove
cargo rq run --quiet
cargo rr run --release
cargo runner run --quiet --bin runner
cargo schema run --quiet --features schema -- schema
cargo t testand run <TAB> (zsh):
❯ run <TAB>
-- just --
build-packages run
default runner
gen-schema -- Drift guard: just gen-schema && git diff --exit-code schemas/ just:runner
install test-release -- Build release bin and verify the facade shims spawn the native binary.
ls
-- cargo (aliases) --
b -- → build lint -- → clippy --all-targets --all-features -- -D warnings -D clippy::all
bb -- → build --bin run --bin runner man -- → run --quiet --features man -- man
bbr -- → build --bin run --bin runner --release meta -- → metadata --format-version 1
bin-run -- → run --quiet --bin run r -- → run
bin-runner -- → run --quiet --bin runner rbin-run -- → run --quiet --bin run --release
c -- → check rbin-runner -- → run --quiet --bin runner --release
cl -- → clippy --all-targets --all-features rm -- → remove
comp -- → run --quiet --bin runner -- completions rq -- → run --quiet
d -- → doc rr -- → run --release
f -- → run --quiet --bin run -- --pm npm dprint fmt cargo:runner -- → run --quiet --bin runner
format -- → run --quiet --bin run -- --pm npm dprint fmt schema -- → run --quiet --features schema -- schema
i -- → install --path . t -- → test
l -- → clippy --all-targets --all-features -- -D warnings -D clippy::all
-- Options --
--dir -- Use this directory instead of the current one
--pm -- Override the detected package manager (also reads RUNNER_PM when omitted). Valid: npm, yarn, pnpm, bun, cargo, deno, uv, poetry, pipenv, go, bundler (alias: bundle), composer
--runner -- Override the detected task runner (also reads RUNNER_RUNNER when omitted). Valid: turbo, nx, make, just, task (alias: go-task), mise, bacon
--fallback -- What to do when no detection signal matches: probe (default, PATH probe), npm (legacy silent fallback), error (refuse). Also reads RUNNER_FALLBACK when omitted.
--on-mismatch -- What to do when the manifest declaration disagrees with the lockfile: warn (default), error (exit 2), ignore (silent). Also reads RUNNER_ON_MISMATCH when omitted.
--explain -- Print a one-line trace describing how the package manager was resolved. Also enabled when RUNNER_EXPLAIN is set to a truthy value.
--no-warnings -- Suppress all non-fatal warnings on stderr. Also enabled when RUNNER_NO_WARNINGS is set to a truthy value.
--schema-version -- Pin JSON output schema version (1 or 2). Defaults to latest. Affects --json output of doctor/list/why only.
--sequential -- Run the given tasks sequentially. Conflicts with `--parallel`
--parallel -- Run the given tasks in parallel. Conflicts with `--sequential`
--keep-going -- Run every task in the chain regardless of failures. Conflicts with `--kill-on-fail`
--kill-on-fail -- Parallel only: SIGKILL siblings on first failure. Accepted but unused in sequential mode
--help -- Print help
--version -- Print versionrunner detects the project, finds its tasks, and completes them through one command.
Use the same shape everywhere:
run <TAB>
runner install test build deployLet each repo decide what the tasks actually mean.
npm install -g runner-runOr:
cargo binstall runner-runOr on Arch Linux:
yay -S runner-run-binOther install methods
cargo install runner-run
cargo install --git=https://github.com/kjanat/runner/ runner-run
cargo install --path .# AUR source build (compiles via cargo):
yay -S runner-runcurl -fsSLO https://raw.githubusercontent.com/kjanat/runner/master/install.sh
bash install.sh
bash install.sh 0.12.2
bash install.sh v0.12.2Use the action to install runner in CI:
- uses: kjanat/runner@master
- run: runner install --frozen test buildrunner install is not a task — it runs the project's toolchain command(s)
(npm ci, cargo fetch, uv sync, …), then chains the listed tasks
(test, then build) sequentially.
That is the point: the workflow stays boring even when the project underneath is npm, pnpm, bun, Cargo, Deno, uv, Make, just, or whatever automation that repo uses.
Install mechanics and outputs
The action installs the runner-run npm package into the runner tool cache with
npm install --global --ignore-scripts --prefix, verifies the installed
runner shim by running runner --version, and adds the npm bin directory to
PATH for later steps.
| I/O | name | description |
|---|---|---|
| Input | version |
npm version spec for runner-run; defaults to latest; accepts numeric v? forms |
| Output | version |
Concrete version reported by the installed runner --version smoke test |
| Output | bin-dir |
npm global bin directory containing runner / run; added to PATH for later steps |
Exact X.Y.Z pins are checked against the executed CLI version; a mismatch
fails the action.
runner # show detected project info
runner <task> [-- <args...>] # run a task
runner run <target> [-- <args...>] # run a task or command
run <target> [-- <args...>] # alias for `runner run`
runner install [--frozen] # install dependencies
runner clean [-y] [--include-framework]
runner list [--raw] [--json] # list available tasks
runner info [--json] # show detected project info
runner doctor [--json] # show every resolver signal
runner why <task> [--json] # explain how a task would dispatch
runner completions [<shell>] [-o <path>]runner completions generates dynamic shell completion registrations.
For bash, zsh, and fish, runner can auto-detect $SHELL:
eval "$(runner completions)"...or get explicit with it
eval "$(runner completions bash)"
eval "$(runner completions zsh)"
eval "$(runner completions fish)"runner completions powershell | Out-String | Invoke-ExpressionThe generated registration includes runner and, when the sibling run binary
exists next to it, run too.
So after setup, this is the workflow:
run <TAB>No per-project command archaeology. No guessing whether this one wants npm, Cargo, Make, just, Deno, uv, or some handcrafted nonsense from 2021.
man runner and man run (plus man runner-<subcommand>) ship with every
install channel — AUR (runner-run / runner-run-bin), npm
(npm i -g runner-run), crates.io, and install.sh. The pages are rendered
from the CLI definition at release time, not committed.
runner run <target> first looks for a matching task.
If no task exists, it falls back to executing <target> through the detected
toolchain where appropriate, such as:
npm exec / npx, yarn run / yarn exec, pnpm exec, bun x / bunx,
deno x, uvx, go run
For package managers without a matching exec primitive, runner falls back to
executing <target> directly from PATH.
The run binary is equivalent to runner run, so:
run clean
run installruns a task or command named clean or install, even when those names also
exist as built-in runner subcommands.
runner detects and works with:
npm, yarn, pnpm, bun, cargo, deno, uv, poetry, pipenv, go, bundler, composer
It aggregates tasks from these runners:
turbo, nx, make, just, go-task, mise, bacon
reading them from:
package.json / package.json5 / package.yaml
turbo.json / turbo.jsonc
deno.json / deno.jsonc
Makefile
justfile
Taskfile
bacon.toml
mise.toml / .mise.toml
Cargo aliases from .cargo/config.toml
pyproject.toml [project.scripts] (run via uv / poetry / pipenv)
It also understands monorepo/workspace context from:
turbo, nx, pnpm, npm/yarn workspaces, Cargo workspaces
Support notes
nx is currently detection-only. runner uses it for project context, but does
not extract Nx tasks as direct task entries yet.
When multiple sources define the same task, runner chooses deterministically: turbo tasks first, then package manifest scripts, then other matching sources.
run <TAB>task completion across projects- One command shape across many ecosystems
- Simple CI with
runner install --frozenplusrun <task>steps - First-class GitHub Actions install step
- Automatic toolchain detection
- Task aggregation from common config files
- Task-first execution with command fallback
- Monorepo/workspace awareness
- Safe clean defaults
- Node version mismatch warnings
- Site: runner.kjanat.dev
- npm:
runner-run - crates.io:
runner-run - aur:
runner-run,runner-run-bin
MIT © 2026 Kaj Kowalski