SuperAPI AI Directory

nix-setup

Deployment & operations

View repository

Updated 10-15 20:09

About this skill

Nix Setup Skill

Nix flake (flakes + nix-command) Assumed development environment setup reference. Templates for each language are made assets/ summarized into,cp usable with a single command.

When to use

  • "Create a nix dev shell" / "Write a flake.nix"
  • "I want to add nix to a new project"
  • "Make nix usable in claude code web / containers"
  • flake.nix / flake.lock / .envrc general questions about
  • nix develop / nix build troubleshooting

What's in 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 を除外

All templates include just, ast-grep, apm (common operational tool).

The template is "at the project root flake.nix + apm.nix are placed side by side." If you want to swap out the language side, apm.nix can be reused.

apm.nix is optional: Can be deleted if the project does not use the APM skill. In that case, flake.nix from apm = import ./apm.nix ... と packages inside apm delete both.just / ast-grep If you only want to keep that, leave it as is.

Quick install

macOS / Linux (recommended)

Determinate Systems installer use.experimental-features = nix-command flakes is enabled from the start, and uninstallation is easy.

curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

Claude Code web / other sandbox environments

For environments where systemd cannot be used, only root exists, or nested namespaces are prohibited, use assets/setup_nix.sh .

  • build-users-group = (empty) for single-user mode
  • sandbox = false does not require chroot
  • experimental-features = nix-command flakes を /etc/nix/nix.conf と $HOME/.config/nix/nix.conf write in both
  • /etc/profile.d/nix.sh place it so PATH is available in subsequent shells as well
cp ~/.claude/skills/nix-setup/assets/setup_nix.sh .
bash setup_nix.sh
. "$HOME/.nix-profile/etc/profile.d/nix.sh"  # 現在の shell にも反映
nix --version

Minimal Flake skeleton

