feat(skills): also load from .config/agents (#1755)

Amolith created

Change summary

internal/config/load.go | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)

Detailed changes

internal/config/load.go 🔗

@@ -365,10 +365,11 @@ func (c *Config) setDefaults(workingDir, dataDir string) {
 	slices.Sort(c.Options.ContextPaths)
 	c.Options.ContextPaths = slices.Compact(c.Options.ContextPaths)
 
-	// Add the default skills directory if not already present.
-	defaultSkillsDir := GlobalSkillsDir()
-	if !slices.Contains(c.Options.SkillsPaths, defaultSkillsDir) {
-		c.Options.SkillsPaths = append([]string{defaultSkillsDir}, c.Options.SkillsPaths...)
+	// Add the default skills directories if not already present.
+	for _, dir := range GlobalSkillsDirs() {
+		if !slices.Contains(c.Options.SkillsPaths, dir) {
+			c.Options.SkillsPaths = append(c.Options.SkillsPaths, dir)
+		}
 	}
 
 	if str, ok := os.LookupEnv("CRUSH_DISABLE_PROVIDER_AUTO_UPDATE"); ok {
@@ -746,24 +747,29 @@ func isInsideWorktree() bool {
 	return err == nil && strings.TrimSpace(string(bts)) == "true"
 }
 
-// GlobalSkillsDir returns the default directory for Agent Skills.
-// Skills in this directory are auto-discovered and their files can be read
+// GlobalSkillsDirs returns the default directories for Agent Skills.
+// Skills in these directories are auto-discovered and their files can be read
 // without permission prompts.
-func GlobalSkillsDir() string {
+func GlobalSkillsDirs() []string {
 	if crushSkills := os.Getenv("CRUSH_SKILLS_DIR"); crushSkills != "" {
-		return crushSkills
-	}
-	if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
-		return filepath.Join(xdgConfigHome, appName, "skills")
+		return []string{crushSkills}
 	}
 
-	if runtime.GOOS == "windows" {
-		localAppData := cmp.Or(
+	// Determine the base config directory.
+	var configBase string
+	if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
+		configBase = xdgConfigHome
+	} else if runtime.GOOS == "windows" {
+		configBase = cmp.Or(
 			os.Getenv("LOCALAPPDATA"),
 			filepath.Join(os.Getenv("USERPROFILE"), "AppData", "Local"),
 		)
-		return filepath.Join(localAppData, appName, "skills")
+	} else {
+		configBase = filepath.Join(home.Dir(), ".config")
 	}
 
-	return filepath.Join(home.Dir(), ".config", appName, "skills")
+	return []string{
+		filepath.Join(configBase, appName, "skills"),
+		filepath.Join(configBase, "agents", "skills"),
+	}
 }