Handwritten SKILL.md parser misreads valid YAML
A skill-pack developer found that a zero-dependency parser for SKILL.md frontmatter mishandled several valid YAML forms, including folded descriptions, single-quoted strings, trailing comments, and nested metadata keys. Compared with js-yaml 4.3.2 on Node 20.19.2, the parser could silently replace a skill’s trigger description with a nested value. Proposed changes explicitly reject multiline scalars, correctly handle quoted values and comments, ignore nested keys, and tighten metadata validation.
The reproduced failures affect skill installation across Claude Code, Cursor, Trae, and Codex, showing how a small frontmatter parser can misconfigure an AI coding tool without an obvious error.
我有个给毕业设计写论文用的技能包,一份 SKILL.md 能装给 Claude Code、Cursor、Trae、Codex 四个工具。安装脚本零依赖,读 SKILL.md 头部的 frontmatter 是自己写的二十来行代码。之前写过输出那一侧:拼回 YAML 时要转义。这次看的是读入这一侧:别人照着 YAML 的正常写法写一个技能,我的解析器能不能读对。
结论是有好几种合法的 YAML 写法会被读错,而且校验脚本 check.js 有时候拦下了、但报的原因不对,有时候干脆放过去了。下面所有结果都是我在 Node 20.19.2 上实际跑出来的,对照用的是 js-yaml 4.3.2。
解析器长什么样
function unquote(v) {
if (/^".*"$/.test(v)) { try { return JSON.parse(v) } catch { return v.slice(1, -1) } }
return v
}
function parseSkill(file) {
const raw = fs.readFileSync(file, 'utf8').replace(/\r\n/g, '\n')
const m = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/)
const meta = {}
if (m) for (const line of m[1].split('\n')) {
const i = line.indexOf(':')
if (i > 0) meta[line.slice(0, i).trim()] = unquote(line.slice(i + 1).trim())
}
return { meta, body: m ? m[2] : raw }
}