- Bump llama-cpp from b9048 to b9159 - Add WebUI build derivation to work around HF bucket fetch in Nix sandbox - Switch MTP patch from .patch to .diff (squashed unified diff applies cleanly) - Refactor default.nix with let bindings for cleaner structure - Add AGENTS.md documenting version/postFetch pitfalls - Add qwen3.6-27b-vllm-50k single-GPU config to llama-swap - Fix --spec-type from "mtp" to "draft-mtp" in llama.cpp configs - Update update-package-hashes skill with fetchpatch/.diff guidance
8.5 KiB
name, description
| name | description |
|---|---|
| update-package-hashes | Update a package in packages/ to a new version and refresh its hashes (src, vendorHash, npmDepsHash, cargoHash, etc.) WITHOUT compiling the package. Use when the user asks to bump, update, or upgrade a specific package under packages/. If version is provided, proceed directly. If not, look up the latest version and ask the user before proceeding. |
Update Package Hashes (Without Building)
If the user provides a package name and target version/rev/tag, proceed directly.
If the user provides only a package name (no version), look up the latest version and ask the user if they want to proceed before updating.
Hard Rules — Read First
- Never run
nix build .#<pkg>or.#packages.<system>.<pkg>. That compiles the package. Only realise FOD sub-attributes (.src,.goModules,.npmDeps,.cargoDeps) — those are pure downloads, not builds. - Never use
nix-prefetch-git,nix-prefetch-github,nix-prefetch-url,nix hash path,nix hash file(on a raw patch/tarball),git clone+ manual hashing,builtins.fetchGit, or any other ad-hoc method to compute hashes. They produce hashes in formats that don't match whatfetchgit/fetchFromGitHub/fetchpatchexpect (notably:fetchFromGitHub { leaveDotGit = true; }is non-deterministic across machines, andfetchpatchnormalizes patches — stripsindex abc..def,From <sha>, signatures — so its hash ≠nix hash fileof the raw.patch). - 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 via helper script (preferred for src on any git forge)
Use the co-located helper script. It wraps nurl and works for any git URL.
./update-package-hashes.sh hash <git-url> <rev-or-tag>
Copy the hash = "sha256-..." line from the output into the package's src block.
Method B — FOD mismatch trick (for everything else)
For vendorHash, npmDepsHash, cargoHash, cargoLock.outputHashes.<crate>, fetchpatch hashes, 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.
nix build .#<name>.src --no-link 2>&1 | tee /tmp/hash.log # for src
nix build .#<name>.goModules --no-link 2>&1 | tee /tmp/hash.log # for vendorHash
nix build .#<name>.npmDeps --no-link 2>&1 | tee /tmp/hash.log # for npmDepsHash
nix build .#<name>.cargoDeps --no-link 2>&1 | tee /tmp/hash.log # for cargoHash
nix build .#<name> --no-link 2>&1 | tee /tmp/hash.log # for fetchpatch / other input FODs (see note)
grep -E '^[[:space:]]*got:' /tmp/hash.log | tail -1 | awk '{print $2}'
fetchpatch note: patches don't have a dedicated sub-attribute, so you must target the package itself. This is safe only when the patch hash is wrong (e.g. lib.fakeHash) — Nix realizes the patch FOD before compilation starts, so a hash mismatch aborts with 0 built (1 failed) and zero compile work. If you accidentally fix all FODs correctly, nix build .#<name> will start compiling. To guard against this: always start patch hashes as lib.fakeHash, run the build, copy got:, paste, and only then re-verify with .src / sub-attribute builds (never re-run .#<name> to confirm).
GitHub PR patches — .patch vs .diff: When fetching a patch from a GitHub pull request, prefer the .diff endpoint over .patch.
https://github.com/<owner>/<repo>/pull/<N>.patch— agit format-patchmbox containing each commit in the PR separately.git apply(whichfetchpatchand the NixpatchPhaseuse) does not replay commit history; it applies hunks against the working tree. PRs that create a file in one commit and delete/rename it in a later commit will fail with errors likeThe next patch would delete the file X, which does not exist.https://github.com/<owner>/<repo>/pull/<N>.diff— a squashed unified diff of the PR's net change. Applies cleanly against any base the PR is mergeable against.
Default to .diff. Only fall back to .patch if you specifically need authorship metadata (rare for Nix patching). If a previously-working .patch URL suddenly fails to apply, switching to .diff is the first thing to try.
Setting the hash to lib.fakeHash (preferred when lib is in scope), sha256-AAAA... (44 A's), or leaving the old one in place all 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 .#<name> (without the .src suffix) compiles — never do that.
Example — Package With src, npmDepsHash, and vendorHash
Use the same pattern for packages that combine a custom src fetcher, Go dependencies, and a nested npm UI derivation. llama-swap is a concrete example because it uses leaveDotGit + postFetch, vendorHash, and a UI package exposed under passthru.ui.
-
Set stale hashes to
lib.fakeHashwhere possible:src.hash = lib.fakeHash; vendorHash = lib.fakeHash; passthru.npmDepsHash = lib.fakeHash; -
Resolve the custom
srchash first; downstream FODs depend on it:nix build .#llama-swap.src --no-link 2>&1 | tee /tmp/llama-swap-src.log grep -E '^[[:space:]]*got:' /tmp/llama-swap-src.log | tail -1 | awk '{print $2}'Put the
got:value intosrc.hashbefore resolving dependency hashes. -
Resolve the UI npm dependency hash from the nested UI derivation:
nix build .#llama-swap.passthru.ui.npmDeps --no-link 2>&1 | tee /tmp/llama-swap-npm.log grep -E '^[[:space:]]*got:' /tmp/llama-swap-npm.log | tail -1 | awk '{print $2}'Put the
got:value intopassthru.npmDepsHash. -
Resolve the Go
vendorHash:nix build .#llama-swap.goModules --no-link 2>&1 | tee /tmp/llama-swap-go.log grep -E '^[[:space:]]*got:' /tmp/llama-swap-go.log | tail -1 | awk '{print $2}'Put the
got:value intovendorHash.For other packages, adapt the flake attribute path to where the FOD is exposed (for example,
.#<name>.npmDeps,.#<name>.passthru.ui.npmDeps, or.#<name>.goModules). -
Re-run the FOD sub-attribute builds to confirm they realise successfully:
nix build .#llama-swap.src --no-link nix build .#llama-swap.passthru.ui.npmDeps --no-link nix build .#llama-swap.goModules --no-linkIf a dependency FOD fails before a hash mismatch (for example,
go.mod requires go >= ...), fix the package inputs minimally (for example, switch to the matchingbuildGo126Module) and re-run the same FOD sub-attribute. Do not build.#llama-swap.
Lookup Latest Version
When the user asks to update a package but doesn't specify a version:
-
Read
packages/<name>/default.nixto find the git URL and current version/tag. -
Determine the tag pattern from the
tagfield (e.g."b${version}"→'b*',"v${version}"→'v*'). -
Run the helper script:
./update-package-hashes.sh releases <git-url> '<pattern>'Shows main HEAD + 5 newest matching tags with commit hashes.
-
Ask the user before proceeding (
Current: b8815 → Latest: b8914 — proceed?).
Flow
- If no version was provided, look up the latest version (see section above) and ask the user to confirm.
- Edit
packages/<name>/default.nix— bumpversion/rev/tag. Check for sibling.nixfiles (e.g.ui.nix) that may also need bumping. - Get the new
srchash with Method A (nurl). If the package uses a custom fetcher, use Method B on.srcinstead. - For each dependency hash (
vendorHash/npmDepsHash/cargoHash/ etc.), use Method B on the matching sub-attribute. - Opaque
outputHashFODs (e.g. opencode'snode_moduleswhich runsbun install) — do NOT attempt locally. Leave as-is and flag for CI in the summary. - Show
git diff -- packages/<name>/and list any hashes left for CI.
Don't Touch What Didn't Change
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.
Optional Shortcut
nix-update --flake <name> --version <v> sometimes handles everything for simple packages. Try it first; fall back to the methods above if it fails.