Description
sanitize() in packages/core/src/config/markdown.ts exists so that "other coding agents accept unquoted colons in frontmatter values" keep working (comment on line 20). But its key pattern is:
const entry = line.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.*)$/)
The character class has no -, so any hyphenated key fails to match, hits if (!entry) return [line], and is returned unsanitized. The retry matter(sanitize(content)) then throws exactly as the first attempt did.
This is unfortunate because allowed-tools is the single most common such key in other agents' command files - precisely the compatibility case the function was written for (see #6985 for .claude/commands/ compatibility).
Steps to reproduce
.opencode/command/review.md:
---
allowed-tools: Read: every file
description: Review helper
---
Review my code.
Actual - ConfigMarkdown.parse() throws Failed to parse YAML frontmatter: incomplete explicit mapping pair. Via parseOption() the error is swallowed and the whole frontmatter block leaks into the body:
data: {}
content: "---
allowed-tools: Read: every file
description: Review helper
---
Review my code."
Expected:
data: { "allowed-tools": "Read: every file", "description": "Review helper" }
content: "Review my code."
An underscore key is the control case and works fine - allowed_tools: Read: every file sanitizes correctly. Dotted keys (tools.read:) fail the same way as hyphenated ones.
Impact
Since parseOption() swallows the error and decode still returns a structurally valid object, the failure is silent:
- Commands (
config/plugin/command.ts:71) run with the raw YAML header, --- delimiters and all, pasted into the prompt sent to the model.
- Agents (
config/plugin/agent.ts:154) lose description, mode, model, steps and permissions entirely, and system becomes the raw file.
- Skills (
skill.ts:84) go through the same path.
OS
Windows (platform-independent - pure regex logic)
Description
sanitize()inpackages/core/src/config/markdown.tsexists so that "other coding agents accept unquoted colons in frontmatter values" keep working (comment on line 20). But its key pattern is:The character class has no
-, so any hyphenated key fails to match, hitsif (!entry) return [line], and is returned unsanitized. The retrymatter(sanitize(content))then throws exactly as the first attempt did.This is unfortunate because
allowed-toolsis the single most common such key in other agents' command files - precisely the compatibility case the function was written for (see #6985 for.claude/commands/compatibility).Steps to reproduce
.opencode/command/review.md:Actual -
ConfigMarkdown.parse()throwsFailed to parse YAML frontmatter: incomplete explicit mapping pair. ViaparseOption()the error is swallowed and the whole frontmatter block leaks into the body:Expected:
An underscore key is the control case and works fine -
allowed_tools: Read: every filesanitizes correctly. Dotted keys (tools.read:) fail the same way as hyphenated ones.Impact
Since
parseOption()swallows the error anddecodestill returns a structurally valid object, the failure is silent:config/plugin/command.ts:71) run with the raw YAML header,---delimiters and all, pasted into the prompt sent to the model.config/plugin/agent.ts:154) losedescription,mode,model,stepsandpermissionsentirely, andsystembecomes the raw file.skill.ts:84) go through the same path.OS
Windows (platform-independent - pure regex logic)