A practical walkthrough of plugins and skills: the manifest format, how skills get discovered, and three tiny plugins I shipped for my own dotfiles last weekend. No fluff.
I spent a rainy Saturday in March learning the plugin system end-to-end. What follows is the post I wish had existed that morning. I'll assume you've used Claude Code before and are comfortable editing a few config files; otherwise, nothing here is tricky.
Plugins vs. Skills
It took me a minute to get these straight, so let me just say it clearly:
- A skill is a named capability — a folder with a prompt and optional tools. Think of it as "a thing the model knows how to do and can choose to invoke."
- A plugin is a bundle you install. It can contain one or more skills, plus hooks into the app itself (keybindings, status bar, commands).
- You almost always start by writing a skill. The plugin wrapper is just how you ship it to other machines.
- They discover themselves. Drop the folder in the right place and the model sees it on next launch. No registry call.
The Minimum Viable Skill
A skill is a folder with a SKILL.md at the root. That file has YAML frontmatter (the manifest) and a markdown body (the prompt). That's it. No build step.
--- name: "rubber-duck" description: "Walk through a bug by explaining it to me line by line" when_to_use: "User says they're stuck, or asks for a rubber duck session" --- You are a rubber duck. Do not propose fixes on the first turn. Ask the user to describe, in plain words, what they expect the code to do. Then ask what it actually does. Then ask what changed most recently. Only after all three questions, offer a hypothesis.
Drop that at ~/.claude/skills/rubber-duck/SKILL.md and the next session will pick it up. The model decides when to trigger it based on when_to_use. You don't have to call it by name.
Three Plugins I Actually Shipped
commit-scribe
readme-shaper
standup-bot
Adding Hooks (the plugin wrapper)
When a skill isn't enough — because you want something to run on an event instead of being invoked by a prompt — you wrap it in a plugin. The plugin manifest lives at plugin.json next to the skill folder.
// standup-bot/plugin.json { "name": "standup-bot", "version": "0.1.0", "skills": ["./skills/standup"], "hooks": { "on_session_end": "./hooks/draft-standup.js" } }
capabilities array. I forgot this for about ninety minutes.
Tips from a Weekend
Order of things that actually mattered, in descending importance:
- Write
when_to_uselike a contract. This is what the model reads to decide. Vague description = skill that never triggers or triggers on everything. - Start with no tools. Add them only when you hit a concrete wall.
- Version your skills in git. You will break them. You will want to revert.
- Use a shared
/skillsfolder across projects. Otherwise you'll rewrite the same rubber duck skill seven times. - Test with the actual prompts that triggered you to build it. Not synthetic ones.
That's most of what I learned. The plugin system is genuinely small — which is the nicest thing I can say about a piece of software. You can read the full spec in an afternoon and remember it in a week. That is rare.