Skip to content

Garbled skill data, when using multi-line syntax #12313

@bukzor

Description

@bukzor

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:corebugSomething isn't workingduplicateThis issue or pull request already existshas reproHas detailed reproduction steps

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions