From f938277527aa084929261879d50d9832b9eab6d3 Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Thu, 9 Jul 2026 22:09:44 -0500 Subject: [PATCH] claude-code: tighten module implementation Remove redundant option machinery, centralize skills shape checks, and use narrower list composition while preserving generated behavior. --- modules/programs/claude-code/default.nix | 42 +++++++++++------------- modules/programs/claude-code/options.nix | 32 ++++++------------ 2 files changed, 29 insertions(+), 45 deletions(-) diff --git a/modules/programs/claude-code/default.nix b/modules/programs/claude-code/default.nix index bf364cad0..4fbb4c962 100644 --- a/modules/programs/claude-code/default.nix +++ b/modules/programs/claude-code/default.nix @@ -5,11 +5,7 @@ ... }: let - inherit (lib) - mkChangedOptionModule - nameValuePair - optionalAttrs - ; + inherit (lib) mkChangedOptionModule; cfg = config.programs.claude-code; @@ -134,12 +130,10 @@ in hasManagedPlugins = legacyPluginPaths != [ ]; useLegacyPluginWrapper = hasManagedPlugins && !supportsPersonalPlugins; - legacyWrapperArgs = lib.flatten ( - map (plugin: [ - "--plugin-dir" - "${plugin}" - ]) legacyPluginPaths - ); + legacyWrapperArgs = lib.concatMap (plugin: [ + "--plugin-dir" + "${plugin}" + ]) legacyPluginPaths; legacyFinalPackage = pkgs.symlinkJoin { name = "claude-code"; @@ -157,19 +151,21 @@ in pluginNames = map (plugin: plugin.name) pluginEntries; - skillNames = - if builtins.isAttrs cfg.skills then - lib.attrNames cfg.skills - else if lib.hm.strings.isPathLike cfg.skills && lib.pathIsDirectory cfg.skills then - lib.attrNames (builtins.readDir cfg.skills) + skillsAreAttrs = builtins.isAttrs cfg.skills; + skillsArePath = lib.hm.strings.isPathLike cfg.skills; + skillsAreDirectory = skillsArePath && lib.pathIsDirectory cfg.skills; + skillNames = lib.attrNames ( + if skillsAreAttrs then + cfg.skills else - [ ]; + lib.optionalAttrs skillsAreDirectory (builtins.readDir cfg.skills) + ); pluginFileEntries = lib.optionalAttrs supportsPersonalPlugins ( lib.listToAttrs ( map ( plugin: - nameValuePair "${cfg.configDir}/skills/${plugin.name}" { + lib.nameValuePair "${cfg.configDir}/skills/${plugin.name}" { inherit (plugin) source; recursive = true; } @@ -209,7 +205,7 @@ in message = "Managed Claude Code MCP, LSP, and plugins require `programs.claude-code.package` version 2.1.76 or later"; } { - assertion = !lib.hm.strings.isPathLike cfg.skills || lib.pathIsDirectory cfg.skills; + assertion = !skillsArePath || skillsAreDirectory; message = "`programs.claude-code.skills` must be a directory when set to a path"; } { @@ -242,10 +238,10 @@ in // { "$schema" = "https://json.schemastore.org/claude-code-settings.json"; } - // optionalAttrs (cfg.marketplaces != { }) { + // lib.optionalAttrs (cfg.marketplaces != { }) { extraKnownMarketplaces = lib.mapAttrs mkMarketplaceEntry cfg.marketplaces; } - // optionalAttrs (disabledMcpServerNames != [ ]) { + // lib.optionalAttrs (disabledMcpServerNames != [ ]) { disabledMcpjsonServers = lib.unique ( (cfg.settings.disabledMcpjsonServers or [ ]) ++ disabledMcpServerNames ); @@ -275,7 +271,7 @@ in (mkRecursiveDirAttrs "commands" cfg.commandsDir) (mkRecursiveDirAttrs "hooks" cfg.hooksDir) (mkRecursiveDirAttrs "rules" cfg.rulesDir) - (lib.mkIf (lib.hm.strings.isPathLike cfg.skills) { + (lib.mkIf skillsArePath { "${cfg.configDir}/skills" = { source = cfg.skills; recursive = true; @@ -283,7 +279,7 @@ in }) pluginFileEntries (mkHookEntries cfg.hooks) - (lib.optionalAttrs (builtins.isAttrs cfg.skills) (lib.mapAttrs' mkSkillEntry cfg.skills)) + (lib.optionalAttrs skillsAreAttrs (lib.mapAttrs' mkSkillEntry cfg.skills)) (mkMarkdownEntries "output-styles" cfg.outputStyles) ]; }; diff --git a/modules/programs/claude-code/options.nix b/modules/programs/claude-code/options.nix index c641b0766..97f9cd109 100644 --- a/modules/programs/claude-code/options.nix +++ b/modules/programs/claude-code/options.nix @@ -5,23 +5,17 @@ ... }: let - inherit (lib) literalExpression mkOption optionalAttrs; + inherit (lib) literalExpression mkOption; jsonFormat = pkgs.formats.json { }; mkContentOption = - { - description, - example ? null, - }: - mkOption ( - { - type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path); - default = { }; - inherit description; - } - // optionalAttrs (example != null) { inherit example; } - ); + { description, example }: + mkOption { + type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path); + default = { }; + inherit description example; + }; mkDirOption = { description, example }: @@ -171,7 +165,7 @@ in example = literalExpression '' [ ./my-local-plugin - fetchFromGithub { + fetchFromGitHub { owner = "some-github-org"; repo = "claude-plugin"; rev = "779a68ebc2a75e4a184d2c87e5a43a758e6458a1"; @@ -193,7 +187,7 @@ in example = literalExpression '' { local-marketplace = ./my-local-marketplace; - gh-marketplace = fetchFromGithub { + gh-marketplace = fetchFromGitHub { owner = "some-github-org"; repo = "claude-marketplace"; rev = "8a873a220b8427b25b03ce1a821593a24e098c34"; @@ -384,13 +378,7 @@ in }; skills = mkOption { - type = lib.types.either (lib.types.attrsOf ( - lib.types.oneOf [ - lib.types.lines - lib.types.path - lib.types.str - ] - )) lib.types.path; + type = with lib.types; either (attrsOf (either lines path)) path; default = { }; description = '' Custom skills for Claude Code.