Skip to content

skilldrop·docs·Explanation

Contributing

How to add or change a skill, a pack, a loop or a subagent, what an RFC is needed for, and the checks a pull request must pass.

skilldrop has one primitive: a skill — a plain folder at packs/<pack>/skills/<name>/ that any agentic IDE can install by copying it. Two supporting surfaces exist to make skills findable and installable: the packs/ folders (role bundles, each with a pack.json) and the skilldrop-cli npm package (bin/skilldrop.js). Contributions come in three shapes, one per lane below.

Before you start

Two reads, in order:

  1. AGENTS.md — the source of truth. Golden rules, verified commands, file placement, skill anatomy, the pre-commit checklist, and the voice rules. This file routes you to it; it does not replace it.
  2. README.md — what each skill does and how it installs into each IDE.

No setup step beyond one line: git config core.hooksPath .githooks, which stops a commit that would publish your own name or email (SECURITY.md). The checks are stdlib Python and Node — python3 and node are the only prerequisites, and only if you want to run the linters locally (CI runs them either way).

Write an RFC first if you are adding a new skill, a new top-level file or directory, changing the skill anatomy or manifest schema, or introducing a repo-wide convention. Copy docs/rfcs/0000-template.md to docs/rfcs/NNNN-<kebab-slug>.md with the next sequential number. Keep it under a page — the RFC records the decision, the PR does the work. No RFC needed for fixes and improvements to an existing skill, doc corrections, or eval additions.

The invariant this repo protects

A skill is one self-contained folder. It has one home pack. The name matches in three places.

skilldrop's entire premise is copy-install portability: cp -R packs/<pack>/skills/<name> ~/.claude/skills/ has to work, in every IDE, forever. Three rules fall out of that, and they are the ones a well-meaning PR most often breaks:

The three lanes

1. Adding a new skill

  1. RFC first — docs/rfcs/NNNN-<slug>.md, including the four-part fit check (concrete artifact / portable / opinionated / category). A skill that is a generic chat helper with no artifact, a thin wrapper around one CLI command, or a duplicate of an existing skill does not belong here — improve the existing one instead.
  2. Create the folder — packs/<pack>/skills/<your-skill>/SKILL.md + manifest.json, per the frontmatter and manifest shapes in AGENTS.md. Keep SKILL.md under ~500 lines; spill into reference.md, templates/, examples/, lenses/, or rubrics/.
  3. Ship Quality bar and Anti-patterns to avoid sections. A skill without them is a description, not a generator.
  4. Add evals/ — evals.json (≥1 realistic prompt + assertions) and eval_queries.json (phrases that should and should not trigger the skill). The no-trigger list is what keeps the description honest.
  5. Set the model tier in both places — the model block in manifest.json and the skill's entry in model-routing.json. Tiers are abstract (light / standard / heavy); a vendor model name in a skill is always wrong. See MODEL-ROUTING.md.
  6. Declare an audience — the pack folder you put it in is its audience, and it also goes in at least one outcomes entry in catalogue.json. A skill with no audience should not have passed the RFC.
  7. Update the skill catalogue — a row in guides/reference/skill-catalogue.md under an existing category, and a row in Installing dependencies (guides/reference/install-targets.md) if it has runtime deps.
  8. Match the voice. Opinionated, not hedged; decisions, not options; ≤2 clarifying questions; ✅/❌ are semantic, never decorative. The full rules are in AGENTS.md — re-read them before drafting.

2. Changing an existing skill

No RFC. The bar is that the skill stays internally consistent, because validate.py checks four kinds of drift:

If the change alters what the skill produces, redo the manual test pass (lane 3's gates, below) and update evals/ to match. If it changes the trigger surface, update eval_queries.json.

3. Changing repo machinery

The CLI (bin/skilldrop.js), the installers (pack.py), routing (route.py, model-routing.json), hooks (RFC-0006), or validate.py itself. RFC required for anything that changes a convention or adds a top-level file; not for a bug fix.

Two things to keep true:

If you add a new invariant, teach validate.py to enforce it. A rule that only lives in prose is a rule that drifts.

Before you open the PR

python3 validate.py                          # repo consistency lint (stdlib only)
node bin/skilldrop.js validate               # catalog structural check
node cli_smoke.js                            # the CLI, run as a user runs it
python3 -m unittest discover -s tests -t .   # the skill scripts' unit tests

All four run in CI on every push and PR. The last two run on Linux, macOS and Windows (.github/workflows/cli.yml). There is no make target.

A skill with a script needs its tests. They go in tests/test_<skill>.py (hyphens become underscores), and must name every script in the skill's scripts/ folder; validate.py fails otherwise. Use only the standard library and the helpers in tests/support.py, and keep them offline. If a test finds a bug you aren't fixing in the same change, mark it @unittest.expectedFailure with a # BUG: line; don't write the test to expect the wrong behaviour.

A script that parses a file a user hands it (an export, a report, a config) should also get a fuzz target in tests/fuzz/targets.py: the command line, the exit codes that mean "handled", and one or two small valid seeds. python3 tests/fuzz/fuzz.py --target <name> --iterations 2000 runs it anywhere; CI fuzzes it with Atheris (RFC-0062).

Then:

git checkout -b feat/<short-kebab-name>      # or fix/… docs/… chore/…
git push origin feat/<short-kebab-name>
gh pr create --base main --head <handle>:feat/<short-kebab-name>

Cutting a release

The npm package skilldrop-cli publishes itself. Bump version in package.json and merge to main — CI publishes via npm OIDC trusted publishing with provenance, then pushes a v<version> tag. The job is version-gated: a push without a bump publishes nothing and fails nothing. Rationale in RFC-0004.

Bump whenever a skill change is worth shipping — users' skilldrop outdated only lights up on a release, so unreleased skill improvements are invisible to everyone who installed via the CLI. The manual fallback (npm publish from the repo root, with the 2FA browser step) still works if CI is down.

Increment the patch digit, one step at a time: 0.4.0 → 0.4.1 → 0.4.2. Never skip a number, and don't jump to a minor because the release feels significant.

BumpWhen
Patch (0.4.1) — the defaultNew skills, skill edits, pack changes, tier changes, docs, CLI bug fixes. Almost everything.
Minor (0.5.0)The CLI's public surface changed: a new command, a new flag, or a changed default.
Major (1.0.0)A deliberate stability commitment. Not yet.

A docs-only change that ships nothing in package.json files (bin/, packs/, catalogue.json, model-routing.json) needs no bump at all — there is nothing new for the registry to carry.

Where to find authoritative information

QuestionFile
Rules, file placement, checklist, voiceAGENTS.md
Claude-Code-specific ergonomics (dogfooding, ${CLAUDE_SKILL_DIR})CLAUDE.md
What each skill does, per-IDE install stepsREADME.md
Why a structural decision was madedocs/rfcs/
Long-form design (CLI surface, telemetry spec)docs/designs/
Which skills a role getspacks/ — each pack's folder and pack.json
What model tier a skill runs at, and whymodel-routing.json + MODEL-ROUTING.md
What CI actually runs.github/workflows/release.yml

When this file is wrong

Flag the drift in your PR instead of working around it. AGENTS.md wins any disagreement — this file is a router over it, and a router that points somewhere stale is a bug. Correcting it is a docs fix and needs no RFC; changing the process it describes needs one.

License

MIT or Apache-2.0, at the user's option (LICENSE). Opening a PR means you agree your contribution ships under both.

Edit this page on GitHub · View source