Hedronite Lesson · Polyglot-Dev / Nix · Fri 2026-10-02

Packaging a patterns crate derivation, devShell, flake check

Beat A taught pattern places and refutability. Beat B puts that binary behind a store path, a shell, and a check.

Lesson Class: Duha (Nix packaging shell · Beat B · topic T1)
Focus: buildRustPackage · cargoLock/cargoHash · mkShell · flake checks
Code Blocks: clean blocks from rust-tops corpus + patterns-demo sketch
Done-criteria: Sketch buildRustPackage, open a Rust devShell, name one checks entry
Grounding: rust-tops cargo-tops.nix + flake.nix · NIX-SYLLABUS #16/#19 framing only · Asr Pills untouched
The Crate Derivation
buildRustPackage: src, lock pin, $out/bin — same noun as Pill 6, Rust road shape.
The Dev Shell
devShells hold rustc/cargo for edit; keep them out of the release closure.
The Flake Check
checks attrs are what nix flake check builds; put the package there for proof.
Beat A taught pattern places and refutability. Beat B puts that binary behind a store path, a shell, and a check.

<!-- hal:authoritative:yaml -->

Beat A taught pattern places and refutability. Beat B puts that binary behind a store path, a shell, and a check.

§I - Frame

Duha Beat B, Nix packaging session 05. Beat A (Rust session 22) taught the Place Map, the Refutability Gate, and the Syntax Kit from TRPL Ch.19. This shell packages a small crate that exercises those moves: one derivation that builds the binary, one devShell that holds the toolchain, one checks entry that nix flake check can run.

Session 04 packaged yesterday's trait-objects crate. Same three packaging moves, new crate noun. Asr owns the Pills cursor and the later Rust-roads rows (#16 crate-as-derivation, #19 flake devShell/checks). Those Done cells stay unmarked today. This bundle does not consume a Pill.

Three moves land by the end:

  1. The Crate Derivation: read rustPlatform.buildRustPackage for a patterns demo binary (src, lock hash, what lands in $out).
  2. The Dev Shell: name devShells.default as the editable toolchain, not the release store path.
  3. The Flake Check: say what nix flake check builds from the checks attribute set.

Done-criteria: Can sketch a buildRustPackage for a patterns binary, open a Rust devShell, and name one flake checks entry that proves the build.

§II - The Crate Derivation

A derivation is still a build spec: inputs in, store path out. For Rust, nixpkgs wraps that as rustPlatform.buildRustPackage. The rust-tops corpus shows the shape in nix/cargo-tops.nix (read-only teach from the repo; no bot build cadence):

{
  lib,
  rustPlatform,
}:

rustPlatform.buildRustPackage {
  pname = "cargo-tops";
  version = "0.1.3";

  src = lib.cleanSource ../.;

  cargoLock.lockFile = ../Cargo.lock;

  buildAndTestSubdir = "crates/cargo-tops";

  doCheck = true;

  meta = {
    description = "init / check / gate for the Rust-TOPS protocol";
    mainProgram = "cargo-tops";
  };
}

Read it the way NIX-SYLLABUS row #16 asks: src is the crate tree; cargoLock.lockFile (or cargoHash when you vendor differently) pins the crate graph; buildAndTestSubdir selects a workspace member; doCheck runs cargo test in the sandbox; the binary lands under $out (usually $out/bin/<mainProgram>).

For today's Patterns lesson, the same skeleton fits a single-binary crate whose main places patterns in match, if let, while let, and let, prints which arm or binding fired, and exits. Swap pname to something like patterns-demo, point src at that crate, keep a real Cargo.lock in tree. The demo can stay on std alone: an Option, a small enum, one destructuring let, one match guard, one @ binding. No network fetches during nix build. Prefer cargoLock.lockFile when the tree has a lock; use cargoHash only when that is the pin style you keep.

Sandbox honesty still rules. Flake inputs and the lock hash must explain every byte that enters the builder. A print-and-exit binary proves the Place Map without needing external services.

§III - The Dev Shell

A release derivation is not a workspace. While you edit the patterns crate you want rustc, cargo, clippy, and rustfmt on PATH without baking them into the binary's runtime closure. That is devShells:

devShells = forAllSystems (
  system:
  let
    pkgs = pkgsFor system;
  in
  {
    default = pkgs.mkShell {
      packages = [
        pkgs.rustc
        pkgs.cargo
        pkgs.clippy
        pkgs.rustfmt
      ];
    };
  }
);

The rust-tops flake.nix uses that pattern (plus cargo-tops itself on the shell). Enter with nix develop. Build the release path separately with nix build .#patterns-demo (or whatever you named the package). Mixing those two jobs is how people ship a toolchain as a runtime dependency by accident.

Pattern matching lives in the Rust binary at match / if let sites, not in the Nix shell. The shell only gives you a pinned compiler so cargo run and cargo test match what the derivation will see.

§IV - The Flake Check

packages is what you install. checks is what CI (and you) ask Nix to build for proof. From the same corpus flake:

checks = forAllSystems (
  system:
  let
    pkgs = pkgsFor system;
  in
  {
    cargo-tops = self.packages.${system}.cargo-tops;
    # ... other proofs ...
  }
);

nix flake check builds every attribute under checks for the current system. Putting the patterns package itself in checks proves the derivation evaluates and builds. A tighter check can runCommand the binary and assert it prints the expected arm lines, still without standing up a second lesson store of tests outside the flake.

Three outputs, three jobs: packages ships, devShells edits, checks proves. That is the packaging shell for Beat A's Patterns crate.

§V - Proof and close

  1. Copy the buildRustPackage skeleton, rename it for a patterns binary, and say what cargoLock.lockFile pins.
  2. Open a mkShell with rustc/cargo and state why those packages are not buildInputs of the release derivation.
  3. Add the package to checks and say what nix flake check will build.
  4. Name which Asr NIX-SYLLABUS rows teach the same moves later (#16, #19) and confirm this Duha bundle did not mark them.

Done-criteria: Can sketch a buildRustPackage for a patterns binary, open a Rust devShell, and name one flake checks entry that proves the build.

Asr keeps the next unmarked Pill / Rust-roads row. Duha Beat B only packages today's T1 crate.

Related