Where Claude Code Skills Live — and the Rule That Keeps Them Tracked

Date:

You spent an afternoon building a skill. By default it landed in a personal folder that no repo sees and no teammate has. That’s real work sitting outside version control.

The short answer: A Claude Code skill lives in one of a few places, and whether it is version-controlled depends entirely on which. Build one interactively and it usually lands in your personal ~/.claude/skills/ — local to your machine, invisible to your team, and gone if you reinstall. The fix is a one-line rule: the moment a skill is worth keeping, commit it into the repo whose domain it serves — <repo>/.claude/skills/<name>/, which is tracked, shared, and reviewable. Personal is for scratch; project is for real. A skill isn’t “done” until its folder is committed.

A skill is a small folder — a SKILL.md and optional scripts/, references/, assets/ (see Anatomy of a Claude Code Skill). Because it’s just files, “tracking” it is nothing exotic: it’s whether those files sit inside a git repository. The trap is that the default location is not a repository.

Where a skill can live (in load precedence)

Claude Code looks for skills in several places, and they resolve in order:

  • Enterprise — org-managed, pushed by an administrator.
  • Personal — ~/.claude/skills/<name>/. Your home directory, not version-controlled. This is where a freshly built skill tends to land.
  • Project — <repo>/.claude/skills/<name>/. Inside a repo, so committing it tracks and shares it.
  • Nested — <subdir>/.claude/skills/<name>/ in a monorepo, scoped to that part of the tree; also committed.
  • Plugin — bundled inside an installed plugin, distributed with it.
  • Account-synced — ~/.claude/skills/synced/, pushed from your Claude account to your terminal sessions.

The distinction that matters for tracking is simple: project and nested skills are git-tracked; personal skills are not (they can be account-synced, which is a convenience, not version control).

Personal is for scratch; project is for real. The difference is one cp and a commit.

Where a skill lives – and whether git sees itThe default location is not a repository. Commit keepable skills by domain.
Default landing: PERSONAL

~/.claude/skills/<name>/ – your home dir, NOT a repo. Where a freshly built skill lands. Local, unshared, losable.

Not version control: ACCOUNT-SYNCED

~/.claude/skills/synced/ pushes from your account to sessions. A convenience – no history, no review, not in team repos.

The rule: COMMIT when worth keeping

Copy the folder into the repo whose DOMAIN it serves, on a branch (never git add -A). Batch skill commits like docs.

Tracked: PROJECT / NESTED

<repo>/.claude/skills/<name>/ – committed, so tracked, shared, reviewable. (Plugins distribute with the plugin.) This is 'real'.

Personal is for scratch; project is for real. The difference is one cp and a commit.

“Tracked” is a property of the location, not the skill

There is nothing to “enable.” A skill is tracked if — and only if — its folder lives inside a repository and has been committed. So the audit is trivial: list ~/.claude/skills/, and anything there that you’d be sad to lose is a skill that isn’t tracked yet. In one real pass we found five skills sitting in the personal folder — genuine, useful tools that existed only on one machine. None were lost, but any of them would have been by a reinstall.

The corollary: building a skill and using it is not the same as keeping it. The keeping step is the commit, and it’s the one most easily forgotten because the skill already works.

The rule: track it the moment it’s worth keeping

Make it a standing convention, not a case-by-case decision: when a skill is generated — by a skill-builder or by hand — commit it into version control immediately. Leave nothing durable in ~/.claude/skills/ alone. Two clarifications keep the rule practical:

  • Scratch is fine in personal. A one-off experiment you’ll delete tomorrow doesn’t need a repo. The rule is about skills you intend to reuse.
  • Skills are documents, so batch their commits. A skill folder is prose and small scripts, not shipping code, so several new skills can ride into one pull request rather than one PR each — the same batching economy that applies to any doc-only change.

Which repo owns it? Home a skill by its domain

Once you decide to track a skill, the only real question is which repo. The answer is the domain it serves, not wherever you happened to build it:

  • A pipeline or infrastructure skill (data crawling, a database-promotion step) belongs in the repo that owns that pipeline.
  • A content or publishing skill belongs in the content repo — even if you built it while working somewhere else.
  • A cross-cutting skill can live in the repo that drives it most, or in a shared-tooling repo if you have one.

