From 9a64b12e321b4635f61735e0dabb05dda951e072 Mon Sep 17 00:00:00 2001 From: Sridhar Ratnakumar <3998+srid@users.noreply.github.com> Date: Mon, 10 Nov 2025 20:10:05 -0500 Subject: [PATCH] cc: extract hm odule --- claude-code/README.md | 21 ++++ claude-code/nix/home-manager-module.nix | 124 ++++++++++++++++++++++++ modules/home/claude-code/default.nix | 86 ++-------------- 3 files changed, 154 insertions(+), 77 deletions(-) create mode 100644 claude-code/README.md create mode 100644 claude-code/nix/home-manager-module.nix diff --git a/claude-code/README.md b/claude-code/README.md new file mode 100644 index 0000000..87ca28d --- /dev/null +++ b/claude-code/README.md @@ -0,0 +1,21 @@ +# Srid's Claude Code Configuration + +## Nix module + +- `nix/home-manager-module.nix` - Home-manager module for auto-wiring this directory layout. + +### Usage + +Import the home-manager module and set `autoWire.dir`: + +```nix +{ + imports = [ ./claude-code/nix/home-manager-module.nix ]; + + programs.claude-code = { + enable = true; + autoWire.dir = ./claude-code; + }; +} +``` + diff --git a/claude-code/nix/home-manager-module.nix b/claude-code/nix/home-manager-module.nix new file mode 100644 index 0000000..ee4ee13 --- /dev/null +++ b/claude-code/nix/home-manager-module.nix @@ -0,0 +1,124 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.programs.claude-code; + + # Auto-wire subagents from subagents/ directory + subagentsDir = cfg.autoWire.dir + "/subagents"; + autoAgents = lib.optionalAttrs (builtins.pathExists subagentsDir) + (lib.mapAttrs' + (fileName: _: + lib.nameValuePair + (lib.removeSuffix ".md" fileName) + (builtins.readFile (subagentsDir + "/${fileName}")) + ) + (builtins.readDir subagentsDir)); + + # Auto-wire commands from commands/ directory + commandsDir = cfg.autoWire.dir + "/commands"; + autoCommands = lib.optionalAttrs (builtins.pathExists commandsDir) + (lib.mapAttrs' + (fileName: _: + lib.nameValuePair + (lib.removeSuffix ".md" fileName) + (builtins.readFile (commandsDir + "/${fileName}")) + ) + (builtins.readDir commandsDir)); + + # Auto-wire skills from skills/ directory + skillsDir = cfg.autoWire.dir + "/skills"; + skillDirs = lib.optionalAttrs (builtins.pathExists skillsDir) + (lib.filterAttrs (_: type: type == "directory") (builtins.readDir skillsDir)); + + # Process skill: if it has default.nix, build and substitute; otherwise use as-is + processSkill = skillName: + let + skillPath = skillsDir + "/${skillName}"; + hasDefaultNix = builtins.pathExists (skillPath + "/default.nix"); + in + if hasDefaultNix then + let + skillPkg = pkgs.callPackage skillPath { }; + in + pkgs.runCommand "${skillName}-skill" { } '' + mkdir -p $out + substitute ${skillPath}/SKILL.md $out/SKILL.md \ + --replace-fail '@${skillName}@' '${skillPkg}/bin/${skillName}' + '' + else + skillPath; + + # Auto-wire MCP servers from mcp/ directory + mcpDir = cfg.autoWire.dir + "/mcp"; + autoMcpServers = lib.optionalAttrs (builtins.pathExists mcpDir) + (lib.mapAttrs' + (fileName: _: + lib.nameValuePair + (lib.removeSuffix ".nix" fileName) + (import (mcpDir + "/${fileName}")) + ) + (builtins.readDir mcpDir)); + + # Auto-load settings from settings.nix + settingsFile = cfg.autoWire.dir + "/settings.nix"; + autoSettings = lib.optionalAttrs (builtins.pathExists settingsFile) + (import settingsFile); + + # Auto-load memory from memory.md + memoryFile = cfg.autoWire.dir + "/memory.md"; + autoMemory = lib.optionalAttrs (builtins.pathExists memoryFile) + { text = builtins.readFile memoryFile; }; + +in +{ + options.programs.claude-code = { + autoWire = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to automatically wire up subagents, commands, skills, and MCP servers from autoWire.dir. + Set to false if you want to manually configure these. + ''; + }; + + dir = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = '' + Path to the claude-code directory containing subagents/, commands/, skills/, mcp/, settings.nix, and memory.md. + When set, these will be automatically discovered and configured. + ''; + }; + }; + }; + + config = lib.mkIf (cfg.enable && cfg.autoWire.dir != null && cfg.autoWire.enable) { + # Link skill directories to ~/.claude/skills/ + home.file = lib.mapAttrs' + (skillName: _: + lib.nameValuePair ".claude/skills/${skillName}" { + source = processSkill skillName; + recursive = true; + } + ) + skillDirs; + + programs.claude-code = { + # Auto-wire settings if settings.nix exists + settings = lib.mkDefault autoSettings; + + # Auto-wire memory if memory.md exists + memory = lib.mkDefault autoMemory; + + # Auto-wire commands from commands/ directory + commands = lib.mkDefault autoCommands; + + # Auto-wire agents from subagents/ directory + agents = lib.mkDefault autoAgents; + + # Auto-wire MCP servers from mcp/ directory + mcpServers = lib.mkDefault autoMcpServers; + }; + }; +} diff --git a/modules/home/claude-code/default.nix b/modules/home/claude-code/default.nix index 7154478..ae9c768 100644 --- a/modules/home/claude-code/default.nix +++ b/modules/home/claude-code/default.nix @@ -1,71 +1,15 @@ -{ flake, pkgs, lib, ... }: -let - claudeCodeDir = flake.inputs.self + /claude-code; - - subagentsDir = claudeCodeDir + "/subagents"; - agents = lib.mapAttrs' - (fileName: _: - lib.nameValuePair - (lib.removeSuffix ".md" fileName) - (builtins.readFile (subagentsDir + "/${fileName}")) - ) - (builtins.readDir subagentsDir); - - commandsDir = claudeCodeDir + "/commands"; - commands = lib.mapAttrs' - (fileName: _: - lib.nameValuePair - (lib.removeSuffix ".md" fileName) - (builtins.readFile (commandsDir + "/${fileName}")) - ) - (builtins.readDir commandsDir); - - skillsDir = claudeCodeDir + "/skills"; - skillDirs = lib.filterAttrs (_: type: type == "directory") (builtins.readDir skillsDir); - - # Process skill: if it has default.nix, build and substitute; otherwise use as-is - processSkill = skillName: - let - skillPath = skillsDir + "/${skillName}"; - hasDefaultNix = builtins.pathExists (skillPath + "/default.nix"); - in - if hasDefaultNix then - let - skillPkg = pkgs.callPackage skillPath { }; - in - pkgs.runCommand "${skillName}-skill" { } '' - mkdir -p $out - substitute ${skillPath}/SKILL.md $out/SKILL.md \ - --replace-fail '@${skillName}@' '${skillPkg}/bin/${skillName}' - '' - else - skillPath; - - mcpDir = claudeCodeDir + "/mcp"; - mcpServers = lib.mapAttrs' - (fileName: _: - lib.nameValuePair - (lib.removeSuffix ".nix" fileName) - (import (mcpDir + "/${fileName}")) - ) - (builtins.readDir mcpDir); -in +{ flake, pkgs, ... }: { - # Packages often used by Claude Code CLI. + # Import the general home-manager module + imports = [ + ../../../claude-code/nix/home-manager-module.nix + ]; + + # Packages often used by Claude Code CLI home.packages = with pkgs; [ tree ]; - # Link skill directories to ~/.claude/skills/ - # (home-manager module doesn't support skills yet, so we link manually) - home.file = lib.mapAttrs' - (skillName: _: - lib.nameValuePair ".claude/skills/${skillName}" { - source = processSkill skillName; - recursive = true; - } - ) - skillDirs; programs.claude-code = { enable = true; @@ -75,19 +19,7 @@ in then flake.inputs.self.packages.${pkgs.system}.claude # see claude-sandboxed.nix else pkgs.claude-code; - # Basic settings for Claude Code - settings = import (claudeCodeDir + "/settings.nix"); - - # System prompt / memory - memory.text = builtins.readFile (claudeCodeDir + "/memory.md"); - - # Automatically discovered commands from commands/ directory - commands = commands; - - # Automatically discovered agents from subagents/ directory - agents = agents; - - # Automatically discovered MCP servers from mcp/ directory - mcpServers = mcpServers; + # Set the claude-code directory for auto-wiring + autoWire.dir = ../../../claude-code; }; }