{ config, lib, pkgs, globalInputs, system, ... }: with lib; let cfg = config.home.roles.development; # Fetch the claude-plugins repository (for humanlayer commands/agents) # Update the rev to get newer versions of the commands claudePluginsRepo = builtins.fetchGit { url = "https://github.com/jeffh/claude-plugins.git"; # To update: change this to the latest commit hash # You can find the latest commit at: https://github.com/jeffh/claude-plugins/commits/main rev = "5e3e4d937162185b6d78c62022cbfd1c8ad42c4c"; ref = "main"; }; in { options.home.roles.development = { enable = mkEnableOption "Enable development tools and utilities"; allowArbitraryClaudeCodeModelSelection = mkOption { type = types.bool; default = false; description = '' Whether to preserve model specifications in Claude Code humanlayer commands and agents. When false (default), the model: line is stripped from frontmatter, allowing Claude Code to use its default model selection. When true, the model: specifications from the source files are preserved, allowing commands to specify opus/sonnet/haiku explicitly. ''; }; }; config = mkIf cfg.enable { home.packages = [ globalInputs.beads.packages.${system}.default pkgs.unstable.claude-code pkgs.unstable.claude-code-router pkgs.unstable.codex # Custom packages pkgs.custom.tea-rbw pkgs.custom.perles ]; # Install Claude Code humanlayer command and agent plugins home.activation.claudeCodeCommands = lib.hm.dag.entryAfter ["writeBoundary"] '' # Clean up old plugin-installed commands and agents to avoid duplicates rm -f ~/.claude/commands/humanlayer:* 2>/dev/null || true rm -f ~/.claude/agents/humanlayer:* 2>/dev/null || true # Create directories if they don't exist mkdir -p ~/.claude/commands mkdir -p ~/.claude/agents # Copy all humanlayer command files and remove model specifications for file in ${claudePluginsRepo}/humanlayer/commands/*.md; do if [ -f "$file" ]; then filename=$(basename "$file" .md) dest="$HOME/.claude/commands/humanlayer:''${filename}.md" # Copy file and conditionally remove the "model:" line from frontmatter ${if cfg.allowArbitraryClaudeCodeModelSelection then "cp \"$file\" \"$dest\"" else "${pkgs.gnused}/bin/sed '/^model:/d' \"$file\" > \"$dest\"" } fi done # Copy all humanlayer agent files and remove model specifications for file in ${claudePluginsRepo}/humanlayer/agents/*.md; do if [ -f "$file" ]; then filename=$(basename "$file" .md) dest="$HOME/.claude/agents/humanlayer:''${filename}.md" # Copy file and conditionally remove the "model:" line from frontmatter ${if cfg.allowArbitraryClaudeCodeModelSelection then "cp \"$file\" \"$dest\"" else "${pkgs.gnused}/bin/sed '/^model:/d' \"$file\" > \"$dest\"" } fi done # Copy local skills from this repo for file in ${./skills}/*.md; do if [ -f "$file" ]; then filename=$(basename "$file" .md) dest="$HOME/.claude/commands/humanlayer:''${filename}.md" cp "$file" "$dest" fi done $DRY_RUN_CMD echo "Claude Code humanlayer commands and agents installed successfully${ if cfg.allowArbitraryClaudeCodeModelSelection then " (model specifications preserved)" else " (model selection removed)" } + local skills" ''; # Set up beads Claude Code integration (hooks for SessionStart/PreCompact) # This uses the CLI + hooks approach which is recommended over MCP for Claude Code home.activation.claudeCodeBeadsSetup = lib.hm.dag.entryAfter ["writeBoundary" "claudeCodeCommands"] '' # Run bd setup claude to install hooks into ~/.claude/settings.json # This is idempotent - safe to run multiple times ${globalInputs.beads.packages.${system}.default}/bin/bd setup claude 2>/dev/null || true $DRY_RUN_CMD echo "Claude Code beads integration configured (hooks installed)" ''; # Note: modules must be imported at top-level home config }; }