Task Runners skill for Claude Code
One command menu for every repo, same in CI. Claude inventories the commands scattered across README, CI and scripts, picks one runner (npm scripts, just, Taskfile or Make), and maps them to standard names like setup, dev, test and check. Tasks fail fast under strict shell settings, list themselves with descriptions, confirm before deploying, and CI calls the very same check task developers run locally.
- name
task-runners - size224 lines · ≈1,800 tokens
- files1
- licenseMIT
- updated
What Claude sees before loading it
This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.
description: Sets up project task automation with Make, just, Taskfile (go-task), or npm scripts — a self-documenting command menu, consistent names like setup, dev, test, lint, and build, strict shell settings, dependencies between tasks, incremental builds with sources and generates, dotenv loading, confirmation on dangerous tasks, and the same commands in CI and locally. Use when creating or cleaning up a Makefile, justfile, Taskfile.yml, or package.json scripts, standardizing developer commands, onboarding onto a repo's tasks, or making CI call the same tasks developers run. Try asking
- Add a justfile to this repo with setup, dev, test, lint and a CI check task
- Our Makefile has 40 targets nobody understands, make it self-documenting and fix the phony targets
- CI runs different commands than we do locally, unify them with a Taskfile
Use it when
- A repo needs a standard set of developer commands
- A Makefile, justfile or Taskfile needs cleanup
- CI and local commands have drifted apart
- New contributors cannot find how to run things
Skip it when
- You are building the CI pipeline itself — use github-actions
- You are building a distributable command-line app — use cli-tool-building
How to check the result
On a fresh clone, running the runner with no arguments lists described tasks, setup then check succeeds, and a deliberately broken test makes check exit non-zero.
The common mistake it prevents
Forgetting .PHONY in a Makefile, so a file or folder named test or build silently turns the task into a no-op.
Done well means: a new contributor runs one command to list tasks and one to set up, task names are predictable across repos, each task fails on the first error, CI calls the same tasks as developers, and dangerous tasks ask for confirmation.
Hard rules
- One task runner per repo as the front door. Language tools (npm, cargo, uv) do the work; the runner only names and sequences them.
- Every task fails fast: strict shell flags, no
|| truewithout a comment. - Running the runner with no arguments lists the tasks with descriptions.
- Deploy, publish, migrate-prod, and data-deletion tasks require confirmation (or an
explicit
CONFIRM=1/--yesin CI) and print the target before acting. - Secrets come from the environment or an untracked
.env; never hardcode them in the task file. Commit.env.example, not.env.
Pick the runner
| Situation | Default | Why |
|---|---|---|
| JS/TS-only repo | npm scripts (package.json) | Already there; npm run lists them |
| Polyglot repo, commands not files | just | Simple syntax, args, --list, no tab/.PHONY traps |
| Need incremental builds, cross-platform, YAML | Taskfile (go-task v3) | sources/generates checksums, deps in parallel, Windows-friendly |
| Already has a Makefile, or C/C++ builds | Make | Ubiquitous, real file-based dependency graph |
| Tool versions + tasks in one file | mise tasks | If the repo already uses mise for runtimes |
Standard names (use these so muscle memory transfers): setup, dev, test, lint,
fmt, typecheck, build, check (everything CI runs), clean, deploy.
Workflow
- [ ] 1. Inventory existing commands (README, CI config, scripts/, package.json)
- [ ] 2. Choose the runner; map commands to standard names
- [ ] 3. Write tasks with descriptions, strict shell, dependencies
- [ ] 4. Add a `check` task that mirrors CI exactly
- [ ] 5. Point CI at the tasks; update README to "run `just` to see tasks"
- [ ] 6. Verify on a clean clone
just
# justfile
set dotenv-load
set shell := ["bash", "-euo", "pipefail", "-c"]
# list tasks
default:
@just --list --unsorted
# install toolchains and dependencies
setup:
uv sync --frozen
pnpm install --frozen-lockfile
# run the app with reload
[group('dev')]
dev:
uv run uvicorn app.main:app --reload
# run tests; pass extra args: just test -k auth
[group('qa')]
test *args:
uv run pytest {{args}}
[group('qa')]
lint:
uv run ruff check .
uv run ruff format --check .
# everything CI runs
check: lint test
# deploy to an environment (default staging)
[confirm('Deploy to the target environment?')]
deploy env='staging':
@echo "Deploying to {{env}}"
./scripts/deploy.sh {{env}}
- Comments directly above a recipe become its
--listdescription. - Recipe lines run in separate shells unless the recipe starts with a shebang
(
#!/usr/bin/env bashplusset -euo pipefail) for multi-line logic. just --dry-run deploy,just --evaluate,just --fmt --unstable(format check varies by version; runjust --helpif a flag is rejected).
Taskfile (go-task v3)
# Taskfile.yml
version: '3'
dotenv: ['.env']
vars:
BIN: ./bin/app
tasks:
default:
cmds: [task --list]
silent: true
build:
desc: Compile the binary (skipped when sources unchanged)
sources: ['**/*.go', go.mod, go.sum]
generates: ['{{.BIN}}']
cmds:
- go build -o {{.BIN}} ./cmd/app
test:
desc: Run tests; extra args after --, e.g. task test -- -run TestAuth
cmds:
- go test ./... {{.CLI_ARGS}}
lint:
desc: Static checks
cmds: [golangci-lint run]
check:
desc: Everything CI runs
deps: [lint, test] # deps run in parallel
deploy:
desc: Deploy to ENV (default staging)
prompt: Deploy {{.ENV | default "staging"}}?
preconditions:
- sh: git diff --quiet
msg: Working tree is dirty; commit first
cmds:
- ./scripts/deploy.sh {{.ENV | default "staging"}}
task --list shows only tasks with desc; task --list-all shows all. Use status:
for “already done” checks that are not file-based (e.g., a container exists). Pass
--yes to skip prompts in CI.
Make (self-documenting)
SHELL := bash
.SHELLFLAGS := -eu -o pipefail -c
.DEFAULT_GOAL := help
MAKEFLAGS += --warn-undefined-variables --no-builtin-rules
.PHONY: help setup test lint check deploy
help: ## List tasks
@grep -hE '^[a-zA-Z_-]+:.*## ' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*## "}; {printf " \033[36m%-12s\033[0m %s\n", $$1, $$2}'
setup: ## Install dependencies
npm ci
test: ## Run tests
npm test
lint: ## Run linters
npm run lint
check: lint test ## Everything CI runs
deploy: ## Deploy (requires CONFIRM=1)
@test "$${CONFIRM:-}" = 1 || { echo "Refusing: run 'make deploy CONFIRM=1'"; exit 1; }
./scripts/deploy.sh
- Recipe lines must start with a tab. Each line is a separate shell unless
.ONESHELL:. - Mark non-file targets
.PHONY, or a file namedtestwill makemake testa no-op. $$escapes$for the shell. macOS ships GNU Make 3.81, which ignores.SHELLFLAGSand lacks other 3.82+/4.x features; require Homebrewgmakeor putset -euo pipefailin multi-line scripts instead.- Use real file targets for build artifacts so Make skips up-to-date work.
npm scripts
{
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"test": "vitest run",
"lint": "eslint . && prettier --check .",
"typecheck": "tsc --noEmit",
"check": "npm run lint && npm run typecheck && npm run test"
}
}
- Pass args after
--:npm test -- --watch.node --run <script>(Node 22+) starts faster thannpm runbut skips pre/post hooks. - Avoid implicit
pre*/post*hooks for important steps; they surprise people, and package managers differ in whether they run them. - Cross-platform: avoid
rm -rfandVAR=x cmdin scripts if Windows contributors exist; userimraf/cross-envor move logic to a Node script. - Parallel:
concurrentlyornpm-run-all2(run-p,run-s).
CI uses the same tasks
# GitHub Actions excerpt
- uses: extractions/setup-just@v3 # or arduino/setup-task, or npm ci
- run: just check
If CI runs commands the task file does not have, developers cannot reproduce CI failures
locally. Move them into check.
Verification
git clone <repo> /tmp/fresh && cd /tmp/fresh
just # or: task / make / npm run -> lists tasks with descriptions
just setup && just check; echo "exit=$?"
just deploy # prompts (or refuses) before doing anything
Break a test on purpose: check must exit non-zero, and so must CI.
Gotchas
- A failing command in the middle of a multi-command line (
a; b) is ignored without strict flags; use&&or strict shell settings. - Tasks that
cdaffect only that line in Make and just (each line is a new shell). - Hidden tasks nobody can discover get reimplemented; every public task needs a description.
- Do not wrap a single command in five layers (npm script -> make -> shell script); one level of indirection is enough.
About this skill
Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.