-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: add nix flake support (sorry for this duplicate) #459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
09d39d6
5d123ce
d316390
13cb91d
23b9067
8437f57
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -148,3 +148,4 @@ CLAUDE.md | |
|
|
||
| # Pnpm | ||
| .pnpm-store/ | ||
| result | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| { | ||
| description = "OpenSpec - AI-native system for spec-driven development"; | ||
|
|
||
| inputs = { | ||
| nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; | ||
| }; | ||
|
|
||
| outputs = { self, nixpkgs }: | ||
| let | ||
| supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; | ||
|
|
||
| forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system); | ||
| in | ||
| { | ||
| packages = forAllSystems (system: | ||
| let | ||
| pkgs = nixpkgs.legacyPackages.${system}; | ||
| in | ||
| { | ||
| default = pkgs.stdenv.mkDerivation (finalAttrs: { | ||
| pname = "openspec"; | ||
| version = "0.18.0"; | ||
|
||
|
|
||
| src = ./.; | ||
|
|
||
| pnpmDeps = pkgs.fetchPnpmDeps { | ||
| inherit (finalAttrs) pname version src; | ||
| pnpm = pkgs.pnpm_9; | ||
| fetcherVersion = 3; | ||
| hash = "sha256-ltG+wmr2aiRmghEMGOZVYifvrY8qdLDfizLq6a8Ds0s="; | ||
| }; | ||
|
|
||
| nativeBuildInputs = with pkgs; [ | ||
| nodejs_20 | ||
| npmHooks.npmInstallHook | ||
| pnpmConfigHook | ||
| pnpm_9 | ||
| ]; | ||
|
|
||
| buildPhase = '' | ||
| runHook preBuild | ||
| pnpm run build | ||
| runHook postBuild | ||
| ''; | ||
|
|
||
| dontNpmPrune = true; | ||
|
|
||
| meta = with pkgs.lib; { | ||
| description = "AI-native system for spec-driven development"; | ||
| homepage = "https://github.com/Fission-AI/OpenSpec"; | ||
| license = licenses.mit; | ||
| maintainers = [ ]; | ||
| mainProgram = "openspec"; | ||
| }; | ||
| }); | ||
| }); | ||
|
|
||
| apps = forAllSystems (system: { | ||
| default = { | ||
| type = "app"; | ||
| program = "${self.packages.${system}.default}/bin/openspec"; | ||
| }; | ||
| }); | ||
|
|
||
| devShells = forAllSystems (system: | ||
| let | ||
| pkgs = nixpkgs.legacyPackages.${system}; | ||
| in | ||
| { | ||
| default = pkgs.mkShell { | ||
| buildInputs = with pkgs; [ | ||
| nodejs_20 | ||
| pnpm_9 | ||
| ]; | ||
|
|
||
| shellHook = '' | ||
| echo "OpenSpec development environment" | ||
| echo "Node version: $(node --version)" | ||
| echo "pnpm version: $(pnpm --version)" | ||
| echo "Run 'pnpm install' to install dependencies" | ||
| ''; | ||
| }; | ||
| }); | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| schema: spec-driven | ||
| created: 2026-01-07 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| ## Context | ||
|
|
||
| OpenSpec is a TypeScript CLI tool using pnpm for dependency management. The project requires Node.js ≥20.19.0. Nix uses its own build system that needs to understand how to fetch dependencies and build the project reproducibly. | ||
|
|
||
| The Nix ecosystem has specific patterns for packaging Node.js/pnpm projects that differ from the traditional npm ecosystem. | ||
|
|
||
| ## Goals | ||
|
|
||
| - Enable OpenSpec to be run directly via `nix run github:Fission-AI/OpenSpec` | ||
| - Support all major platforms (Linux x86/ARM, macOS x86/ARM) | ||
| - Use existing pnpm-lock.yaml for reproducible builds | ||
| - Provide development environment for Nix users | ||
|
|
||
| ## Non-Goals | ||
|
|
||
| - Replace existing npm/pnpm publishing workflow | ||
| - Publish to nixpkgs (can be done later as separate effort) | ||
| - Support Windows (Nix doesn't run natively on Windows) | ||
|
|
||
| ## Decisions | ||
|
|
||
| ### Use stdenv.mkDerivation instead of buildNpmPackage | ||
|
|
||
| **Decision**: Package OpenSpec using `stdenv.mkDerivation` with pnpm hooks. | ||
|
|
||
| **Rationale**: The zigbee2mqtt package in nixpkgs demonstrates the current best practice for pnpm projects. Using `buildNpmPackage` with pnpm requires complex configuration, while `mkDerivation` with the right hooks is more straightforward and better supported. | ||
|
|
||
| **Alternative considered**: Using `buildNpmPackage` with `npmConfigHook = pkgs.pnpmConfigHook` - this is the older pattern and causes issues with dependency fetching. | ||
|
|
||
| ### Use fetchPnpmDeps with explicit pnpm version | ||
|
|
||
| **Decision**: Use `pkgs.fetchPnpmDeps` with `pnpm = pkgs.pnpm_9` and `fetcherVersion = 3`. | ||
|
|
||
| **Rationale**: | ||
| - pnpm lockfile version 9.0 requires fetcherVersion 3 | ||
| - Explicit pnpm_9 ensures consistency between fetch and build | ||
| - This is the documented way to handle pnpm projects in nixpkgs | ||
|
|
||
| ### Multi-platform support without flake-utils | ||
|
|
||
| **Decision**: Implement multi-platform support using plain Nix with `nixpkgs.lib.genAttrs`. | ||
|
|
||
| **Rationale**: Per user request, avoid extra dependencies. The `genAttrs` pattern is simple and well-understood in the Nix community. | ||
|
|
||
| ### Node.js 20 instead of latest | ||
|
|
||
| **Decision**: Pin to nodejs_20 to match package.json engines requirement. | ||
|
|
||
| **Rationale**: Ensures consistency with development environment and npm package requirements. Avoids potential compatibility issues with newer Node versions. | ||
|
|
||
| ## Key Implementation Details | ||
|
|
||
| ### Dependency Hash Management | ||
|
|
||
| The `pnpmDeps.hash` field must be updated whenever dependencies change. The workflow: | ||
| 1. Set hash to fake value (all zeros) | ||
| 2. Run `nix build` | ||
| 3. Nix fails with actual hash | ||
| 4. Update flake.nix with correct hash | ||
|
|
||
| This is standard Nix workflow for fixed-output derivations. | ||
|
|
||
| ### Build Inputs | ||
|
|
||
| Required nativeBuildInputs: | ||
| - `nodejs_20` - runtime | ||
| - `npmHooks.npmInstallHook` - handles installation phase | ||
| - `pnpmConfigHook` - configures pnpm environment | ||
| - `pnpm_9` - pnpm executable | ||
|
|
||
| The `dontNpmPrune = true` is important to keep all dependencies after build. | ||
|
|
||
| ## Risks / Trade-offs | ||
|
|
||
| **[Risk]** Hash needs updating when dependencies change → **Mitigation**: Document this clearly; error message from Nix provides correct hash | ||
|
|
||
| **[Risk]** Nix builds might lag behind npm releases → **Mitigation**: This is fine; Nix users can still use npm if they need bleeding edge | ||
|
|
||
| **[Trade-off]** Additional maintenance burden for hash updates → **Benefit**: Better experience for Nix ecosystem users | ||
|
|
||
| ## Migration Plan | ||
|
|
||
| 1. Add flake.nix to repository | ||
| 2. Test builds on multiple platforms (can use GitHub Actions with Nix) | ||
| 3. Update README with Nix installation instructions | ||
| 4. Optionally add to CI pipeline to catch hash mismatches early | ||
|
|
||
| No breaking changes - this is purely additive. | ||
|
|
||
| ## Open Questions | ||
|
|
||
| - Should we add automatic hash updating to CI? (Could use nix-update-script) | ||
| - Should we submit to nixpkgs after validation? (Separate decision) | ||
| - Do we want to support older Node versions in flake? (Probably no - stick to package.json requirement) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| ## Why | ||
|
|
||
| OpenSpec users on NixOS or using the Nix package manager cannot easily install or run OpenSpec without going through npm. Adding a Nix flake makes OpenSpec a first-class citizen in the Nix ecosystem, enabling users to run `nix run github:Fission-AI/OpenSpec -- init` or include OpenSpec in their development environments declaratively. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - Add `flake.nix` to repository root with multi-platform support (x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin) | ||
| - Package uses pnpm for dependency management (matching existing development workflow) | ||
| - Support both direct execution via `nix run` and installation via `nix profile install` | ||
| - Provide dev shell for contributors using Nix | ||
|
|
||
| ## Capabilities | ||
|
|
||
| ### New Capabilities | ||
| - `nix-flake-support`: Nix flake configuration for building and running OpenSpec | ||
|
|
||
| ### Modified Capabilities | ||
| - None | ||
|
|
||
| ## Impact | ||
|
|
||
| - **New files**: `flake.nix` in repository root | ||
| - **Documentation**: Should add installation instructions for Nix users | ||
| - **CI/CD**: Could add flake checking to CI pipeline (optional) | ||
| - **Maintenance**: Requires updating pnpmDeps hash when dependencies change |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: Multi-platform Nix flake | ||
| The system SHALL provide a Nix flake that builds OpenSpec for multiple platforms. | ||
|
|
||
| #### Scenario: Build on Linux x86_64 | ||
| - **WHEN** user runs `nix build` on x86_64-linux system | ||
| - **THEN** system builds OpenSpec package successfully | ||
| - **AND** package includes the `openspec` binary | ||
|
|
||
| #### Scenario: Build on macOS ARM | ||
| - **WHEN** user runs `nix build` on aarch64-darwin system | ||
| - **THEN** system builds OpenSpec package successfully | ||
| - **AND** package includes the `openspec` binary | ||
|
|
||
| #### Scenario: Build on Linux ARM | ||
| - **WHEN** user runs `nix build` on aarch64-linux system | ||
| - **THEN** system builds OpenSpec package successfully | ||
|
|
||
| #### Scenario: Build on macOS x86_64 | ||
| - **WHEN** user runs `nix build` on x86_64-darwin system | ||
| - **THEN** system builds OpenSpec package successfully | ||
|
|
||
| ### Requirement: Direct execution via nix run | ||
| The system SHALL allow users to run OpenSpec directly from GitHub without installing. | ||
|
|
||
| #### Scenario: Run init command from GitHub | ||
| - **WHEN** user runs `nix run github:Fission-AI/OpenSpec -- init` | ||
| - **THEN** system downloads and builds OpenSpec | ||
| - **AND** executes `openspec init` command | ||
|
|
||
| #### Scenario: Run any OpenSpec command | ||
| - **WHEN** user runs `nix run github:Fission-AI/OpenSpec -- <command> <args>` | ||
| - **THEN** system executes `openspec <command> <args>` | ||
|
|
||
| ### Requirement: pnpm dependency management | ||
| The system SHALL use pnpm for building OpenSpec in the Nix flake. | ||
|
|
||
| #### Scenario: Fetch dependencies with pnpm | ||
| - **WHEN** Nix builds the package | ||
| - **THEN** system uses `fetchPnpmDeps` to download dependencies | ||
| - **AND** uses pnpm-lock.yaml for reproducible builds | ||
| - **AND** uses fetcherVersion 3 for lockfile version 9.0 | ||
|
|
||
| #### Scenario: Build with pnpm | ||
| - **WHEN** Nix runs the build phase | ||
| - **THEN** system executes `pnpm run build` | ||
| - **AND** produces dist directory with compiled TypeScript | ||
|
|
||
| ### Requirement: Node.js version compatibility | ||
| The system SHALL use Node.js 20 as specified in package.json engines field. | ||
|
|
||
| #### Scenario: Build with correct Node version | ||
| - **WHEN** Nix builds OpenSpec | ||
| - **THEN** system uses nodejs_20 from nixpkgs | ||
| - **AND** build succeeds without version compatibility errors | ||
|
|
||
| ### Requirement: Development shell | ||
| The system SHALL provide a Nix development shell for contributors. | ||
|
|
||
| #### Scenario: Enter dev shell | ||
| - **WHEN** user runs `nix develop` in OpenSpec repository | ||
| - **THEN** system provides shell with nodejs_20 and pnpm_9 | ||
| - **AND** displays welcome message with versions | ||
| - **AND** provides instructions to run `pnpm install` | ||
|
|
||
| ### Requirement: Proper binary installation | ||
| The system SHALL install the openspec binary correctly. | ||
|
|
||
| #### Scenario: Binary in PATH | ||
| - **WHEN** package is built or installed | ||
| - **THEN** `openspec` binary is available in `$out/bin/openspec` | ||
| - **AND** binary is executable | ||
| - **AND** binary can be invoked without full path when installed | ||
|
|
||
| #### Scenario: Binary executes correctly | ||
| - **WHEN** user runs the installed `openspec` command | ||
| - **THEN** system executes the CLI entry point | ||
| - **AND** all subcommands work correctly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: Fission-AI/OpenSpec
Length of output: 2736
🏁 Script executed:
Repository: Fission-AI/OpenSpec
Length of output: 1512
🏁 Script executed:
Repository: Fission-AI/OpenSpec
Length of output: 233
🏁 Script executed:
Repository: Fission-AI/OpenSpec
Length of output: 142
🏁 Script executed:
Repository: Fission-AI/OpenSpec
Length of output: 45
🏁 Script executed:
Repository: Fission-AI/OpenSpec
Length of output: 45
🏁 Script executed:
Repository: Fission-AI/OpenSpec
Length of output: 1198
Use proper markdown headings instead of bold text to maintain document hierarchy.
Lines 143 and 154 should use h5 headings (
#####) rather than bold emphasis, as they represent subsections under "Step 1: Install the CLI globally" (which is h4). Using proper headings improves semantic structure, accessibility, and automated document processing.📝 Proposed fix
Apply the same fix to line 154:
📝 Committable suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
143-143: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🤖 Prompt for AI Agents