devkit-skill-authoring
by @chempa
Use when writing, validating, publishing, or versioning a skill for a devkit registry - the SKILL.md format, the frontmatter rules, and the init/validate/publish loop.
devkit-skill-authoring
How to write a skill that a devkit registry will accept and that Claude will actually load. Everything here is the behaviour of @devkit/core, which is the one validator the CLI, the server, CI, and the in-browser editor all share - so what passes locally passes on publish, for the same reasons.
When to use this
- Writing a new skill, or fixing one the registry rejected
- Deciding what belongs in
SKILL.mdversus areferences/file - Publishing, versioning, yanking, or forking
- Working against more than one registry and needing the right one
The whole loop
devkit init my-skill # scaffold a folder that already validates
$EDITOR my-skill/SKILL.md
devkit validate my-skill # the registry's own checks, locally
devkit publish my-skill # upload it
If you do not have the CLI yet, it comes from the registry itself and needs no token - it is a client and holds no skills:
curl -sSL https://your-registry.example.com/install/cli | sh
devkit login https://your-registry.example.com # prompts for a token
Mint the token at /manage/settings. Publishing needs the publish scope.
A skill is one folder
my-skill/
SKILL.md ← required, at the root
references/ ← optional, ships with the skill
checklist.md
There is no manifest. The YAML frontmatter at the top of SKILL.md is the metadata, and the body below it is what Claude loads.
The folder name is the slug, and it must equal the frontmatter name. Slugs are lowercase, hyphen-separated, 3-64 characters, starting and ending alphanumeric. all and cli are refused - the registry already serves those install URLs.
Frontmatter
---
name: code-reviewer
description: Use when reviewing a diff for correctness, dead code, and missing tests.
version: 1.0.0
author: your-handle
license: MIT
tags: [ai, claude, code-review]
status: beta
created: 2026-08-02
updated: 2026-08-02
---
| Key | Required | Rule |
|---|---|---|
name | yes | Must equal the folder name |
description | yes | 10-200 characters, one line |
version | yes | SemVer; must not already exist in the registry |
author | yes | Letters, digits, _ . -; max 40 |
license | yes | An SPDX identifier (MIT, Apache-2.0, …) |
tags | yes | Inline list, 1-8 entries |
status | yes | stable, beta, or deprecated |
created / updated | no | YYYY-MM-DD |
featured | no | Set by the registry, not by you |
The frontmatter parser is deliberately not YAML. It handles key: scalar, inline lists ([a, b, c]), quoted scalars, and # comments - and it throws on indentation, nested maps, block sequences (- item), and multi-line scalars (|, >) rather than mis-parsing them quietly. Keep every value on one line.
For the exact rules, every error message, and what each one means, read references/frontmatter.md.
The description is the field that matters
It is the only part of the skill Claude sees before deciding whether to load it. It has to carry the trigger conditions by itself. Write when to use this, not what this is:
# good - names the situations that should match
description: Use when reviewing a diff, preparing a PR, or asked to check code for bugs.
# bad - accurate, and gives nothing to match against
description: A code review helper.
A skill with a vague description is not a broken skill; it is a skill that never gets loaded, which is worse, because nothing reports it.
The body
Everything below the closing --- is the skill. It is what Claude loads and what the catalogue renders, so it has two readers and must work for both. It must be non-empty.
Keep SKILL.md focused. Anything long - checklists, tables, worked examples - goes in a sibling file that the body points at on demand:
For the full colour formula, read `references/palette.md`.
Every file in the folder is published and lands in the installer's ~/.claude/skills/<slug>/, so those siblings are on their disk afterwards.
For how to write a body Claude actually follows, read references/writing-well.md.
What gets published
Everything in the folder, except housekeeping: .DS_Store, Thumbs.db, .git, .gitignore, .gitkeep, .keep, node_modules, .devkit.json, and editor leftovers matching ~, .#, or .tmp.. Those are your repository's business and nobody downstream's.
There are no secrets in a skill folder. Everything in it is published, and on a public registry, world-readable.
Limits, all enforced at publish:
| Limit | Value | Why |
|---|---|---|
| Files per skill | 64 | A skill is documentation, not a package |
| One file | 512 KB | Same |
| Whole skill | 2 MB | Bounds the upload and the unpacked size |
| Path length | 100 bytes incl. <slug>/ | ustar's name field |
Paths may not be absolute, contain .. or . segments, use backslashes, or contain NUL. The install writes straight into ~/.claude/skills/<slug>/, so this is a security boundary rather than tidiness.
Versions are immutable
Publishing a version that already exists is a 409. To change a published skill, bump version: and publish again.
An install pins a content digest, verified on download, so "the skill I installed" and "the skill in the registry" can be compared - and a bad version is rolled back by installing the previous one rather than by hoping somebody reconstructs it.
latest is the highest release. A pre-release (2.0.0-rc.1) is installable by exact version but never becomes the default.
Publishing, registries, tokens, yanking, forking, and visibility are covered in references/publishing.md.
Before you publish
- Folder name and frontmatter
nameare identical -
descriptionnames trigger conditions, 10-200 chars, one line - Every frontmatter value is on a single line
-
versionis SemVer and has not been published before - The body is non-empty and reads on its own
- No secrets anywhere in the folder
devkit validate my-skill
Then try the real install, somewhere disposable:
export CLAUDE_HOME=$(mktemp -d)
devkit install my-skill
find "$CLAUDE_HOME"
CLAUDE_HOME redirects the install target, so you can inspect exactly what an installer gets without touching your real ~/.claude.
When something is rejected
references/troubleshooting.md maps each error the validator, the CLI, and the server produce to its cause and its fix.