build: package the kitchen CLI as a Nix flake (task 0001)
Add a flake-parts flake whose default package Bun-compiles the kitchen CLI into a self-contained native binary, built in the sandbox with dependencies vendored by bun2nix. Bun is pinned via a dedicated nixpkgs-bun input (Bun 1.3.13) that bun2nix follows, so nixpkgs can track unstable without moving the compile toolchain onto a release that emits empty binaries. bun2nix is both a flake input and an npm devDependency, and a postinstall hook keeps the checked-in bun.nix in sync with the lockfile.
This commit is contained in:
53
.claude/tasks/0001-flake-build.md
Normal file
53
.claude/tasks/0001-flake-build.md
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
spec: nix-flake-packaging
|
||||
---
|
||||
|
||||
## What to build
|
||||
|
||||
The tracer bullet for packaging the repository as a Nix flake: a flake-parts flake whose default package Bun-compiles the `kitchen` CLI into a self-contained native binary, built reproducibly in the sandbox with vendored dependencies.
|
||||
|
||||
This is the whole risk seam — a Nix build is sandboxed with no network, while `bun install` fetches from npm, so the dependency closure must be vendored before anything compiles.
|
||||
Bun dependencies are vendored via bun2nix (a flake input) reading the workspace lockfile into a checked-in generated expression, kept in sync with the lockfile by a postinstall hook so a dependency change needs no separate manual regeneration.
|
||||
A single pinned Bun version is shared by the build derivation (and later the dev shell), avoiding point releases known to produce empty binaries under sandboxed native compilation.
|
||||
|
||||
Once this compiles, the remaining outputs (`nix run`, `nix develop`, checks) hang off the working flake in the next slice.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] The flake is structured with flake-parts, with `x86_64-linux` in the systems list and nixpkgs tracking `nixpkgs-unstable`.
|
||||
- [x] bun2nix is a flake input, and its generated vendoring expression is checked in and regenerated by a postinstall hook on lockfile changes.
|
||||
- [x] A single Bun version is pinned in one place and consumed by the build derivation.
|
||||
- [x] `nix build` produces a runnable `kitchen` binary reproducibly with no network access during the build.
|
||||
- [x] The compiled binary embeds its dependencies and runs on a machine with no Node.js or Bun runtime present.
|
||||
- [x] The default package is consumable as a flake input from another configuration.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The tracer bullet builds and all six criteria were verified end-to-end against a real `nix build`, not just by inspection.
|
||||
|
||||
### The Bun pin
|
||||
|
||||
bun2nix compiles the binary with the `bun` from *its own* nixpkgs, baked into its setup hook at bun2nix build time.
|
||||
So pinning Bun means controlling the nixpkgs that bun2nix follows, not overlaying `bun` in this flake's package set.
|
||||
The pin is a dedicated `nixpkgs-bun` input fixed to one revision (Bun 1.3.13), with `bun2nix.inputs.nixpkgs.follows = "nixpkgs-bun"`.
|
||||
That revision is the one bun2nix 2.1.2 itself locks, so the compile toolchain matches what bun2nix was tested against.
|
||||
`nixpkgs` still tracks `nixpkgs-unstable` for everything else, and updating it cannot move Bun.
|
||||
The dev shell in task 0002 consumes the same `nixpkgs-bun`, keeping "develop with the version that compiles" true from one place.
|
||||
|
||||
### Vendoring and the postinstall hook
|
||||
|
||||
bun2nix is both a flake input (native builder) and an npm devDependency, so the `postinstall: bun2nix -o bun.nix` hook regenerates the checked-in `bun.nix` on any `bun install` even outside the Nix dev shell.
|
||||
The build passes `dontRunLifecycleScripts = true` so that same postinstall does not fire redundantly inside the sandbox.
|
||||
|
||||
### Verification performed
|
||||
|
||||
`nix build` produced a 101 MB native ELF that runs to exit 0 under `env -i` (empty environment, no Node or Bun, `ldd` shows only glibc), confirming the embedded-runtime and no-network claims — the compile derivation is a normal sandboxed derivation with networking disabled.
|
||||
A throwaway consumer flake built the package through `inputs.kitchen.packages.x86_64-linux.default`, confirming criterion 6.
|
||||
|
||||
### Deviations from the plan
|
||||
|
||||
- The nix-community cachix `nixConfig` block that the bun2nix templates ship was dropped, because the spec lists "any binary cache or substituter setup" as out of scope.
|
||||
Consequence: a first build with a cold store compiles bun2nix from source.
|
||||
A developer who wants the prebuilt bun2nix can add the substituter to their own Nix configuration.
|
||||
- `packages/bin/src/index.ts` is still the placeholder entry point.
|
||||
The CLI's behaviour belongs to the core-parser and cli-view specs, so the compiled binary is a no-op that exits 0 — enough to prove the packaging seam.
|
||||
Reference in New Issue
Block a user