fix(server): recover skill frontmatter Claude Code itself accepts - #7814
fix(server): recover skill frontmatter Claude Code itself accepts#7814Exotic209093 wants to merge 3 commits into
Conversation
parseSkillFrontmatter strict-YAML-parsed SKILL.md frontmatter and dropped the entry entirely on any parse failure. Claude Code's own frontmatter parser is more lenient: an unquoted description containing a "word: " sequence (e.g. a URL or clause with a colon) is valid there but strict YAML rejects it as an ambiguous nested mapping. A skill that demonstrably loads in Claude Code was invisible in T3's own scanner. Add a fallback that recovers name/description as flat "key: value" scalars when strict parsing fails, but only when the value doesn't look like broken YAML syntax (an unterminated flow collection, block scalar, anchor, alias, or tag) — those still count as malformed, matching existing behavior for frontmatter Claude Code wouldn't load either. Fixes pingdotgg#7757
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f97d0d156e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Straightforward bug fix that adds lenient fallback parsing for skill frontmatter when strict YAML fails, ensuring T3 discovers the same skills Claude Code accepts. Limited scope, defensive implementation that rejects real YAML errors, and comprehensive test coverage for edge cases. You can add or adjust custom eligibility rules. Learn more. |
Both Macroscope and Codex caught a real gap in the lenient fallback: it recovered name/description per-line independently, so a document with one genuinely broken field (e.g. name: [unclosed) alongside a fine one (description: ...) surfaced the skill anyway with the broken field silently dropped — exactly the case the fallback was supposed to exclude, since Claude Code wouldn't load that file at all. A broken line in a field this scanner doesn't even read had the same gap. Any top-level line whose value looks like broken YAML structure now fails the whole document as malformed, regardless of which field it's in, before recovering name/description from the rest.
|
Good catch, both of you — the per-line recovery was independent per field, so a document with one genuinely broken line (in a recognized field or not) alongside a fine one still surfaced the skill with the broken bit silently dropped, exactly the case this was supposed to exclude. Fixed: any top-level line with broken-looking YAML structure now fails the whole document as malformed before recovering anything, regardless of which field it's in. Added regression tests for both scenarios. |
… rules Macroscope caught a real gap: the lenient fallback copied everything after the colon verbatim, so "name: demo # display label" recovered as "demo # display label" instead of "demo" — no comment stripping, no quote-escape handling. Parse the isolated value with the real YAML parser instead of manual trimming. This also keeps the one case the fallback exists for working correctly: an unquoted value with its own embedded ": " parses as a one-entry mapping in isolation (not a string), so it falls through to the untouched raw text exactly as before.
|
Good catch — the fallback was copying everything after the colon verbatim, so a trailing YAML comment or quote escaping wasn't handled. Switched to parsing the isolated value with the real YAML parser: it strips comments and unescapes quotes correctly, and the one case this fallback exists for (an unquoted value with its own embedded ": ") still parses as a one-entry mapping in isolation, not a string, so it correctly falls through to the raw text as before. |
Summary
Fixes #7757.
parseSkillFrontmatterinapps/server/src/provider/Drivers/ClaudeSkills.tsstrict-YAML-parses eachSKILL.md's frontmatter and drops the entry entirely on any parse error. Claude Code's own frontmatter parser is more lenient: an unquoted scalar description containing aword:sequence (e.g.description: ... via kane-cli: run browser objectives, ...) is valid there, but strict YAML rejects it as an ambiguous nested mapping (mapping values are not allowed here). A skill that demonstrably loads and works in Claude Code was invisible in T3's own scanner and the$picker — the same cache snapshot showed the contradiction directly: the skill appeared inslashCommands(from the CLI's own probe) whileskillsstayed[].Fix
When strict YAML parsing fails, fall back to recovering
name/descriptionas flatkey: valuescalars — the only two fields this scanner reads — instead of dropping the skill. The fallback only kicks in per-line for top-level, unindented keys, and explicitly still treats a value as malformed if it looks like it was attempting real YAML structure that broke (starts with[,{,|,>,&,*, or!— an unterminated flow collection, block scalar, anchor, alias, or tag). That keeps the existing "genuinely broken YAML" behavior intact (e.g.name: [unclosedstill gets dropped, matching Claude Code, which wouldn't load that either) while recovering the specific leniency gap the issue reports.Test plan
kane-clifrontmatter from the issue; confirmed it fails before the fix (dropped as malformed) and passes after (recovered with the correct name/description).vp test run apps/server/src/provider/Drivers/ClaudeSkills.test.ts— 10 passed, including the existing malformed-YAML test (name: [unclosed) which still correctly drops the skill.vp run --filter t3 typecheck— clean (only pre-existing, unrelated suggestions in other files).vp linton changed files — clean.Note
Low Risk
Parser fallback is limited to two scalar skill fields and still drops structurally broken YAML. No auth, data, or API surface changes.
Overview
Skills that Claude Code loads but T3 dropped as malformed YAML now show up in discovery (and the
$picker).When strict YAML parse fails,
parseSkillFrontmatterfalls back to reading top-levelname/descriptionas flatkey: valuescalars. That covers unquoted descriptions with a colon (e.g.via kane-cli: run ...). Values that look like broken YAML structure ([,{,|,>,&,*,!) still count as malformed and are skipped.Adds a regression test for the
kane-clifrontmatter from the issue.Reviewed by Cursor Bugbot for commit f97d0d1. Configure here.
Note
Recover skill frontmatter that
ClaudeCodeaccepts but strict YAML rejectsAdds a lenient fallback to
parseSkillFrontmatterso that when strict YAML parsing fails, it still recoversnameanddescriptionfrom flatkey: valuescalars. Values starting with YAML structural tokens ([,{,|, etc.) are rejected to avoid misinterpreting real structure as plain scalars, and trailing# commentsare stripped.namefields that cause the whole skill to be skipped.{kind: 'malformed'}for structurally broken values, so previously-rejected skills are the only ones affected.Macroscope summarized 98a98ba.