Developer guide
How to find, install, write and publish a skill — in the browser, from a terminal, or from inside an agent. Everything here works against the live catalogue.
Install the CLI
Three ways in. They serve the same binaries, covered by the same checksums.
$ npm install -g llmskillhub$ curl -fsSL https://raw.githubusercontent.com/Priy6anshu/llmsh/main/install.sh | sh$ go install github.com/Priy6anshu/llmsh/cmd/llmsh@latestThe npm package is llmskillhub and the command it installs is llmsh — llmsh was taken on the registry. The installer checks each download against the release's SHA256SUMS and refuses a mismatch.
Install a skill
$ llmsh install anthropics/mcp-builderThat resolves the latest approved version, downloads it, recomputes the tree digest, compares it to the manifest, and only then unpacks. A mismatch is refused rather than warned about.
$ llmsh install anthropics/mcp-builder@1.0.0$ llmsh install anthropics/mcp-builder --dir ./skillsA published version never changes, so pinning one means the bytes you tested are the bytes you get.
Anatomy of a skill
my-skill/
├── SKILL.md # required: the manifest and the instructions
├── scripts/ # optional: code the agent can run
├── references/ # optional: documentation it can read on demand
├── assets/ # optional: templates, images, data
└── examples/ # optionalOnly SKILL.md is required, and only those four directory names are recognised. Anything else is allowed — you will see a note at publish, but nothing is refused for its layout.
$ llmsh init my-skillScaffolds the folder and asks for what the validator requires.
The manifest
YAML frontmatter at the top of SKILL.md. Two fields are required.
---
name: pdf-form-filler
description: Fills PDF forms from structured data and extracts values back out. Use when the user mentions PDF forms, filling a PDF, or pulling fields out of one.
license: Apache-2.0
compatibility: Requires Python 3.11+
metadata:
llmskillhub:
version: 1.2.0
categories: [documents]
keywords: [pdf, forms, extraction]
repository: https://github.com/you/pdf-form-filler
capabilities:
network: false
filesystem: read-write
shell: false
---
# PDF form filler
Instructions for the agent go here...Fields the spec defines
namerequired- Lowercase letters, digits and single hyphens. Must match the directory name, and it is the skill's global address — names are not scoped by owner.
descriptionrequired- What it does and when to use it. This is the field an agent routes on, so name the phrases someone would actually type. No angle brackets — descriptions are embedded in prompt scaffolding, where they are reserved.
license- A licence name, or a pointer to a bundled file.
compatibility- Environment requirements, if there are any. Most skills need none.
allowed-tools- Space-separated tools pre-approved to run. Experimental in the spec.
metadata- Anything else. Ours lives under
metadata.llmskillhub.
metadata.llmskillhub
version- Semver. Without it you pass
--versionat publish; with it, the publish is refused if the two disagree rather than quietly relabelled. categories,keywords- How it is found. Both feed search and the category browser.
repository,homepage,authors- Where it came from and who wrote it.
capabilities- What it touches:
network,shell,filesystem(none,read,read-write) and namedsecrets. Worth filling in — it is what tells someone installing your skill what it will do, and it is shown on the page beside it.
Limits
| Limit | Maximum | |
|---|---|---|
| Archive on the wire | 5 MiB | the .skill zip itself |
| Uncompressed total | 25 MiB | every entry inflated, summed |
| Compression ratio | 50:1 | uncompressed over compressed |
| Files | 500 | |
| Single file | 4 MiB | |
| SKILL.md | 256 KiB | |
| Path length / depth | 255 / 12 | |
| name | 64 chars | lowercase, digits and single hyphens |
| description | 1024 chars | 40 minimum; 500 is the comfortable length |
| compatibility | 500 chars |
A package well inside these is the normal case — most skills are a few tens of kilobytes. Exceeding one is a refusal rather than a warning, so it is worth knowing before you publish.
Publishing
Check it locally first — this never touches the network:
$ llmsh validate ./my-skillThen the same checks on the server, storing nothing:
$ llmsh publish ./my-skill --dry-runAnd for real:
$ llmsh publish ./my-skillPublishing reads your git repository. It refuses to ship uncommitted work by accident — pass --allow-dirty if you mean it — and records the commit the version came from.
Every version is reviewed before it is listed, including updates to a skill that is already public — the live version keeps serving while the new one waits, so publishing never takes your skill down.
$ llmsh status you/my-skillShows each version and where it has got to.
Versions and digests
A version's identity is the tree digest: a hash over the file list and contents, not over the zip. Zip output is not reproducible across producers, so hashing the archive would make the same files package to different identities on different machines.
Published versions are immutable. The same bytes cannot be published twice under different numbers either — that is refused as duplicate content.
/owner/skill the current approved version
/owner/skill/v/1.2.0 those exact bytes, permanently
/compare/owner/skill any two versions, side by sideYanking withdraws a version from resolution without deleting it: anyone who pinned it keeps working, and nothing new resolves to it.
Tokens and CI
Create one at your account. A token can do less than you can, which is the point — one pasted into a build job is copied into places you do not control.
| skills:read | Read your own skills, including versions not yet public |
| skills:publish | Publish new versions |
| skills:manage | Deprecate, yank and delete your skills |
Use it without writing anything to disk:
LLMSH_TOKEN=lsh_... llmsh publish ./my-skillThe token is shown once, when you create it, and never again. Lost means make a new one.
The HTTP API
Everything the CLI does is over HTTP, and the read endpoints need no authentication. Base URL https://api.llmskillhub.com.
| GET /v1/skills | list and search; q, category, sort, limit |
| GET /v1/skills/{owner}/{slug} | one skill |
| GET /v1/skills/{owner}/{slug}/versions | every approved version |
| GET /v1/skills/{owner}/{slug}/files | the file list at a version |
| GET /v1/skills/{owner}/{slug}/file | one file's contents |
| GET /v1/skills/{owner}/{slug}/download | a short-lived URL for the archive |
| GET /v1/skills/{owner}/{slug}/diff | between two versions |
| GET /v1/categories | categories with counts |
| GET /v1/users/{handle} | a publisher and their skills |
| GET /v1/me | who a token belongs to |
$ curl https://api.llmskillhub.com/v1/skills?q=pdfErrors are RFC 7807 problem documents with a stable code, so you can branch on the machine-readable field rather than on prose.
Mirrored skills
Some skills here were published by us on behalf of their authors, from open-licensed repositories. Those pages say so, name the source commit and the licence, and state that the author has not claimed the page.
A mirror is only ever made from a licence that permits redistribution, and the original licence file travels inside the package.
If one is yours: sign in with the GitHub account that owns the source and the page becomes yours, with its skills. It is matched on your numeric GitHub id, so a rename does not break it and nobody who later takes your old username can claim it. To have a mirror removed instead, use the link in the footer.