Skip to content

English · Español

Lab 01 — Extend the Justfile

Pre-req: read ../theory/02-engineering-hygiene.md and ../theory/03-dev-environment.md. Goal: internalize just by adding one new recipe that you'll use in later phases. No peeking at solutions/01-justfile-ref.md until 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 recipes
  • setupuv sync --all-extras + uv run pre-commit install
  • lintruff check + ruff format --check + mypy src
  • fmtruff check --fix + ruff format
  • testuv run pytest
  • nbstrip — strip outputs from any committed notebook
  • clean — wipe build/cache artifacts
  • phase00 — chain setup → lint → test

§2 Your task

Add a new recipe called manifest that:

  1. Takes one positional argument: topic (e.g., just manifest softmax-stability).
  2. Generates a directory experiments/$(date +%F)-{topic}/.
  3. Writes a file experiments/$(date +%F)-{topic}/manifest.json containing at minimum:
  4. id: "$(date +%F)-{topic}"
  5. git_sha: from git rev-parse HEAD
  6. git_dirty: true if git status --porcelain is non-empty, false otherwise
  7. seed: 42 (placeholder — real scripts pass it)
  8. versions: output of uv run python -c "from utils.seeding import log_versions; import json; print(json.dumps(log_versions()))"
  9. hardware: { "cpu": "$(uname -p)", "kernel": "$(uname -r)", "os": "$(. /etc/os-release; echo $PRETTY_NAME)" }
  10. started_at: ISO-8601 UTC $(date -u +%FT%TZ)
  11. 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, jq from the OS).
  • Idempotent: running the recipe twice in the same day with the same topic overwrites the manifest cleanly (your call: rotate by HH:MM:SS, or overwrite — defend your choice in the journal).
  • Cross-shell: recipes run under sh by default, not fish. If you need anything bashism-heavy, set set shell := ["bash", "-cu"] at the top of the Justfile and explain why in a comment.
  • Quote {topic} safely — topic could be softmax stability or phase-12-something or worse. No command injection through topic.

§4 Tests

Add a test to tests/test_justfile.py (you may need to create it) that:

  1. Calls just manifest test-topic via subprocess.
  2. Asserts the manifest file exists.
  3. Asserts it parses as JSON.
  4. Asserts the versions.python field starts with 3.11.
  5. Asserts the git_sha field 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 in experiments/.
  • Re-running just manifest <same-topic> works (no errors, no partial-write).
  • pytest tests/test_justfile.py passes.
  • just lint is 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)

  1. just --evaluate shows recipe expansion without running anything — useful for debugging quoting.
  2. git rev-parse HEAD returns the full sha; you don't need git log -1 --pretty=%H.
  3. For "dirty" detection, git diff-index --quiet HEAD -- is cleaner than parsing git status --porcelain.

If you reach for solutions/01-justfile-ref.md before completing this, mark dod.lab_attempted_before_solutions: false in learners/borja/phase-00/checkpoint.json. Honesty matters here — the phase-gatekeeper checks.