From 91be7cce763fa4022c7cf025a71b0c366d1b6e77 Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Wed, 18 Feb 2026 20:51:14 -0600 Subject: [PATCH] claude-code: fix skills implementation Claude skills are only found when using `SKILL.md` entrypoints. Attribute names should be used for the directory structure, not the filename. Signed-off-by: Austin Horstman --- modules/programs/claude-code.nix | 15 ++++++++------- .../programs/claude-code/mixed-content.nix | 6 +++--- .../programs/claude-code/skill-subdir/SKILL.md | 12 ++++++++++++ tests/modules/programs/claude-code/skills-dir.nix | 8 ++++---- .../modules/programs/claude-code/skills-path.nix | 4 ++-- .../programs/claude-code/skills-subdir.nix | 5 +++++ .../skills/{test-skill.md => test-skill/SKILL.md} | 0 7 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 tests/modules/programs/claude-code/skill-subdir/SKILL.md rename tests/modules/programs/claude-code/skills/{test-skill.md => test-skill/SKILL.md} (100%) diff --git a/modules/programs/claude-code.nix b/modules/programs/claude-code.nix index dfc0fc55..16387e67 100644 --- a/modules/programs/claude-code.nix +++ b/modules/programs/claude-code.nix @@ -298,14 +298,14 @@ in default = { }; description = '' Custom skills for Claude Code. - The attribute name becomes the skill filename or directory name, and the value is either: - - Inline content as a string (creates .claude/skills/.md) - - A path to a file (creates .claude/skills/.md) + The attribute name becomes the skill directory name, and the value is either: + - Inline content as a string (creates .claude/skills//SKILL.md) + - A path to a file (creates .claude/skills//SKILL.md) - A path to a directory (creates .claude/skills// with all files) ''; example = lib.literalExpression '' { - xlsx = ./skills/xlsx.md; + xlsx = ./skills/xlsx/SKILL.md; data-analysis = ./skills/data-analysis; pdf-processing = ''' --- @@ -334,8 +334,9 @@ in type = lib.types.nullOr lib.types.path; default = null; description = '' - Path to a directory containing skill files for Claude Code. - Skill files from this directory will be symlinked to .claude/skills/. + Path to a directory containing skill directories for Claude Code. + Each skill directory should contain a SKILL.md entrypoint file. + Skill directories from this path will be symlinked to .claude/skills/. ''; example = lib.literalExpression "./skills"; }; @@ -516,7 +517,7 @@ in recursive = true; } else - lib.nameValuePair ".claude/skills/${name}.md" ( + lib.nameValuePair ".claude/skills/${name}/SKILL.md" ( if lib.isPath content then { source = content; } else { text = content; } ) ) cfg.skills; diff --git a/tests/modules/programs/claude-code/mixed-content.nix b/tests/modules/programs/claude-code/mixed-content.nix index 74864200..67c6ef79 100644 --- a/tests/modules/programs/claude-code/mixed-content.nix +++ b/tests/modules/programs/claude-code/mixed-content.nix @@ -38,14 +38,14 @@ assertFileExists home-files/.claude/commands/path-command.md assertFileExists home-files/.claude/agents/inline-agent.md assertFileExists home-files/.claude/agents/path-agent.md - assertFileExists home-files/.claude/skills/inline-skill.md - assertFileExists home-files/.claude/skills/path-skill.md + assertFileExists home-files/.claude/skills/inline-skill/SKILL.md + assertFileExists home-files/.claude/skills/path-skill/SKILL.md assertFileContent home-files/.claude/commands/path-command.md \ ${./test-command.md} assertFileContent home-files/.claude/agents/path-agent.md \ ${./test-agent.md} - assertFileContent home-files/.claude/skills/path-skill.md \ + assertFileContent home-files/.claude/skills/path-skill/SKILL.md \ ${./test-skill.md} ''; } diff --git a/tests/modules/programs/claude-code/skill-subdir/SKILL.md b/tests/modules/programs/claude-code/skill-subdir/SKILL.md new file mode 100644 index 00000000..6f154df6 --- /dev/null +++ b/tests/modules/programs/claude-code/skill-subdir/SKILL.md @@ -0,0 +1,12 @@ +--- +name: data-processing +description: Process and transform structured data files. +--- + +# Data Processing Skill + +Use this skill for data-processing tasks. + +## Supporting files +- `extract.md`: extraction workflow details +- `convert.md`: conversion workflow details diff --git a/tests/modules/programs/claude-code/skills-dir.nix b/tests/modules/programs/claude-code/skills-dir.nix index 4f15a558..0a43e387 100644 --- a/tests/modules/programs/claude-code/skills-dir.nix +++ b/tests/modules/programs/claude-code/skills-dir.nix @@ -5,10 +5,10 @@ }; nmt.script = '' - assertFileExists home-files/.claude/skills/test-skill.md - assertLinkExists home-files/.claude/skills/test-skill.md + assertFileExists home-files/.claude/skills/test-skill/SKILL.md + assertLinkExists home-files/.claude/skills/test-skill/SKILL.md assertFileContent \ - home-files/.claude/skills/test-skill.md \ - ${./skills/test-skill.md} + home-files/.claude/skills/test-skill/SKILL.md \ + ${./skills/test-skill/SKILL.md} ''; } diff --git a/tests/modules/programs/claude-code/skills-path.nix b/tests/modules/programs/claude-code/skills-path.nix index 374e97a0..89424647 100644 --- a/tests/modules/programs/claude-code/skills-path.nix +++ b/tests/modules/programs/claude-code/skills-path.nix @@ -7,8 +7,8 @@ }; nmt.script = '' - assertFileExists home-files/.claude/skills/test-skill.md - assertFileContent home-files/.claude/skills/test-skill.md \ + assertFileExists home-files/.claude/skills/test-skill/SKILL.md + assertFileContent home-files/.claude/skills/test-skill/SKILL.md \ ${./test-skill.md} ''; } diff --git a/tests/modules/programs/claude-code/skills-subdir.nix b/tests/modules/programs/claude-code/skills-subdir.nix index 3c7567fd..9b2c31bf 100644 --- a/tests/modules/programs/claude-code/skills-subdir.nix +++ b/tests/modules/programs/claude-code/skills-subdir.nix @@ -7,10 +7,15 @@ }; nmt.script = '' + assertFileExists home-files/.claude/skills/data-processing/SKILL.md assertFileExists home-files/.claude/skills/data-processing/extract.md assertFileExists home-files/.claude/skills/data-processing/convert.md + assertLinkExists home-files/.claude/skills/data-processing/SKILL.md assertLinkExists home-files/.claude/skills/data-processing/extract.md assertLinkExists home-files/.claude/skills/data-processing/convert.md + assertFileContent \ + home-files/.claude/skills/data-processing/SKILL.md \ + ${./skill-subdir/SKILL.md} assertFileContent \ home-files/.claude/skills/data-processing/extract.md \ ${./skill-subdir/extract.md} diff --git a/tests/modules/programs/claude-code/skills/test-skill.md b/tests/modules/programs/claude-code/skills/test-skill/SKILL.md similarity index 100% rename from tests/modules/programs/claude-code/skills/test-skill.md rename to tests/modules/programs/claude-code/skills/test-skill/SKILL.md