-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Problem
Currently skills, hooks, and other artifacts need to be uniquely named otherwise links break — when conflicts are detected, a plugin-name or hash prefix is appended to the artifact folder name. This only works for specific marketplaces where they follow unique naming standards.
This is fine for internal plugins since we control the naming. But doesn't work for public plugins like superpowers which have names conflicting with other plugins.
Current Behavior
When plugins are synced, skills are copied to client skill directories (e.g., .claude/skills/, .agents/skills/). The folder name on disk becomes the skill's identity — it's how clients discover and reference skills.
Current dedup logic (src/utils/skill-name-resolver.ts):
- No conflict → folder name as-is (e.g.,
coding-standards/) - Folder name conflicts across plugins →
{plugin}_{skill}(e.g.,plugin-a_coding-standards/) - Folder AND plugin name conflict →
{org}_{plugin}_{skill}(e.g.,acme_plugin-a_coding-standards/)
Why this breaks
Dedup only kicks in when there's a conflict. This means the same skill gets different names depending on what other plugins are installed:
- User installs
superpowersplugin → skill lands asbrainstorming/ - User installs another plugin that also has
brainstorming/→ both get renamed tosuperpowers_brainstorming/andother_brainstorming/
Any hardcoded references to brainstorming (in AGENTS.md, other skills, etc.) break silently when step 2 happens.
Proposed Solution: Always-Namespaced Mode
Add a config option to always prefix skill names with the plugin namespace, regardless of conflicts:
# workspace.yaml
skillNamespace: always # default: "auto" (current behavior)| Mode | Behavior |
|---|---|
auto (default) |
Current behavior — only prefix on conflict |
always |
Every skill gets {plugin}_{skill} naming |
Implementation Guide
Key files
| File | Change |
|---|---|
src/models/workspace-config.ts |
Add skillNamespace field to schema |
src/utils/skill-name-resolver.ts |
Add mode param to resolveSkillNames(), always-qualify path |
src/core/sync.ts |
Thread config through buildPluginSkillNameMaps() calls (~lines 1841 and 2220) |
tests/unit/utils/skill-name-resolver.test.ts |
Add always mode tests (existing tests cover current tiers) |
docs/src/content/docs/reference/configuration.mdx |
Document new option |
docs/src/content/docs/guides/plugins.mdx |
Update dedup section |
Implementation detail
In src/utils/skill-name-resolver.ts, add a mode parameter to resolveSkillNames(). When always, skip the "no conflict" fast path (line 90-101) and always qualify with plugin name.
Scope boundaries
- Skills that reference other skills by name in their content (e.g., "run the
brainstormingskill first") would still need to use the namespaced name. This is a documentation/convention problem, not a code problem. - The
{org}_{plugin}_{skill}tier 3 disambiguator is still needed even inalwaysmode if two plugins from different orgs have the same plugin name.
Related
- PR fix(sync): deduplicate repo skills and rename heading #339 fixed a separate issue: repository skills (discovered from workspace repos, embedded as an index in AGENTS.md) had duplicates. Those now deduplicate by picking a winner (
.agents/priority, then largest file). That is a different mechanism from plugin skill dedup — repo skills are pointers in an index, not copied files.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status