[BUG] parse-frontmatter.sh returns body content as frontmatter when the markdown body contains ---
Preflight
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
Description
The two scripts in plugins/plugin-dev/skills/plugin-settings/scripts/ both pull frontmatter out with sed -n '/^---$/,/^---$/{ /^---$/d; p; }'.
A sed range reopens every time the start pattern matches again, so any --- further down the file starts a second range. Put a horizontal rule in the body of a settings file and whatever follows it gets treated as frontmatter.
I hit this because my settings file had a --- separator in the docs section under the frontmatter, and the plugin kept coming up disabled even though enabled: true was right there at the top.
Steps to Reproduce
.claude/my-plugin.local.md:
---
enabled: true
---
# My Plugin
---
## Config reference
enabled: false
Then run the parser the way its own --help shows:
$ ./plugins/plugin-dev/skills/plugin-settings/scripts/parse-frontmatter.sh .claude/my-plugin.local.md enabled
true
false
Expected
true. Frontmatter is the block between the first two --- markers, so the enabled: false in the config docs shouldn't be part of it.
Actual
Two lines. And since the help text tells you to use it like this:
ENABLED=$(./parse-frontmatter.sh .claude/my-plugin.local.md enabled)
if [ "$ENABLED" = "true" ]; then
the test compares against "true\nfalse", fails, and you get the disabled path with nothing printed to tell you why. That's what cost me the debugging time — it doesn't error, it just answers wrong.
Other things I ran into in the same two files
parse-frontmatter.sh:
enabled: falseerrors withField 'enabled' not found. The not-found check is[ -z "$VALUE" ], which can't tell a missing key from one whose value is empty orfalse.- The field name goes straight into a
greppattern, so a key likemy.fieldwill match a similarly-named key instead. - If the closing
---is missing, the range just runs to EOF and the whole file comes back as frontmatter. No error.
validate-settings.sh:
- Check 3 counts
---anywhere in the file and passes if there are 2+. A file with no frontmatter at all but two horizontal rules in the body validates fine. - Check 7 reads the leaked multi-line value, so a file with a plain
enabled: truegets warned that it "should be boolean (true/false)". - Check 8 skips every
---when finding the body, so horizontal rules get dropped and the "body present (N lines)" count comes out short.
Environment
Repo at main (ab9b2cf). This is in the scripts themselves, so it isn't tied to a particular CLI version.
Fix
Branch: https://github.com/Sagexd08/claude-code/tree/fix/parse-frontmatter-range
Requires the opening --- on line 1 and quits at the closing one, so nothing from the body can get in. Also takes the first match for a key rather than all of them, checks whether the key exists before stripping the value off, and matches key names literally instead of as a regex.
Cases I checked, including the ones that already worked, to make sure nothing regressed: body containing a --- rule, enabled: false, empty value, single and double quoted values, a key with a . in it, no frontmatter, unterminated frontmatter, a no-frontmatter file with two body rules, and a valid file with a body rule. Both scripts pass bash -n and still read the repo's own SKILL.md files (plugin-settings and hookify/writing-rules) correctly. Files with no --- in the body behave the same as before.
I would have sent this as a PR but POST /repos/anthropics/claude-code/pulls gives me a 404 from a fork right now, so the branch is there if someone wants to pull it in, or I can open a PR if external ones get turned back on.