Replace the stale Bun-only project-scaffold spec with a Nix-aware packaging spec, and record the flake-parts + bun2nix + pinned-Bun decision as ADR 0007.
83 lines
7.3 KiB
Markdown
83 lines
7.3 KiB
Markdown
## Problem Statement
|
|
|
|
The repository was scaffolded as a Bun workspaces monorepo before the developer adopted Nix.
|
|
There is no declarative, reproducible way to build, run, or install the `kitchen` CLI, and no reproducible development environment.
|
|
A contributor must install the right Bun version and tooling by hand, and the "no Node.js runtime on target machines" promise is trusted rather than enforced.
|
|
The developer wants to install the CLI declaratively — as a flake input in a system or home configuration — and to enter a fully specified dev shell with a single command.
|
|
|
|
## Solution
|
|
|
|
Package the whole repository as a Nix flake, structured with flake-parts, exposing the `kitchen` CLI as an installable package plus a development shell, a runnable app, and a set of checks.
|
|
Bun dependencies are vendored reproducibly with bun2nix so the sandboxed build needs no network.
|
|
Bun itself is pinned so the version used to develop is the version used to compile.
|
|
The flake is the single declarative entry point: build it, run it, install it, or develop in it.
|
|
|
|
## User Stories
|
|
|
|
1. As the developer, I want to install the `kitchen` CLI declaratively via a flake input, so that it lands in my system or home configuration reproducibly without manual build steps.
|
|
2. As the developer, I want `nix build` to produce the compiled `kitchen` binary, so that the artifact is built the same way on any machine.
|
|
3. As the developer, I want `nix run` to execute the CLI without a prior install, so that I can try it ad hoc.
|
|
4. As a contributor, I want `nix develop` to drop me into a shell with the exact Bun and tooling the project expects, so that I do not have to install or match versions by hand.
|
|
5. As a contributor using direnv, I want the dev shell to load automatically on entering the directory, so that the environment is present without a manual command.
|
|
6. As the developer, I want `nix flake check` to run the test suites and the linter, so that a single command verifies the project reproducibly and can gate CI later.
|
|
7. As the developer, I want the compiled binary to embed its dependencies, so that no Node.js or Bun runtime is required on the target machine.
|
|
8. As a maintainer, I want dependency vendoring to stay in sync with the lockfile automatically, so that adding or removing a dependency does not require a separate manual regeneration step I might forget.
|
|
9. As a maintainer, I want the Bun version pinned and shared between the dev shell and the build, so that a Bun release that breaks sandboxed compilation cannot silently diverge dev from build.
|
|
|
|
## Implementation Decisions
|
|
|
|
- **Flake structure: flake-parts.**
|
|
Per-system outputs (package, dev shell, app, checks) are declared through flake-parts' `perSystem` module, and system-independent configuration sits at the top level.
|
|
This keeps per-system and top-level outputs separate and lets tooling integrations compose as modules.
|
|
- **Outputs.**
|
|
The flake exposes a default package building the `kitchen` binary, a default app pointing at that binary, a default dev shell, and a checks set aggregating tests and lint.
|
|
`nix build`, `nix run`, `nix develop`, and `nix flake check` are the supported entry points.
|
|
- **Dependency vendoring: bun2nix.**
|
|
Bun workspace dependencies are vendored via bun2nix, which reads the lockfile and produces a generated Nix expression the build consumes.
|
|
A postinstall hook regenerates that expression on any dependency change, keeping it in sync with the lockfile without a manual step.
|
|
bun2nix is added as a flake input.
|
|
- **Binary build via Bun's native compiler.**
|
|
The package derivation compiles the CLI to a self-contained native binary that embeds its dependencies, so the runtime closure on the target has no Node.js or Bun.
|
|
The vendored dependencies are consumed at build time only.
|
|
- **Bun pinned.**
|
|
A single pinned Bun version is shared by the dev shell and the build derivation.
|
|
The pin avoids Bun releases known to break native compilation inside the Nix sandbox, where specific point releases have produced empty binaries.
|
|
- **Systems: `x86_64-linux` only** for now, declared in the flake-parts systems list.
|
|
Additional targets are a one-line addition when a real target appears; vendoring and compilation are per-platform, so each added system carries its own build.
|
|
- **nixpkgs tracks `nixpkgs-unstable`**, to follow a recent Bun.
|
|
- **Lint as a check: treefmt-nix.**
|
|
Biome runs as a `nix flake check` through the treefmt-nix flake-parts module, so lint verification is reproducible and shares one configuration with the existing biome setup.
|
|
- **direnv auto-load.**
|
|
A direnv configuration using `use flake` loads the dev shell automatically for direnv users.
|
|
- **The monorepo it packages is unchanged.**
|
|
The existing Bun workspaces layout (`@kitchen-md/core` and `@kitchen-md/bin`) and the `kitchen` binary target are the inputs to the flake; the flake wraps them without restructuring the packages.
|
|
|
|
## Testing Decisions
|
|
|
|
- The flake's verification surface is its outputs, exercised as commands rather than unit tests.
|
|
The highest seam is `nix flake check`: it composes the package build, the Bun test suites, and the biome lint into one reproducible gate.
|
|
- **Build seam.**
|
|
`nix build` must produce a runnable `kitchen` binary; a minimal check invokes the built binary (for example `--help`) and asserts a zero exit, mirroring the existing smoke-test approach in `@kitchen-md/bin` but against the Nix artifact.
|
|
- **Dev-shell seam.**
|
|
Entering the dev shell must expose the pinned Bun and biome; this is verified by the presence and versions of those tools in the shell.
|
|
- **Application behaviour is not re-tested here.**
|
|
The parser and CLI behaviour are covered by their own specs' unit, integration, and smoke tiers, which run under the Bun test runner and are invoked by `nix flake check`.
|
|
This spec's tests concern packaging and environment reproducibility only.
|
|
- Prior art: the existing smoke tests in `@kitchen-md/bin` invoke the CLI as a black box; the build-seam check reuses that black-box style against the Nix-built binary.
|
|
|
|
## Out of Scope
|
|
|
|
- The parser and CLI implementation and their behaviour, covered by the core-parser and cli-view specs.
|
|
- Publishing either package to a registry, and the future Obsidian plugin's own repository and packaging.
|
|
- CI/CD wiring; `nix flake check` is designed to be CI-callable, but the CI configuration itself is separate.
|
|
- Multi-system and cross-compilation beyond `x86_64-linux`, and any binary cache or substituter setup.
|
|
- A NixOS or home-manager module wrapping the package; the package output is directly consumable without one.
|
|
- git-hooks integration; treefmt-nix covers the lint check, and pre-commit hooks can be added later as another flake-parts module.
|
|
|
|
## Further Notes
|
|
|
|
- Because Bun's native compiler bundles dependencies into the binary, the vendoring problem is confined to build time; nothing about the dependency closure reaches consumers of the installed CLI.
|
|
- The Bun-version pin is a correctness constraint, not just hygiene: native compilation has produced empty binaries in the sandbox on specific Bun point releases, so the dev shell and build must never drift apart on Bun version.
|
|
- The decision to package with a flake, vendor via bun2nix, and pin Bun is recorded in ADR 0007.
|
|
- This spec replaces the removed project-scaffold spec's role for anything Nix-related; the underlying Bun monorepo layout that spec documented is retained in the codebase.
|