TheFocus.AI TheFocus.AI
01 reproducible foundations → Lesson 2

Chapter 02: Lock the Environment

Create a devenv project, declare tools, freeze its inputs, and prove what the lockfile does.

~45–90 minutes

TUTOR WITH THEFOCUS.AI

Agent Integration

Copy this prompt into Claude, ChatGPT, or any external AI assistant. It points the assistant to the course instructions and links it to your student profile to track your progress and customize observations.

Please tutor me in this lesson using the following context. First, read the instructions at: https://courses.thefocus.ai/llms.txt My Student ID is: <none> The lesson markdown source is at: https://courses.thefocus.ai/nix-agent-lab/01-reproducible-foundations/02-lock-the-environment.md

You are not enrolled yet. Enroll to generate a Student ID to track lesson completions and store learning notes.

Chapter 02: Lock the Environment

Objective

Create a devenv project, declare tools, freeze its inputs, and prove what the lockfile does.

Your tutor should stop at each gate and wait for your evidence before continuing.

Concept

A project needs a recipe and a resolved version of that recipe’s inputs. devenv.nix declares the environment. devenv.yaml names upstream inputs. devenv.lock records resolved revisions. Commit all three. A branch name such as rolling is a policy for future updates, not a fixed version.

The devenv executable is another dependency. Installing it into a user profile bootstraps the project; that does not automatically pin its version with the project. Keep its version in your validation record. Chapter 11 installs the CLI from the same resolved Nixpkgs revision as the project.

Application dependencies need the same discipline. This lab uses the Python standard library so there is no second resolver to hide the first lesson. In a real Python or JavaScript app, commit the application lockfile too.

Concept check

Q1. What changes when you run devenv update?

Q2. Does committing devenv.nix alone fix exact package versions?

Concept answer key — attempt first

Answer key (concept)

Q1. Resolved input revisions may change; review the lock diff and rerun checks. Pass criteria: an update is an intentional dependency change.

Q2. No. Commit the YAML and lock as well. Pass criteria: distinguish declarations from resolved sources.

Gate: Install and smoke-test devenv

nix profile install nixpkgs#devenv nixpkgs#bashInteractive
devenv version
bash --version

nix profile install is supported by the installer guidance; newer Nix also calls this operation nix profile add. Modern Bash avoids relying on Apple’s old /bin/bash. Do not change your login shell for this exercise.

Gate: Prepare the project

mkdir agent-lab
cd agent-lab
git init
devenv init

Now download the lab archive and extract it into a separate temporary directory. Inspect it before copying files. It contains a completed environment reference and an intentionally incomplete application enhancement. Start with the small configuration below; later gates introduce the other files.

Replace devenv.nix with:

{ pkgs, ... }:
{
  packages = with pkgs; [ git jq ripgrep curl bashInteractive ruff ];
  languages.python.enable = true;
}

Keep the YAML generated by devenv init, or use this minimal input declaration:

inputs:
  nixpkgs:
    url: github:cachix/devenv-nixpkgs/rolling

Gate: Resolve and verify

devenv update
devenv shell

Inside the shell:

python --version
ruff --version
rg --version
python -c 'import sys; print(sys.executable)'

Pass: every tool runs and Python resolves under /nix/store. Run exit to return to your ordinary shell. Tool versions depend on your resolved input; do not compare them with an invented example version.

Gate: Freeze the result

git add devenv.nix devenv.yaml devenv.lock .gitignore
git commit -m 'Declare and lock the development environment'
git diff --exit-code -- devenv.lock

Record devenv version alongside the commit. Re-enter the shell without running devenv update; confirm the lock remains unchanged. The downloadable starter intentionally has no fabricated lockfile: this gate generates the actual one for your project, and all later clones must use it.

Known failure modes

  • A missing lock means another machine may resolve newer dependencies.
  • A Python import missing from Nix will not be fixed by an unexplained host pip install. Declare the dependency through the project’s chosen Python integration.
  • An untracked file may be excluded when using Git-backed flakes. Stage source files before evaluating the final flake lab.
  • A successful environment evaluation is not evidence that the application tests ran.

Check your understanding

Q3. How would you make a deliberate dependency update reviewable?

Q4. Why retain the bootstrap CLI version?

Answer key — attempt every question first

Answer key

Q3. Update in a branch, inspect the lock diff, test supported systems, then review. Pass criteria: lock diff plus validation.

Q4. It affects evaluation and process behavior outside application package versions. Pass criteria: name the CLI as part of the execution record.

References


← Chapter 01 · Next: Chapter 03 →

Previous Lesson 2 of 12 Next