Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ Hermes はオーケストレーター役の AI エージェントで、実装は
cd ~/.dotfiles/nix

# 副作用なしビルド確認 (CI と同じ検証を手元で)
USER=ciuser nix build .#darwinConfigurations.default.system --no-link --impure
# --extra-experimental-features: このリポジトリは nix.conf を所有しないため、
# bare な nix サブコマンドには用途単位で明示する (nix/README.md の「前提」を参照)
USER=ciuser nix --extra-experimental-features "nix-command flakes" \
build .#darwinConfigurations.default.system --no-link --impure

# 適用 (sudo 必須、USER=$USER は sudo の env_reset で USER=root になるのを回避、--impure は username 動的解決のため必須)
sudo USER=$USER darwin-rebuild switch --flake .#default --impure
Expand All @@ -110,7 +113,11 @@ darwin-rebuild --list-generations

## 重要な設計判断

- **`nix.enable = false`**: ローカル PC に Determinate Nix がインストールされている前提。nix-darwin の native Nix 管理は Determinate daemon と競合するため、`nix/darwin.nix` で明示的に無効化している。実験的機能 (nix-command / flakes) は Determinate がデフォルト有効化しているため別途宣言不要
- **`nix.enable = false`**: ローカル PC に Determinate Nix がインストールされている前提。nix-darwin の native Nix 管理は Determinate daemon と競合するため、`nix/darwin.nix` で明示的に無効化している
- **experimental-features はこのリポジトリの所有物ではない**: `nix.enable = false` により nix-darwin は `/etc/nix/nix.conf` を生成しないため、nix-command / flakes の有効・無効はホスト任せ(Determinate Nix を入れてあっても無効なホストは実在する)。恒久的に有効化したい場合は Determinate 公式の管理経路で行い、dotfiles / nix-darwin では宣言しない
- 実行契約: bare な `nix` サブコマンドを呼ぶ側が用途単位で `--extra-experimental-features "nix-command flakes"` を明示する。`darwin-rebuild` は自前で有効化して呼ぶ生成物なので明示不要
- CI 例外: `nix-check` workflow は installer action が有効化するため、workflow 内は bare のままでよい
- 診断手順と背景は `nix/README.md` の「前提: experimental-features は用途単位で明示する」を参照
- **PC 名・ユーザー名のリポジトリ非格納**: `darwinConfigurations.default` で output 名を hostname フリーに固定し、`username = builtins.getEnv "USER"` で macOS ローカルアカウント名を実行時解決する。公開リポジトリに PC 名や個人アカウント名を晒さないための設計。`--impure` フラグが必須になる代償と引き換え (S15)
- **`homebrew.onActivation.cleanup = "zap"`**: 宣言外パッケージは Cellar ごと削除する強い管理。宣言外のパッケージが残らないよう破壊的に同期する (`nix/modules/darwin/homebrew.nix` のコメント参照)

Expand All @@ -133,6 +140,8 @@ triage で「無視」マークした項目は OS デフォルト値が PC 間
- `nix flake check` (構文・型・依存解決)
- `USER=ciuser nix build .#darwinConfigurations.default.system --no-link --impure` (closure ビルド)

workflow 内が bare な `nix` なのは、`DeterminateSystems/nix-installer-action` が nix-command / flakes を有効化するため。ローカルで同じ検証を回すときはホスト任せになるので `--extra-experimental-features "nix-command flakes"` を明示する(「主要コマンド」節の形が対応する)。

`darwin-rebuild switch` の activation 自体は CI 範囲外 (環境差で消耗するため)。実機での `darwin-rebuild build` → `switch` で検証する方針。

# 公開リポジトリでの参照ポリシー
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@ echo sub-1 | sudo tee /etc/dotfiles-role # sub-1 で運用する場合
5. Install Nix and apply (Homebrew パッケージ層)
```terminal
zsh ~/.dotfiles/nix/scripts/install-nix.zsh
cd ~/.dotfiles/nix && sudo USER=$USER nix run nix-darwin -- switch --flake .#default --impure
cd ~/.dotfiles/nix && sudo USER=$USER nix --extra-experimental-features "nix-command flakes" \
run nix-darwin -- switch --flake .#default --impure
```

`--extra-experimental-features` は、このリポジトリが `/etc/nix/nix.conf` を所有せず
nix-command / flakes の有効・無効をホスト任せにしているため必要。理由と他のコマンド例は
[`nix/README.md`](nix/README.md) の「前提」節を参照。

