Reference

justfile task surface reference

One of the reference files my agents read on demand when a rule's trigger fires, published as they read it.

Source
rob/agents/reference/justfile-task-surface.md
Revision
26282440

Standing rule (full text; the always-loaded rule is a summary of this)

Delete the wave sections of this rule when the migration board shows waves 0-3 Done.

Never add a Makefile or a new scripts/*.sh task runner to one of Rob’s repos. A top-level justfile is the only task surface. New repos start with one; existing repos are mid-migration and each carries its own Migrate-the-repo-task-surface-to-just Backlog task with the per-repo mapping — read that task before touching a Makefile, and don’t invent a different plan.

The migration runs in waves and the task carries a wave: label. wave:0-pilot (sf2loki) goes alone and first; wave:1-hub is the two shared .github repos; wave:2-fleet is everything else, any order; wave:3-last is brewmdm-control-plane, whose ruleset gates twelve individual job names instead of a ci-success aggregator, so renaming a CI job there also needs a ruleset edit. Do not start a wave before the previous one lands — the pilot exists to correct this standard first.

The frozen standard

Seven mandatory recipes, same names in every repo: default, setup, fmt, fmt-check, lint, test, check. default is @just --list.

check is everything that runs with only the language toolchain installed, and it is the pre-commit gate. ci is the sanctioned superset: check plus the legs CI gates that need a Docker daemon, a service container, or cross-compilation — and nothing else. Write it as ci: check <heavy legs>, and give every leg in it a comment naming which of those three it needs.

Most repos have no such legs, so they have no ci recipe at all and check is the whole gate. Do not add an empty one.

set shell := ["bash", "-euo", "pipefail", "-c"]

No set quiet, no set minimum-version, no unstable features — just --dump --dump-format json must exit 0. Every public recipe carries a # doc comment and exactly one of six groups: check, build, dev, gen, infra, release. default and setup are ungrouped; helpers are [private] or _-prefixed. just --fmt --check must exit 0.

Scripts

Absorb thin wrappers — env defaults, a command -v guard, one tool invocation — into the recipe and git rm the file. Keep real programs, shipped runtime artifacts and shell test suites as files, and give each one a recipe that becomes the only supported way to invoke it. A script executed by something other than a developer or CI (a systemd timer, a cloud environment provisioner, an end-user verification script) stays untouched and deliberately unreferenced.

Wiring

Every build/test/lint/generate step becomes a one-line just <recipe>. AGENTS.md gets a ## Task interface section naming just check as the gate — it does not list recipes. Fix generators that emit make … at source, not the generated file.

Where a tool version pins depends on the runner

Never let both sides pin the same tool. Whichever installs later wins on PATH, so a one-sided bump silently makes the other pin a lie.

  • GitHub-hosted — every rknightion repo. CI installs extractions/setup-just, SHA-pinned, with an explicit just-version. Other tool versions live in the justfile as # renovate:-annotated := assignments, with renovate.json pointed at /^justfile$/.
  • arc-arm64 — m7kni self-hosted. The runner image is the pin. just, actionlint, golangci-lint, sqlc, hadolint and xmllint are baked in by the private CI tools repository (runner-image/Dockerfile, renovate-annotated ARGs). Do not add extractions/setup-just and do not go install those tools — delete the step. A workflow that needs a specific version asserts it and fails loudly; it never reinstalls.

check is everything that runs with only the language toolchain installed, and it is the pre-commit gate. ci is the sanctioned superset: check plus the legs CI gates that need a Docker daemon, a service container, or cross-compilation — and nothing else. Write it as ci: check <heavy legs>, and give every leg in it a comment naming which of those three it needs.

That comment is the guard. Without it ci becomes the bin for anything slow or awkward, check quietly stops meaning much, and the fleet is back to a per-repo gate. A leg that runs fine on a bare toolchain belongs in check however long it takes.

ci-tools’ Tool version drift workflow fails when the Dockerfile ARG and the published image disagree, and lists any repo still carrying a second pin.

Bumping an arc-arm64 pin is a four-step deploy, in this order: edit the Dockerfile → rebuild → repin the scale-set digest in the private runner infrastructure repository (applications/gh-runner/runners-arm64-values.yaml) → only then update the workflow assertion. Landing the workflow change first fails every m7kni job, because the assertion runs against a runner still on the old digest.