feat(lib): add mkPackagesFor for overlay-friendly package sets - #150
Merged
Conversation
r-vdp
force-pushed
the
mk-packages-for
branch
2 times, most recently
from
April 15, 2026 09:20
0fba6b1 to
e69e4fa
Compare
A blueprint flake's `packages.${system}` is built against blueprint's
own nixpkgs instance (derived from inputs.nixpkgs plus any
nixpkgs.config/overlays). An overlay that just exposes that set, e.g.
final: _: { foo = self.packages.${final.system}; }
drags a second, independent nixpkgs evaluation into every consumer,
since `final` is never used to build anything. `inputs.nixpkgs.follows`
doesn't help — it only changes which source gets re-imported.
mkPackagesFor re-loads the packages/ tree against a caller-supplied
pkgs, with the same scope arguments (pkgs, flake, inputs, system,
perSystem, pname). perSystem.self resolves within the new scope so
intra-set references stay on the caller's nixpkgs.
bp // {
overlays.default = final: _: { foo = bp.mkPackagesFor final; };
}
unfilteredPackages is now defined in terms of mkPackagesFor, so there
is a single loader for the packages/ tree. Existing outputs are
unchanged (verified: identical drv hashes for packages and devShells
via llm-agents.nix as a fixture).
r-vdp
added a commit
to r-vdp/llm-agents.nix
that referenced
this pull request
Apr 15, 2026
overlays.default hands back packages.${system} as-is, which means
applying it pulls a second nixpkgs evaluation into the consumer
(import inputs.nixpkgs { config.allowUnfree = true; } via blueprint).
inputs.nixpkgs.follows doesn't help — it only changes which source
gets re-imported, not that it gets re-imported.
Add overlays.shared-nixpkgs using blueprint's new mkPackagesFor
(numtide/blueprint#150) so packages are rebuilt against the consumer's
final and share its dependency graph. Measured on a NixOS config that
uses pi/tuicr/rtk/openspec via the overlay: ~0.5M fewer function calls
out of ~20M (~2.5%). overlays.default is unchanged for users who want
cache hits independent of their nixpkgs pin.
Fixes numtide#1172
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A blueprint flake that wants to expose its
packages/as a nixpkgs overlaycurrently has no good option. The obvious
doesn't build anything against
final— it hands back the set blueprintalready built from
inputs.nixpkgs(with whatevernixpkgs.config/overlaysthe flake configured). The consumer ends up evaluating a second, independent
nixpkgs instance for those packages.
inputs.nixpkgs.followsdoesn't help; itonly changes which source gets re-imported, but still imports a second instance.
Concretely, in a NixOS config consuming
llm-agents.nix(which uses exactlythis pattern), this accounts for ~2M extra function calls / ~9% of total eval
time per host.
Change
Add a
mkPackagesForoutput that reloads thepackages/tree against acaller-supplied
pkgs. Packages see the same scope arguments as inpackages.<system>(pkgs,flake,inputs,system,perSystem,pname); onlypkgsis swapped.perSystem.selfresolves within the newscope so intra-set references stay on the caller's nixpkgs.
unfilteredPackagesis redefined in terms ofmkPackagesFor, so there is asingle loader for the
packages/tree. Existing outputs are unchanged(verified: identical drv hashes for
packagesanddevShellsviallm-agents.nix as a fixture).
Related: #90, numtide/llm-agents.nix#1172