Home › Agent Skills › Naming, versioning, packaging
Agent Skills · Build

Naming, versioning, packaging

kebab-case name capped at 64 chars, a version field nothing reads, and a .skill file that is just a zip.

In one line

The name regex is enforced, the version key is enforced against you, and the .skill archive is a zip named from the directory rather than from the name field.

Why you'd careThe problem it solves

Two decisions here get made wrong in the same predictable way, and both cost an afternoon.

The first is versioning. You bump version: 0.1.0 to 0.2.0 in your SKILL.md, expecting something downstream to notice — a cache to invalidate, an install to be offered an upgrade, a resolver to prefer the newer one. Nothing happens, because nothing we can find reads that key, and the one tool that definitely does look at it treats it as an error.

The second is naming. You pick a name that reads well in a sentence, with a capital or a space in it, and it works fine locally right up until you try to package or register it. Then a regex you never saw rejects it. Anthropic's own authoring template gets this wrong in the example it hands you, which is a fair sign of how easy it is to trip over.

ConceptWhat it is

Three separate things sit under this heading and they are not a pipeline, which is why they get conflated.

Naming is a format rule on the frontmatter name key: lowercase letters, digits and hyphens only, no leading or trailing hyphen, no doubled hyphens, at most 64 characters. Alongside it is the directory name, a separate string with no enforced rules that the packaging script nonetheless uses to name its output.

Versioning has two entirely different meanings that share a word. There is the version: key some authors put in frontmatter, and there is the Skills API, which cuts real server-side versions of a registered skill through its own endpoints. The second is a genuine version system that other API calls reference. The first is a string in a file. They are unrelated, and confusing them is the root of the “I bumped it and nothing happened” complaint.

Packaging is the conversion of a folder into a single distributable file with a .skill extension. It is a zip archive, and the extension is the only thing distinguishing it from any other zip.

The connective tissue: the packaging step runs the naming and frontmatter rules as a gate. So naming is not merely stylistic — it is the thing that decides whether the folder can become a distributable artefact at all.

How it worksThe mechanics

The name check, as implemented in quick_validate.py: it must match ^[a-z0-9-]+$, must not start or end with a hyphen or contain --, and must be at most 64 characters. Straightforward, and Anthropic's own guidance still fails it. The template frontmatter block inside plugin-dev/skills/skill-development/SKILL.md — the block presented as the shape to copy — reads name: Skill Name. Title case, with a space. That is two violations of the regex the same toolchain enforces. Copy the template literally and you cannot package the result.

Packaging behaviour, from package_skill.py:

code
# validation runs first; failure aborts the build
# the archive is named from the DIRECTORY, not the name key
skill_filename = output_path / f"{skill_name}.skill"   # skill_name = skill_path.name

# zipfile.ZIP_DEFLATED; paths are relative to the parent,
# so the folder itself is the top-level entry in the archive

# excluded from the zip
__pycache__/   node_modules/   *.pyc   .DS_Store
evals/         <- only at the skill root

Three consequences. The .skill file is an ordinary zip, so unzip -l will read one. Its filename comes from the directory, so a directory and a name field that disagree produce an archive named after the one you were not thinking about. And because validation gates the build, any frontmatter problem is a packaging problem.

On version:, here is what is checkable rather than assumed. It is not in the validator's six-key allowlist, so it is a hard failure. Thirteen of the 25 first-party skills carry it anyway. The plugin-dev plugin manifest that ships those skills has no version key at all, and only 14 of 295 entries in the official marketplace manifest carry a plugin-level version (re-counted 2026-09-12). We have not found a consumer that reads the skill-level key. We cannot prove none exists — that would need the closed-source loader — but the stronger and sufficient claim is that it is not free: it is the single most common reason a first-party skill fails validation.

At a glanceSee it

Naming, versioning, packaging diagram

Naming and frontmatter act as the gate on packaging, and real versioning only starts after registration.

Where it runsSurfaces and availability

