I tried symlinking into a shared directory, and it fixed the duplication but created a worse problem: editing a skill for one repo silently changed the agent's behavior in another repo.
So I built capshelf - a CLI that keeps your skills, settings, and MCP servers in one shared git repo, with each project pinned to its own copy. It currently supports Claude Code, Codex and Pi and allows you to pin skills, Pi extensions, settings values, and MCP server entries.
The main idea was to vendor skills into a project in a controlled way by pinning them using a content hash. Capshelf has a manifest that lists installed items and a lockfile that saves hashes and source commits of all installed items.
To start building your skills repository, init capshelf in one of your repositories and point it to an empty git repo: $ capshelf init --data /some/local/gitrepo --no-upstream
Then, you can share your local skills to the data repo: $ capshelf share security-review --to project To promote without pinning for all project users: $ capshelf share design-review --to local
This will start tracking the skill using capshelf and pin the current version in this repository.
Then in another project, initialize capshelf and add the skills you need: $ capshelf add design-review
If you, or your agent, edit the design-review skill, you can easily promote it so that other projects can take the updates. Every project pins an exact content hash, so promoting an edit from project A leaves project B running the old version until someone runs capshelf update there.
If you're familiar with terraform this might remind you of the terraform plan/apply approach.
When you work in a team, to share a skill you promote and push or create a PR. You can review the changes like any other PR. When a teammate clones your project they get the exact versions the lockfile pins, and a CI check can fail any PR whose config drifted from them.
To try it: $ brew install genged/tap/capshelf
Repo is here: https://github.com/genged/capshelf