nix-claude-code:用 Nix 声明式配置 Claude Code
dryvist/nix-claude-code
dryvist/nix-claude-code 是一个 Nix flake,把 Claude Code 的插件、marketplace、技能、hooks、MCP 和权限规则封装成可组合的 home-manager 模块,在 macOS 和 Linux 上可复现。
Declarative Claude Code in Nix — plugins, marketplaces, skills, hooks, MCP, and permissions as composable home-manager modules. Reproducible on macOS and Linux.
A Nix flake that ships Claude Code as composable home-manager modules. Drop it into your flake — you get a fully-configured Claude Code with a curated plugin stack, statusline, hooks, MCP servers, and permission rules. All declared in Nix, reproducible across machines, rolled back with one command.
What you get
- All marketplaces, no fiddling. Anthropic's official marketplaces (
claude-plugins-official,anthropic-agent-skills) plus 15+ curated community marketplaces, wired up to refresh automatically. - Plugins as data. Every plugin you enable is declared in
programs.claude.enabledPlugins, version-pinned inflake.lock, rolled back atomically withdarwin-rebuild --rollback. - Full-trust auto mode. Claude Code ships with
defaultMode = "auto"and zero hard-coded allow/ask/deny rules — every tool call goes to the auto-mode classifier, which reads the conversation and the repo instead of pattern-matching a command prefix. The structured permission data is still here and still exported for Codex, Gemini, and any other agent that has no classifier of its own. - Statusline themes. Pick
powerline,ccstatusline, ordaniel3303's theme with one option. - Optional account switching. Enable
claude-swaponly where needed for manual Claude subscription switching and parallel terminal sessions. - MCP plumbing. Surface
programs.claude.mcpServersfrom your favorite MCP runtime; we wire them into Claude'ssettings.jsonexactly the way Anthropic specifies. - Built on Anthropic's official spec. Reads
.claude-plugin/marketplace.jsonand.claude-plugin/plugin.jsonper the official plugin reference. No proprietary formats; no surprises.
Installation
Add nix-claude-code to your flake inputs:
{ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; home-manager.url = "github:nix-community/home-manager/release-26.05"; home-manager.inputs.nixpkgs.follows = "nixpkgs"; nix-claude-code.url = "github:dryvist/nix-claude-code"; nix-claude-code.inputs.nixpkgs.follows = "nixpkgs"; nix-claude-code.inputs.home-manager.follows = "home-manager"; }; }
Or scaffold from a template:
nix flake init -t github:dryvist/nix-claude-code#minimal
# or, if you already use flake-parts:
nix flake init -t github:dryvist/nix-claude-code#flake-partsUsage
The simplest setup imports homeModules.default:
{ outputs = { home-manager, nix-claude-code, nixpkgs, ... }: { homeConfigurations."you" = home-manager.lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.aarch64-darwin; modules = [ nix-claude-code.homeModules.default ({ ... }: { home.username = "you"; home.homeDirectory = "/Users/you"; home.stateVersion = "25.11"; programs.claude.enable = true; }) ]; }; }; }
Then activate:
nix run home-manager#switch -- --flake .#you claude # ready to go
Switch Claude subscriptions
claude-swap is disabled by default. Enable it to install the manual account-switching CLI:
programs.claude.swap.disabled = false;
After activation, log in to each Claude subscription interactively and run
cswap add for each account. Use cswap switch <alias> to change the active
account, or cswap run <alias> -- … to start a parallel terminal-local Claude
session. The module does not configure automatic switching or store account
credentials in Nix.
Pick and choose
homeModules.default enables everything. Or compose à-la-carte:
| Module | What it ships |
|---|---|
homeModules.default |
All of the below, sane defaults — the 95% answer |
homeModules.claude |
Alias of default |
homeModules.core |
settings.json, auto-mode posture, the claude-code binary |
homeModules.plugins |
Marketplace + plugin management |
homeModules.statusline |
Powerline / ccstatusline / daniel3303 themes |
homeModules.hooks |
Marketplace-refresh hook |
homeModules.mcp |
programs.claude.mcpServers option (you populate from any runtime) |
homeModules.latest |
Opt-in auto-installer for the latest Claude Code release |
Want only settings.json and the permission posture, nothing else? Import homeModules.core
and skip the rest. Want the plugins but not the statusline? Import homeModules.core +
homeModules.plugins.
See docs/settings.md for the full settings.json option catalog,
including the freeform passthrough for keys with no typed option yet.
Already on flake-parts?
{ outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { imports = [ inputs.nix-claude-code.flakeModule ]; # ... }; }
Architecture
flowchart LR
A[17 marketplace inputs<br/>flake.nix] --> B[lib.parseMarketplace]
C[data/permissions/*.nix<br/>Nix-native data] --> D[lib.mkDefaultPermissions]
D --> P[Codex / Gemini / other<br/>agents without a classifier]
B --> E[modules/plugins.nix]
F[modules/core.nix<br/>defaultMode=auto, no rules] --> G[~/.claude/settings.json]
E --> G
H[modules/statusline] --> I[~/.claude/statusline]
J[modules/hooks] --> K[~/.claude/hooks/]
L[modules/mcp<br/>mcpServers option] --> G
M[pkgs.claude-code] --> N[~/.nix-profile/bin/claude]
Loading
See docs/architecture.md for the full breakdown.
API
The lib.* exports are designed for any AI-agent tool that wants to consume Claude-spec data:
{ inputs, lib, ... }: let market = inputs.nix-claude-code.lib.parseMarketplace inputs.jacobpevans-cc-plugins; # market :: { name; description; owner; plugins; raw; } skills = inputs.nix-claude-code.lib.discoverSkills inputs.anthropic-agent-skills; # skills :: [{ name; path; pluginRoot; }] perms = inputs.nix-claude-code.lib.mkDefaultPermissions { tool = "codex"; }; # perms :: { allow; allowMcp; ask; deny; denyExact; denyPatterns; webfetchDomains; } # (`ask` is always empty — see data/permissions/README.md. Claude Code # itself no longer consumes this; auto mode is its gate.) in # ... build whatever you need
| Lib export | Purity | Returns |
|---|---|---|
lib.parseMarketplace |
pure | { name; description; owner; plugins; raw; } |
lib.parsePlugin |
pure | { name; description; version; author; raw; } |
lib.discoverSkills |
pure | [{ name; path; pluginRoot; }] |
lib.discoverCommands |
pure | [{ name; path; pluginRoot; }] |
lib.discoverAgents |
pure | [{ name; path; pluginRoot; frontmatter; }] |
lib.discoverHooks |
pure | hooks.json attrset |
lib.toSettingsJson |
pure | ~/.claude/settings.json shape |
lib.permissions.{allow,ask,deny,domains,toolSpecific} |
data | Permission lists |
lib.mkDefaultPermissions |
pure | Composed permissions for a tool |
lib.wrapCommandsAsSkills { pkgs } |
impure | Derivation wrapping commands/<name>.md as synthetic SKILL.md files |
Compatibility
| Component | Supported |
|---|---|
| Claude Code | latest stable (auto-tracked from Anthropic upstreams) |
| nixpkgs | nixos-26.05 (override via inputs.nix-claude-code.inputs.nixpkgs.follows) |
| home-manager | release-26.05 |
| Platforms | aarch64-darwin, x86_64-darwin, aarch64-linux, x86_64-linux |
| Plugin spec | Anthropic official |
Comparison
| nix-claude-code | Hand-maintained .claude/ |
|
|---|---|---|
| Reproducible across machines | ✓ | ✗ |
| Atomic rollback | ✓ (--rollback) |
✗ |
| Version-pinned plugins | ✓ (flake.lock) |
✗ |
| Auto-refresh marketplaces | ✓ (opt-in hook) | manual |
| One-command setup on a new machine | ✓ | hours of /plugin install |
| Anthropic plugin spec compliant | ✓ | depends on what you wrote |
Contributing
- Add a marketplace: append to
flake.nixinputs and the wiring inflake/modules.nix. - Add a statusline theme: drop a
<name>.nixfile inmodules/statusline/. - Add a permission rule: edit
data/permissions/*.nix. These are the source of truth for permission rules across AI agent tools that have no classifier of their own (Codex, Gemini). Claude Code does not consume them — teach the auto-mode classifier instead, viaprograms.claude.autoMode. - Add a lib helper: write a pure function in
lib/, add anix-unittest inchecks/lib/.
Pre-commit hooks run treefmt, deadnix, statix, and YAML/TOML validation. CI runs
nix flake check on every PR.
See docs/adopters.md for the full integration guide.
License
MIT © Jacob P. Evans — see LICENSE.
Part of a larger ecosystem of ~40 repos — see how it all fits together.
来源:GitHub · github.com