diff --git a/AGENTS.md b/AGENTS.md index d4b1bc6..212e1a2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,8 @@ # Flakebox agent notes +This project uses the Linked Specs convention; consult the `linked-specs` +skill before working with specs or governed code. + ## What this repo is - Flakebox is a Nix-based Rust dev-env toolkit. diff --git a/checks/ast-grep-rules.nix b/checks/ast-grep-rules.nix index f9f8f67..554e988 100644 --- a/checks/ast-grep-rules.nix +++ b/checks/ast-grep-rules.nix @@ -1,8 +1,14 @@ -{ pkgs }: +{ pkgs, flakeboxLib }: pkgs.runCommand "ast-grep-rules" { nativeBuildInputs = [ pkgs.ast-grep ]; - src = pkgs.lib.cleanSource ../.; + src = pkgs.lib.sources.cleanSourceWith { + src = ../.; + filter = flakeboxLib.source.filters.all [ + pkgs.lib.sources.cleanSourceFilter + (flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]) + ]; + }; } '' cp -r "$src" source diff --git a/checks/cell-aware-cross-inputs/default.nix b/checks/cell-aware-cross-inputs/default.nix index df3b1fd..a318ecc 100644 --- a/checks/cell-aware-cross-inputs/default.nix +++ b/checks/cell-aware-cross-inputs/default.nix @@ -34,7 +34,17 @@ let package = craneLib.buildPackage { pname = "cell-aware-cross-inputs"; version = "0.1.0"; - src = craneLib.cleanCargoSource ./.; + src = craneLib.cleanCargoSource ( + flakeboxLib.source.fromPaths { + root = ./.; + paths = [ + "Cargo.toml" + "Cargo.lock" + "src" + ]; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; + } + ); strictDeps = true; }; }); diff --git a/checks/custom-stdenv/default.nix b/checks/custom-stdenv/default.nix index d5b4f78..3661309 100644 --- a/checks/custom-stdenv/default.nix +++ b/checks/custom-stdenv/default.nix @@ -29,7 +29,11 @@ let cargoArtifacts = null; cargoVendorDir = null; doInstallCargoArtifacts = false; - src = ./.; + src = flakeboxLib.source.fromFileset { + root = ./.; + fileset = ./default.nix; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; + }; buildPhaseCargoCommand = '' set -x if [[ "$(${pkgs.which}/bin/which cc)" != *clang-wrapper-${clangMajor}* ]]; then diff --git a/checks/nextest/default.nix b/checks/nextest/default.nix index ae50818..081214a 100644 --- a/checks/nextest/default.nix +++ b/checks/nextest/default.nix @@ -14,6 +14,7 @@ let src = flakeboxLib.source.fromPaths { root = rootDir; paths = buildPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; craneLib = craneLib'.overrideArgs { diff --git a/checks/source-tests.nix b/checks/source-tests.nix index b5e0255..3f7286e 100644 --- a/checks/source-tests.nix +++ b/checks/source-tests.nix @@ -22,8 +22,8 @@ let }; baseline = mkFixtureSource (fixture + "/baseline"); - excludedChange = mkFixtureSource (fixture + "/excluded-change"); - selectedChange = mkFixtureSource (fixture + "/selected-change"); + linkedSpecsEdit = mkFixtureSource (fixture + "/excluded-change"); + selectedInputEdit = mkFixtureSource (fixture + "/selected-change"); buildFiles = source.filesetFromPaths { root = fixture + "/baseline"; @@ -67,11 +67,11 @@ let fails = value: !(builtins.tryEval (builtins.deepSeq value true)).success; in assert lib.assertMsg ( - toString baseline == toString excludedChange -) "changes to excluded content must preserve the source store path"; + toString baseline == toString linkedSpecsEdit +) "Linked Specs edits must preserve the build source store path"; assert lib.assertMsg ( - toString baseline != toString selectedChange -) "changes to selected content must alter the source store path"; + toString baseline != toString selectedInputEdit +) "selected build input edits must alter the build source store path"; assert lib.assertMsg ( !(source.filters.all [ (_path: _type: false) diff --git a/checks/workspace-cross-compile/default.nix b/checks/workspace-cross-compile/default.nix index d9174b1..6b203bc 100644 --- a/checks/workspace-cross-compile/default.nix +++ b/checks/workspace-cross-compile/default.nix @@ -28,6 +28,7 @@ let src = flakeboxLib.source.fromPaths { root = rootDir; paths = buildPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; craneLib = @@ -87,6 +88,7 @@ let src = flakeboxLib.source.fromPaths { root = rootDir; paths = testPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; }; } diff --git a/checks/workspace-sanity/default.nix b/checks/workspace-sanity/default.nix index bdd2d92..c62bd46 100644 --- a/checks/workspace-sanity/default.nix +++ b/checks/workspace-sanity/default.nix @@ -23,6 +23,7 @@ let src = flakeboxLib.source.fromPaths { root = rootDir; paths = buildPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; craneLib = @@ -77,6 +78,7 @@ let src = flakeboxLib.source.fromPaths { root = rootDir; paths = testPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; }; } diff --git a/docs/building-new-project.md b/docs/building-new-project.md index 042bf6b..a24083c 100644 --- a/docs/building-new-project.md +++ b/docs/building-new-project.md @@ -329,6 +329,7 @@ index cb41316..08c8f65 100644 + ".cargo" + "src" + ]; ++ filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; + }; + + legacyPackages = (flakeboxLib.craneMultiBuild { }) (craneLib': @@ -439,6 +440,7 @@ The next binding is: ".cargo" "src" ]; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; ``` diff --git a/docs/flakeboxLib.md b/docs/flakeboxLib.md index 50991c6..680a68e 100644 --- a/docs/flakeboxLib.md +++ b/docs/flakeboxLib.md @@ -21,6 +21,7 @@ let src = flakeboxLib.source.fromPaths { root = ./.; paths = buildPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; in # ... @@ -36,11 +37,13 @@ Reuse path lists when later build stages need extra inputs: buildSrc = flakeboxLib.source.fromPaths { root = ./.; paths = buildPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; testSrc = flakeboxLib.source.fromPaths { root = ./.; paths = buildPaths ++ [ "scripts" ]; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; ``` @@ -66,10 +69,12 @@ in { buildSrc = source.fromFileset { root = ./.; fileset = buildFiles; + filter = source.filters.excludeDirectoriesNamed [ "specs" ]; }; testSrc = source.fromFileset { root = ./.; fileset = fs.union buildFiles ./scripts; + filter = source.filters.excludeDirectoriesNamed [ "specs" ]; }; } ``` diff --git a/docs/getting-started.md b/docs/getting-started.md index f96fe1d..5c9582a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -70,6 +70,7 @@ Following modifications to `flake.nix` are needed: buildSrc = flakeboxLib.source.fromPaths { root = ./.; paths = buildPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; # Add toolchain x profile build matrix diff --git a/flake.nix b/flake.nix index aad6c7a..67ed677 100644 --- a/flake.nix +++ b/flake.nix @@ -96,6 +96,7 @@ nixpkgs ; }; + in { inherit overlays; @@ -147,6 +148,7 @@ ".cargo" "flakebox-bin" ]; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; outputs = (flakeboxLib.craneMultiBuild { }) ( diff --git a/lib/default.nix b/lib/default.nix index 23d9611..08272c7 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -65,7 +65,10 @@ lib.makeScope pkgs.newScope ( docs = pkgs.stdenv.mkDerivation { name = "docs"; - src = ../docs; + src = lib.sources.cleanSourceWith { + src = ../docs; + filter = self.source.filters.excludeDirectoriesNamed [ "specs" ]; + }; # Depend on the generated options reference used by the book. buildInputs = [ optionsDocMd ]; diff --git a/lib/flakeboxBin.nix b/lib/flakeboxBin.nix index c80b458..997b6c2 100644 --- a/lib/flakeboxBin.nix +++ b/lib/flakeboxBin.nix @@ -1,17 +1,16 @@ { - lib, pkgs, + source, }: let - fs = lib.fileset; - fileSet = fs.unions [ - ../Cargo.toml - ../Cargo.lock - ../flakebox-bin - ]; - src = fs.toSource { + src = source.fromPaths { root = ../.; - fileset = fileSet; + paths = [ + "Cargo.toml" + "Cargo.lock" + "flakebox-bin" + ]; + filter = source.filters.excludeDirectoriesNamed [ "specs" ]; }; in pkgs.rustPlatform.buildRustPackage { diff --git a/lib/specs/ARCH-flakebox-nix-library.md b/lib/specs/ARCH-flakebox-nix-library.md new file mode 100644 index 0000000..ae46fe1 --- /dev/null +++ b/lib/specs/ARCH-flakebox-nix-library.md @@ -0,0 +1,28 @@ +# ARCH-flakebox-nix-library: Flakebox Nix library architecture + +This record refines [ARCH-flakebox](../../specs/ARCH-flakebox.md) for `lib/`. + +`mkLib pkgs { modules, config }` is the library composition boundary. It +evaluates built-in modules, caller extensions, and caller configuration, then +returns a scoped library instance bound to one package set and system. Modules +declare options and contribute through shared aggregation points for generated +repository files, shell environment and hooks, Git hooks, Just rules, and +GitHub workflows. + +The generated root is the declarative desired project state. The library +materializes it, gives it a content identity, and exposes it and its generated +shell hook to development shells. The `flakebox` CLI, outside this scope, owns +comparison and synchronization with a mutable worktree. + +Target constructors provide target-specific build arguments and Rust component +targets. Toolchain constructors combine those descriptions with Fenix and an +enhanced Crane instance. `craneMultiBuild` maps consumer-defined outputs across +the configured toolchain and Cargo-profile cells while resolving each cell's +build-input roles. + +Source construction remains explicit and caller-owned. Callers select every +input their build or check consumes and apply additional predicates where +needed. Repository-derived sources exclude directories named `specs` +recursively so governing records do not enter builds or invalidate their +source identities. `docs/flakeboxLib.md` owns the public source and build-matrix +API details; checks provide executable conformance coverage. diff --git a/specs/ARCH-flakebox.md b/specs/ARCH-flakebox.md new file mode 100644 index 0000000..93e72e2 --- /dev/null +++ b/specs/ARCH-flakebox.md @@ -0,0 +1,31 @@ +# ARCH-flakebox: Flakebox architecture + +Flakebox is a Nix-flake-delivered toolkit for Rust development environments. +Its main boundaries are the Nix library in `lib/`, the `flakebox` CLI, the +default project template, user documentation, and checks built against the +public library. + +`flake.nix` exposes the overlay, template, and `mkLib` constructor, then +instantiates system-specific packages, checks, and development shells. `mkLib` +evaluates Flakebox's built-in modules together with caller modules and +configuration. The resulting library instance provides generated project +state, shells, source selection, target and toolchain construction, Crane +integration, build-matrix assembly, and supporting helpers. The detailed +library topology is described by +[ARCH-flakebox-nix-library](../lib/specs/ARCH-flakebox-nix-library.md). + +Modules contribute declarative project state and shell behavior. The library +materializes that state as an immutable candidate root and exposes it to +development shells. The CLI is the imperative boundary: it checks the candidate +against a mutable project checkout and explicitly installs it when requested; +it also owns local lint and documentation entry points. It does not generate +the candidate contents. + +Rust build inputs flow through explicit source selection into enhanced Crane +instances and then through the configured profile and toolchain cells. +Directories named `specs` contain governing documentation, not build inputs, +and repository-derived build sources prune them recursively. Checks exercise +the public library with evaluation assertions, realistic fixture builds, and +generated integration behavior. User procedures and API details remain in +`docs/`, while generated option documentation owns the complete configuration +reference. diff --git a/templates/default/flake.nix b/templates/default/flake.nix index 83d511b..07907e9 100644 --- a/templates/default/flake.nix +++ b/templates/default/flake.nix @@ -38,6 +38,7 @@ buildSrc = flakeboxLib.source.fromPaths { root = ./.; paths = buildPaths; + filter = flakeboxLib.source.filters.excludeDirectoriesNamed [ "specs" ]; }; multiBuild = (flakeboxLib.craneMultiBuild { }) (