@@ -1046,15 +1046,37 @@ func GlobalSkillsDirs() []string {
return paths
}
+// projectSkillSubdirs lists the conventional subdirectories where
+// project-level skills are discovered. Shared across working-dir and
+// git-root lookups to prevent drift when a new convention is added.
+var projectSkillSubdirs = []string{
+ ".agents/skills",
+ ".crush/skills",
+ ".claude/skills",
+ ".cursor/skills",
+}
+
// ProjectSkillsDir returns the default project directories for which Crush
-// will look for skills.
+// will look for skills. In addition to the working directory, it also
+// checks the git working tree root so that monorepo-level skills are
+// discovered when the user is inside a subdirectory.
+// Working-directory paths come first so local skills take precedence
+// over monorepo-level ones.
func ProjectSkillsDir(workingDir string) []string {
- return []string{
- filepath.Join(workingDir, ".agents/skills"),
- filepath.Join(workingDir, ".crush/skills"),
- filepath.Join(workingDir, ".claude/skills"),
- filepath.Join(workingDir, ".cursor/skills"),
+ dirs := make([]string, 0, len(projectSkillSubdirs)*2)
+ for _, sub := range projectSkillSubdirs {
+ dirs = append(dirs, filepath.Join(workingDir, sub))
+ }
+
+ // When the working directory is inside a git repository, also look at
+ // the repository root so monorepo-level .agents/skills are found.
+ if root := worktreeRoot(workingDir); root != "" && root != workingDir {
+ for _, sub := range projectSkillSubdirs {
+ dirs = append(dirs, filepath.Join(root, sub))
+ }
}
+
+ return dirs
}
func isAppleTerminal() bool { return os.Getenv("TERM_PROGRAM") == "Apple_Terminal" }