DEV Community

Dibyanshu kumar
Dibyanshu kumar

Posted on

Why I Built a Centralized Skill Registry Instead of Using Claude Code Plugins

Why I Built a Centralized Skill Registry Instead of Using Claude Code Plugins

Claude Code has a plugin system. It's well-designed — namespaced skills, marketplace distribution, versioned releases. So why did I build my own centralized skill management layer on top of plain .claude/skills/ directories?

Because plugins solve the distribution problem. I needed to solve the coordination problem.

The Setup

I work across multiple repos — different tech stacks, different teams, different build systems. Each repo needs Claude Code skills tailored to its architecture: how to run tests, how to structure PRs, what patterns to follow in code review.

At first, I copied skill files into each repo's .claude/skills/ directory. Within a week, the copies drifted. I'd fix a bug in one repo's /review-pr skill and forget to propagate it. Worse, some skills — like /develop (a 12-phase Jira-to-PR orchestrator) — span 16 files and 4,000+ lines. Copy-pasting that across repos was not sustainable.

Why Not Plugins?

Claude Code plugins were the obvious answer. They're designed for exactly this: package skills into a distributable unit, install across projects. But when I evaluated them against my requirements, several gaps emerged.

1. Namespacing Adds Friction to Muscle Memory

Plugin skills are namespaced: /my-plugin:develop instead of /develop. This is a good design decision for preventing conflicts in the ecosystem, but when you're the sole consumer of your skills across your own repos, the namespace is overhead. I want to type /develop PROJ-123 everywhere, not /my-plugin:develop PROJ-123.

Standalone .claude/skills/ directories give you bare /skill-name invocations. I wanted that simplicity and centralized management.

2. No Built-in Multi-Repo Coordination

Plugins are install-and-forget — you install them per project and they work independently. But my workflow requires cross-repo awareness. When a Jira ticket comes in, I need to figure out which repo it belongs to before executing any skill.

I built a /dispatch skill that scores Jira tickets against a registry of projects using weighted signals:

  • Component match: +10 points
  • Label match: +5 points
  • Keyword match: +2 points (capped at +10)

If the top score is >= 10 and >= 2x the runner-up, it auto-routes. Otherwise, it asks the user. Plugins have no concept of this — they don't know about other repos or how to route work between them.

3. Per-Project Configuration Without Forking

Each repo has different thresholds for when a PR gets a full multi-agent review vs. a quick single-agent pass. Different build commands. Different branch naming conventions. Different default branches.

Plugins handle this with plugin-level settings.json, but that configuration lives inside the plugin. If two repos need different thresholds for the same skill, you'd need either:

  • Two separate plugins (defeats the purpose of sharing)
  • Configuration logic inside the skill that reads from some external source

I went with the second approach directly: a registry.json that stores per-project metadata, and a config.json per project profile that tunes skill behavior. The skills are shared; the configuration is project-specific. The central repo has a directory per project profile, each with its own skills, agents, and config. A top-level dispatch/ skill handles cross-repo routing.

4. Symlinks > Install Cycles

When I update a skill, the change should be live immediately in every repo. No reinstall, no version bump, no marketplace push.

Symlinks do this. Each project's .claude/skills directory is a symlink pointing to the corresponding profile in the central repo. Edit a skill file in the central repo, and every project sees it instantly. This is critical during active development — when I'm iterating on a skill, I don't want a publish-install cycle between each test.

Plugins require either re-running --plugin-dir or doing /reload-plugins. With symlinks and --add-dir, Claude Code's live change detection picks up edits automatically.

5. The Registry as a Metadata Layer

The real power isn't just shared skills — it's the registry.json that sits above them. Each project entry contains its repo path, profile directory, tech stack, Jira routing signals (components, keywords, labels), available skills, and build commands. This enables:

  • Dynamic routing: /dispatch reads the registry to score and route tickets
  • Skill validation: Before executing, verify the target project actually supports that skill
  • Status checks: /dispatch status verifies all symlinks are intact and repos exist
  • Project discovery: /dispatch list shows all registered projects in a table

None of this exists in the plugin model because plugins don't need it — they're scoped to a single project. A centralized registry is only valuable when you're managing skills across projects.

The Setup Script

A setup script reads the registry and creates all the symlinks — each project's .claude/skills and .claude/agents directories point back to the central repo's profile for that project.

Key decisions:

  • Symlink subdirectories, not the entire .claude/ — this preserves each project's local settings.local.json and session artifacts
  • Backup before replacing — if a project already has a skills/ directory, back it up with a timestamp
  • Idempotent — running it twice is safe; it skips correct symlinks

New team member onboarding: clone the central repo, run the setup script, done. Every project gets the latest skills.

When Plugins Are the Right Choice

This approach isn't universally better than plugins. Plugins win when:

  • You're distributing to the community — namespacing and marketplaces matter
  • You want versioned releases — semver, changelogs, controlled rollouts
  • Skills are self-contained — no cross-repo coordination needed
  • You need to bundle MCP servers or hooks — plugins package these alongside skills
  • Multiple consumers with different needs — the marketplace model handles this well

My approach wins when:

  • You control all the target repos — no need for marketplace discovery
  • Skills need cross-repo awareness — routing, shared configuration, project metadata
  • You want instant propagation — symlinks over install cycles
  • Bare skill names matter/develop over /plugin:develop
  • Per-project config must be separate from skill logic — registry + config.json pattern

The Hybrid Path

These aren't mutually exclusive. You could package a centralized skill registry as a plugin that manages symlinks and registry state. Or use plugins for truly standalone skills (like a generic /explain-code) while using the registry pattern for workflow skills that need cross-repo context.

The point isn't that plugins are wrong. It's that "how do I share skills across repos?" and "how do I coordinate AI workflows across repos?" are different problems. Plugins answer the first. A centralized registry with dispatch routing answers the second.


This is part 3 of a series on scaling Claude Code for enterprise workflows. Previously: How I Stopped Losing Work to Context Window Overflow and How I Taught an AI Agent to Save Its Own Progress.

Top comments (0)