Homing by domain keeps each skill next to the code and docs it’s about, so a reader who clones that repo gets the tool that fits it — and you don’t end up with a publishing skill stranded in a data repo just because that’s where your terminal happened to be open.

Moving a personal skill into version control

The mechanics are ordinary git:

  1. Copy the skill folder from ~/.claude/skills/<name>/ into the target repo’s .claude/skills/<name>/.
  2. Add and commit it on a branch (git add .claude/skills/<name>, then commit) — never a blind git add -A, which can sweep in unrelated working changes.
  3. Push and open a pull request, batching it with any other doc-only work in flight.

That’s the whole ceremony. The skill keeps working from the personal copy in the meantime; the committed copy is what makes it durable and shared.

Seeing what your skills cost: /skill-doctor

Tracking is about not losing skills; the /skill-doctor command is about knowing whether they earn their place. It reports each skill’s invocation frequency, its context cost, and candidates that never fire — the usage signal you need to prune dead weight or fix a skill that should be triggering but isn’t. Version control tells you where your skills are; /skill-doctor tells you which ones matter.

Committing a skill is step one. Once a deploy step copies those repo-owned skills into the folder the tool actually loads, the deployed copy can drift from its source — see When your skills folder is a deploy target for the drift and orphan guards that catch it.

The short version

A skill is files, so tracking it just means keeping those files in a repo. By default a new skill lands in personal ~/.claude/skills/, which no repo sees — so make it a rule to commit every keepable skill into the repo whose domain it serves (<repo>/.claude/skills/<name>/), the moment it’s built. Personal is for scratch; project and nested locations are the tracked ones; plugins distribute with the plugin. Batch skill commits like any doc change, home each skill by its domain, and use /skill-doctor to see which skills actually get used.

Frequently Asked Questions

Where do skills I build normally get saved?

Usually your personal ~/.claude/skills/ — your home directory, which is not a git repository. That’s convenient but means the skill isn’t tracked or shared until you commit it into a repo.

Are personal skills backed up at all?

They can be synced from your Claude account to your terminal sessions (~/.claude/skills/synced/), which is a convenience, but it isn’t version control — no history, no review, not shared through your team’s repos. Treat account sync as a nicety, not the system of record.

Which repo should a skill go in?

The one whose domain the skill serves — a publishing skill in the content repo, a pipeline skill in the pipeline repo — regardless of where you built it. Homing by domain keeps the tool next to the code it’s about.

Do I need a separate pull request for each skill?

No. A skill is documents and small scripts, so batch several into one PR rather than one PR per skill — the same economy as any doc-only change.

How do I know if a skill is even being used?

Run /skill-doctor. It reports invocation frequency, context cost per skill, and skills that never fire, so you can prune unused ones or fix a description that isn’t triggering.

Share post:

Subscribe

Popular

More like this
Related

How to Merge Spreadsheets by URL (and Why Our Tool Reported 5 Misses That Weren’t)

Matching two spreadsheets on a URL column is the same job as matching a stock list to a price list by product code. It goes wrong in the same two places: how you clean the code, and how you count what didn't match.

Many-to-One: Why a Mapping Backlog Outgrows Its Target Taxonomy

You're mapping a messy source vocabulary onto a clean target taxonomy. The target has about 5,600 slots, so the job must be roughly 5,600 decisions — right? The backlog is already past 8,900, and still climbing.

The Fix That Didn’t Take: When a Content-Hash Gate Skips Your Code Change

You shipped a fix to how one field is computed, re-ran the pipeline across everything, and it reported a clean run. Then the consistency check still flags those records as wrong. The fix is in the code, the rebuild "ran" — and the records never changed. Your own optimisation skipped them.

Your Dedup Scan Is Over-Counting — Because It Forgot What You Already Fixed

The report said 80 duplicate groups still to resolve. You'd been resolving them for days. You run it again after a big batch and it *still* says 80-ish. The backlog isn't stubborn — the scan is counting work you already finished.