{
  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 goes into.direnv if .envrc に use flake write and direnv allow。

Common tools (included in all templates)

tool Purpose Why include it every time
just task runner justfile is the project standard
ast-grep Structural search / lint Statically enforce rules that cannot be written with grep
apm Agent dependency manager apm.yml Distribute skills/prompts in a reproducible form with

How to use language-specific templates

To introduce a template, flake.nix + apm.nix place side by side in the project root just do:

# 例: 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

  • moonbit-overlay.packages.${system}.moon-patched_latest use
  • The overlay is pinned to known working versions (50118f5c3c0298b5cb17cc6f1c346165801014c8). The latest HEAD may depend on packages treated as broken in nixpkgs-unstable (e.g., tcc), and there are periods when even evaluation does not pass. After confirming it works, update
  • moon.mod.json if there is moon update automatically run (first time only)
  • Reference: vibe-lang's flake.nix

Rust

  • rust-overlay manage toolchain with
  • default is stable.latest.default + rust-analyzer / clippy / rustfmt
  • Pin to a specific version: rust-bin.stable."1.91.0".default
  • rust-toolchain.toml integration: rust-bin.fromRustupToolchainFile ./rust-toolchain.toml
  • WASM target: targets = [ "wasm32-wasip1" "wasm32-unknown-unknown" ]

TypeScript

  • nodejs_24 + pkgs.pnpm (top-level)
  • nodePackages.* was removed from nixpkgs in 2025 — nodePackages.pnpm cannot be used
  • PNPM_HOME project-local ($PWD/.pnpm) toward $HOME avoid contamination
  • If switching to npm / yarn, pkgs.pnpm remove and pkgs.nodejs_24 use the npm included with, orpkgs.yarn add

Python + uv

  • pkgs.python3 + pkgs.uv
  • Since uv manages the Python version itself, the nix side is treated as a fallback
  • UV_PROJECT_ENVIRONMENT=$PWD/.venv, UV_CACHE_DIR=$PWD/.uv-cache does not pollute $HOME

Haskell

  • pkgs.haskellPackages.{ghc,cabal-install,haskell-language-server,hlint,ormolu,ghcid}
  • nixpkgs standard (haskellPackages) configuration using. GHC version pinning is pkgs.haskell.packages.ghc98 replace with etc.
  • If even stricter reproducibility is needed, haskell.nix Consider (IOHK). However, the learning cost and complexity jump up.
  • If using stack, add pkgs.stack , and switch to a policy of pinning GHC withstack.yaml の resolver .
  • on macOS stdenv.cc.cc.lib is not in PATH, so some FFI runs into trouble → append buildInputs = [ pkgs.zlib ] etc.

OCaml

  • pkgs.ocamlPackages.{ocaml,dune_3,findlib,merlin,ocaml-lsp,ocamlformat,utop} + pkgs.opam
  • nixpkgs standard OCaml 5.x series. Pinned versions include pkgs.ocaml-ng.ocamlPackages_5_2 etc.
  • opam managed: shellHook が OPAMROOT=$PWD/.opam confines state to the project local, and only the first time automatically runs opam init + opam switch create default --empty . From the second time onward, opam env only eval do
  • By using an empty switch, the nix-provided ocaml is used as-is, avoiding double management of the compiler.
  • .gitignore に .opam/ is included, so do not accidentally commit state.
  • Additional libraries are placed project-locally with opam install <pkg> .
  • merlin は ocaml-lsp dependencies. Having both installed makes editor integration complete.

OxCaml (Jane Street's fork)

  • Not included in nixpkgs. Following the officially recommended "opam + source build" flow, the nix side provides only opam と build toolchain (autoconf, automake, m4, pkg-config, gmp, libffi).
  • On the first execution of shellHook:
    1. $OPAMROOT/.opam create
    2. oxcaml-dev create switch as empty
    3. opam pin add -ny git+https://github.com/oxcaml/oxcaml で upstream repo を pin
    4. opam switch set-invariant --packages oxcaml-dev set invariant with
  • Do not automatically run the actual compiler build(takes 5-20 minutes / ~1 GB). The user explicitly runs the following:
    opam install oxcaml-dev
    opam install dune merlin ocaml-lsp-server ocamlformat utop
    
  • Support: arm64 macOS / arm64 Linux / x86_64 Linux. x86_64 macOS works but is unofficially supported.
  • With the ocaml template, it "uses the same opam infrastructure but a different switch", so both templates can be switched and used separately.

apm.nix mechanism

microsoft/apm is not an npm package but a PyInstaller-bundled native binaryIt is distributed via

  • _internal/ includes the Python 3.12 runtime + dependency libraries
  • Standalone apm binary is _internal is referenced in the co-located directory, so it cannot be extracted and used.
  • on Linux autoPatchelfHook Rewrite links to glibc / libstdc++ / zlib to those in the nix store
  • $out/libexec/apm/ Place it entirely in$out/bin/apm is a makeWrapper wrapper to it
  • dontStrip = true + dontPatchELF = true is required — PyInstaller appends a PKG archive to the end of Mach-O / ELF. stdenv's default strip / patchelf trims the end, so unless this is disabled, it fails at runtime with Could not load PyInstaller's embedded PKG archive .

Version update procedure:

# 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 を差し替え

Handling npm tools with Nix (as of 2026)

nodePackages.* The correct path after the abolition of

  1. pkgs.pnpm / top-level packages — This first. If it is in nixpkgs, use it.
  2. buildNpmPackage + importNpmLock — Build official packages with lockfiles yourself. Fully pinned.
  3. NPM_CONFIG_PREFIX="$PWD/.npm-global" を shellHook で — Impure but project-scoped. An escape hatch when hash tracking is heavy.
  4. npx / pnpm dlx — A CLI used only occasionally.

Avoid: npm install -g WritingnodePackages.* refer todream2nix / node2nix newly adopt

buildNpmPackage skeleton

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 なし
};

home-manager (optional)

If you want to declaratively manage your entire user environment (zsh / git / starship / CLI packages) with Nix expressions, use assets/home-manager/ . When using it together with chezmoi, dot_zshrc etc. to chezmoi forget and then transfer ownership to home-manager.

File structure

  • flake.nix — two outputs: macOS desktop profile (macos) and for Claude Code web / ephemeral Linux (ccweb)
  • common.nix — common to all hosts (zsh, git, starship, direnv, fzf, basic CLI)
  • macos.nix — aarch64-darwin specific (heavy tools like helix, neovim)
  • ccweb.nix — x86_64-linux minimal configuration (keep it thin with a target cold start < 2 minutes)

Usage

# 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

Notes when managing in a public repo

This template is written with zero secrets (username / email is a flake.nix variable, and does not include hostnames, tokens, or known_hosts). It is OK to put it on public GitHub.

For your own private secrets (SSH config, internal hosts, API tokens), use one of the following:

  1. ./private.nix create imports and load it with.gitignore exclude with (included in the template)
  2. sops-nix / agenix commit while encrypted with

Cold start guideline on Claude Code web

Step with cache.nixos.org bare
setup_nix.sh 20-40 seconds same as left
flake evaluation + substitute 30-90 seconds 2-8 minutes
activation (symlink expansion) a few seconds same as left
Total 1-2 minutes 4-12 minutes

ccweb.nix The more heavy packages you add to , the longer the cold start becomes. Keep the common parts in common.nix and follow the policy of writing only additional packages inccweb.nix .

Introducing into an existing repo

Unlike a new project (cp assets/<lang>/flake.nix .), an existing repo has the following pitfalls.

1. cp back up existing files before

The template's cp overwrites the existing .envrc / flake.nix / .gitignore as is. Follow the backup → merge procedure:

# 既存を保存
[ -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 を参照しつつ手でマージ

2. .envrc merge policy for

If there is an existing .envrc に export DATABASE_URL=... etc.,use flake を beginning placed in the existing export is left behind (based on the devShell env, overridden with repo-specific values).

# 正しい順序
use flake                              # まず devShell を起動
dotenv_if_exists .env.local            # secrets
export DATABASE_URL="postgres://..."   # 既存 export を温存

Conversely, export is written first, use flake may be overridden by

3. lockfile migration (npm → pnpm, etc.)

package-lock.json と pnpm-lock.yaml mixing is a source of undefined behavior. If migrating, make it a separate PR and separate it from the Nix conversion:

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"

During rebase, if pnpm-lock.yaml conflicts, do not fix it by hand pnpm install regenerate with git add。

4. CI の actions/setup-node replace

Rewrite the Node-related steps in the existing ci.yml with the Nix conversion diff:

-      - 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 on the pnpm install --frozen-lockfile && pnpm build && pnpm test side, define actions/cache (move it to the justfile). Keeping the pnpm store separately with

5. Handling monorepos

pnpm-workspace.yaml For monorepos using / turborepo / Nx, place one flake.nix at the root and it will be shared across all workspaces nix develop is shared. Keep dev tools specific to each package in package.json 's devDependencies, and limit nix to language runtimes + cross-cutting tools (just / ast-grep).

6. Existing .gitignore integration with

assets/ocaml/.gitignore や assets/oxcaml/.gitignore Copying .gitignore overwrites the existing

  • result / result-* (Nix build output) must be added
  • .direnv/ (nix-direnv cache) is added

direnv integration

Each language template includes .envrc is already bundled.flake.nix If you copy it together with cd the devShell is automatically applied at

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 is required — with plain direnv, flake evaluation runs every time you cd and you wait 10-60 seconds.nix-direnv creates a cache + GC root and reduces it to < 100ms.assets/home-manager/common.nix In programs.direnv.nix-direnv.enable = true it is already enabled with

Bundled .envrc patterns:

  • moonbit: use flake only (minimal)
  • rust: use flake + watch_file rust-toolchain.toml — automatic reload when switching toolchains
  • typescript / python-uv: use flake + dotenv_if_exists .env.local — loading local API keys, etc.

Editor integration

VS Code の direnv.direnv If you install the direnv plugin for the extension / Helix / Neovim, the LSP server inherits the devShell PATH. rust-analyzer uses flake.nix 's rustToolchain,moon ide picks up the overlay version of moon, and so on, achieving consistency.

Cleaning up GC roots

nix-direnv-prune     # 使われていない .direnv を検出して除去

About once every six months./nix/store When

GitHub Actions

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 has grown too large.

puts the Nix store on GitHub Actions' free cache. For personal projects it is sufficient. For large-scale use, consider Cachix / attic.

error: experimental Nix feature 'nix-command' is disabled

mkdir -p ~/.config/nix
echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf

error: cannot build on ... due to sandbox

Troubleshooting/etc/nix/nix.conf に sandbox = false In container / rootless environments, the sandbox does not work. Writesetup_nix.sh does this).

error: attribute 'pnpm' missing / nodePackages.pnpm cannot be found

nixpkgs >= 24.11 In nodePackages.* has been removed.pkgs.pnpm Use (top-level).

macOS で /nix/store permission error

The Determinate installer is recommended. If doing it manually, APFS volume splitting is required on Apple Silicon.

autoPatchelfHook failed (libstdc++.so.6 not found)

buildInputs に stdenv.cc.cc.lib added.apm.nix The same workaround as done in .

Updating flake inputs

nix flake update              # 全 input
nix flake update nixpkgs      # 個別

Reference links