# Claude Code Skill Versioning: How I Versioned 64 Skills With a Changelog From Git

Claude Code skill versioning for a large skill set: version lines, one plugin version, a git-drafted changelog, lint that flags gaps, and SemVer bump rules.

Topic: Claude & MCP
Published: 2026-11-13
URL: https://productivitytech.io/claude-code-skill-versioning/

*Disclosure: this article contains affiliate links to Wispr Flow. If you subscribe through them, I earn a commission at no extra cost to you. Nobody at Wispr reviewed this article before publication.*

## Short answer

**Claude Code skill versioning**, when you have dozens of skills, is a small contract: a version line in each `SKILL.md`, one version for the set in `.claude-plugin/plugin.json`, a changelog you actually keep, and a lint check that flags skills with no version. In [my October 2026 audit](/claude-code-memory-lessons/), skills with a version went from **30** of **64**, no changelog, to all **64**, with a changelog generated from git. The free [personal-memory template](https://github.com/Sinfjell/personal-memory-template) ships the version lines, `plugin.json`, `CHANGELOG.md`, and the lint warnings — not my private skill set, and not a git-based changelog generator.

👉 [**Use this template on GitHub**](https://github.com/Sinfjell/personal-memory-template) — click *Use this template*, make the copy private, run `/setup`. Star the repo if it helps you keep the pattern around. Product page: [/products/personal-memory-template/](/products/personal-memory-template/).

When I draft longer skill instructions, I often dictate them into Claude Code with [Wispr Flow](/claude-code-voice-vs-wispr-flow/) — same habit as in my [Wispr Flow review](/wispr-flow-review/). <a href="/go/wispr/?position=skill-versioning-top&via=md&from=%2Fclaude-code-skill-versioning%2F" rel="sponsored nofollow noopener" data-cta-product="wispr-flow" data-cta-location="skill-versioning-top">Try Wispr Flow’s free plan</a> if you want to test that workflow.

## Why skills need versions

A skill is a procedure the agent loads when the description matches. When you change the steps — for example how `invoice-client` builds a draft for Acme or Example Client — every session that uses that skill gets the new behaviour. Without a version and a changelog entry, you cannot tell *what* changed or *when*. That matters if the same skill is referenced from several projects or client reading maps by name.

This is **agent skills versioning** as hygiene, not a marketing feature. Anthropic’s skill docs focus on `name` and `description` for discovery ([Agent Skills overview](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)); they do not replace a changelog you maintain in the repo. The same idea shows up when you ship reusable tooling — see [building an MCP server](/build-mcp-server-tutorial/) and [custom MCP server lessons](/custom-mcp-server-lessons/) for neighbouring “what changed in the tool” problems.

## The version line in SKILL.md

In the template, each English skill puts a version line immediately after the YAML frontmatter. From [`skills/ingest/SKILL.md`](https://github.com/Sinfjell/personal-memory-template/blob/main/skills/ingest/SKILL.md) (MIT License):

```markdown
---
name: ingest
description: Use after a finished piece of work, or when the user says "ingest"…
---
_Version 0.1.0 · source: skills/ingest/SKILL.md_
```

`setup` and `invoice-client` use the same shape. The Norwegian simple variant under `enkel/skills/` uses a `_Versjon …_` line that the same lint regex accepts. Reading maps name the skill (`invoice-client`), not the version, so bumping the skill does not force edits across every client file — the same facts-vs-skills split as in the [LLM wiki template](/llm-wiki-template-claude-code/).

This body line is **skill versioning Claude** practice in the template. It is not a documented frontmatter field in Anthropic’s Agent Skills format.

## One version for the set: plugin.json

Claude Code plugins use a manifest at `.claude-plugin/plugin.json`. The [plugins overview](https://code.claude.com/docs/en/plugins) describes that file as giving the plugin its name and optional metadata. The [plugins reference](https://code.claude.com/docs/en/plugins-reference) documents an optional `version` string: setting it keeps users on that version until you change it (Claude Code does not enforce SemVer on the string).

The template’s manifest (checked on `main`, version **0.2.0** at time of writing):

```json
{
  "name": "memory",
  "description": "Skills that work on this knowledge base, versioned alongside the facts they read",
  "version": "0.2.0"
}
```

Source: [`.claude-plugin/plugin.json`](https://github.com/Sinfjell/personal-memory-template/blob/main/.claude-plugin/plugin.json). One plugin version for the whole set; each skill still shows its own version on its second line, as [`CHANGELOG.md`](https://github.com/Sinfjell/personal-memory-template/blob/main/CHANGELOG.md) states.

Keeping the always-on rules file short is a separate problem — [CLAUDE.md too long](/claude-md-too-long/) — but versioned skills belong with procedures, not in that always-on file.

## Generating the changelog from git

The template’s `CHANGELOG.md` uses [Keep a Changelog](https://keepachangelog.com/) and [SemVer](https://semver.org/). It says: collect under `[Unreleased]`; cut a version when you link the skills somewhere new or share them.

**Honest split:** in **my** knowledge base I draft changelog entries from git history. The **public template does not ship a git-based changelog generator or a pre-commit hook** — only `CHANGELOG.md` for you to maintain and `scripts/lint.py` for warnings. Treat the next command as a suggestion for drafting, not a template feature:

```bash
# Suggestion: list commits that touched one skill since the last tag
git log --oneline "$(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~20)"..HEAD -- skills/ingest/
```

Copy the useful lines under `[Unreleased]`, rewrite them as Added / Changed / Fixed, bump the skill’s version line, and when you cut a release, move the block under `## [x.y.z] - YYYY-MM-DD` and bump `plugin.json`. That is how I keep a **Claude Code changelog skill** history readable without inventing release notes.

## A lint check that flags unversioned skills

Run:

```bash
python3 scripts/lint.py
```

Verified behaviour in [`scripts/lint.py`](https://github.com/Sinfjell/personal-memory-template/blob/main/scripts/lint.py) on `main`:

- **WARN** if a `skills/*/SKILL.md` (or `enkel/skills/*/SKILL.md`) has no `_Version …_` / `_Versjon …_` line in the first few lines after the frontmatter.
- **WARN** if `.claude-plugin/plugin.json` has a `"version"` that has no matching `## [that-version]` section in `CHANGELOG.md`.
- Warnings alone exit **0**; only ERROR-level findings (broken links, oversized index, and similar) exit **1**. Lint does **not** block commits by itself.

**Optional:** wire the script into a pre-commit hook if you want the warning in your face every commit. Example hook body (optional — not shipped by the template):

```bash
#!/usr/bin/env bash
# optional: .git/hooks/pre-commit
python3 scripts/lint.py
```

Make it executable with `chmod +x .git/hooks/pre-commit`. In my own knowledge base I run lint before every commit; the public scaffold leaves that choice to you. The same “automate the check” idea sits next to the ingest loop in [Claude Code automation](/claude-code-automation/).

## When to bump patch, minor or major

From the template [`CHANGELOG.md`](https://github.com/Sinfjell/personal-memory-template/blob/main/CHANGELOG.md), aligned with [SemVer](https://semver.org/) and [Keep a Changelog](https://keepachangelog.com/):

| Change | Bump |
| --- | --- |
| New skill, or new behaviour in an existing skill | **MINOR** |
| Fix or wording only | **PATCH** |
| Removed or renamed skill | **MAJOR** |

Collect under `[Unreleased]`. Cut a version when you link the skills somewhere new or share them. Bump the skill’s own line when that skill changes; bump `plugin.json` when you cut the set. That is the whole **Claude Code skills update** policy the template documents — no extra ceremony.

## Where this fits in the series

1. Architecture: [five-layer Claude Code memory system](/claude-code-memory-system/) (March).
2. Measured failures: [7 lessons from the October 2026 audit](/claude-code-memory-lessons/) — including the skills-with-a-version row (**30** of **64** to all **64**) this post expands.
3. Always-on rules: [CLAUDE.md too long](/claude-md-too-long/).
4. Auto-memory load window: [Claude Code auto memory not working?](/claude-code-auto-memory-limit/).
5. Template product page: [free LLM wiki template for Claude Code](/llm-wiki-template-claude-code/).
6. This post: **Claude Code skill versioning** — version lines, plugin version, changelog, lint, bump rules.

👉 [**Use this template on GitHub**](https://github.com/Sinfjell/personal-memory-template) — *Use this template*, make it private, run `/setup`.

If you write a lot of skill instructions by voice into the terminal, <a href="/go/wispr/?position=skill-versioning-end&via=md&from=%2Fclaude-code-skill-versioning%2F" rel="sponsored nofollow noopener" data-cta-product="wispr-flow" data-cta-location="skill-versioning-end">Wispr Flow’s free plan</a> is the dictation path I compared with Claude Code `/voice` in [Claude Code /voice vs Wispr Flow](/claude-code-voice-vs-wispr-flow/).

[Subscribe below](#foot-sub) if you want template updates and later series posts by email.

## FAQ: Claude Code skill versioning

<!-- faq -->
