Claude Code as an Operator Platform — MCP Integrations + Declarative Config

Claude CodeMCPAI IntegrationNixOSAutomationDevOps
Image 1

What it is

I treat Claude Code as load-bearing infrastructure: a declarative NixOS / Home Manager module generates ~/.claude/settings.json (allow-rules, deny-rules, hooks, MCP wiring), ships 32 custom slash-command skills for repeated infra ops, and auto-loads path-scoped rules when editing matching files. Every machine in the homelab runs the same AI operator with the same guardrails.

Why it exists

Most Claude Code setups live as a settings.json someone edited once, a .claude/commands/*.md pile that grew organically, and some mcp__* tools bolted on ad-hoc. That's fine for a single machine. It breaks the moment you have 16 NixOS profiles and want the same agent to behave identically on each — same permissions, same deny list, same hooks, same skill set.

I wanted Claude Code to be a managed OS component, not a hand-configured tool: one Nix module produces ~/.claude/settings.json, one set of skills ships with the flake, one hook runs before every tool use, and one MCP config wires every server with env vars from git-crypt-encrypted secrets. Rebuild any node and Claude Code comes up fully configured, no manual steps.

Architecture

user/app/claude-code/claude-code.nix is the whole story. It generates the user-level settings file from typed Nix attributes, symlinks the repo's .claude/{commands,rules,hooks}/* into ~/.claude/, and exposes the MCP server wiring via ~/.dotfiles/.mcp.json. Hooks fire on every PreToolUse and PostToolUse — primarily the sensitive-file block-list that refuses reads/writes into SSH keys, credential files, ~/.gnupg/, /etc/shadow, etc. Skills are markdown files; rules are markdown files with a paths: frontmatter glob so Claude Code auto-loads the right context when you open a matching file.

What I built

  • Declarative Claude Code Nix moduleuser/app/claude-code/claude-code.nix (14 KB) generates ~/.claude/settings.json with 82 allow rules (tight globs for every Bash pattern I actually need, plus every Read/Edit/Write/Grep/Glob I use), 34 deny rules (SSH private keys, /etc/shadow, ~/.gnupg/, credential files, ~/.aws/, ~/.kube/config, browser session files, crypto wallets, .git-crypt/, etc.), and hook registrations.
  • PreToolUse / PostToolUse hooks.claude/hooks/block-sensitive-files.sh intercepts every Bash / Read / Edit / Write / Grep / Glob call. Refuses operations on sensitive paths even if a clever prompt convinces the model to try. Prompt-injection defense at the harness level, not the model level.
  • 32 custom skill commands.claude/commands/*.md — each is a declarative slash command with a short description, tool allowlist, and a small shell / MCP body. Examples: /deploy-lxc (remote build + switch on an LXC profile), /check-database / /check-redis / /check-kuma (health-checks), /manage-pfsense / /manage-nas / /manage-proxmox / /manage-matrix / /manage-tailscale (node admin), /audit-infrastructure / /audit-project-security / /audit-project-docs (audit workflows), /network-performance, /docker-startup-nas, /wake-on-lan-nas, /unlock-nas, /install-app, /remove-app, /list-apps, /merge-branches, /docs-health, /deploy-finance-tagger, /deploy-liftcraft-test, /sync-vivaldi, /update-infra-vps-and-nas, and more.
  • 6 path-scoped rule files.claude/rules/{nixos,deployment,darwin,docs,sway,gaming}.md with paths: frontmatter glob that scopes activation. Editing a **/*.nix file loads nixos.md (feature-flag patterns, profile inheritance, secrets imports). Editing **/deploy.sh loads deployment.md. No full-context bloat — the relevant rule lands in context only when it applies.
  • 5 MCP servers wired from the same flake~/.dotfiles/.mcp.json is git-tracked; env vars (PLANE_API_KEY, GRAFANA_URL, POSTGRES_MCP_CONNECTION_STRING, etc.) come from git-crypt-encrypted secrets. Servers: Plane (self-hosted project management), Perplexity (cited web search replacing WebSearch), Grafana (dashboards + PromQL, read/write), PostgreSQL (scoped read-only for safety), n8n (workflow automation over my self-hosted instance).
  • Per-machine sync via symlinks.claude/commands/, .claude/rules/, and .claude/hooks/ live in the dotfiles repo; the Nix module symlinks them into ~/.claude/ on every profile so edits propagate on aku sync without manual copying.
  • Fleet-consistent — 16 flake profiles (desktops, laptops, VPS, NAS, Proxmox LXCs, nix-darwin macOS) all get the same Claude Code setup. A change to the module or the rules ripples to every machine on the next rebuild.
  • Plane workflow integrationAKU workspace in self-hosted Plane holds the ticketing for both my own infra and the LiftCraft dev work. Claude can create work items, comment, transition status, query cycles — all via MCP. Closes the "what was I doing yesterday" gap without leaving the terminal.

Results

  • 32 custom skills available as /slash-commands from any Claude Code session.
  • 82 allow rules / 34 deny rules — tight permissions, explicit denies for sensitive files.
  • 6 path-scoped rule files that load on glob match, not on every turn.
  • 5 MCP servers wired from the same Nix module + git-crypt secrets.
  • One git push → every machine on the fleet updates via aku sync.
  • Zero hand-configured Claude Code installs across the homelab.

Stack

NixOS, Home Manager, Claude Code, Model Context Protocol (MCP), Plane (self-hosted), Grafana, PostgreSQL, n8n, Perplexity, Bash, git-crypt.

Status