claude-code - 💡(How to fix) Fix Cowork plugin upload: SKILL.md frontmatter angle brackets silently fail validation

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Cowork's .plugin bundle upload (Directory → Plugins → Personal → Add plugin) rejects bundles with Plugin validation failed whenever any SKILL.md YAML frontmatter contains literal angle brackets in a quoted string — even when:

  • The bundle passes claude plugin validate locally.
  • The YAML parses correctly with every standard parser.
  • The same bundle structure (sans the offending bracket pair) installs cleanly.

The rejection is silent in ~/Library/Logs/Claude/main.log (only the request shows, no response error) and in claude.ai-web.log (no MARKETPLACE_ERROR:* entry, unlike marketplace-sync failures which return per-plugin detail). The UI surfaces only Plugin validation failed with no further information.

Error Message

The rejection is silent in ~/Library/Logs/Claude/main.log (only the request shows, no response error) and in claude.ai-web.log (no MARKETPLACE_ERROR:* entry, unlike marketplace-sync failures which return per-plugin detail). The UI surfaces only Plugin validation failed with no further information.

  1. Surface the actual server-side rejection reason in either the UI or the local upload log. The marketplace-sync path already does this (per-plugin error array); the bundle-upload path does not.

Root Cause

Cowork's .plugin bundle upload (Directory → Plugins → Personal → Add plugin) rejects bundles with Plugin validation failed whenever any SKILL.md YAML frontmatter contains literal angle brackets in a quoted string — even when:

  • The bundle passes claude plugin validate locally.
  • The YAML parses correctly with every standard parser.
  • The same bundle structure (sans the offending bracket pair) installs cleanly.

The rejection is silent in ~/Library/Logs/Claude/main.log (only the request shows, no response error) and in claude.ai-web.log (no MARKETPLACE_ERROR:* entry, unlike marketplace-sync failures which return per-plugin detail). The UI surfaces only Plugin validation failed with no further information.

Code Example

---
   name: site-setup
   description: >-
     Triggers on \"add site\", \"configure site\", \"add <domain> to wp-tools\",
     or any onboarding request.
   ---
RAW_BUFFERClick to expand / collapse

Summary

Cowork's .plugin bundle upload (Directory → Plugins → Personal → Add plugin) rejects bundles with Plugin validation failed whenever any SKILL.md YAML frontmatter contains literal angle brackets in a quoted string — even when:

  • The bundle passes claude plugin validate locally.
  • The YAML parses correctly with every standard parser.
  • The same bundle structure (sans the offending bracket pair) installs cleanly.

The rejection is silent in ~/Library/Logs/Claude/main.log (only the request shows, no response error) and in claude.ai-web.log (no MARKETPLACE_ERROR:* entry, unlike marketplace-sync failures which return per-plugin detail). The UI surfaces only Plugin validation failed with no further information.

Reproduction

  1. Create a minimal plugin with name: wp-tools (or any name), one skill, and this frontmatter:

    ---
    name: site-setup
    description: >-
      Triggers on \"add site\", \"configure site\", \"add <domain> to wp-tools\",
      or any onboarding request.
    ---
  2. Zip into a .plugin bundle and upload via Cowork's "Add plugin" UI.

  3. Receive Plugin validation failed. No local log detail.

Remove the <domain> substring (or any other <word>-style placeholder in a quoted YAML value) and the same bundle installs cleanly.

Diagnosis

Binary-searched a real wp-tools bundle (5 skills) over ~8 incremental builds. Isolated the failure to a single SKILL.md frontmatter, then to the frontmatter (not the body), then to a single character pair (< and >).

The placeholder <domain> is a common pattern when describing trigger phrases for skills (matches the convention used throughout Anthropic's own skill examples for arguments like <filename>, <path>, etc.). Plugin authors writing SKILL.md descriptions are likely to hit this.

The probable cause is a server-side validator running the frontmatter through HTML-aware sanitization that treats <word> as an unclosed tag. The fact that the rejection is silent makes the bug particularly hard to discover.

What would help

  1. Surface the actual server-side rejection reason in either the UI or the local upload log. The marketplace-sync path already does this (per-plugin error array); the bundle-upload path does not.
  2. Don't HTML-sanitize YAML string values — they are not HTML.
  3. At minimum, document the restriction in plugins-reference under SKILL.md frontmatter conventions.

Environment

  • Claude Desktop (macOS), Cowork
  • Bundle built via the documented zip-the-plugin-root convention; same build script produces other plugins that upload fine.
  • Both private-repo and brand-new-name plugins exhibit the behavior; ruled out via incremental binary search.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix Cowork plugin upload: SKILL.md frontmatter angle brackets silently fail validation