Skip to content

fix(agents): parse frontmatter on the --- delimiter line, not any --- substring#3590

Open
chuenchen309 wants to merge 1 commit into
github:mainfrom
chuenchen309:fix/parse-frontmatter-delimiter-line
Open

fix(agents): parse frontmatter on the --- delimiter line, not any --- substring#3590
chuenchen309 wants to merge 1 commit into
github:mainfrom
chuenchen309:fix/parse-frontmatter-delimiter-line

Conversation

@chuenchen309

Copy link
Copy Markdown
Contributor

Description

CommandRegistrar.parse_frontmatter finds the closing frontmatter delimiter with content.find("---", 3) — a raw substring search (src/specify_cli/agents.py). It stops at the first --- anywhere after the opening, including one embedded in a frontmatter value or inside an indented YAML literal block, rather than a --- that occupies its own line (the actual YAML document-separator).

Any command source file whose frontmatter contains --- in a value gets a corrupted description and a corrupted body written into the generated agent files, silently:

from specify_cli.agents import CommandRegistrar

content = """---
description: Separate sections with --- markers
argument-hint: "[name]"
---
Real body starts here.
"""
CommandRegistrar.parse_frontmatter(content)
  • Before: frontmatter {'description': 'Separate sections with'} — description truncated, argument-hint silently dropped, and the rest (markers\nargument-hint: ...\n---\n...) spills into the body.
  • After: {'description': 'Separate sections with --- markers', 'argument-hint': '[name]'} and body Real body starts here.

The sibling frontmatter handler in this codebase, VibeIntegration._inject_frontmatter_flag (src/specify_cli/integrations/vibe/__init__.py), already scans for a line-anchored ---; parse_frontmatter was the only frontmatter reader using a substring find. This change makes them consistent. parse_frontmatter is called before rendering every command into each agent's directory (register_commands, extensions, and preset/core commands), so the fix covers all of those paths.

Testing

  • uv sync && uv run pytesttests/test_extensions.py + tests/test_presets.py724 passed; no regression.
  • Added test_parse_frontmatter_dash_in_value (in TestParseFrontmatter), which fails on main (assert 'Separate sections with' == '...--- markers') and passes with the fix.
  • ruff check src/specify_cli/agents.py → clean.
  • Also verified the standard, no-frontmatter, unterminated-frontmatter, and indented-literal-block cases still behave correctly.

AI Disclosure

  • No AI tools were used in preparing this PR.
  • AI tools were used — this change was authored by an AI coding agent (Claude Code / Claude Opus 4.8) running on this account: it found the bug, wrote the repro, wrote the test, and drafted this description. The human account holder reviews every change and is accountable for it. The verification above is real and re-runnable from the diff. If this isn't the kind of contribution you want, say so and I'll close it.

… substring

CommandRegistrar.parse_frontmatter located the closing delimiter with
content.find("---", 3), a raw substring search. It stopped at the first
"---" anywhere after the opening — including one embedded in a
frontmatter value (e.g. a description "Separate sections with ---
markers") or inside an indented literal block — which truncated the
frontmatter and spilled the remainder into the body, silently corrupting
both the parsed metadata and the rendered command body.

Match the closing "---" on line boundaries, mirroring the line-anchored
scan already used by VibeIntegration._inject_frontmatter_flag.
@chuenchen309
chuenchen309 requested a review from mnriem as a code owner July 19, 2026 08:09
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.

1 participant