description
the skills setup path builds SKILL.md frontmatter by hand (to match the release packaging output) instead of using yaml.safe_dump. the _quote helper wraps each value in a double-quoted yaml scalar but only escapes backslash and the quote:
def _quote(v):
escaped = v.replace("\\", "\\\\").replace('"', '\\"')
return f'"{escaped}"'
a double-quoted yaml scalar cannot carry a raw newline or a control character. so:
- a multiline (block-scalar)
description: in the command template is emitted with raw newlines inside the quoted scalar, and reparses with the newlines collapsed to spaces (silent corruption).
- a control character (U+0000–U+001F except tab/newline, or U+007F) makes the generated SKILL.md fail to load at all (
ReaderError: unacceptable character).
the description comes straight from the template frontmatter (frontmatter.get("description")), so any command whose description is a block scalar hits the multiline case.
this is the SKILL.md sibling of the toml escaping fixed in #3341 and the goose yaml issue #3382. affects TomlIntegration/skills path in src/specify_cli/integrations/base.py and the identical _quote in src/specify_cli/integrations/hermes/__init__.py.
repro (via any skills integration, e.g. hermes): a template with
---
description: |
first line
second line
---
produces a SKILL.md whose parsed description is "first line second line " instead of "first line\nsecond line\n".
note: i used an ai assistant to help investigate and write this up.
description
the skills setup path builds
SKILL.mdfrontmatter by hand (to match the release packaging output) instead of using yaml.safe_dump. the_quotehelper wraps each value in a double-quoted yaml scalar but only escapes backslash and the quote:a double-quoted yaml scalar cannot carry a raw newline or a control character. so:
description:in the command template is emitted with raw newlines inside the quoted scalar, and reparses with the newlines collapsed to spaces (silent corruption).ReaderError: unacceptable character).the description comes straight from the template frontmatter (
frontmatter.get("description")), so any command whose description is a block scalar hits the multiline case.this is the SKILL.md sibling of the toml escaping fixed in #3341 and the goose yaml issue #3382. affects
TomlIntegration/skills path insrc/specify_cli/integrations/base.pyand the identical_quoteinsrc/specify_cli/integrations/hermes/__init__.py.repro (via any skills integration, e.g. hermes): a template with
produces a SKILL.md whose parsed description is
"first line second line "instead of"first line\nsecond line\n".note: i used an ai assistant to help investigate and write this up.