fix(coding-agent): ignore unknown skill frontmatter fields

This commit is contained in:
Mario Zechner 2026-02-04 14:20:24 +01:00
parent fcfbc82ec2
commit d0679dcfc0
5 changed files with 6 additions and 42 deletions

View file

@ -8,6 +8,7 @@
### Fixed
- Ignored unknown skill frontmatter fields when loading skills
- Fixed `/reload` not picking up changes in global settings.json ([#1241](https://github.com/badlogic/pi-mono/issues/1241))
- Fixed Unix bash detection to fall back to PATH lookup when `/bin/bash` is unavailable, including Termux setups ([#1230](https://github.com/badlogic/pi-mono/pull/1230) by [@VaclavSynacek](https://github.com/VaclavSynacek))

View file

@ -176,7 +176,8 @@ Pi validates skills against the Agent Skills standard. Most issues produce warni
- Name exceeds 64 characters or contains invalid characters
- Name starts/ends with hyphen or has consecutive hyphens
- Description exceeds 1024 characters
- Unknown frontmatter fields
Unknown frontmatter fields are ignored.
**Exception:** Skills with missing description are not loaded.

View file

@ -5,20 +5,6 @@ import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
import { parseFrontmatter } from "../utils/frontmatter.js";
import type { ResourceDiagnostic } from "./diagnostics.js";
/**
* Standard frontmatter fields per Agent Skills spec.
* See: https://agentskills.io/specification#frontmatter-required
*/
const ALLOWED_FRONTMATTER_FIELDS = new Set([
"name",
"description",
"license",
"compatibility",
"metadata",
"allowed-tools",
"disable-model-invocation",
]);
/** Max name length per spec */
const MAX_NAME_LENGTH = 64;
@ -91,19 +77,6 @@ function validateDescription(description: string | undefined): string[] {
return errors;
}
/**
* Check for unknown frontmatter fields.
*/
function validateFrontmatterFields(keys: string[]): string[] {
const errors: string[] = [];
for (const key of keys) {
if (!ALLOWED_FRONTMATTER_FIELDS.has(key)) {
errors.push(`unknown frontmatter field "${key}"`);
}
}
return errors;
}
export interface LoadSkillsFromDirOptions {
/** Directory to scan for skills */
dir: string;
@ -197,16 +170,9 @@ function loadSkillFromFile(
try {
const rawContent = readFileSync(filePath, "utf-8");
const { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);
const allKeys = Object.keys(frontmatter);
const skillDir = dirname(filePath);
const parentDirName = basename(skillDir);
// Validate frontmatter fields
const fieldErrors = validateFrontmatterFields(allKeys);
for (const error of fieldErrors) {
diagnostics.push({ type: "warning", message: error, path: filePath });
}
// Validate description
const descErrors = validateDescription(frontmatter.description);
for (const error of descErrors) {

View file

@ -65,19 +65,14 @@ describe("skills", () => {
expect(diagnostics.some((d: ResourceDiagnostic) => d.message.includes("description is required"))).toBe(true);
});
it("should warn when unknown frontmatter fields are present", () => {
it("should ignore unknown frontmatter fields", () => {
const { skills, diagnostics } = loadSkillsFromDir({
dir: join(fixturesDir, "unknown-field"),
source: "test",
});
expect(skills).toHaveLength(1);
expect(
diagnostics.some((d: ResourceDiagnostic) => d.message.includes('unknown frontmatter field "author"')),
).toBe(true);
expect(
diagnostics.some((d: ResourceDiagnostic) => d.message.includes('unknown frontmatter field "version"')),
).toBe(true);
expect(diagnostics).toHaveLength(0);
});
it("should load nested skills recursively", () => {