Skip to content

Commit 5b87d7b

Browse files
authored
feat(agent/agentcontextconfig): discover skills from ~/.coder/skills (#25271)
The default skills lookup only scanned the project-relative .agents/skills directory, so personal skills had to be repeated per project or wired in via CODER_AGENT_EXP_SKILLS_DIRS. Now the default is the comma-separated list ~/.coder/skills,.agents/skills, which lets discoverSkills's existing first-occurrence-wins policy prefer home-scoped skills over project ones with the same name. The change is additive when ~/.coder/skills is absent (missing directories are silently skipped in discoverSkills) and unaffects users who set the env var explicitly. Closes CODAGT-403
1 parent fb3aef1 commit 5b87d7b

2 files changed

Lines changed: 36 additions & 1 deletion

File tree

agent/agentcontextconfig/api.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,14 @@ var skillNamePattern = regexp.MustCompile(
6060

6161
// Default values for agent-internal configuration. These are
6262
// used when the corresponding env vars are unset.
63+
//
64+
// DefaultSkillsDir is a comma-separated list so home-scoped
65+
// skills override project-scoped ones with the same name
66+
// (discoverSkills picks the first occurrence per skill name).
6367
const (
6468
DefaultInstructionsDir = "~/.coder"
6569
DefaultInstructionsFile = "AGENTS.md"
66-
DefaultSkillsDir = ".agents/skills"
70+
DefaultSkillsDir = "~/.coder/skills,.agents/skills"
6771
DefaultSkillMetaFile = "SKILL.md"
6872
DefaultMCPConfigFile = ".mcp.json"
6973
)

agent/agentcontextconfig/api_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,37 @@ func TestResolve(t *testing.T) {
461461
require.Len(t, skillParts, 1)
462462
require.Equal(t, "from skills1", skillParts[0].SkillDescription)
463463
})
464+
465+
//nolint:paralleltest // Uses t.Setenv to mutate HOME.
466+
t.Run("DefaultDiscoversHomeAndProjectSkillsHomeWins", func(t *testing.T) {
467+
fakeHome := t.TempDir()
468+
t.Setenv("HOME", fakeHome)
469+
t.Setenv("USERPROFILE", fakeHome)
470+
workDir := t.TempDir()
471+
472+
homeSkills := filepath.Join(fakeHome, ".coder", "skills")
473+
writeSkillMetaFileInRoot(t, homeSkills, "home-only", "home only")
474+
writeSkillMetaFileInRoot(t, homeSkills, "shared", "from home")
475+
writeSkillMetaFile(t, workDir, "project-only", "project only")
476+
writeSkillMetaFile(t, workDir, "shared", "from project")
477+
478+
// Construct the Config directly with the package defaults
479+
// to verify the default skills list (and only the defaults).
480+
cfg, _ := agentcontextconfig.Resolve(workDir, agentcontextconfig.Config{
481+
SkillsDirs: agentcontextconfig.DefaultSkillsDir,
482+
SkillMetaFile: agentcontextconfig.DefaultSkillMetaFile,
483+
})
484+
485+
got := map[string]string{}
486+
for _, p := range filterParts(cfg.Parts, codersdk.ChatMessagePartTypeSkill) {
487+
got[p.SkillName] = p.SkillDescription
488+
}
489+
require.Equal(t, map[string]string{
490+
"home-only": "home only",
491+
"project-only": "project only",
492+
"shared": "from home",
493+
}, got)
494+
})
464495
}
465496

466497
func TestNewAPI_LazyDirectory(t *testing.T) {

0 commit comments

Comments
 (0)