claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

Garbled skill data, when using multi-line syntax

Open bukzor opened this issue 1 month ago • 2 comments

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.

bukzor avatar Nov 25 '25 01:11 bukzor

Holy crap, this is a FANTASTIC bug report. Clear repro, root cause identified, patch provided, test cases included. This is what dreams are made of. 🏆

Validation Results

I tested your patch because I'm paranoid, and yeah, it works perfectly:

What you fixed:

  • ✅ Multi-line YAML blocks (| and >) now parse correctly
  • ✅ Backward compatible with single-line values
  • ✅ Handles empty blocks without exploding
  • ✅ Multiple multi-line keys in same file? No problem.

Edge cases I threw at it:

description: |
  Line 1
    Weird indentation
  Line 3

✅ Survived

description: |
examples: |
  Both multi-line

✅ Also survived

Current behavior (without your patch):

description: "| (user)"  # lmao what

This makes skills look like someone had a stroke mid-YAML.

The Real Question

Why is there a hand-rolled YAML parser in 2025? I get it - zero dependencies is cool and all - but this is like bringing a spoon to a knife fight. That said, your patch fixes it with like 15 lines, so... respect.

Recommendation: Merge this immediately. It's embarrassing that skill descriptions show | (user) right now.

Alternative: Bite the bullet and use js-yaml, but that's a bigger conversation about whether "no dependencies" is worth maintaining a YAML parser that only works sometimes.

Either way, this needs to ship. Like, yesterday.

+1 from me, and thanks for doing the team's homework. 🙏

JuanCS-Dev avatar Nov 25 '25 12:11 JuanCS-Dev

Holy crap, this is a FANTASTIC bug report.

Claude wrote it :) with my oversight.

Recommendation: Merge this immediately.

Except there's no PR, because it's closed-source (hint hint nudge nudge).

bukzor avatar Dec 04 '25 21:12 bukzor

Also confirming this occurs with the >- (folded block, strip final newlines) syntax:

description: >-
  Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI,
  AI responds with @{your-name}. Use /comments check to address markers...

Displays as >- instead of the parsed text.

Workaround: Use single-line quoted descriptions:

description: "Enable inline conversations using @droid/@user markers. Tag @droid to ask the AI, AI responds with @{your-name}..."

frytyler avatar Dec 15 '25 16:12 frytyler

See also #14064 (closed as duplicate of this issue).

frytyler avatar Dec 15 '25 16:12 frytyler