Skip to content

bug(skills): YAML block scalar descriptions (> / |) parsed as literal character instead of multiline text #4869

@yiliang114

Description

@yiliang114

What happened?

When a SKILL.md frontmatter uses YAML block scalar syntax for the description field:

---
name: my-skill
description: >
  This is a multiline folded
  description for the skill.
---

The description displays as the literal character > instead of the full multiline text.

Root cause

The custom YAML parser at packages/core/src/utils/yaml-parser.ts splits on the first : and takes the remainder as a plain string value (line 72-96). It has no handling for YAML block scalar indicators (>, >-, |, |-). The subsequent indented continuation lines are either misinterpreted as nested object keys or silently dropped.

The same parser is used in both skill loading paths:

  • packages/core/src/skills/skill-load.ts (extension skills)
  • packages/core/src/skills/skill-manager.ts (project/user/bundled skills)

skill-manager.ts already imports the full yaml npm package (v2.8.1) and uses it for hooks: parsing (lines 707-719), with the comment:

// Use full YAML parser for hooks as they have nested structures

But the description field still goes through the custom parser.

Expected behavior

Block scalar descriptions should be parsed correctly per the YAML 1.2 spec. Claude Code handles this correctly by using a full YAML parser (yaml npm v2.8.3+) for all frontmatter fields.

Suggested fix

Replace parseYaml(frontmatterYaml) with yaml.parse(frontmatterYaml) (the yaml npm package already installed) for all frontmatter fields, not just hooks:. This is a one-line change per call site and the downstream field access (frontmatter['description'], frontmatter['name'], etc.) stays identical since both return plain JS objects.

One thing to watch: the custom parser silently returns partial results on malformed YAML, while yaml.parse() throws. The existing try/catch in both skill-load.ts and skill-manager.ts already covers this, but worth verifying edge cases. A fallback to the simple parser on yaml.parse() failure preserves backward compatibility.

Reproduction

  1. Create a skill with block scalar description:
    ---
    name: test-multiline
    description: >
      This is a multiline
      description that should be folded.
    ---
    # Test skill body
  2. Load the skill in Qwen Code
  3. Check the skill picker — description shows > instead of the full text

Metadata

Metadata

Assignees

Labels

category/coreCore engine and logicpriority/P2Medium - Moderately impactful, noticeable problemscope/extensionsExtension configurationtype/bugSomething isn't working as expected

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions