Files
nixos-configs/home/roles/development/default.nix
John Ogle 19ee298b71 Add beads Claude plugin installation via home-manager
- Add beadsRepo reference from flake input
- Add activation script to install beads as marketplace plugin
- Updates known_marketplaces.json and config.json declaratively
2026-01-08 19:21:58 -08:00

144 lines
5.6 KiB
Nix

{ 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";
};
# Beads repository is available via globalInputs.beads from the flake
beadsRepo = globalInputs.beads;
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
];
# 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
$DRY_RUN_CMD echo "Claude Code humanlayer commands and agents installed successfully${
if cfg.allowArbitraryClaudeCodeModelSelection
then " (model specifications preserved)"
else " (model selection removed)"
}"
'';
# Install beads Claude plugin as a marketplace
home.activation.claudeCodeBeadsPlugin = lib.hm.dag.entryAfter ["writeBoundary" "claudeCodeCommands"] ''
# Create plugin directories
mkdir -p ~/.claude/plugins/marketplaces
mkdir -p ~/.claude/plugins/repos
# Remove old beads marketplace if it exists (to ensure clean update)
rm -rf ~/.claude/plugins/marketplaces/beads-marketplace
# Copy beads repository to marketplaces directory
# Using cp -r because the source is a Nix store path (read-only)
cp -r ${beadsRepo} ~/.claude/plugins/marketplaces/beads-marketplace
chmod -R u+w ~/.claude/plugins/marketplaces/beads-marketplace
# Update known_marketplaces.json to include beads-marketplace
KNOWN_MARKETPLACES="$HOME/.claude/plugins/known_marketplaces.json"
if [ ! -f "$KNOWN_MARKETPLACES" ]; then
echo '{}' > "$KNOWN_MARKETPLACES"
fi
# Add beads-marketplace entry using jq (merge with existing)
${pkgs.jq}/bin/jq --arg installPath "$HOME/.claude/plugins/marketplaces/beads-marketplace" \
'. + {"beads-marketplace": {
"source": {"source": "github", "repo": "steveyegge/beads"},
"installLocation": $installPath,
"lastUpdated": (now | strftime("%Y-%m-%dT%H:%M:%S.000Z"))
}}' "$KNOWN_MARKETPLACES" > "$KNOWN_MARKETPLACES.tmp" && mv "$KNOWN_MARKETPLACES.tmp" "$KNOWN_MARKETPLACES"
# Update config.json to install the beads plugin
CONFIG_JSON="$HOME/.claude/plugins/config.json"
if [ ! -f "$CONFIG_JSON" ]; then
echo '{"repositories": {}}' > "$CONFIG_JSON"
fi
# Add beads to installed repositories
${pkgs.jq}/bin/jq --arg installPath "$HOME/.claude/plugins/marketplaces/beads-marketplace" \
'.repositories["beads-marketplace/beads"] = {
"source": {"source": "marketplace", "marketplace": "beads-marketplace", "plugin": "beads"},
"installLocation": $installPath,
"installedAt": (now | strftime("%Y-%m-%dT%H:%M:%S.000Z"))
}' "$CONFIG_JSON" > "$CONFIG_JSON.tmp" && mv "$CONFIG_JSON.tmp" "$CONFIG_JSON"
$DRY_RUN_CMD echo "Claude Code beads plugin installed successfully"
'';
# Note: modules must be imported at top-level home config
};
}