See [`nix/README.md`](nix/README.md) for details.

6. Place dotfiles symlinks (Tier 1) and run explicit setup scripts (Tier 2)
Expand Down
68 changes: 56 additions & 12 deletions nix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,36 @@
- spec: `docs/superpowers/specs/2026-05-02-nix-migration-design.md`
- plan: `docs/superpowers/plans/2026-05-02-nix-migration.md`

## 前提: experimental-features は用途単位で明示する

このリポジトリは Nix 本体の設定 (`/etc/nix/nix.conf`) を所有しない。`nix/darwin.nix` の
`nix.enable = false` により nix-darwin は nix.conf を生成せず(nix-darwin 側で
`mkIf nix.enable` に括られている)、`nix.settings.experimental-features` を書いても効かない。
nix-command / flakes を有効にするかどうかは Determinate Nix 側の設定とホストの実測次第で、
**Determinate を入れてあっても無効なホストは実在する**。

そのため、このドキュメントの `nix` コマンド例はすべて用途単位でフラグを明示する:

```sh
nix --extra-experimental-features "nix-command flakes" <subcommand> ...
```

- `darwin-rebuild` は nix-command / flakes を自前で有効化して呼ぶ生成物なので明示不要
- `setup/cutover.zsh` の pre-flight build と `nix/tests/*.bats` も同じ契約で書かれている
(回帰テスト: `setup/tests/cutover.bats`)
- 恒久的に有効化したい場合は Determinate 公式の管理経路で行う。dotfiles 側では宣言しない
- 手元のホストの直接の設定は以下で見られる。ファイル不在は「設定が無い」という正常な観測なので、
stderr を捨てて非ゼロ終了を握り潰す

```sh
grep -H experimental-features /etc/nix/nix.conf ~/.config/nix/nix.conf 2>/dev/null || true
```

この 2 ファイルに直接の設定が見つからなくても「無効」と断定はできない。`include` / `!include`
で読み込まれる別ファイルや `NIX_CONFIG` 環境変数など間接的な設定経路まではここでは診断しない。
結論としてホストの状態に賭けず、常に用途単位でフラグを付ける。フラグ付きで `nix config show`
を叩くとフラグ自身の効果を読んでしまい判定にならない

## ロールバック

直前世代に戻す:
Expand All @@ -33,8 +63,8 @@ sudo zsh ~/.dotfiles/setup/rollback.zsh

## flake.lock の更新運用

- `nix flake update` で全 input を最新に更新できる
- 特定 input だけ更新する場合: `nix flake lock --update-input nixpkgs`
- 全 input を最新に更新: `nix --extra-experimental-features "nix-command flakes" flake update`
- 特定 input だけ更新: `nix --extra-experimental-features "nix-command flakes" flake lock --update-input nixpkgs`
- 更新後は必ず `darwin-rebuild build --flake .#default --impure` で検証してからコミット
- `flake.lock` は必ずコミットする(再現性確保のため)
- 更新頻度の方針: **必要時のみ**(依存ライブラリの脆弱性 / nixpkgs に必要なパッケージが入ったタイミング等)
Expand Down Expand Up @@ -140,15 +170,26 @@ name か id と照合する) で飛ばす。

`brew install` 即試用の代替手段:

| やりたいこと | コマンド |
|---|---|
| nixpkgs にある CLI を一時的に試す | `nix shell nixpkgs#ripgrep`(その shell セッション限定 / `exit` で消える) |
| nixpkgs 最新で試す | `nix run nixpkgs/master#foo` |
| 1 回だけ実行 | `nix run nixpkgs#foo -- --args` |
| nixpkgs に無い GUI を試す | 現実的には手動 `brew install` → 気に入ったら `casks` に追加 → switch / 気に入らなければ `brew uninstall` |
```sh
# nixpkgs にある CLI を一時的に試す (その shell セッション限定 / exit で消える)
nix --extra-experimental-features "nix-command flakes" shell nixpkgs#ripgrep

# nixpkgs 最新で試す
nix --extra-experimental-features "nix-command flakes" run nixpkgs/master#foo

# 1 回だけ実行
nix --extra-experimental-features "nix-command flakes" run nixpkgs#foo -- --args
```

nixpkgs に無い GUI は、現実的には手動 `brew install` → 気に入ったら `casks` に追加 → switch /
気に入らなければ `brew uninstall`。

