Skip to content

Commit 3150c39

Browse files
authored
Merge pull request #1631 from dgageot/fix-1616
Support recursive ~/.agents/skills
2 parents 54f8c74 + 88fc1d2 commit 3150c39

3 files changed

Lines changed: 60 additions & 4 deletions

File tree

docs/USAGE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ Skills are automatically discovered from the following locations (in order, late
11171117
**Global locations** (from home directory):
11181118
- `~/.codex/skills/` — Recursive search (Codex format)
11191119
- `~/.claude/skills/` — Flat search (Claude format)
1120-
- `~/.agents/skills/` Flat search (Agent Skills standard)
1120+
- `~/.agents/skills/` Recursive search (Agent Skills standard)
11211121

11221122
**Project locations** (from git root up to current directory):
11231123
- `.claude/skills/` — Flat search, only at current working directory

pkg/skills/skills.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type Skill struct {
3232
// Global locations (from home directory):
3333
// - ~/.codex/skills/ (recursive)
3434
// - ~/.claude/skills/ (flat)
35-
// - ~/.agents/skills/ (flat)
35+
// - ~/.agents/skills/ (recursive)
3636
//
3737
// Project locations (from git root up to cwd, closest wins):
3838
// - .claude/skills/ (flat, only at cwd)
@@ -50,8 +50,8 @@ func Load() []Skill {
5050
for _, skill := range loadSkillsFromDir(filepath.Join(homeDir, ".claude", "skills"), false) {
5151
skillMap[skill.Name] = skill
5252
}
53-
// Load from agents user directory (flat)
54-
for _, skill := range loadSkillsFromDir(filepath.Join(homeDir, ".agents", "skills"), false) {
53+
// Load from agents user directory (recursive)
54+
for _, skill := range loadSkillsFromDir(filepath.Join(homeDir, ".agents", "skills"), true) {
5555
skillMap[skill.Name] = skill
5656
}
5757
}

pkg/skills/skills_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,62 @@ description: A global agents skill
337337
assert.True(t, found, "Expected to find global-skill from ~/.agents/skills")
338338
}
339339

340+
func TestLoad_AgentsSkillsGlobalRecursive(t *testing.T) {
341+
// Create a temp home directory with nested .agents/skills
342+
tmpHome := t.TempDir()
343+
t.Setenv("HOME", tmpHome)
344+
345+
// Create a deeply nested skill under ~/.agents/skills/
346+
nestedSkillDir := filepath.Join(tmpHome, ".agents", "skills", "project-a", "skill-one")
347+
require.NoError(t, os.MkdirAll(nestedSkillDir, 0o755))
348+
349+
skillContent := `---
350+
name: skill-one
351+
description: A nested global agents skill
352+
---
353+
354+
# Nested Skill
355+
`
356+
require.NoError(t, os.WriteFile(filepath.Join(nestedSkillDir, "SKILL.md"), []byte(skillContent), 0o644))
357+
358+
// Also create a flat skill to make sure both work
359+
flatSkillDir := filepath.Join(tmpHome, ".agents", "skills", "flat-skill")
360+
require.NoError(t, os.MkdirAll(flatSkillDir, 0o755))
361+
362+
flatContent := `---
363+
name: flat-skill
364+
description: A flat global agents skill
365+
---
366+
367+
# Flat Skill
368+
`
369+
require.NoError(t, os.WriteFile(filepath.Join(flatSkillDir, "SKILL.md"), []byte(flatContent), 0o644))
370+
371+
// Change to a temp directory that doesn't have any skills
372+
tmpCwd := t.TempDir()
373+
t.Chdir(tmpCwd)
374+
375+
skills := Load()
376+
377+
// Both nested and flat skills should be found
378+
foundNested := false
379+
foundFlat := false
380+
for _, s := range skills {
381+
switch s.Name {
382+
case "skill-one":
383+
foundNested = true
384+
assert.Equal(t, "A nested global agents skill", s.Description)
385+
assert.Equal(t, filepath.Join(nestedSkillDir, "SKILL.md"), s.FilePath)
386+
case "flat-skill":
387+
foundFlat = true
388+
assert.Equal(t, "A flat global agents skill", s.Description)
389+
assert.Equal(t, filepath.Join(flatSkillDir, "SKILL.md"), s.FilePath)
390+
}
391+
}
392+
assert.True(t, foundNested, "Expected to find nested skill-one from ~/.agents/skills/project-a/skill-one")
393+
assert.True(t, foundFlat, "Expected to find flat-skill from ~/.agents/skills/flat-skill")
394+
}
395+
340396
func TestLoad_AgentsSkillsProjectFromNestedDir(t *testing.T) {
341397
// Create a fake git repo with .agents/skills at the root
342398
tmpRepo := t.TempDir()

0 commit comments

Comments
 (0)