Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/reference/search-paths.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ Skill files provide specialized capabilities with progressive disclosure. Within

1. `.agents/skills/*/SKILL.md` (each subdirectory in `.agents/skills/` can contain a `SKILL.md` file)
2. `.cursor/skills/*/SKILL.md` (each subdirectory in `.cursor/skills/` can contain a `SKILL.md` file)
3. `.opencode/skills/*/SKILL.md` (each subdirectory in `.opencode/skills/` can contain a `SKILL.md` file)
4. `.github/skills/*/SKILL.md` (each subdirectory in `.github/skills/` can contain a `SKILL.md` file)
5. `.claude/skills/*/SKILL.md` (each subdirectory in `.claude/skills/` can contain a `SKILL.md` file)
6. `.gemini/skills/*/SKILL.md` (each subdirectory in `.gemini/skills/` can contain a `SKILL.md` file)
7. `.augment/skills/*/SKILL.md` (each subdirectory in `.augment/skills/` can contain a `SKILL.md` file)
8. `.windsurf/skills/*/SKILL.md` (each subdirectory in `.windsurf/skills/` can contain a `SKILL.md` file)
9. `.codex/skills/*/SKILL.md` (each subdirectory in `.codex/skills/` can contain a `SKILL.md` file)

**Example:**
```
Expand All @@ -51,6 +58,36 @@ Skill files provide specialized capabilities with progressive disclosure. Within
.cursor/skills/
├── code-review/
│ └── SKILL.md
└── refactoring/
└── SKILL.md

.opencode/skills/
├── testing/
│ └── SKILL.md
└── debugging/
└── SKILL.md

.github/skills/
├── deployment/
│ └── SKILL.md
└── ci-cd/
└── SKILL.md

.claude/skills/
├── analysis/
│ └── SKILL.md
└── writing/
└── SKILL.md

.gemini/skills/
├── search/
│ └── SKILL.md
└── multimodal/
└── SKILL.md

.codex/skills/
├── code-gen/
│ └── SKILL.md
└── refactoring/
└── SKILL.md
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation example is missing directory structures for Augment and Windsurf skills, which were added to the search paths list above. For consistency and completeness, examples should be provided for all newly supported agent skill directories.

Suggested change
└── SKILL.md
└── SKILL.md
.augment/skills/
├── testing/
│ └── SKILL.md
└── debugging/
└── SKILL.md
.windsurf/skills/
├── navigation/
│ └── SKILL.md
└── layout/
└── SKILL.md

Copilot uses AI. Check for mistakes.
```
Expand Down
21 changes: 14 additions & 7 deletions pkg/codingcontext/agent_paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,37 +30,44 @@ var agentsPaths = map[Agent]agentPathsConfig{
// OpenCode agent paths
AgentOpenCode: {
rulesPaths: []string{".opencode/agent", ".opencode/rules"},
skillsPath: ".opencode/skills",
commandsPath: ".opencode/command",
// No skills or tasks paths defined for OpenCode
// No tasks path defined for OpenCode
},
// Copilot agent paths
AgentCopilot: {
rulesPaths: []string{".github/copilot-instructions.md", ".github/agents"},
// No skills, commands, or tasks paths defined for Copilot
skillsPath: ".github/skills",
// No commands or tasks paths defined for Copilot
},
// Claude agent paths
AgentClaude: {
rulesPaths: []string{".claude", "CLAUDE.md", "CLAUDE.local.md"},
// No skills, commands, or tasks paths defined for Claude
skillsPath: ".claude/skills",
// No commands or tasks paths defined for Claude
},
// Gemini agent paths
AgentGemini: {
rulesPaths: []string{".gemini/styleguide.md", ".gemini", "GEMINI.md"},
// No skills, commands, or tasks paths defined for Gemini
skillsPath: ".gemini/skills",
// No commands or tasks paths defined for Gemini
},
// Augment agent paths
AgentAugment: {
rulesPaths: []string{".augment/rules", ".augment/guidelines.md"},
// No skills, commands, or tasks paths defined for Augment
skillsPath: ".augment/skills",
// No commands or tasks paths defined for Augment
},
// Windsurf agent paths
AgentWindsurf: {
rulesPaths: []string{".windsurf/rules", ".windsurfrules"},
// No skills, commands, or tasks paths defined for Windsurf
skillsPath: ".windsurf/skills",
// No commands or tasks paths defined for Windsurf
},
// Codex agent paths
AgentCodex: {
rulesPaths: []string{".codex", "AGENTS.md"},
// No skills, commands, or tasks paths defined for Codex
skillsPath: ".codex/skills",
// No commands or tasks paths defined for Codex
},
}
266 changes: 266 additions & 0 deletions pkg/codingcontext/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2377,6 +2377,272 @@ description: A Cursor IDE skill
}
},
},
{
name: "discover skills from .opencode/skills directory",
setup: func(t *testing.T, dir string) {
// Create task
createTask(t, dir, "test-task", "", "Test task content")

// Create skill in .opencode/skills directory
skillDir := filepath.Join(dir, ".opencode", "skills", "opencode-skill")
if err := os.MkdirAll(skillDir, 0o755); err != nil {
t.Fatalf("failed to create skill directory: %v", err)
}

skillContent := `---
name: opencode-skill
description: A skill for OpenCode
---

# OpenCode Skill

This is a skill for OpenCode.
`
skillPath := filepath.Join(skillDir, "SKILL.md")
if err := os.WriteFile(skillPath, []byte(skillContent), 0o644); err != nil {
t.Fatalf("failed to create skill file: %v", err)
}
},
taskName: "test-task",
wantErr: false,
checkFunc: func(t *testing.T, result *Result) {
if len(result.Skills.Skills) != 1 {
t.Fatalf("expected 1 skill, got %d", len(result.Skills.Skills))
}
skill := result.Skills.Skills[0]
if skill.Name != "opencode-skill" {
t.Errorf("expected skill name 'opencode-skill', got %q", skill.Name)
}
},
Comment on lines +2408 to +2416
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test verification is incomplete compared to the existing .cursor/skills test. It should also verify the Description field and Location field to ensure the skill metadata is properly extracted and populated. The .cursor test at lines 2318-2323 checks both of these fields.

Copilot uses AI. Check for mistakes.
},
{
name: "discover skills from .github/skills directory",
setup: func(t *testing.T, dir string) {
// Create task
createTask(t, dir, "test-task", "", "Test task content")

// Create skill in .github/skills directory
skillDir := filepath.Join(dir, ".github", "skills", "copilot-skill")
if err := os.MkdirAll(skillDir, 0o755); err != nil {
t.Fatalf("failed to create skill directory: %v", err)
}

skillContent := `---
name: copilot-skill
description: A skill for GitHub Copilot
---

# Copilot Skill

This is a skill for GitHub Copilot.
`
skillPath := filepath.Join(skillDir, "SKILL.md")
if err := os.WriteFile(skillPath, []byte(skillContent), 0o644); err != nil {
t.Fatalf("failed to create skill file: %v", err)
}
},
taskName: "test-task",
wantErr: false,
checkFunc: func(t *testing.T, result *Result) {
if len(result.Skills.Skills) != 1 {
t.Fatalf("expected 1 skill, got %d", len(result.Skills.Skills))
}
skill := result.Skills.Skills[0]
if skill.Name != "copilot-skill" {
t.Errorf("expected skill name 'copilot-skill', got %q", skill.Name)
}
},
Comment on lines +2446 to +2454
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test verification is incomplete compared to the existing .cursor/skills test. It should also verify the Description field and Location field to ensure the skill metadata is properly extracted and populated. The .cursor test at lines 2318-2323 checks both of these fields.

Copilot uses AI. Check for mistakes.
},
{
name: "discover skills from .augment/skills directory",
setup: func(t *testing.T, dir string) {
// Create task
createTask(t, dir, "test-task", "", "Test task content")

// Create skill in .augment/skills directory
skillDir := filepath.Join(dir, ".augment", "skills", "augment-skill")
if err := os.MkdirAll(skillDir, 0o755); err != nil {
t.Fatalf("failed to create skill directory: %v", err)
}

skillContent := `---
name: augment-skill
description: A skill for Augment
---

# Augment Skill

This is a skill for Augment.
`
skillPath := filepath.Join(skillDir, "SKILL.md")
if err := os.WriteFile(skillPath, []byte(skillContent), 0o644); err != nil {
t.Fatalf("failed to create skill file: %v", err)
}
},
taskName: "test-task",
wantErr: false,
checkFunc: func(t *testing.T, result *Result) {
if len(result.Skills.Skills) != 1 {
t.Fatalf("expected 1 skill, got %d", len(result.Skills.Skills))
}
skill := result.Skills.Skills[0]
if skill.Name != "augment-skill" {
t.Errorf("expected skill name 'augment-skill', got %q", skill.Name)
}
},
Comment on lines +2484 to +2492
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test verification is incomplete compared to the existing .cursor/skills test. It should also verify the Description field and Location field to ensure the skill metadata is properly extracted and populated. The .cursor test at lines 2318-2323 checks both of these fields.

Copilot uses AI. Check for mistakes.
},
{
name: "discover skills from .windsurf/skills directory",
setup: func(t *testing.T, dir string) {
// Create task
createTask(t, dir, "test-task", "", "Test task content")

// Create skill in .windsurf/skills directory
skillDir := filepath.Join(dir, ".windsurf", "skills", "windsurf-skill")
if err := os.MkdirAll(skillDir, 0o755); err != nil {
t.Fatalf("failed to create skill directory: %v", err)
}

skillContent := `---
name: windsurf-skill
description: A skill for Windsurf
---

# Windsurf Skill

This is a skill for Windsurf.
`
skillPath := filepath.Join(skillDir, "SKILL.md")
if err := os.WriteFile(skillPath, []byte(skillContent), 0o644); err != nil {
t.Fatalf("failed to create skill file: %v", err)
}
},
taskName: "test-task",
wantErr: false,
checkFunc: func(t *testing.T, result *Result) {
if len(result.Skills.Skills) != 1 {
t.Fatalf("expected 1 skill, got %d", len(result.Skills.Skills))
}
skill := result.Skills.Skills[0]
if skill.Name != "windsurf-skill" {
t.Errorf("expected skill name 'windsurf-skill', got %q", skill.Name)
}
},
Comment on lines +2522 to +2530
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test verification is incomplete compared to the existing .cursor/skills test. It should also verify the Description field and Location field to ensure the skill metadata is properly extracted and populated. The .cursor test at lines 2318-2323 checks both of these fields.

Copilot uses AI. Check for mistakes.
},
{
name: "discover skills from .claude/skills directory",
setup: func(t *testing.T, dir string) {
// Create task
createTask(t, dir, "test-task", "", "Test task content")

// Create skill in .claude/skills directory
skillDir := filepath.Join(dir, ".claude", "skills", "claude-skill")
if err := os.MkdirAll(skillDir, 0o755); err != nil {
t.Fatalf("failed to create skill directory: %v", err)
}

skillContent := `---
name: claude-skill
description: A skill for Claude
---

# Claude Skill

This is a skill for Claude.
`
skillPath := filepath.Join(skillDir, "SKILL.md")
if err := os.WriteFile(skillPath, []byte(skillContent), 0o644); err != nil {
t.Fatalf("failed to create skill file: %v", err)
}
},
taskName: "test-task",
wantErr: false,
checkFunc: func(t *testing.T, result *Result) {
if len(result.Skills.Skills) != 1 {
t.Fatalf("expected 1 skill, got %d", len(result.Skills.Skills))
}
skill := result.Skills.Skills[0]
if skill.Name != "claude-skill" {
t.Errorf("expected skill name 'claude-skill', got %q", skill.Name)
}
},
Comment on lines +2560 to +2568
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test verification is incomplete compared to the existing .cursor/skills test. It should also verify the Description field and Location field to ensure the skill metadata is properly extracted and populated. The .cursor test at lines 2318-2323 checks both of these fields.

Copilot uses AI. Check for mistakes.
},
{
name: "discover skills from .gemini/skills directory",
setup: func(t *testing.T, dir string) {
// Create task
createTask(t, dir, "test-task", "", "Test task content")

// Create skill in .gemini/skills directory
skillDir := filepath.Join(dir, ".gemini", "skills", "gemini-skill")
if err := os.MkdirAll(skillDir, 0o755); err != nil {
t.Fatalf("failed to create skill directory: %v", err)
}

skillContent := `---
name: gemini-skill
description: A skill for Gemini
---

# Gemini Skill

This is a skill for Gemini.
`
skillPath := filepath.Join(skillDir, "SKILL.md")
if err := os.WriteFile(skillPath, []byte(skillContent), 0o644); err != nil {
t.Fatalf("failed to create skill file: %v", err)
}
},
taskName: "test-task",
wantErr: false,
checkFunc: func(t *testing.T, result *Result) {
if len(result.Skills.Skills) != 1 {
t.Fatalf("expected 1 skill, got %d", len(result.Skills.Skills))
}
skill := result.Skills.Skills[0]
if skill.Name != "gemini-skill" {
t.Errorf("expected skill name 'gemini-skill', got %q", skill.Name)
}
},
Comment on lines +2598 to +2606
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test verification is incomplete compared to the existing .cursor/skills test. It should also verify the Description field and Location field to ensure the skill metadata is properly extracted and populated. The .cursor test at lines 2318-2323 checks both of these fields.

Copilot uses AI. Check for mistakes.
},
{
name: "discover skills from .codex/skills directory",
setup: func(t *testing.T, dir string) {
// Create task
createTask(t, dir, "test-task", "", "Test task content")

// Create skill in .codex/skills directory
skillDir := filepath.Join(dir, ".codex", "skills", "codex-skill")
if err := os.MkdirAll(skillDir, 0o755); err != nil {
t.Fatalf("failed to create skill directory: %v", err)
}

skillContent := `---
name: codex-skill
description: A skill for Codex
---

# Codex Skill

This is a skill for Codex.
`
skillPath := filepath.Join(skillDir, "SKILL.md")
if err := os.WriteFile(skillPath, []byte(skillContent), 0o644); err != nil {
t.Fatalf("failed to create skill file: %v", err)
}
},
taskName: "test-task",
wantErr: false,
checkFunc: func(t *testing.T, result *Result) {
if len(result.Skills.Skills) != 1 {
t.Fatalf("expected 1 skill, got %d", len(result.Skills.Skills))
}
skill := result.Skills.Skills[0]
if skill.Name != "codex-skill" {
t.Errorf("expected skill name 'codex-skill', got %q", skill.Name)
}
},
Comment on lines +2636 to +2644
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test verification is incomplete compared to the existing .cursor/skills test. It should also verify the Description field and Location field to ensure the skill metadata is properly extracted and populated. The .cursor test at lines 2318-2323 checks both of these fields.

Copilot uses AI. Check for mistakes.
},
Comment on lines +2380 to +2645
Copy link

Copilot AI Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is significant code duplication across all seven new test cases. According to the custom coding guideline, this project uses table-driven tests as the standard. Consider consolidating these similar test cases into a single table-driven test with different agent directories as parameters to reduce duplication and improve maintainability.

Copilot generated this review using guidance from repository custom instructions.
}

for _, tt := range tests {
Expand Down