Garbled skill data, when using multi-line syntax

Resolved 💬 8 comments Opened Nov 25, 2025 by bukzor Closed Feb 27, 2026

Bug Description

User-defined skill descriptions that use YAML multi-line literal blocks (| or >) are displayed as "| (user)" instead of showing the actual description text.

Steps to Reproduce

  1. Create a skill with multi-line description in ~/.claude/skills/example/SKILL.md:
---
name: example-skill
description: |
  This is a multi-line description.
  It should display properly.
---
  1. Run claude and invoke the Skill tool
  2. Observe the skill description shows as: | (user)

Expected Behavior

The full description text should be displayed:

This is a multi-line description. It should display properly. (user)

Root Cause

The frontmatter parser function qF() (line 286209 in bundled cli.js v2.0.51) is a hand-rolled YAML parser that doesn't handle multi-line literal blocks. It only parses single-line key: value pairs.

When it encounters description: |, it captures only the "|" character as the value, ignoring the subsequent indented lines.

Proposed Fix

Minimal patch to add multi-line block support while maintaining the existing minimalist parser approach:

function qF(A) {
    let Q = /^---\s*\n([\s\S]*?)---\s*\n?/,
        B = A.match(Q);
    if (!B) return {
        frontmatter: {},
        content: A
    };
    let G = B[1] || "",
        Z = A.slice(B[0].length),
        I = {},
        Y = G.split(`
`);
    let blockKey = null,
        blockLines = [];
    for (let J of Y) {
        if (blockKey !== null) {
            if (!J.match(/^\S/)) {
                blockLines.push(J.trim());
                continue;
            } else {
                I[blockKey] = blockLines.join("\n");
                blockKey = null;
                blockLines = [];
            }
        }
        let W = J.indexOf(":");
        if (W > 0) {
            let X = J.slice(0, W).trim(),
                F = J.slice(W + 1).trim();
            if (X) {
                if (F === "|" || F === ">") {
                    blockKey = X;
                    blockLines = [];
                    continue;
                }
                let V = F.replace(/^["']|["']$/g, "");
                I[X] = V
            }
        }
    }
    if (blockKey !== null) I[blockKey] = blockLines.join("\n");
    return {
        frontmatter: I,
        content: Z
    }
}

Changes:

  • Added blockKey and blockLines state to track multi-line blocks
  • Detect | or > as value and enter block collection mode
  • Collect subsequent indented lines until non-indented line found
  • Join collected lines and assign to the key

Tested with:

  • Multi-line literal blocks (|)
  • Folded blocks (>)
  • Single-line values (backward compatible)
  • Mixed frontmatter with both single and multi-line values

Version

  • @anthropic-ai/claude-code: 2.0.51
  • Node: v18+

Alternative Solution

Replace the hand-rolled parser with a proper YAML library like js-yaml, though this adds a dependency.

View original on GitHub ↗

This issue has 8 comments on GitHub. Read the full discussion on GitHub ↗