nix-scaffold
Skill11 starsChanged 3 months agoMITView on GitHub
Scaffold, fix, or diagnose shell.nix and flake.nix files. Use when creating a new Nix dev shell, fixing broken Nix builds (pinned URL errors, stale hashes, missing buildInputs), or migrating between nixpkgs channels. Enforces project conventions - no verbose shellHook echos, minimal footprint.
In this repository18 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- android-app-reverserSkill
- android-emulator-app-live-inspectSkill
- aula-pii-scanSkill
- de-ai-proseSkill
- de-ai-repoSkill
- drawio-figure-reviewerSkill
- explainer-videoSkill
- justfile-hygieneSkill
- model-raceSkill
- phase1-prd-grillSkill
- phase2-backlog-snowballSkill
- phase3-backlog-ralphSkill
- readme-improverSkill
- refactor-smellerSkill
- scrub-for-publicSkill
- xterm-tmux-controlSkill
- zellij-controlSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. About 0 are common, 6 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 12
Never add verbose echos to
shellHook: - only what's strictly needed (e.g. - Very specific: line 13
If a
shell.nixorflake.nixalready exists, use it: - do not replace it without the user's explicit approval. - Very specific: line 14
Prefer shell.nix for simple dev shells.
- Distinctive: line 27
Before writing anything, check what exists:
- Distinctive: line 35
If files already exist, read them first.
- Very specific: line 60
If a Justfile exists in the project, ensure just is in buildInputs (otherwise recipes won't run inside the shell).
- Very specific: line 71
If nix-prefetch-url isn't available, fall back to letting Nix fail once and copy the got: hash from the error.
- Very specific: line 73
If the project uses .envrc with use nix or use flake, warn the user that changes will take effect on the next direnv allow (or direnv …
- Distinctive: line 77
Run the evaluator and capture the real error:
- Distinctive: line 105
After any change, confirm the shell actually enters:
- Distinctive: line 113
If validation fails, loop back to Step 2b with the new error.
- Distinctive: line 133
If you could not fix it, say so plainly and state what would be needed (e.g.
- Very specific: line 147
If the existing shell.nix / flake.nix already works, say so and don't touch it.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Nix Scaffold -- shell.nix / flake.nix Authoring and Repair
Scaffolds a clean Nix dev environment or diagnoses failures in an existing one. Respects these hard rules:
- Never add verbose echos to
shellHook- only what's strictly needed (e.g. setting env vars, exporting paths). No "Welcome to..." banners, no status spam. - If a
shell.nixorflake.nixalready exists, use it - do not replace it without the user's explicit approval. Diagnose and patch instead. - Prefer
shell.nixfor simple dev shells. Only reach forflake.nixif the project already uses flakes or the user asks for flake output.
When to use
- User asks to "make a shell.nix", "add a nix dev shell", "pin nixpkgs"
nix-shell/nix developfails with a cryptic error (hash mismatch, missing attribute, eval error)- Migrating channels (e.g. 24.11 -> 25.05 -> unstable)
- User pastes a Nix error and asks what's wrong
Procedure
Step 1: Survey the project
Before writing anything, check what exists:
ls shell.nix flake.nix flake.lock default.nix .envrc 2>/dev/nullAlso look for language hints to choose sensible buildInputs: Cargo.toml, pyproject.toml, package.json, CMakeLists.txt, go.mod, Justfile, .tool-versions.
If files already exist, read them first. Do not overwrite.
Step 2a: Scaffolding a new shell.nix
Minimal, pinned template. Fill in buildInputs based on what you found in Step 1:
{ pkgs ? import (fetchTarball {
# Pin to a specific nixpkgs revision. Update the URL + sha256 together.
url = "https://github.com/NixOS/nixpkgs/archive/<REV>.tar.gz";
sha256 = "<SHA256>";
}) {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
# language toolchain
# build tools (just, cmake, ...)
# test/lint tools
];
# Omit shellHook entirely unless strictly required.
# If needed, add it here - only env exports, no echos/banners.
}If a Justfile exists in the project, ensure just is in buildInputs (otherwise recipes won't run inside the shell).
To get a current pinned rev + hash, run (once, to fill in the template). Pick the current stable branch - check https://channels.nixos.org/ if unsure which is current:
CHANNEL="nixos-25.05" # substitute current stable
REV=$(curl -s "https://api.github.com/repos/NixOS/nixpkgs/commits/${CHANNEL}" | jq -r .sha)
SHA=$(nix-prefetch-url --unpack "https://github.com/NixOS/nixpkgs/archive/${REV}.tar.gz")
echo "REV=$REV SHA=$SHA"If nix-prefetch-url isn't available, fall back to letting Nix fail once and copy the got: hash from the error.
If the project uses .envrc with use nix or use flake, warn the user that changes will take effect on the next direnv allow (or direnv reload).
Step 2b: Diagnosing a broken shell.nix / flake.nix
Run the evaluator and capture the real error:
nix-shell --run true 2>&1 | tail -50
# or for flakes:
nix develop --command true 2>&1 | tail -50Common failure modes and fixes:
| Error fragment | Cause | Fix |
hash mismatch ... got: sha256-XXXX | Pinned URL changed or sha is wrong | Replace the sha256 with the got: value from the error |
attribute '...' missing | Package renamed/removed in channel | Search nixpkgs for the new attribute name (use https://search.nixos.org/packages, or nix-env -qaP |grep <name> on non-flake systems), or pin to an older rev |
infinite recursion encountered | Self-referential let/overlay, or with pkgs; at top-level scope leaking into itself | Isolate the offending binding; scope with pkgs; only inside lists like buildInputs = with pkgs; [ ... ]; |
getting status of '/nix/store/...' / No such file | Missing store path | Rebuild / re-realise the path: nix-store --realise <path> or just re-run nix-shell/nix develop to re-download. For flakes, deleting flake.lock and re-locking can refresh references. Do NOT run nix-collect-garbage - that removes paths, making it worse. |
error: experimental feature 'flakes' is disabled | Flakes not enabled | Use nix --extra-experimental-features 'nix-command flakes' develop or enable in config |
unable to download '...' / TLS errors | Pinned URL 404 or network | Verify URL is reachable; try the channel's current rev |
For flakes, also check flake.lock staleness:
nix flake metadata 2>&1 | head -20
nix flake update --commit-lock-file # only if user wants to bumpStep 3: Validate
After any change, confirm the shell actually enters:
nix-shell --run 'echo OK && which just cargo python3 2>/dev/null'
# or
nix develop --command bash -c 'echo OK'If validation fails, loop back to Step 2b with the new error. Do not claim success until the shell enters cleanly.
Step 4: Report
Summarize in this format:
## Nix Shell Status
**State:** <NEW | PATCHED | DIAGNOSED-NOT-FIXED>
**Changes:**
- shell.nix: <created | pinned rev updated | added N buildInputs | ...>
**Validation:** `nix-shell --run true` exits 0
**Notes:**
- <anything the user should know: channel chosen, inputs deliberately omitted, etc.>If you could not fix it, say so plainly and state what would be needed (e.g. "pinned rev is no longer in nixpkgs history; user must choose a replacement channel").
Anti-patterns (do NOT produce these)
shellHookthat echos a welcome banner, PS1 changes,figlet, environment listings- Including an empty
shellHook = '''';block when no hook is needed - just omit it with pkgs;at top-level scope (outside list context) - causes infinite-recursion eval errors- Unpinned
import <nixpkgs> {}in a project that needs reproducibility - Mixing
fetchTarballpins withflake.nix(pick one mechanism) - Overwriting an existing shell.nix "to clean it up" without being asked
- Adding packages "just in case" - only what the project actually needs
Tone
If the existing shell.nix / flake.nix already works, say so and don't touch it. Don't rewrite something that isn't broken just because it could be styled differently.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

