---
title: "Chapter 02: Lock the Environment"
description: "Create a devenv project, declare tools, freeze its inputs, and prove what the lockfile does."
type: "lesson"
order: 2
chapter: "01-reproducible-foundations"
duration: "45–90 minutes"
---

# 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?

<details>
<summary>Concept answer key — attempt first</summary>

## 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.

</details>

## Gate: Install and smoke-test devenv

```bash
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

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

Now download the [lab archive](/downloads/nix-agent-lab.zip) 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:

```nix
{ 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:

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

## Gate: Resolve and verify

```bash
devenv update
devenv shell
```

Inside the shell:

```bash
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

```bash
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?

<details>
<summary>Answer key — attempt every question first</summary>

## 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.

</details>

## References

- [Inputs](https://devenv.sh/inputs/)
- [Pinning](https://devenv.sh/pinning/)
- [Python integration](https://devenv.sh/languages/python/)

---

[← Chapter 01](/nix-agent-lab/01-reproducible-foundations/01-nix-on-your-mac/) · [Next: Chapter 03 →](/nix-agent-lab/01-reproducible-foundations/03-tests-that-push-back/)
