nix-claude-code
Declarative Claude Code in Nix — plugins, marketplaces, skills, hooks, MCP, and permissions as composable home-manager modules. Reproducible on macOS and Linux.
Links
README
From the repo.
nix-claude-code
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-parts
Usage
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 | Session-output capture + marketplace-refresh hooks |
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]
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.
Collected info
- ★ 3 stars
- ⎇ 1 forks
- Language: Nix
- Source updated: 9/19/2026
Config for your environment
Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). No API key — you connect directly.
Tool
OS
Config file: ~/.cursor/mcp.json
{
"mcpServers": {
"mcp-server": {
"url": "{MCP_ENDPOINT_URL}"
}
}
}Paste into mcpServers in the config file. Restart Cursor after saving.
If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.