dot_claude/skills/nix-setup/SKILL.md
Set up Nix flakes for development environments. Includes ready-to-use flake.nix templates for MoonBit, Rust, TypeScript (with pnpm), Python+uv, each preloaded with just / ast-grep / apm. Covers installation on sandboxed environments like Claude Code web, the buildNpmPackage idiom, direnv integration, and GitHub Actions. Use when starting a new project with Nix, adding a flake to an existing project, bootstrapping Nix in a container or CI image, or troubleshooting a broken Nix setup.
npx skillsauth add mizchi/chezmoi-dotfiles nix-setupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Nix flake (flakes + nix-command) 前提の開発環境セットアップ リファレンス。各言語の雛形を assets/ にまとめ、cp 一発で使えるようにしてある。
flake.nix / flake.lock / .envrc に関する質問全般nix develop / nix build のトラブル調査assets/assets/
├── setup_nix.sh # 単一ユーザー Nix を sandbox 無効で入れるインストーラ (container / CCW 向け)
├── apm.nix # microsoft/apm (Agent Package Manager) の Nix derivation
├── moonbit/{flake.nix,.envrc} # moonbit-overlay + moon
├── rust/{flake.nix,.envrc} # rust-overlay + stable pinned + cargo-nextest/watch
├── typescript/{flake.nix,.envrc} # nodejs_24 + pnpm (top-level)
├── python-uv/{flake.nix,.envrc} # python3 + uv
├── haskell/{flake.nix,.envrc} # GHC + cabal + HLS + hlint + ormolu
├── ocaml/{flake.nix,.envrc,.gitignore} # OCaml 5 + dune + merlin + ocaml-lsp + utop
├── oxcaml/{flake.nix,.envrc,.gitignore} # Jane Street OxCaml (opam source build)
└── home-manager/ # multi-host home-manager flake (macos + ccweb)
├── flake.nix
├── common.nix
├── macos.nix # aarch64-darwin: full desktop
├── ccweb.nix # x86_64-linux: minimal sandbox
└── .gitignore # private.nix / *.secret.nix を除外
全テンプレートに just, ast-grep, apm が入っている(共通運用ツール)。
テンプレは「プロジェクトルートに flake.nix + apm.nix を並置する」前提。言語側を差し替えたくなったら apm.nix は使い回せる。
apm.nix はオプション: APM skill を使わないプロジェクトなら削除して良い。その場合 flake.nix から apm = import ./apm.nix ... と packages 内の apm を両方消す。just / ast-grep だけ残したいならそのまま。
Determinate Systems インストーラ を使う。experimental-features = nix-command flakes が最初から有効で、アンインストールも容易。
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
systemd が使えない、root しかいない、ネスト化 namespace を禁じられた環境向けに assets/setup_nix.sh を使う。
build-users-group = (空) で single-user モードsandbox = false で chroot を要求しないexperimental-features = nix-command flakes を /etc/nix/nix.conf と $HOME/.config/nix/nix.conf の両方に書く/etc/profile.d/nix.sh を置いて以降の shell でも PATH が通るcp ~/.claude/skills/nix-setup/assets/setup_nix.sh .
bash setup_nix.sh
. "$HOME/.nix-profile/etc/profile.d/nix.sh" # 現在の shell にも反映
nix --version
{
description = "...";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = import nixpkgs { inherit system; };
in {
devShells.default = pkgs.mkShell {
packages = [ /* ... */ ];
shellHook = ''...'';
};
});
}
nix develop で devShells.default に入る。direnv なら .envrc に use flake と書いて direnv allow。
| ツール | 用途 | なぜ毎回入れるか |
|-------|------|----------------|
| just | タスクランナー | justfile がプロジェクト標準 |
| ast-grep | 構造検索・lint | grep では書けないルールを静的に強制 |
| apm | Agent 依存マネージャ | apm.yml でスキル/プロンプトを再現性ある形で配布 |
雛形の導入は flake.nix + apm.nix をプロジェクトルートに並置 するだけ:
# 例: MoonBit プロジェクト
cp ~/.claude/skills/nix-setup/assets/apm.nix .
cp ~/.claude/skills/nix-setup/assets/moonbit/flake.nix .
nix develop # 初回はビルド
# direnv 派なら:
echo 'use flake' > .envrc && direnv allow
moonbit-overlay.packages.${system}.moon-patched_latest を使う50118f5c3c0298b5cb17cc6f1c346165801014c8)。最新 HEAD は nixpkgs-unstable で broken 扱いのパッケージ (例: tcc) に依存することがあり、評価すら通らない時期がある。更新は動作確認してからmoon.mod.json があれば moon update を自動実行(初回のみ)flake.nixrust-overlay で toolchain 管理stable.latest.default + rust-analyzer / clippy / rustfmtrust-bin.stable."1.91.0".defaultrust-toolchain.toml 連携: rust-bin.fromRustupToolchainFile ./rust-toolchain.tomltargets = [ "wasm32-wasip1" "wasm32-unknown-unknown" ]nodejs_24 + pkgs.pnpm (top-level)nodePackages.* は 2025 年に nixpkgs から削除された — nodePackages.pnpm は使えないPNPM_HOME をプロジェクトローカル ($PWD/.pnpm) に向けて $HOME 汚染を避けるpkgs.pnpm を外して pkgs.nodejs_24 に付属する npm を使うか、pkgs.yarn を追加pkgs.python3 + pkgs.uvUV_PROJECT_ENVIRONMENT=$PWD/.venv, UV_CACHE_DIR=$PWD/.uv-cache で $HOME を汚さないpkgs.haskellPackages.{ghc,cabal-install,haskell-language-server,hlint,ormolu,ghcid}haskellPackages) を使う構成。GHC バージョン固定は pkgs.haskell.packages.ghc98 等に差し替えhaskell.nix (IOHK) を検討。ただし学習コストと複雑度は跳ね上がるpkgs.stack を追加し、stack.yaml の resolver で GHC を固定する方針に切替えstdenv.cc.cc.lib が PATH にないので一部 FFI で困る → buildInputs = [ pkgs.zlib ] などを追記pkgs.ocamlPackages.{ocaml,dune_3,findlib,merlin,ocaml-lsp,ocamlformat,utop} + pkgs.opampkgs.ocaml-ng.ocamlPackages_5_2 等OPAMROOT=$PWD/.opam で state をプロジェクトローカルに閉じ込め、初回だけ opam init + opam switch create default --empty を自動実行。2 回目以降は opam env だけを eval する.gitignore に .opam/ が含まれているので state を誤って commit しないopam install <pkg> で project-local に落ちるmerlin は ocaml-lsp の依存。両方入れておくとエディタ連携が完全opam と build toolchain (autoconf, automake, m4, pkg-config, gmp, libffi) だけ提供$OPAMROOT/.opam を作成oxcaml-dev スイッチを empty で作成opam pin add -ny git+https://github.com/oxcaml/oxcaml で upstream repo を pinopam switch set-invariant --packages oxcaml-dev で invariant 設定opam install oxcaml-dev
opam install dune merlin ocaml-lsp-server ocamlformat utop
apm.nix の仕組みmicrosoft/apm は npm パッケージではなく PyInstaller バンドルされたネイティブバイナリで配布される。
_internal/ に Python 3.12 ランタイム + 依存ライブラリが同梱されるapm バイナリは _internal を同居ディレクトリで参照するので、切り出して使うことはできないautoPatchelfHook で glibc / libstdc++ / zlib へのリンクを nix store 内のものに書き換え$out/libexec/apm/ に丸ごと配置し、$out/bin/apm はそこへの makeWrapper ラッパーdontStrip = true + dontPatchELF = true が必須 — PyInstaller は Mach-O / ELF の末尾に PKG アーカイブを append する。stdenv の既定 strip / patchelf は末尾を削るので、これを無効化しないと実行時に Could not load PyInstaller's embedded PKG archive で落ちるバージョン更新手順:
# 1. 新しいリリースの SHA256 を取得
for a in darwin-arm64 darwin-x86_64 linux-arm64 linux-x86_64; do
curl -sSL "https://github.com/microsoft/apm/releases/download/vX.Y.Z/apm-${a}.tar.gz.sha256"
done
# 2. assets/apm.nix の version と sources.*.sha256 を差し替え
nodePackages.* 廃止後の正道:
pkgs.pnpm / top-level packages — まずこれ。nixpkgs 内にあれば使う。buildNpmPackage + importNpmLock — lockfile のある公式パッケージを自前でビルド。完全にピン留めされる。NPM_CONFIG_PREFIX="$PWD/.npm-global" を shellHook で — impure だがプロジェクトスコープ。hash 追従が重い場合の逃げ道。npx / pnpm dlx — たまにしか使わない CLI。避けるべき: npm install -g をそのまま shellHook に書く (ユーザー $HOME 汚染)、nodePackages.* を参照する (削除済み)、dream2nix / node2nix を新規採用する (メンテ停止気味)。
buildNpmPackage の骨格my-cli = pkgs.buildNpmPackage {
pname = "my-cli";
version = "1.2.3";
src = pkgs.fetchFromGitHub {
owner = "owner"; repo = "my-cli"; rev = "v1.2.3";
hash = "sha256-...";
};
# lockfile ベースに切り替えるなら:
# npmDeps = pkgs.importNpmLock { npmRoot = ./.; };
npmDepsHash = "sha256-...";
dontNpmBuild = true; # pure CLI なら build なし
};
ユーザー環境全体(zsh / git / starship / CLI パッケージ)を Nix 式で宣言的に管理したい場合は assets/home-manager/ を使う。chezmoi と併用する場合は dot_zshrc 等を chezmoi forget してから home-manager に所有権を移す。
flake.nix — macOS desktop プロファイル (macos) と Claude Code web / ephemeral Linux 用 (ccweb) の 2 出力common.nix — 全ホスト共通(zsh, git, starship, direnv, fzf, 基本 CLI)macos.nix — aarch64-darwin 固有(helix, neovim 等の重量ツール)ccweb.nix — x86_64-linux 最小構成(cold start < 2 分を目標に薄く保つ)# 1. コピー
cp -r ~/.claude/skills/nix-setup/assets/home-manager ~/.config/home-manager
cd ~/.config/home-manager
# 2. flake.nix 先頭の `username` / `email` を書き換え
$EDITOR flake.nix
# 3. 適用
home-manager switch --flake .#macos # macOS
home-manager switch --flake .#ccweb # Claude Code web 等 Linux
このテンプレは 秘密情報ゼロ で書いてある(username / email は flake.nix の変数、ホスト名・トークン・known_hosts は含まない)。公開 GitHub に置いて OK。
自分専用の秘密(SSH 設定、内部ホスト、API トークン)は以下のいずれかで:
./private.nix を作って imports で読み込む。.gitignore で除外(テンプレに含めてある)sops-nix / agenix で暗号化したまま commit| 工程 | cache.nixos.org あり | 素 |
|---|---|---|
| setup_nix.sh | 20-40 秒 | 同左 |
| flake 評価 + substitute | 30-90 秒 | 2-8 分 |
| activation (symlink 展開) | 数秒 | 同左 |
| 合計 | 1-2 分 | 4-12 分 |
ccweb.nix に heavy パッケージを追加するほど cold start が延びる。共通部分は common.nix に寄せて、ccweb.nix は追加パッケージだけを書く方針を守る。
新規プロジェクト (cp assets/<lang>/flake.nix .) と違い、既存 repo では以下の罠がある。
cp 前に既存ファイルを退避テンプレの cp はそのまま既存 .envrc / flake.nix / .gitignore を上書きする。退避 → マージの手順を踏む:
# 既存を保存
[ -f .envrc ] && cp .envrc .envrc.pre-nix
# テンプレを展開
cp ~/.claude/skills/nix-setup/assets/typescript/flake.nix .
cp ~/.claude/skills/nix-setup/assets/typescript/.envrc .
# 既存の export などを復元
# .envrc.pre-nix を参照しつつ手でマージ
.envrc のマージ方針既存 .envrc に export DATABASE_URL=... 等があるなら、use flake を 先頭 に置いて既存 export を後ろに残す(devShell の env を土台に、repo 固有値で上書き)。
# 正しい順序
use flake # まず devShell を起動
dotenv_if_exists .env.local # secrets
export DATABASE_URL="postgres://..." # 既存 export を温存
反対に export を先に書くと use flake で上書きされる可能性がある。
package-lock.json と pnpm-lock.yaml の混在は不定動作の元。移行するなら 別 PR にして Nix 化と分ける:
git switch -c chore/pnpm-migration
rm package-lock.json && rm -rf node_modules
corepack enable && corepack prepare pnpm@10 --activate
pnpm install # 再解決
pnpm why <critical-dep> # major drift 確認
pnpm build && pnpm test # 動作確認
git add pnpm-lock.yaml package.json && git rm package-lock.json
git commit -m "chore: migrate npm -> pnpm lockfile"
rebase 中に pnpm-lock.yaml が衝突したら 手で直さず pnpm install で再生成 → git add。
actions/setup-node 置換既存 ci.yml の Node 関連ステップを Nix 化差分で書き換える:
- - uses: actions/setup-node@v4
- with:
- node-version: 24
- cache: pnpm
- - run: pnpm install --frozen-lockfile
- - run: pnpm test
+ - uses: DeterminateSystems/nix-installer-action@main
+ - uses: DeterminateSystems/magic-nix-cache-action@main
+ - run: nix develop --command just ci
just ci 側で pnpm install --frozen-lockfile && pnpm build && pnpm test を定義(justfile に移す)。pnpm store は別途 actions/cache で保持するのが cold-build を避けるコツ。
pnpm-workspace.yaml / turborepo / Nx を使う monorepo は root に flake.nix を 1 つ置けば全 workspace で nix develop が共有される。各 package 固有の dev tool は package.json の devDependencies に留め、nix は言語ランタイム + 横断ツール (just / ast-grep) に絞る。
.gitignore との統合assets/ocaml/.gitignore や assets/oxcaml/.gitignore をコピーすると既存の .gitignore を上書きする。マージ必要。
result / result-* (Nix ビルド成果) を必ず追加.direnv/ (nix-direnv キャッシュ) を追加各言語テンプレには .envrc が同梱済み。flake.nix と一緒にコピーすれば cd 時に devShell が自動適用される。
cp ~/.claude/skills/nix-setup/assets/apm.nix .
cp ~/.claude/skills/nix-setup/assets/rust/flake.nix .
cp ~/.claude/skills/nix-setup/assets/rust/.envrc .
direnv allow # 最初だけ承認
nix-direnv が必須 — 素の direnv だと cd のたびに flake 評価が走って 10-60 秒待たされる。nix-direnv はキャッシュ + GC root を作って < 100ms に縮める。assets/home-manager/common.nix では programs.direnv.nix-direnv.enable = true で有効化済み。
同梱 .envrc のパターン:
use flake のみ(最小)use flake + watch_file rust-toolchain.toml — toolchain 切替時の自動 reloaduse flake + dotenv_if_exists .env.local — ローカル API キー等の読込VS Code の direnv.direnv 拡張 / Helix / Neovim の direnv プラグインを入れると LSP サーバーが devShell の PATH を継承する。rust-analyzer が flake.nix の rustToolchain を使う、moon ide が overlay 版の moon を掴む、といった一致が取れる。
nix-direnv-prune # 使われていない .direnv を検出して除去
半年に一度くらい。/nix/store が肥大化してきたら。
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- name: Run tests in dev shell
run: nix develop --command just test
magic-nix-cache-action は GitHub Actions の無料キャッシュに Nix store を載せる。私製プロジェクトなら十分。大規模なら Cachix / attic を検討。
error: experimental Nix feature 'nix-command' is disabledmkdir -p ~/.config/nix
echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf
error: cannot build on ... due to sandboxcontainer / rootless 環境では sandbox が効かない。/etc/nix/nix.conf に sandbox = false を書く(setup_nix.sh はこれをやる)。
error: attribute 'pnpm' missing / nodePackages.pnpm が見つからないnixpkgs >= 24.11 では nodePackages.* が削除されている。pkgs.pnpm (top-level) を使う。
/nix/store の権限エラーDeterminate インストーラが推奨。手動でやるなら Apple Silicon では APFS ボリューム分割が必要。
libstdc++.so.6 not found)buildInputs に stdenv.cc.cc.lib を追加。apm.nix でやっているのと同じ対処。
nix flake update # 全 input
nix flake update nixpkgs # 個別
tools
Use when working on github.com/mizchi/pkspec, especially release readiness, version bumps, GitHub Actions/Nix release checks, adapter DSL work, or the experimental Playwright/Vitest coverage presets. Covers the repo's spec gates, pkfire release flow, pkl CLI dependency gotchas, and what is intentionally still experimental.
data-ai
指定されたリポジトリ、複数リポジトリ、または GitHub organization から、ドメイン固有の専門用語、業界用語、社内・プロダクト用語、リポジトリ実装マップ、技術構成、オンボーディング向け Mermaid 構成図を抽出・生成するときに使う。ユーザーが「用語集を作る」「ドメイン辞書を作る」「オンボーディング資料にする」「repo/org を見て専門用語をまとめる」「AI が再確認しなくてよい知識ベースを作る」と依頼したら起動する。
development
Guide for writing MoonBit bindings to JavaScript using `extern "js"`. Use when adding FFI declarations against browser/Node/Deno APIs or npm packages, wrapping JS objects behind opaque types, bridging Promises with `async fn` and `Promise::wait()`, configuring `moon.pkg` exports for esm/cjs/iife output, or handling null/undefined at the JS boundary.
testing
技術記事の再現性 (読者が手元で再現できるか) を評価するスキル。subagent に「初見の読者として手元で再現を試みる」シミュレーションをさせ、足りない情報をリストアップさせる。記事ドラフトの最終チェック、または公開後フィードバック前の事前検証で使う。