English · Español
Lab 01 — Extend the Justfile¶
Pre-req: read
../theory/02-engineering-hygiene.mdand../theory/03-dev-environment.md. Goal: internalizejustby adding one new recipe that you'll use in later phases. No peeking atsolutions/01-justfile-ref.mduntil you've made it work.
§1 Background¶
just is a task runner — recipes are like make targets but without make's tab-indentation footgun, recursive-make pain, or implicit rebuild semantics. Recipes are explicit, parameterized, and composable.
Current recipes in /Justfile:
default— list all recipessetup—uv sync --all-extras+uv run pre-commit installlint—ruff check+ruff format --check+mypy srcfmt—ruff check --fix+ruff formattest—uv run pytestnbstrip— strip outputs from any committed notebookclean— wipe build/cache artifactsphase00— chainsetup → lint → test
§2 Your task¶
Add a new recipe called manifest that:
- Takes one positional argument:
topic(e.g.,just manifest softmax-stability). - Generates a directory
experiments/$(date +%F)-{topic}/. - Writes a file
experiments/$(date +%F)-{topic}/manifest.jsoncontaining at minimum: id:"$(date +%F)-{topic}"git_sha: fromgit rev-parse HEADgit_dirty:trueifgit status --porcelainis non-empty,falseotherwiseseed:42(placeholder — real scripts pass it)versions: output ofuv run python -c "from utils.seeding import log_versions; import json; print(json.dumps(log_versions()))"hardware:{ "cpu": "$(uname -p)", "kernel": "$(uname -r)", "os": "$(. /etc/os-release; echo $PRETTY_NAME)" }started_at: ISO-8601 UTC$(date -u +%FT%TZ)- Prints the path to the manifest at the end.
§3 Constraints¶
- No external dependencies. Use only what's already in the lockfile (
python,git, coreutils,jqfrom the OS). - Idempotent: running the recipe twice in the same day with the same
topicoverwrites the manifest cleanly (your call: rotate by HH:MM:SS, or overwrite — defend your choice in the journal). - Cross-shell: recipes run under
shby default, notfish. If you need anything bashism-heavy, setset shell := ["bash", "-cu"]at the top of the Justfile and explain why in a comment. - Quote
{topic}safely —topiccould besoftmax stabilityorphase-12-somethingor worse. No command injection throughtopic.
§4 Tests¶
Add a test to tests/test_justfile.py (you may need to create it) that:
- Calls
just manifest test-topicviasubprocess. - Asserts the manifest file exists.
- Asserts it parses as JSON.
- Asserts the
versions.pythonfield starts with3.11. - Asserts the
git_shafield is a 40-character hex string.
Use tmp_path for the test directory if you can; otherwise document why the test runs in-tree.
§5 Stop conditions¶
You're done when:
-
just manifest <some-topic>produces a valid JSON manifest inexperiments/. - Re-running
just manifest <same-topic>works (no errors, no partial-write). -
pytest tests/test_justfile.pypasses. -
just lintis still green (no shell warnings, no new lint errors). - Commit:
lab: phase-00 add manifest recipe.
§6 What you'll have learned¶
By the end:
- just parameterized recipes + quoting.
- Shell composition ($(...), conditional return codes).
- Why determinism manifests matter (you'll write one by hand here; later phases consume record_manifest() from src/utils/).
- How recipes interact with pre-commit and the lockfile.
§7 Hints (use sparingly)¶
just --evaluateshows recipe expansion without running anything — useful for debugging quoting.git rev-parse HEADreturns the full sha; you don't needgit log -1 --pretty=%H.- For "dirty" detection,
git diff-index --quiet HEAD --is cleaner than parsinggit status --porcelain.
If you reach for
solutions/01-justfile-ref.mdbefore completing this, markdod.lab_attempted_before_solutions: falseinlearners/borja/phase-00/checkpoint.json. Honesty matters here — the phase-gatekeeper checks.