Skip to content

fix(skills): match closing frontmatter delimiter on its own line - #3739

Open
Quratulain-bilal wants to merge 2 commits into
github:mainfrom
Quratulain-bilal:fix/skill-setup-frontmatter-dashes
Open

fix(skills): match closing frontmatter delimiter on its own line#3739
Quratulain-bilal wants to merge 2 commits into
github:mainfrom
Quratulain-bilal:fix/skill-setup-frontmatter-dashes

Conversation

@Quratulain-bilal

Copy link
Copy Markdown
Contributor

Problem

SkillsIntegration.setup parses each command template's frontmatter with raw.split("---", 2). A bare substring split stops at the first --- anywhere — including one embedded inside a value. A template whose description contains ---, e.g.

---
description: Separate sections with --- markers
name-marker: sentinel
---
Body of the command.

is mis-parsed three ways:

  • the description is truncated to Separate sections with (or dropped entirely, falling back to the generic Spec Kit: <name> workflow);
  • every frontmatter key after the embedded marker is silently lost;
  • the leftover frontmatter spills into the installed skill body.

Fix

Locate the closing --- on its own line (line-anchored scan) for both the description parse and the body strip, mirroring the hardened CommandRegistrar.parse_frontmatter scan.

  • The frontmatter block is parsed unstripped, so trailing newlines in literal (|) block scalars still survive.
  • The body slice keeps the newline after the marker, so output stays byte-for-byte identical to the old split("---", 2)[2] for well-formed templates (verified with a differential check across normal / empty-body / trailing-space cases).

Tests

Adds TestSkillFrontmatterEmbeddedDashes covering the dashed-description truncation and the frontmatter-spilled-into-body cases. Both fail on the pre-fix code and pass after. Full skills integration suite: 342 passed, 3 skipped, 0 failures.

SkillsIntegration.setup parsed each command template's frontmatter with
raw.split("---", 2). A bare substring split stops at the first `---`
*anywhere*, so a template whose description embeds `---` (e.g.
"Separate sections with --- markers") truncated the parsed frontmatter:
later keys were dropped, the description fell back to the generic default,
and the leftover frontmatter spilled into the skill body.

Scan for the closing `---` on its own line instead, for both the
description parse and the body strip. The frontmatter block is parsed
unstripped so trailing newlines in literal (|) block scalars still survive,
and the body slice keeps the newline after the marker so output stays
byte-for-byte identical to the old split for well-formed templates.

Adds regression tests covering the dashed-description truncation and the
frontmatter-spilled-into-body cases.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Hardens skills frontmatter parsing so embedded --- values do not truncate metadata or spill into the body.

Changes:

  • Adds line-anchored closing-delimiter detection.
  • Adds regression tests for dashed descriptions and body integrity.
Show a summary per file
File Description
src/specify_cli/integrations/base.py Hardens skills frontmatter parsing and stripping.
tests/integrations/test_skill_frontmatter_quoting.py Tests embedded-dash handling.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment on lines +1640 to +1644
fm_close = next(
(
i
for i in range(1, len(fm_lines))
if fm_lines[i].rstrip() == "---"
if fm_close is not None:
try:
fm = yaml.safe_load(parts[1])
fm = yaml.safe_load("".join(fm_lines[1:fm_close]))

@mnriem mnriem left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address Copilot feedback

Hermes overrides SkillsIntegration.setup() with its own copy of the
frontmatter parse and body strip, and Kimi's _is_speckit_generated_skill()
parses frontmatter independently, so all three carried the same
split("---", 2) bug the base class just fixed. A description such as
"Separate sections with --- markers" truncates the parsed frontmatter at the
embedded marker, dropping later keys and spilling the remainder into the
body; for Kimi that means a Speckit-generated skill is no longer recognized
on teardown and gets left behind.

Scan for a closing "---" on its own line instead. The body slice keeps
whatever trails the marker so output stays byte-for-byte identical for
well-formed templates.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants