Blog

Don't Repeat Yourself: Sharing Skills Across Claude Code Plugins

Kris Geusebroek

April 3, 2026
4 minutes

Introduction

If you have been building your own Claude Code plugins for a while, chances are you've run into a familiar itch: you want the same skill available in two different plugins, so you just copy it. It works, until you need to update that skill and suddenly realise you have to hunt down every copy of it scattered across your plugin directories.

Sound familiar? I've been there. In this post I want to show you how to apply the DRY principle — Don't Repeat Yourself — to your Claude Code plugin skills by introducing a shared top-level skills directory and using symbolic links to wire things up.

The problem with copying skills

A Claude Code plugin lives in a directory and can expose skills — small markdown files that describe a command or capability Claude can use. When you have more than one plugin, it is tempting to structure things like this:

claude-plugin-project-root/
└── plugins/
    ├── devops-plugin/
    │   └── skills/
    │       ├── deploy.md
    │       └── commit-message.md   # 👈 copy
    └── review-plugin/
        └── skills/
            ├── review-pr.md
            └── commit-message.md   # 👈 another copy

The commit-message.md skill is useful in both plugins so it ends up in both. At first that feels fine. Then you improve the skill, and you have to remember to update it in every location. Miss one and you have two plugins behaving differently for the same operation — the kind of subtle inconsistency that is annoying to debug and easy to ship.

Extract skills into a shared top-level directory

The fix is straightforward: give shared skills a single home and let the plugins that need them point to that home. Create a skills directory at the top level of your plugin project — one level above the plugins:

claude-plugin-project-root/
├── skills/                         # shared skills live here
│   └── commit-message.md
└── plugins/
    ├── devops-plugin/
    │   └── skills/
    │       └── deploy.md
    └── review-plugin/
        └── skills/
            └── review-pr.md

I admit there is nothing exciting about moving a file up one directory. The interesting part is what comes next.

Connect plugins to shared skills using symbolic links

Instead of copying commit-message.md into each plugin's skills directory, create a symbolic link from the plugin back to the shared file:

# from the claude-plugin-project-root
ln -s ./skills/commit-message.md \
      ./plugins/devops-plugin/skills/commit-message.md

ln -s ./skills/commit-message.md \
      ./plugins/review-plugin/skills/commit-message.md

The result looks like this on disk:

claude-plugin-project-root/
├── skills/
│   └── commit-message.md           # the one source of truth
└── plugins/
    ├── devops-plugin/
    │   └── skills/
    │       ├── deploy.md
    │       └── commit-message.md -> ../../../skills/commit-message.md
    └── review-plugin/
        └── skills/
            ├── review-pr.md
            └── commit-message.md -> ../../../skills/commit-message.md

You can verify the correct setting of the symbolic link with the ls -la plugins/devops-plugin/skills/ command.

Both plugins now see commit-message.md exactly as before, but there is only one file to maintain. Update it once and all plugins benefit immediately. Remember to use a relative path as the symlink target, not an absolute path, so the link keeps working after cloning.

Making symlinks work in a git repository

Symbolic links are tracked by git, so your team gets the same structure when they clone the repository — no manual setup required. You can verify the symlinks are tracked correctly with:

git ls-files --stage claude-plugin-project-root/plugins/devops-plugin/skills/commit-message.md

You should see the mode 120000, which is git's way of saying the file is a symlink:

120000 a3f5b2c1... 0    claude-plugin-project-root/plugins/devops-plugin/skills/commit-message.md

On MacOs and Linux this just works. One thing to keep in mind: on Windows, creating symlinks requires either Developer Mode to be enabled or the process to run with elevated permissions. If your team works cross-platform, it is worth documenting this in your repository's README.

Conclusion

That's all there is to it. By extracting shared skills into a single top-level directory and using symbolic links to connect them to the plugins that need them, you get the same benefits you would expect from any DRY refactoring: one place to update, no risk of copies drifting out of sync, and a structure that scales cleanly as you add more plugins.

Cheers 🙏

Written by

Kris Geusebroek

Contact

Let’s discuss how we can support your journey.