Plugin skill names with non-ASCII (e.g. Japanese) characters are sanitized to hyphens, causing identifier collisions and "Unknown skill" on Skill-tool invocation

Open 💬 0 comments Opened Jun 9, 2026 by ParkMasakazu

Summary

When a plugin bundles skills whose directory names (and SKILL.md frontmatter name) contain non-ASCII characters (Japanese, in our case), Claude Code generates the namespaced skill identifier by replacing each non-ASCII character with a single hyphen - while preserving ASCII characters. This produces two problems:

  1. Identifier collisions — every skill with the same number of non-ASCII characters collapses to the same identifier. In our plugin, all 13 two-character-named skills become the single identifier my-plugin:--.
  2. Unknown skill on Skill-tool invocation — the assistant calling the Skill tool with the actual name (my-plugin:残量) fails with Unknown skill: my-plugin:残量, because the registered identifier is the sanitized/collided my-plugin:--. The available-skills list injected into the model context likewise shows every such skill as the sanitized colliding name, making them indistinguishable to the model.

The same SKILL.md works correctly as a personal skill (~/.claude/skills/残量/SKILL.md, un-namespaced): typing /残量 resolves and runs. The defect is specific to the plugin namespacing path.

Environment

| Item | Value |
|---|---|
| Claude Code | 2.1.169 |
| Node | v24.11.1 |
| OS | macOS 26.5 (build 25F71) |
| Plugin source | local directory-type marketplace |
| Plugin | a plugin bundling ~23 skills under skills/<name>/SKILL.md |

Steps to reproduce

  1. Create a plugin with a directory-type marketplace.
  2. Add two or more skills whose directory names are non-ASCII and have the same character count, e.g.:
  • skills/残量/SKILL.md (frontmatter name: 残量)
  • skills/改善/SKILL.md (frontmatter name: 改善)
  1. Install/enable the plugin (claude plugin install ...) and start a session.
  2. Inspect the available skills, and have the assistant attempt Skill("my-plugin:残量").

Observed behavior

  • In the available-skills list, the skills appear under sanitized, colliding identifiers. Each non-ASCII char → one -, ASCII preserved. Actual examples observed in our plugin (raphael-skills):
  • 残量 / 改善 / 調査 (2 chars) → raphael-skills:--
  • マージ (3) → raphael-skills:---
  • コミット / 要件定義 (4) → raphael-skills:----
  • E2Eテスト (E2E + テスト) → raphael-skills:E2E---
  • PRP仕様書 (PRP + 仕様書) → raphael-skills:PRP---
  • Assistant Skill-tool call Skill("raphael-skills:残量")Unknown skill: raphael-skills:残量.
  • A user typing the slash form /raphael-skills:-- does resolve (the slash menu disambiguates by description) and loads the intended skill — confirming the registered command name is the sanitized --, not the original 残量.

Expected behavior

  • The namespaced identifier should preserve the skill's (Unicode) name, e.g. raphael-skills:残量, consistent with how personal skills already behave (~/.claude/skills/残量//残量 works).
  • The model-facing identifier and the actually-invokable name must match.
  • If sanitization is intentional, it must be collision-free and documented.

Impact

  • Plugins localized with non-ASCII skill names are effectively un-invocable by name: the assistant cannot call them (Unknown skill), and multiple skills become indistinguishable in both the identifier and the model-facing list.
  • Inconsistency: identical SKILL.md content works as a personal skill but breaks as a plugin skill.

Docs reference

  • "How a skill gets its command name" (code.claude.com/docs/en/skills): plugin skills/ subdirectory command name = directory name, namespaced by plugin. There is no documented mention of non-ASCII sanitization.
  • Plugin manifest schema (code.claude.com/docs/en/plugins-reference): the plugin name is described as "Unique identifier (kebab-case, no spaces)" — this constrains the plugin name, and does not state that skill names must be ASCII or that non-ASCII is prohibited.

Possibly related (not confirmed same root cause)

  • #14873 — UTF-8 multi-byte handling in skill descriptions
  • #34144 — plugin skill slash commands return Unknown skill under certain config

Suggested fix direction

Either preserve Unicode in the generated namespaced identifier, or apply a documented, collision-free transliteration; in all cases ensure parity with personal-skill resolution and that the model-facing identifier equals the invokable name.

View original on GitHub ↗