mcpField
N
nix-flake-organization

nix-flake-organization

github.com/darkmatter开发0305 次安装5 天前更新
代码仓库

关于 nix-flake-organization

面向 Nix flake 仓库的审查与重构 Skill,指导将 `flake/` 作为公共输出层、将 `src/` 用作实现层,并提供迁移和验证流程。

主要功能

  1. 01分离公共输出与实现
  2. 02保持输出转接层精简
  3. 03按功能组织代码
  4. 04迁移时保留输出名称
  5. 05验证 flake 输出与构建

适用场景

  1. 01重构内容拥挤的 `flake.nix`
  2. 02将模块逻辑移出输出配置
  3. 03梳理 flake 公共 API

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/darkmatter/skills --skill nix-flake-organization

安装后在 Claude Code 中输入/nix-flake-organization确认已加载。

详细介绍

Nix flake 组织结构

将 flake/ 保留为公共输出层,将 src/ 保留为实现层。flake 目录树负责命名、路由和重新导出输出;功能行为、模块主体、软件包派生项、应用脚本和辅助逻辑则放在 src/<name>/... 下。

在这些边界内应用 codebase-design: 将每项功能的实现集中在一起,仅在隐藏复杂性或实现有用复用时才进行拆分。Nix 输出适配器是有意义的公共入口;额外的内部转发文件则必须有其独立用途。保留 Nix 的职责划分,不要强行套用 TypeScript 的 models/ 和 services/ 目录。

适用场景

  • 用户要求重新组织或重构 Nix flake 布局。
  • flake 输出过于集中在 flake.nix 中,或与实现代码混杂。
  • NixOS、nix-darwin、Home Manager 或 flake-parts 模块直接在输出接线文件中包含业务逻辑。
  • 仓库需要明确区分公共 flake API 和内部实现。

不适用场景

  • 任务只是添加一个软件包、应用或模块,不涉及更改仓库布局。
  • 仓库不是 Nix flake。
  • 用户明确要求保留其他既定的项目布局。

标准提示词

将请求整理为实施计划时,使用这段改进后的提示词:

重新组织此仓库,使其公共 flake 接口位于顶层 flake/ 目录中:适用时包含 flake/apps、flake/packages、flake/lib 和 flake/modules/{flake-parts,home-manager,darwin,nixos}。将 flake.nix 保持为精简入口,并确保 flake/ 下的每个文件都足够精简:它可以声明输出名称、导入实现文件、组合 flake-parts 模块,以及适配公共调用约定,但不得包含派生项逻辑、应用脚本、选项/配置主体、服务行为或辅助实现。将这些实现细节集中在面向功能的 src/<name>/... 路径中。结构调整期间保留现有输出属性名称;更改公共接口时遵循仓库的兼容性政策。使用 nix flake show、nix flake check,以及具有代表性的软件包/模块求值或构建进行验证。

目标结构

优先采用此结构,并根据现有仓库调整名称:

flake.nix
flake/default.nix
flake/apps/default.nix
flake/packages/default.nix
flake/lib/default.nix
flake/checks/default.nix       # if checks exist
flake/devShells/default.nix    # if devShells exist
flake/overlays/default.nix     # if overlays exist
flake/modules/flake-parts/default.nix
flake/modules/home-manager/default.nix
flake/modules/darwin/default.nix
flake/modules/nixos/default.nix
src/<name>/app.nix
src/<name>/package.nix
src/<name>/lib.nix
src/<name>/modules/flake-parts.nix
src/<name>/modules/home-manager.nix
src/<name>/modules/darwin.nix
src/<name>/modules/nixos.nix

如果存在 flake-parts 模块,flake/modules/flake-parts 应与各平台模块目录并列,即使用户简略的示例中未提及它。

面向功能意味着按领域概念分组,而不是按输出类型分组。如果某个概念(如 vpn)同时包含软件包、应用和 NixOS 模块,就将它们放在 src/vpn/ 下。如果某个软件包没有关联模块,使用 src/<pkg-name>/package.nix 即可。如果仓库已经按平台组织,可以在 src/ 下保留这种结构,但不要机械地在 src/ 下重建整个 flake/ 目录树。

薄层规则

