mcpField
N
nix-platform-specific-options

nix-platform-specific-options

github.com/edmundmiller開発8044 回インストール今日更新
リポジトリ

nix-platform-specific-options について

nix-platform-specific-optionsは、プラットフォーム依存のオプションを含むNixモジュール作成の参考スキルです。プラットフォーム判定にoptionalAttrs、設定条件にmkIfを使い、オプション欠落や無限再帰を防ぐ方法を説明します。

主な機能

  1. 01プラットフォーム判定と設定判定の使い分け
  2. 02プラットフォーム固有のオプションパスの非表示
  3. 03モジュール評価時の無限再帰の回避
  4. 04静的なオプション既定値とconfigでの解決
  5. 05よくある再帰パターンのデバッグ

活用シーン

  1. 01NixOSとDarwin向けのモジュールオプション作成
  2. 02プラットフォーム間のオプション欠落エラーの調査
  3. 03再帰を引き起こすconfig参照の特定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/edmundmiller/dotfiles --skill nix-platform-specific-options

インストール後、Claude Code で/nix-platform-specific-optionsを入力して読み込まれたか確認します。

詳細

Nix のモジュールにおけるプラットフォーム固有のオプション

概要

プラットフォーム固有のオプション(NixOS と Darwin)を隠す必要がある Nix モジュールを記述する際、mkIf だけを使うと無限再帰が発生します。このスキルでは、正しいパターンについて説明します。

問題

mkIf は遅延評価されますが、モジュールの評価中にはオプションのパスが可視のままです。そのため、次のようなエラーが発生します。

error: The option `users.defaultUserShell' does not exist.

または、オプションのデフォルト値や optionalAttrs の条件で config を参照すると、無限再帰が発生します。

パターン

プラットフォームのチェックには optionalAttrs を、設定に依存するチェックには mkIf を使います。

チェックの種類ツール評価時期
プラットフォーム(isDarwin、!isDarwin)optionalAttrs解析時
設定値(cfg.enable、cfg.flavor)mkIf遅延

例

❌ 誤り:プラットフォームのチェックに mkIf を使用
config = mkIf (!isDarwin) {
  users.defaultUserShell = pkgs.zsh;  # Darwin sees this path!
};
✅ 正しい:プラットフォームのチェックに optionalAttrs を使用
config = optionalAttrs (!isDarwin) {
  users.defaultUserShell = pkgs.zsh;  # Hidden from Darwin
};
❌ 誤り:optionalAttrs の条件で設定値を使用
# cfg.flavor evaluated at parse time → infinite recursion
(optionalAttrs (isDarwin && cfg.flavor == "personal") {
  services.onepassword-secrets.enable = true;
})
✅ 正しい:optionalAttrs の中に mkIf をネスト
# Platform check at parse time, config check lazy
(optionalAttrs isDarwin (mkIf (cfg.flavor == "personal") {
  services.onepassword-secrets.enable = true;
}))
❌ 誤り:オプションのデフォルト値で config を参照
options.modules.foo = {
  user = mkOpt types.str config.user.name;  # Infinite recursion!
};
✅ 正しい:デフォルト値は静的にし、設定セクションで config を使用
options.modules.foo = {
  user = mkOpt types.str null;
};

config = mkIf cfg.enable (let
  user = if cfg.user != null then cfg.user else config.user.name;
in {
  # Use 'user' variable here
});

組み合わせパターン

プラットフォーム固有のオプションと設定に依存する動作の両方があるモジュールでは、次のようにします。

config = mkIf cfg.enable (mkMerge [
  # Common config (all platforms)
  { /* ... */ }

  # Darwin-only options
  (optionalAttrs isDarwin {
    programs.zsh.interactiveShellInit = "...";
  })

  # NixOS-only options
  (optionalAttrs (!isDarwin) {
    users.defaultUserShell = pkgs.zsh;
  })

  # Darwin + config-dependent (nested)
  (optionalAttrs isDarwin (mkIf (cfg.flavor == "personal") {
    services.onepassword-secrets.enable = true;
  }))
]);

クイックリファレンス

シナリオパターン
NixOS 専用のオプションoptionalAttrs (!isDarwin) { ... }
Darwin 専用のオプションoptionalAttrs isDarwin { ... }
プラットフォーム+有効化チェックoptionalAttrs isDarwin (mkIf cfg.enable { ... })
プラットフォーム+設定値optionalAttrs isDarwin (mkIf (cfg.foo == "bar") { ... })
設定から取得するオプションのデフォルト値デフォルト値に null を使用し、config セクションで解決する

デバッグ

_module.freeformType または anon-43 に言及する無限再帰エラーが発生した場合:

  1. オプションのデフォルト値に config. の参照がないか検索します
  2. optionalAttrs の条件に cfg. の参照がないか検索します
  3. プラットフォーム固有のオプションを囲む mkIf (!isDarwin) または mkIf isDarwin がないか検索します
# Find problematic patterns
grep -rn "mkOpt.*config\." modules/
grep -rn "optionalAttrs.*cfg\." modules/
grep -rn "mkIf.*isDarwin" modules/

コメント