How to Build a Modular Skill System in Claude Code for Multiple Clients
Isolated skills break at scale. Learn how to build a modular skill system in Claude Code where one update propagates across every client and workflow.
The Problem with One-Off Skills at Scale
When you start working with Claude Code across multiple client projects, the temptation is to write skills — custom slash commands, tool definitions, prompt templates — directly inside each project. It feels fast. And it is, for one client.
Then you get five clients. Ten. You fix a bug in a skill for Client A, and Clients B through J are still running the broken version. Someone on your team adds a better version of a search skill, and now you have three variations floating across different repos, none of them talking to each other.
That’s the core problem a modular skill system solves: one authoritative definition, propagated everywhere. This guide walks through how to build that in Claude Code, whether you’re managing a small agency setup or a large multi-team deployment.
What Counts as a “Skill” in Claude Code
Before designing a system, it helps to be precise about what you’re actually modularizing.
In Claude Code, a skill is any reusable capability you give the agent to draw on repeatedly. These fall into a few categories:
Custom Slash Commands
Stored in .claude/commands/ within a project directory, slash commands are Markdown files that define a prompt and optional $ARGUMENTS placeholders. When you type /skill-name in a Claude Code session, Claude reads the file and executes accordingly.
.claude/
commands/
summarize-pr.md
generate-tests.md
update-changelog.md
These are project-scoped by default, which is exactly the problem for multi-client work.
Global User-Level Commands
Coding agents automate the 5%. Remy runs the 95%.
The bottleneck was never typing the code. It was knowing what to build.
Claude Code also reads from ~/.claude/commands/. Anything in that directory is available across every project on your machine. This is the first foothold for modularity — but it only works for a single developer’s machine, not a whole team.
MCP Tool Definitions
Model Context Protocol (MCP) servers expose tools that Claude Code can call. An MCP server running locally or remotely can serve as a centralized skill registry — one server, many clients, all pulling from the same tool definitions.
CLAUDE.md Directives
The CLAUDE.md file at the project root (or at ~/.claude/CLAUDE.md globally) sets behavioral instructions, context, and workflow guidance. Skills can be defined as instruction patterns here, though this approach is better for lightweight conventions than complex tool logic.
Understanding which type of skill you’re dealing with matters because each has different propagation characteristics and different trade-offs.
Designing the Architecture Before Writing a Line
Rushing to build before designing is the fastest way to recreate the mess you’re trying to escape. A modular skill system needs a clear architecture first.
The Core Principle: Single Source of Truth
Every skill should live in exactly one place. Clients consume it — they don’t own it. This sounds obvious, but the default structure of Claude Code makes it easy to accidentally let clients own their skills.
Your target state looks something like this:
skills-repo/ ← single source of truth
commands/
code-review.md
write-tests.md
generate-docs.md
mcp-server/
src/
tools/
package.json
client-a/ ← consumer, not owner
.claude/
commands/ ← symlinked or generated from skills-repo
CLAUDE.md ← references shared skills, client-specific context
client-b/
.claude/
commands/
CLAUDE.md
Three Viable Propagation Strategies
Strategy 1: Git submodule + symlinks
Keep your skills in a dedicated git repository. Each client project adds it as a submodule. A setup script symlinks the relevant commands into .claude/commands/. When you update the skills repo, clients pull the submodule update.
This works well for teams with strong git discipline. The downside: submodule management has rough edges, and developers who aren’t careful will let submodules drift.
Strategy 2: npm package
Package your skills as an npm module. Include a post-install script that copies or symlinks command files into .claude/commands/. Clients add the package to devDependencies, and updating is as simple as bumping the version.
{
"name": "@yourorg/claude-skills",
"version": "1.4.0",
"scripts": {
"postinstall": "node scripts/install-commands.js"
}
}
This is cleaner than submodules for most teams. Versioning is explicit, rollback is easy, and npm handles distribution.
Strategy 3: Centralized MCP server
Run a single MCP server that all client Claude Code instances connect to. Skills live on the server — clients just get tool access. Updates deploy once, take effect everywhere immediately.
This is the most powerful option and the most operationally complex. It requires running infrastructure and managing authentication across clients. But for agencies serving many clients simultaneously, it’s often the right call.
Building the Shared Skill Library
With an architecture chosen, here’s how to actually build the library.
Step 1: Audit Existing Skills
Before writing new ones, inventory what you have. Go through each client project and list every .claude/commands/ file. Look for duplicates and near-duplicates — “generate-tests.md” and “write-unit-tests.md” that do roughly the same thing.
Group them:
- Universal skills: work the same across all clients (code review, changelog generation, PR description writing)
- Parameterized skills: same structure, different configuration (API doc generation where the base URL changes per client)
- Client-specific skills: genuinely unique to one project, shouldn’t be shared
Remy doesn't build the plumbing. It inherits it.
Other agents wire up auth, databases, models, and integrations from scratch every time you ask them to build something.
Remy ships with all of it from MindStudio — so every cycle goes into the app you actually want.
Only universal and parameterized skills belong in the shared library. Client-specific ones stay in the project.
Step 2: Write Skills That Accept Parameters
Hardcoded values are the enemy of reuse. Use $ARGUMENTS in slash commands to keep skills flexible:
---
description: Generate API documentation for a specific endpoint
---
Generate comprehensive API documentation for the following endpoint:
$ARGUMENTS
Include: request parameters, response shape, error codes, and a usage example.
Follow the project conventions defined in CLAUDE.md.
For MCP tools, use typed input schemas so Claude knows exactly what to pass:
server.tool(
"generate-api-docs",
{
endpoint: z.string().describe("The API endpoint path"),
method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]),
authRequired: z.boolean().default(false)
},
async ({ endpoint, method, authRequired }) => {
// skill logic
}
);
Step 3: Use CLAUDE.md for Client-Specific Configuration
The CLAUDE.md file is where client-specific context lives — not the skills themselves. A well-structured CLAUDE.md tells the shared skills how to behave for this particular client:
# Project Context
**Client**: Acme Corp
**Tech Stack**: Next.js 14, TypeScript, PostgreSQL, Prisma
**Test Framework**: Vitest
**Code Style**: ESLint with airbnb config
## Skill Configuration
- API base URL: https://api.acme.com/v2
- Default branch: main
- Changelog format: keep-a-changelog
Your shared skills read this context from the project and adapt. Claude Code automatically includes CLAUDE.md content in the context window, so skills can reference these values without any special imports.
Step 4: Version Your Skills Explicitly
Add a version comment to every skill file. This sounds pedantic but it matters when you’re debugging why a skill behaves differently across clients:
---
description: Summarize pull request for review
version: 2.1.0
---
In an npm package setup, the package version pins the skill version. With git submodules, the submodule commit hash does the same job.
Propagating Updates Across Clients
A modular system is only as good as its propagation mechanism. Here’s how to handle updates without manually touching every client.
For the npm Package Approach
Set up a CI pipeline that publishes a new package version when changes merge to main in the skills repo. Clients then have two options:
Option A: Automated dependency updates
Use Renovate or Dependabot to automatically open PRs in each client repo when the skills package publishes a new version. Clients review, approve, and merge. Clean audit trail, explicit consent on each update.
Option B: Pinned ranges with manual bumps
Clients pin to a minor range ("@yourorg/claude-skills": "^1.0.0"). npm update pulls the latest compatible version. Less overhead, slightly less control.
For breaking changes in skills — where you’ve changed argument structure or behavior significantly — bump the major version and document the migration.
For the Git Submodule Approach
Write a short update script that each client project can run:
#!/bin/bash
# update-skills.sh
git submodule update --remote skills
npm run install-commands
echo "Skills updated to $(git -C skills rev-parse --short HEAD)"
Run this in CI on a schedule, or trigger it manually when a skills release goes out. Either way, the update is a one-command operation per client.
For the MCP Server Approach
Seven tools to build an app. Or just Remy.
Editor, preview, AI agents, deploy — all in one tab. Nothing to install.
Updates deploy to the server. Clients pick them up immediately on next tool call — no action required on the client side.
The complexity is in deployment: you need zero-downtime deploys if clients are actively using skills, and you need to handle tool schema changes carefully. Adding a new optional parameter is safe. Removing a parameter or changing its type can break running sessions.
A sensible policy: never remove parameters, only deprecate them. Add new functionality through new tools or new optional parameters.
Testing Before Propagating
Build a test suite for your shared skills before you propagate updates. This can be as simple as a set of input/output pairs that you verify with each release:
describe("code-review skill", () => {
it("identifies missing error handling", async () => {
const result = await runSkill("code-review", {
code: sampleCodeWithMissingErrorHandling
});
expect(result).toContain("error handling");
});
});
Run this suite in the skills repo CI before publishing. Catching a regression at the source is far cheaper than debugging it across ten client projects.
Where MindStudio Fits
If you’re building a modular skill system for Claude Code, one of the stickier problems is skills that touch external services: sending emails, generating images, searching the web, triggering workflows in other tools.
Rolling your own integrations for each of these eats time fast. You end up with bespoke API wrappers that need maintenance, rate limiting logic, auth handling — infrastructure that has nothing to do with the actual skill logic.
MindStudio’s Agent Skills Plugin addresses this directly. It’s an npm SDK (@mindstudio-ai/agent) that gives Claude Code — and any other agent — access to 120+ typed capabilities as simple method calls. Your shared skills can call agent.sendEmail(), agent.searchGoogle(), agent.generateImage(), or agent.runWorkflow() without managing any of the underlying infrastructure.
This fits naturally into the npm package propagation strategy. Add @mindstudio-ai/agent as a dependency in your skills package, and every client that pulls the package update gets access to those capabilities immediately.
A concrete example: you have a skill that generates a client-facing summary after a code review. With the Agent Skills Plugin, that skill can automatically send the summary as an email — one method call, no SMTP setup, no API keys to manage per client:
import MindStudio from '@mindstudio-ai/agent';
const agent = new MindStudio();
// Inside your code-review skill handler
await agent.sendEmail({
to: clientEmail,
subject: `Code Review Summary — ${prTitle}`,
body: reviewSummary
});
Because the integration layer is centralized in MindStudio, updates to that infrastructure (better rate limiting, new retry logic, expanded APIs) propagate to your skills automatically — without touching your skill definitions.
You can try MindStudio free at mindstudio.ai.
Common Mistakes to Avoid
Even with a clean architecture, a few patterns consistently cause problems.
Letting Clients Modify Shared Skills Directly
If a client project has edit access to the shared skill files — via a checked-in copy rather than a submodule or package — someone will eventually modify them for that specific client. Now you have divergence again.
Other agents start typing. Remy starts asking.
Scoping, trade-offs, edge cases — the real work. Before a line of code.
Enforce a read-only relationship at the tooling level. Package consumers can’t push to the package. Submodule consumers shouldn’t have write access to the submodule remote. If a client needs different behavior, that’s a CLAUDE.md configuration change, not a skill modification.
Building Skills That Are Too Broad
A skill called “do-code-stuff” that tries to cover code review, refactoring, and documentation in one prompt is hard to reuse cleanly. Skills should have a single, well-defined job. If you find yourself writing “or if the user wants X, do Y instead” in a skill, that’s a signal to split it.
Skipping Semantic Versioning
Treating all updates as interchangeable patches causes problems fast. A changed argument structure in a skill is a breaking change — it deserves a major version bump. Teams that skip this end up debugging mysterious failures because a client is running skill v1.2.0 while the documentation assumes v2.0.0.
Hardcoding Model-Specific Behavior
Some skills work well with Claude 3.5 Sonnet but produce different results with Haiku or Opus. If your shared skills are model-agnostic — relying on clear instructions rather than model-specific quirks — they’re more durable. Document any known model dependencies explicitly in the skill’s front matter.
No Rollback Plan
At some point, a skill update will cause problems in production. Have a rollback procedure defined before you need it: which command reverts the submodule, how to pin a previous package version, how to roll back an MCP server deploy. Running a drill before the first real incident is worth the time.
FAQ
Can Claude Code access skills defined outside the project directory?
Yes. Skills in ~/.claude/commands/ are available globally across all projects on a single machine. MCP servers can also expose tools globally, regardless of which project directory Claude Code is running in. The global user-level commands directory is the simplest option for solo developers; MCP servers scale better for teams.
How do you handle client-specific skill variations without forking the shared library?
Use parameterization and CLAUDE.md configuration. The skill definition stays in the shared library, but reads project-specific values from CLAUDE.md. If two clients genuinely need behavior that can’t be unified through parameters, treat them as different skills — don’t try to merge them into one tangled definition. One clean shared skill is better than one overloaded skill.
What’s the best way to test shared skills before deploying to clients?
Build an integration test suite in the skills repository that runs against representative inputs. For slash commands, test the prompt output against known-good responses using Claude’s API directly. For MCP tools, test the tool logic with unit tests and mock the Claude Code integration. Run tests in CI on every merge to the main branch, and block publishing if tests fail.
How do you manage authentication when skills call external APIs?
Keep auth credentials out of the skill definitions. Use environment variables at the project level, or centralize credential management through a service like MindStudio’s Agent Skills Plugin that handles auth at the infrastructure layer. Skills should assume credentials are available in the environment — they shouldn’t know where those credentials came from.
Can multiple developers on a team use the same shared skill library?
Plans first. Then code.
Remy writes the spec, manages the build, and ships the app.
Yes, and this is one of the primary benefits. Package-based distribution works best for teams: each developer’s machine pulls the same package version, gets the same command files installed, and runs the same skill logic. MCP server-based distribution is even cleaner for teams — everyone connects to the same server, and there’s nothing to install on individual machines.
What happens when you update a skill that’s actively being used by clients?
For slash commands and installed packages, updates take effect the next time a developer updates their dependencies — there’s no live interruption. For MCP servers, changes deploy immediately on next tool call. Document breaking changes clearly in release notes, use semantic versioning to signal them, and give clients advance notice before major version releases that change existing behavior.
Key Takeaways
- Define skills in one place and have clients consume them — never let clients own or modify shared skills directly.
- Three viable propagation strategies: git submodules with symlinks, npm package distribution, or a centralized MCP server. Choose based on your team size and operational comfort.
- Use
$ARGUMENTSand typed input schemas to keep skills flexible across clients. Use CLAUDE.md for client-specific configuration. - Version your skills explicitly with semantic versioning. Breaking changes get major version bumps.
- For skills that call external services, handle auth and infrastructure at the distribution layer — not inside the skill definitions.
- Test skills in the source repo before propagating updates. Catching regressions at the source is cheaper than debugging them across multiple clients.
A modular skill system is an investment that pays off as soon as you hit your third or fourth client. The earlier you build the infrastructure, the less manual repair work accumulates. If you’re already managing Claude Code across multiple projects, MindStudio’s Agent Skills Plugin is worth looking at for the external integration layer — it handles the infrastructure so your shared skills can stay focused on reasoning, not plumbing.