`nix shell` / `nix run` は永続インストールしないので、後片付けが要らない。お試しは基本これに倒すこと。

`--extra-experimental-features` を落とすと `experimental Nix feature 'nix-command' is disabled`
で即座に失敗する。理由は冒頭の「前提」を参照。他リポジトリの Makefile 等から `nix shell` で
ツールチェインを固定する場合も、同じ理由で呼び出し側にフラグを持たせる。

## Per-host 構成 (/etc/dotfiles-role)

複数 Mac で dotfiles を運用する際、PC ごとに異なる subset を入れるための仕組み。`/etc/dotfiles-role` (root 所有、machine-wide 設定) で切り替える。
Expand Down Expand Up @@ -183,10 +224,12 @@ echo sub-1 | sudo tee /etc/dotfiles-role

# 3. ビルド確認 (副作用なし)
cd ~/.dotfiles/nix
nix build .#darwinConfigurations.default.system --no-link --impure
nix --extra-experimental-features "nix-command flakes" \
build .#darwinConfigurations.default.system --no-link --impure

# 4. 初回ブートストラップ + 実機適用
sudo USER=$USER nix run nix-darwin -- switch --flake .#default --impure
sudo USER=$USER nix --extra-experimental-features "nix-command flakes" \
run nix-darwin -- switch --flake .#default --impure
```

### role の切り替え
Expand Down Expand Up @@ -245,7 +288,7 @@ sudo USER=$USER darwin-rebuild switch --flake .#default --impure

```sh
git restore nix/flake.lock
nix flake update
nix --extra-experimental-features "nix-command flakes" flake update
```

### `darwin-rebuild` がビルドエラーで失敗する
Expand All @@ -268,7 +311,8 @@ nix-darwin が未インストールの状態で初めて適用する場合:

```sh
cd ~/.dotfiles/nix
nix run nix-darwin -- switch --flake .#default --impure
nix --extra-experimental-features "nix-command flakes" \
run nix-darwin -- switch --flake .#default --impure
```

### 宣言から外した Homebrew パッケージが残る
Expand Down
20 changes: 14 additions & 6 deletions nix/darwin.nix
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,23 @@
system.primaryUser = username;

# Determinate Nix (公式インストーラの最新版) と nix-darwin の native Nix 管理は
# 同時稼働できないため、nix-darwin 側の管理を無効化する。
# Determinate Nix は nix-command / flakes をデフォルトで有効化済みなので、
# 旧来の `nix.settings.experimental-features` 宣言は不要。
#
# 本修正は CI 検証 (S14) で `darwin-rebuild switch` が以下のエラーで失敗した
# ことから発見した本番ブロッカー:
# 同時稼働できないため、nix-darwin 側の管理を無効化する。有効にすると activation が
# 以下で止まる:
# error: Determinate detected, aborting activation
# Determinate uses its own daemon to manage the Nix installation that
# conflicts with nix-darwin's native Nix management.
#
# この宣言の帰結として、/etc/nix/nix.conf は nix-darwin の管理対象から外れる
# (nix-darwin は nix.settings 由来の設定一式を `mkIf nix.enable` で括っており、
# off の間は nix.conf を一切生成しない)。したがって experimental-features
# (nix-command / flakes) の所有者は Determinate 側であり、このリポジトリは
# その値を宣言も保証もしない。Determinate を入れてあっても
# nix-command が無効なホストは実在する。
#
# 契約: bare な `nix` サブコマンドを呼ぶ側が用途単位で
# `--extra-experimental-features "nix-command flakes"` を明示する
# (setup/cutover.zsh の pre-flight build、nix/tests/*.bats、nix/README.md の例)。
# `darwin-rebuild` は自前で有効化して呼ぶ生成物なので明示不要。
nix.enable = false;

# ユーザー宣言(nix-darwin が users.users.<name> として要求する最低限の宣言)
Expand Down
11 changes: 7 additions & 4 deletions nix/scripts/install-nix.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,11 @@ util::info "Full Disk Access is granted."
# ---- 3. Determinate Nix インストーラ --------------------------------------

# Determinate Nix は nix-darwin の native Nix 管理 (nix.enable) と競合するため、
# nix-darwin 側で `nix.enable = false` を宣言している (nix/darwin.nix)。
# experimental-features (nix-command / flakes) は Determinate がデフォルト有効化済み。
# nix-darwin 側で `nix.enable = false` を宣言している (nix/darwin.nix)。その帰結として
# experimental-features (nix-command / flakes) は Determinate 側の所有物になり、
# このリポジトリは値を宣言も保証もしない。インストール直後に有効とは限らないため、
# bare な `nix` サブコマンドを呼ぶ側が用途単位で
# `--extra-experimental-features "nix-command flakes"` を明示する (nix/README.md の「前提」)。
util::info "Installing Determinate Nix..."

if ! curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix \
Expand All @@ -85,5 +88,5 @@ util::info ""
util::info "NEXT STEPS:"
util::info " 1. Restart your terminal (or run: source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh)"
util::info " 2. cd ${HOME}/.dotfiles/nix"
util::info " 3. nix build .#darwinConfigurations.default.system --no-link --impure # 副作用なし closure 確認"
util::info " 4. sudo USER=\$USER nix run nix-darwin -- switch --flake .#default --impure # 初回ブートストラップ + 実機適用"
util::info " 3. nix --extra-experimental-features \"nix-command flakes\" build .#darwinConfigurations.default.system --no-link --impure # 副作用なし closure 確認"
util::info " 4. sudo USER=\$USER nix --extra-experimental-features \"nix-command flakes\" run nix-darwin -- switch --flake .#default --impure # 初回ブートストラップ + 実機適用"
11 changes: 6 additions & 5 deletions setup/cutover.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ darwin-rebuild --list-generations > "${generations_log}"
util::info "=== pre-flight: nix build ==="
# --extra-experimental-features: darwin-rebuild 自体は nix-command/flakes を内蔵で
# 有効化して呼び出す生成物だが、ここは darwin-rebuild を経由しない素の `nix build`
# 直接呼び出しのため、システムの nix.conf が nix-command/flakes をデフォルト有効化
# していない環境(Determinate Nix 前提が崩れている、または未設定の素の Nix)では
# 明示しないと `experimental Nix feature 'nix-command' is disabled` で失敗する。
# CI (.github/workflows/nix-check.yml) はインストール直後の Determinate Nix で
# デフォルト有効なため未指定で足りるが、実機は環境依存のため明示して揃える。
# 直接呼び出しのため、システムの nix.conf が nix-command/flakes を有効化していない
# ホストでは `experimental Nix feature 'nix-command' is disabled` で失敗する。
# このリポジトリは nix.conf を所有しない (nix/darwin.nix の `nix.enable = false`)
# ため有効かどうかはホスト任せで、Determinate Nix を入れてあっても無効なホストは
# 実在する。CI (.github/workflows/nix-check.yml) は installer action が有効化するので
# 未指定でも通るが、実機に合わせて常に明示する。
if ! nix build "${DOTFILES_ROOT}/nix#darwinConfigurations.default.system" --no-link --impure \
--extra-experimental-features "nix-command flakes"; then
util::error "nix build に失敗しました。switch は実行しません"
Expand Down
15 changes: 7 additions & 8 deletions setup/tests/cutover.bats
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,13 @@ setup() {
}

@test "cutover.zsh's pre-flight nix build explicitly enables nix-command/flakes" {
# Regression test: on a machine where nix-command/flakes isn't enabled by
# default (e.g. a plain Nix install rather than Determinate Nix, or a
# host nix.conf without the experimental-features line), a bare `nix
# build` on this direct (non darwin-rebuild-wrapped) invocation fails
# with "experimental Nix feature 'nix-command' is disabled" before ever
# reaching darwin-rebuild switch. Reproduced and confirmed fixed against
# the real flake on 2026-08-22 (see migrate.zsh single-invocation
# recovery incident). darwin-rebuild itself already bakes this flag in,
# Regression test: this repo does not own nix.conf (nix/darwin.nix sets
# `nix.enable = false`), so whether nix-command/flakes is enabled is up to
# the host — a Determinate Nix install is no guarantee, and hosts with
# Determinate but the feature disabled do exist. Without the flag, this
# direct (non darwin-rebuild-wrapped) `nix build` fails with "experimental
# Nix feature 'nix-command' is disabled" before ever reaching
# darwin-rebuild switch. darwin-rebuild itself already bakes the flag in,
# so only this standalone call needs it.
_install_stubs "${STUB_BIN}" 0
PATH="${STUB_BIN}:${PATH}" run zsh "${SETUP_DIR}/cutover.zsh"
Expand Down
Loading