fix(coding-agent): load nested markdown skills (#8255)

This commit is contained in:
Cristina Poncela Cubeiro 2026-08-17 19:59:55 +02:00 • committed by GitHub
parent 1c28f3032e
commit 5e11f65865
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 16 additions and 3 deletions

View file

@ -36,7 +36,7 @@ Pi loads skills from:
Discovery rules:
- In `~/.pi/agent/skills/` and `.pi/skills/`, direct root `.md` files are discovered as individual skills when they have valid skill frontmatter with a non-empty `description`
- In all skill locations, directories containing `SKILL.md` are discovered recursively
- In `~/.agents/skills/` and project `.agents/skills/`, root `.md` files are ignored
- In `~/.agents/skills/` and project `.agents/skills/`, root `.md` files are ignored, but nested `.md` files in grouping folders are discovered when they declare skill frontmatter
- Root Markdown files other than `SKILL.md` that do not look like skills are ignored silently
Disable discovery with `--no-skills` (explicit `--skill` paths still load).

View file

@ -397,7 +397,12 @@ function collectSkillEntries(
}
const relPath = toPosixPath(relative(root, fullPath));
if (mode === "pi" && dir === root && isFile && entry.name.endsWith(".md") && !ig.ignores(relPath)) {
const shouldIncludeMarkdownFile =
isFile &&
entry.name.endsWith(".md") &&
!ig.ignores(relPath) &&
((mode === "pi" && dir === root) || (mode === "agents" && dir !== root));
if (shouldIncludeMarkdownFile) {
entries.push(fullPath);
continue;
}

View file

@ -440,13 +440,19 @@ Content`,
expect(result.skills.some((r) => r.path === middleSkill && r.enabled)).toBe(true);
});
it("should ignore root markdown files in .agents/skills", async () => {
it("should ignore root markdown files in .agents/skills but discover nested markdown skills", async () => {
const agentsSkillsDir = join(tempDir, ".agents", "skills");
mkdirSync(join(agentsSkillsDir, "nested-skill"), { recursive: true });
mkdirSync(join(agentsSkillsDir, "third-party"), { recursive: true });
mkdirSync(join(agentsSkillsDir, "third-party", "vendor", "pack"), { recursive: true });
const rootSkill = join(agentsSkillsDir, "root-file.md");
const nestedSkill = join(agentsSkillsDir, "nested-skill", "SKILL.md");
const nestedMarkdownSkill = join(agentsSkillsDir, "third-party", "child-skill.md");
const deeplyNestedMarkdownSkill = join(agentsSkillsDir, "third-party", "vendor", "pack", "deep-skill.md");
writeFileSync(rootSkill, "---\nname: root-file\ndescription: Root markdown file\n---\n");
writeFileSync(nestedSkill, "---\nname: nested-skill\ndescription: Nested skill\n---\n");
writeFileSync(nestedMarkdownSkill, "---\nname: child-skill\ndescription: Nested markdown skill\n---\n");
writeFileSync(deeplyNestedMarkdownSkill, "---\nname: deep-skill\ndescription: Deep markdown skill\n---\n");
const pm = new DefaultPackageManager({
cwd: join(tempDir, "work"),
@ -458,6 +464,8 @@ Content`,
const result = await pm.resolve();
expect(result.skills.some((r) => r.path === rootSkill)).toBe(false);
expect(result.skills.some((r) => r.path === nestedSkill && r.enabled)).toBe(true);
expect(result.skills.some((r) => r.path === nestedMarkdownSkill && r.enabled)).toBe(true);
expect(result.skills.some((r) => r.path === deeplyNestedMarkdownSkill && r.enabled)).toBe(true);
});
it("should keep ~/.agents/skills user-scoped when cwd is under home in a non-git directory", async () => {