From 6b3b59ce7fe64d2181d5b966beaea81d08375de7 Mon Sep 17 00:00:00 2001 From: Evan Reichard Date: Thu, 16 Apr 2026 17:25:51 -0400 Subject: [PATCH] docs(skills): tighten update-package-hashes guidance --- .pi/skills/update-package-hashes/SKILL.md | 83 ++++++++++++++--------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/.pi/skills/update-package-hashes/SKILL.md b/.pi/skills/update-package-hashes/SKILL.md index c242204..4147c14 100644 --- a/.pi/skills/update-package-hashes/SKILL.md +++ b/.pi/skills/update-package-hashes/SKILL.md @@ -7,45 +7,64 @@ description: Update a package in packages/ to a new version and refresh its hash Require the user to supply the **package name** and **target version/rev/tag**. Ask if missing. -## Hard Rule +## Hard Rules — Read First -**Never run `nix build .#`** — it compiles. Only realise FOD sub-attributes (`.src`, `.goModules`, `.npmDeps`, `.cargoDeps`) which are pure downloads. +1. **Never run `nix build .#`** or `.#packages..`. That compiles the package. Only realise **FOD sub-attributes** (`.src`, `.goModules`, `.npmDeps`, `.cargoDeps`) — those are pure downloads, not builds. +2. **Never** use `nix-prefetch-git`, `nix-prefetch-url`, `nix hash path`, `git clone` + manual hashing, `builtins.fetchGit`, or any other ad-hoc method to compute hashes. They produce hashes in formats that don't match what `fetchgit`/`fetchFromGitHub`/etc. expect, and you will waste time chasing mismatches. +3. There are exactly **two** correct ways to get a hash, both listed below. If neither fits, stop and ask the user — don't improvise. + +## The Only Two Methods + +### Method A — `nurl` (preferred for `src` on any git forge) + +`nurl` works for **any git URL**, not just GitHub: `gitea.va.reichard.io`, `gitlab`, `codeberg`, `sourcehut`, plain `https://...git`, all fine. It downloads the source and prints a complete fetcher expression with the correct hash. + +```bash +nix run nixpkgs#nurl -- +``` + +Examples: +```bash +nix run nixpkgs#nurl -- https://github.com/owner/repo v1.2.3 +nix run nixpkgs#nurl -- https://gitea.va.reichard.io/evan/slack-cli.git 0a9484257a2adc414aa4cdab4fb9539a37e04d1f +``` + +Copy the `hash = "sha256-..."` line into the package's `src` block. + +### Method B — FOD mismatch trick (for everything else) + +For `vendorHash`, `npmDepsHash`, `cargoHash`, `cargoLock.outputHashes.`, or any `src` using a custom fetcher (`leaveDotGit`, `postFetch`, `fetchSubmodules`, etc. — applies to `llama-cpp` and `llama-swap`), realise the **specific FOD sub-attribute** and read the `got:` line from the error. + +```bash +nix build .#.src --no-link 2>&1 | tee /tmp/hash.log # for src +nix build .#.goModules --no-link 2>&1 | tee /tmp/hash.log # for vendorHash +nix build .#.npmDeps --no-link 2>&1 | tee /tmp/hash.log # for npmDepsHash +nix build .#.cargoDeps --no-link 2>&1 | tee /tmp/hash.log # for cargoHash +grep -E '^[[:space:]]*got:' /tmp/hash.log | tail -1 | awk '{print $2}' +``` + +Setting the hash to `sha256-AAAA...` (44 A's) or leaving the old one in place both work — the build will fail at the FOD with `got: sha256-...` which is the correct value. + +**Note:** `.src`, `.goModules`, etc. are sub-attributes of the derivation. They download but do not compile. `nix build .#` (without the `.src` suffix) compiles — never do that. ## Flow -1. Edit `packages//default.nix` — bump `version` / `rev` / `tag`. Check for sibling `.nix` files (e.g. `ui.nix`). +1. Edit `packages//default.nix` — bump `version` / `rev` / `tag`. Check for sibling `.nix` files (e.g. `ui.nix`) that may also need bumping. +2. Get the new `src` hash with **Method A** (`nurl`). If the package uses a custom fetcher, use **Method B** on `.src` instead. +3. For each dependency hash (`vendorHash` / `npmDepsHash` / `cargoHash` / etc.), use **Method B** on the matching sub-attribute. +4. **Opaque `outputHash` FODs** (e.g. opencode's `node_modules` which runs `bun install`) — do NOT attempt locally. Leave as-is and flag for CI in the summary. +5. Show `git diff -- packages//` and list any hashes left for CI. -2. **`src` hash** — use `nurl` (downloads source only, prints the fetcher expression): +## Resolving Tags Without Cloning - ```bash - nix run nixpkgs#nurl -- https://github.com// - ``` +```bash +git ls-remote refs/tags/ +``` - Paste the new `hash = "sha256-..."` into the `src` block. +## Don't Touch What Didn't Change -3. **Dependency hashes** (`vendorHash`, `npmDepsHash`, `cargoHash`, `cargoLock.outputHashes.`) — after the version bump the old hash is already wrong, so just trigger the mismatch: +Skip pinned sub-dependencies whose inputs didn't change — e.g. `slack-cli`'s `python-snappy` / `zstd-python` PyPI tarballs are pinned by the upstream `dfindexeddb`, not by the slack-cli rev. - ```bash - nix build .#.goModules --no-link 2>&1 | tee /tmp/hash.log # or .npmDeps / .cargoDeps - grep -E '^[[:space:]]*got:' /tmp/hash.log | tail -1 | awk '{print $2}' - ``` +## Optional Shortcut - Paste into the matching attribute. - -4. **Custom fetchers** (`leaveDotGit`, `postFetch`, `fetchSubmodules`) — `nurl` will be wrong. Use the same mismatch trick on `.src`: - - ```bash - nix build .#.src --no-link 2>&1 | tee /tmp/hash.log - ``` - - Applies to `llama-cpp` and `llama-swap`. - -5. **Opaque `outputHash` FODs** (e.g. opencode `node_modules` runs `bun install`) — do NOT attempt locally. Leave as-is and flag for CI in the summary. - -6. Show `git diff -- packages//` and list any hashes left for CI. - -## Notes - -- Don't touch hashes whose inputs didn't change (e.g. `slack-cli`'s pinned `python-snappy`/`zstd-python`). -- Resolve a tag → rev without cloning: `git ls-remote refs/tags/`. -- `nix-update --flake --version ` can sometimes do all of this; try it first for simple packages. +`nix-update --flake --version ` sometimes handles everything for simple packages. Try it first; fall back to the methods above if it fails.