SurfaceStatusNotes
Claude CodeYesNo packaging step at all. The folder is the install unit, and edits are picked up mid-session: Claude Code watches skill directories, so adding, editing or removing a skill takes effect without restarting — only creating a top-level skills directory that did not exist at startup needs a restart. The invocation name comes from the directory, not frontmatter, except in plugins. Source: code.claude.com/docs/en/skills, "Live change detection" and "How a skill gets its command name".
Agent SDKYesSame — folders on disk, no archive. Which folders are visible depends on settingSources/setting_sources, and the plugins option can load skills from a specific path. Source: code.claude.com/docs/en/agent-sdk/skills.
Claude Desktop / claude.aiYesCorrected. The install unit is a zip file uploaded through Settings > Features; no primary Anthropic page documents a .skill archive format or a packaging script naming claude.ai, so both claims are withdrawn. Skills here are per-user and cannot be centrally managed or distributed org-wide, and they do not sync to the API. Desktop surfaces the same account-level set ("Customize" in the sidebar). Sources: agent-skills/overview, "claude.ai" and "Cross-surface availability"; code.claude.com/docs/en/skills.
Claude API / Messages APIYesConfirmed. Custom skills register through the Skills API (/v1/skills) as a zip archive or individual files, and versioning is real: each create returns a latest_version_id (a skver_… version ID), there is a Create Skill Version endpoint, and requests pin a specific version or use latest. Custom skills are workspace-wide. Sources: agent-skills/overview; build-with-claude/skills-guide, "Managing custom skills".
Managed AgentsYesConfirmed. Each skills entry carries type, skill_id and an optional version that pins a version or defaults to latest. The agent itself is versioned independently, a session can pin an agent version, and a session can override the skill set without creating a new agent version. Sources: managed-agents/skills; managed-agents/sessions.
Plugin marketplacesYesConfirmed as a distribution path, with the causal claim removed. Skills ship as files inside the plugin repo at <plugin>/skills/<skill-name>/SKILL.md, namespaced plugin-name:skill-name so they cannot collide with personal or project skills, and a skill folder with a .claude-plugin/plugin.json loads as a plugin in its own right. There is no required archive step (a plugin can optionally ship as a zip archive source since v2.1.224); whether any validator would reject the keys these skills use is not documented anywhere primary. Source: code.claude.com/docs/en/skills, "Where skills live".
Amazon BedrockNoConfirmed. Agent Skills are listed as not supported, so there is nothing to package for. Source: build-with-claude/claude-in-amazon-bedrock.
Google Vertex AINoConfirmed, same listing. Source: build-with-claude/claude-on-vertex-ai.
Microsoft FoundryYesWas Unverified. "On Claude Platform on AWS and Microsoft Foundry, upload custom Skills through the Skills API," and Foundry inherits the Claude API's Skills behaviour — so the packaging and versioning contract is the API's. Hosted on Anthropic deployments only. Sources: agent-skills/overview; build-with-claude/claude-in-microsoft-foundry.
OpenAI Codex CLI / ChatGPTYesWas Unverified. It has its own documented naming and distribution: skills are directories resolved across repository (.agents/skills up to the repo root), user ($HOME/.agents/skills), admin (/etc/codex/skills) and bundled system scopes, and broader distribution is through plugins. No zip-install path is documented — and since Anthropic documents no .skill format either, the original comparison had no subject. Source: developers.openai.com/codex/skills.

The trade this page names is real but the count was off. Server-side version resolution exists on every Anthropic surface that registers skills by ID — the Claude API, Managed Agents, and by inheritance Microsoft Foundry and Claude Platform on AWS — and each of those is a surface you cannot edit in place. The surfaces you can edit in place have no version concept at all, and Claude Code goes further than "the next session picks it up": it watches the directories and applies edits within the running session. So the working pattern stands and is sharper than before. Draft locally, where the loop is a file save and a version string in frontmatter buys you nothing, then register through the Skills API when the behaviour has stabilised and you need something addressable that other calls can pin. What does not survive is the idea that shipping standalone forces you into a validated archive format: the documented distribution units are a zip to claude.ai, a zip or file set to the Skills API, and a plugin, as plain files in a repo or, since v2.1.224, a zip archive.

ExampleIn the real world

You have ~/.claude/skills/Deploy Runbook/ with name: Deploy Runbook and version: 1.2.0 in its frontmatter. It has worked locally for months. A sister team asks for a copy, so you go to package it.

python3 package_skill.py "~/.claude/skills/Deploy Runbook" stops at validation: Unexpected key(s) in SKILL.md frontmatter: version. You remove the line and run again. Now: Name 'Deploy Runbook' should be kebab-case.

You rename the frontmatter key to deploy-runbook and rerun. It passes and writes Deploy Runbook.skill — because the archive name comes from the directory, which you never touched, and now the file has a space in it and disagrees with the skill inside. You rename the directory to deploy-runbook and rebuild to get deploy-runbook.skill.

Three failures, each of which had been latent for months. Nothing about the skill's behaviour changed at any point. What changed is that packaging applied rules the local loader had never bothered to apply. If you had wanted a real version story, none of this would have provided it either — that lives in the Skills API, behind registration, and the 1.2.0 you deleted was never connected to it.

Not thisWhat it is often confused with

  • Not semantic versioningthe frontmatter version: key is a free string with no resolver, no comparison and no upgrade path. Writing 2.0.0 communicates intent to human readers and nothing else.
  • Not the Skills API versionthat is a real server-side object with its own create and list endpoints, referenced by ID in API calls. It has nothing to do with the string in your file.
  • Not a proprietary archive format.skill is a deflate zip. Any zip tool opens it, and the folder is its top-level entry.
  • Not a plugina plugin is a repository with a manifest that can carry many skills plus commands, agents and hooks. Plugins are distributed by marketplace, not by .skill file.
  • Not a package managerthere is no dependency resolution, no lockfile, no transitive install. Packaging produces one self-contained archive and stops there.

LimitsWhen not to reach for it

  • You are still iterating.Packaging a skill you are changing daily adds a build step to every edit. Stay on the folder until behaviour settles.
  • Distribution is through a plugin repo.Then .skill archives are the wrong unit entirely — users get skills by installing the plugin, and the validation gate never applies.
  • You want upgrade semantics.Bumping version: will not deliver them. If consumers need to pin and upgrade, register the skill through the Skills API, which is the only place that concept exists.
  • You are renaming a shipped skill.skill-creator explicitly instructs preserving both the directory name and the name field unchanged when revising. A rename breaks anything referring to the old one and buys nothing.
  • The skill needs local files outside its folder.Packaging captures the directory and nothing else, so an absolute path to something on your machine will ship as a dangling reference.
Checked

Verified 2026-09-12. Moves on a scale of months. Re-check before you depend on it. Provider: Anthropic.

A living map of modern AI — kept current every morning