位置允许不允许
flake.nix输入、最简 outputs、导入 ./flake包/模块实现
flake/appsApp 输出名称和导入Shell 脚本、封装器、运行时行为
flake/packages包输出名称和导入mkDerivation、覆盖层、构建逻辑
flake/lib公共辅助函数重新导出辅助函数实现
flake/checks检查输出名称和导入测试框架实现
flake/devShells开发 Shell 输出名称和导入工具设置逻辑、Shell 钩子
flake/overlays覆盖层输出名称和导入包覆盖和构建逻辑
flake/modules/flake-partsflake-parts 导入和模块组合perSystem 构建逻辑、派生项、App 脚本
flake/modules/*公共模块导出和导入选项、config、断言、服务
src/<name>/...所有实现细节公共输出架构决策

薄层不等于空文件。薄文件可以适配调用约定、传递 inputs、self 或 pkgs,并保留公共属性名称。无需阅读实现细节也应能理解它。

遵守配置的文件长度限制。如果一个内聚模块超出限制,应先寻找可独立拆分的职责;否则,记录范围明确的限制提高或例外情况。若选项、默认值、断言和配置有助于说明某项功能,即使这会让模块变长,也应将它们保留在模块内。

对于模块输出,薄层意味着 flake/modules/<platform>/default.nix 是一个重新导出点。它会从 src/ 导入完整模块,并将其接入公共输出属性。这并不意味着要在单个模块内拆分选项和配置;选项和配置应在 src/<name>/modules/<platform>.nix 中保持在一起。

# flake/modules/nixos/default.nix
{ ... }:
{
  flake.nixosModules.vpn = import ../../../src/vpn/modules/nixos.nix;
}

# src/vpn/modules/nixos.nix
{ config, lib, pkgs, ... }:
{
  options.services.vpn = { ... };
  config = lib.mkIf config.services.vpn.enable { ... };
}

在 flake-parts 仓库中,perSystem 通常负责 packages、apps、checks 和 devShells。应保持 flake/modules/flake-parts 中的 perSystem 组合精简;包的派生项仍应放在 src/<name>/package.nix 中,App 行为放在 src/<name>/app.nix 中,开发 Shell/检查实现放在 src/<name>/... 中。不要同时通过直接的 flake/packages 接线和 flake-parts perSystem 接线定义同一个输出。

迁移工作流

  1. 清点当前的公共输出:packages、apps、lib、checks、devShells、overlays、nixosModules、darwinModules、homeManagerModules,以及 flake-parts 导入项。
  2. 首先保留公共输出架构。移动文件时不要重命名输出属性,除非用户要求进行破坏性变更。
  3. 如果当前输出交错定义在同一个文件中,先将各输出系列拆分到足以独立移动的程度;避免一次性大规模重写。
  4. 创建 flake/ 目录,将其作为输出垫片,并一次移动一个输出系列。
  5. 将实现移至面向功能的 src/<name>/...;除非仓库本身已采用面向平台的结构,否则不要在 src/ 下重建 flake/ 目录树。
  6. 将共享实现放在 src/<name>/lib.nix 或 src/shared/<name>.nix,而不是 flake/lib。
  7. 对重命名后的输出遵循仓库的兼容性策略。仅在该策略要求时保留别名;否则更新使用方并移除过时路径。
  8. 对于没有示例目录的输出(如 formatter),为其创建独立且精简的 flake/<output>/ 垫片,或将其留在最近的现有组合文件中;不要把它们并入无关目录。
  9. 每移动一个系列后,都使用 nix flake show、nix flake check 和针对性的构建/求值进行验证。

常见错误

  • 将 flake.nix 移入 flake/;Nix 要求 flake.nix 位于仓库根目录。
  • 把 flake/ 当作新的实现目录,而不是精简的公共层。
  • 因为觉得 flake/lib 像是共享代码的集中目录,就把实现藏在其中。
  • 将选项声明、config、断言或服务放入 flake/modules/*。
  • 忘记 packages.${system} 和 apps.${system} 是系统专属的,而模块输出通常不是。
  • 把 perSystem 构建逻辑放进 flake/modules/flake-parts,而不是从 src/<name>/... 导入实现。
  • 在没有明确兼容性理由的情况下,为同一个派生包同时创建直接输出接线和 flake-parts perSystem 接线。
  • 在 flake/lib、flake/modules 和 src 之间创建循环导入。
  • 在仅移动文件的重构中更改公共输出名称。
  • 因为改动看起来只是调整路径,就跳过验证。

模板化脚本

打包 shell 脚本时,将可复用的脚本逻辑保存在独立源文件中,而不是内嵌在较长的 Nix 字符串中。仅使用 Nix 替换特定于软件包的默认值。

优先使用 nixpkgs 风格的 @name@ 占位符和 replaceVars:

writeTextFile {
  name = "tool";
  destination = "/bin/tool";
  executable = true;
  text = builtins.readFile (replaceVars ./tool.sh {
    default_config = builtins.toJSON config;
  });
}

在脚本中,将所有 Nix 替换项集中放在顶部,并确保运行时值可通过参数或环境变量覆盖:

default_config() {
  cat <<'JSON'
@default_config@
JSON
}

: "${TOOL_JQ:=jq}"

tool_config() {
  if [ -n "${TOOL_CONFIG_JSON:-}" ]; then
    printf '%s\n' "$TOOL_CONFIG_JSON"
  else
    default_config
  fi
}

这样可以让脚本在 Nix 之外也能使用,使 Nix 耦合关系易于审查,避免充斥引号的内嵌 shell 字符串,并符合当前 nixpkgs 约定;如今 substituteAll 已由 replaceVars 取代。

审查清单

  • flake/ 文件主要包含导入、属性名称、重新导出和公共调用约定适配器。
  • src/<name>/... 包含派生包、脚本、选项、配置、服务、断言和辅助工具。
  • 现有公共输出名称仍可使用,或已有明确的迁移说明。
  • 模块系列彼此分离:home-manager、darwin、nixos 和 flake-parts 不会相互泄漏平台专属逻辑。
  • 验证命令同时涵盖系统专属输出和模块求值路径。
  • 模板化脚本保存在独立文件中,通过 replaceVars 使用 @name@ 占位符,并将 Nix 专属默认值集中放在顶部,同时为可复用行为提供环境变量/参数覆盖。

工具

无。这是一项纯提示词与审查技能。请使用仓库现有的 Nix 命令进行验证。

参考

没有单独的参考文件。请使用上面的规范提示词、精简层规则、迁移工作流和审查清单。

评论

支持 Markdown