Skip to content
// Kamil Kuklewski
Back to Blog

How I Built Three Claude Code Skills and Published Them as a Plugin Marketplace

Kamil Kuklewski

A Claude Code skill is a folder with a SKILL.md file: a name, a description that tells Claude when to use it, and instructions, optionally with scripts and reference files next to it. You package one or more skills into a plugin, list plugins in a marketplace.json, and anyone can install them with two commands. I did this three times, and this post shows the real repo behind it.

What a Claude Code skill is (and how it differs from a slash command or an MCP server)

A skill is a reusable procedure that Claude loads when the task matches its description, or when you invoke it by name, like /site-audit. The instructions live in a markdown file, so there is nothing to compile or host.

Two neighbours get confused with it:

  • Slash command: a saved prompt you trigger by name. In current Claude Code, custom commands have been merged into skills: a file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy, and skills add a folder for supporting files and automatic loading when relevant. In my repo every skill is also invoked with a slash, so in daily use the difference is small.
  • MCP server: a running process that exposes tools, for example database or API access. A skill is instructions; an MCP server is capability. They combine well: my seo-content plugin ships both a skill and a bundled MCP server that talks to Search Console. A plugin declares its MCP servers in a .mcp.json file next to the manifest.

My rule of thumb: if the work is "follow this procedure", write a skill. If Claude needs to reach a system it cannot reach today, add an MCP server.

The three skills I built

All three solve something I was doing by hand on client projects.

site-audit is a pre-launch and regression audit of a website: SEO, Core Web Vitals, accessibility, responsiveness and semantic HTML. It audits one sample of every page type rather than only the home page, and it writes a tracked was-to-now checklist into the audited repo so a later --recheck shows what got fixed. More in my website audit checklist post.

seo-content turns your own Google Search Console data into content opportunities and review-ready blog drafts (/seo-gaps writes briefs, /blog-draft turns a brief into a draft). Every user brings their own keys, and per-client key paths live in each repo's .seo-content.json. The research behind this post came out of it. More in the Search Console briefs post.

ladder-adoption finds which rung of the Steps of AI Adoption a repo stands on and the smallest next action (/ladder), and includes a supervised loop for one production incident (/incident-response). It lives in its own repo and is listed in the marketplace for one-stop install. More in the AI adoption ladder post.

Anatomy of a skill: SKILL.md, scripts, references, templates

Here is the smallest useful shape, copied from the skeleton my scaffold script uses:

---
name: __NAME__
description: __DESCRIPTION__ Use when the user says "...", "...", or invokes /__NAME__. Usage: /__NAME__ [args]
---

# __NAME__

`$SKILL_DIR` = the base directory of this skill (shown above as "Base directory for this skill").
Reference bundled files as `$SKILL_DIR/scripts/...` — never hard-code `~/.claude/...` paths.

## Arguments

## Workflow
1.

## Rules
-

The frontmatter is what matters most. The description is how Claude decides to pick the skill, so I write the trigger phrases users actually say into it ("audit this page", "check before launch", "recheck the audit").

A real skill grows a few folders around SKILL.md. site-audit has scripts/ (code scan, HTTP checks, a headless DOM audit, a Lighthouse wrapper), references/, templates/ and a checklist.md that holds the item IDs and severities. Three decisions made them reliable:

  1. Scripts for anything deterministic. Counting, comparing and measuring is done by code; Claude interprets results and writes the report.
  2. Files referenced through the skill's base directory. No absolute paths, so the skill works as an installed plugin and as a copy in ~/.claude/skills/. validate.sh fails the build if it finds a hard-coded local path.
  3. State in the repo, not in agent memory. site-audit writes its checklist into the audited project, and /ladder writes a profile file there. A headless run on another machine starts from the same state.

From skill to plugin to marketplace

A plugin is a folder with a manifest. A marketplace is a repo with a catalog. This is my layout:

.claude-plugin/marketplace.json   catalog — one entry per plugin
plugins/<name>/
  .claude-plugin/plugin.json      plugin manifest (name, version, description)
  skills/<skill>/SKILL.md         one folder per skill (+ scripts/, templates/, references/)
  tests/                          plugin's own regression tests (optional)
  README.md
templates/plugin-skeleton/        starting point for a new plugin
scripts/new-plugin.sh <name>      scaffold a plugin from the skeleton and register it in the catalog
scripts/validate.sh               validate the catalog, every plugin, and run plugin tests

The plugin manifest for site-audit (description trimmed):

{
  "name": "site-audit",
  "description": "Pre-launch and regression quality audit of a website ...",
  "version": "0.2.2",
  "author": { "name": "Kamil Kuklewski", "url": "https://github.com/kkuklewski" },
  "homepage": "https://github.com/kkuklewski/claude-plugins/tree/main/plugins/site-audit",
  "repository": "https://github.com/kkuklewski/claude-plugins",
  "license": "MIT",
  "keywords": ["claude-code", "skills", "web", "audit", "seo"]
}

And the catalog, .claude-plugin/marketplace.json, trimmed to the two kinds of entry. A local plugin points at a folder; ladder-adoption points at its own GitHub repo:

{
  "name": "kkuklewski",
  "owner": { "name": "Kamil Kuklewski", "url": "https://github.com/kkuklewski" },
  "plugins": [
    {
      "name": "site-audit",
      "source": "./plugins/site-audit",
      "version": "0.2.2",
      "category": "development"
    },
    {
      "name": "ladder-adoption",
      "source": { "source": "github", "repo": "kkuklewski/ladder-adoption" },
      "category": "productivity"
    }
  ]
}

Two conventions I follow: a plugin may hold several related skills (seo-content has seo-gaps and blog-draft), but unrelated skills get their own plugin so people install only what they need. And I never write the skeleton by hand anymore:

scripts/new-plugin.sh my-plugin "One-line description"
# edit plugins/my-plugin/skills/my-plugin/SKILL.md
scripts/validate.sh

new-plugin.sh copies the skeleton, renames the placeholders and appends the entry to marketplace.json. validate.sh runs claude plugin validate on the catalog and on every plugin, checks that the catalog version matches the plugin's own plugin.json, rejects hard-coded local paths, and runs each plugin's tests/run.sh if it has one.

The tests are plain shell. site-audit serves two fixture pages (good.html, bad.html) on a local port, audits them headlessly and asserts which checklist IDs fire. seo-content runs its opportunity analysis on fixture rows and checks the MCP server handshake, with no network and no credentials.

How to install a skill or plugin in Claude Code

From my marketplace:

/plugin marketplace add kkuklewski/claude-plugins
/plugin install <plugin>@kkuklewski

For example /plugin install site-audit@kkuklewski. Plugins load at session start or when you reload plugins, so reload after installing. Skills from an installed plugin are namespaced as /<plugin>:<skill> (for example /seo-content:seo-gaps); I use the short names in this post.

The ladder-adoption repo is also a marketplace by itself:

/plugin marketplace add kkuklewski/ladder-adoption
/plugin install ladder-adoption@ladder-adoption

You can also load a plugin from a local clone while developing: claude --plugin-dir ./ladder-adoption, which is the route I use before pushing. To use a single skill without a plugin, copy its folder into ~/.claude/skills/ (available in every project on your machine) or .claude/skills/ (one project).

What I would do differently

  • Write the test and validate.sh first. I added validation after the first plugin and immediately found a version mismatch between catalog and manifest. Now it is a check, not a review comment.
  • Keep per-client configuration out of the skill. Site-specific tuning goes into a config file in the audited repo (.site-audit.json for accepted exceptions and private routes, .seo-content.json for a path to the client's key, never the key). The skill stays generic and the repo stays the source of truth.
  • Never hard-code ~/.claude paths. Use the base directory. It is the difference between a skill that works on my machine and one that works on yours.
  • Do not split plugins early. Related skills in one plugin share scripts and config. Split when the audiences differ.
  • Skills propose, humans apply. /ladder never changes settings, and /incident-response never deploys or merges. That constraint is written into the skill, and it is why I am comfortable running them on client repos.

If you want help building skills like this into your own delivery process, tell me about your project. For how I pair-build with Claude Code in general, see pair-building with Claude Code.

Where to find more Claude Code skills

Start with the official Skills and Plugins pages in the Claude Code docs at code.claude.com, and the Discover tab of /plugin, which lists Anthropic's official marketplace and any marketplace you have added. Beyond that, search GitHub for the claude-code-skills topic and read before you install: a skill is instructions plus possibly scripts that run on your machine, so treat it like any dependency. My own catalog is at github.com/kkuklewski/claude-plugins.

FAQ

Do skills work in Claude Code?

Yes. That is where I build and run all three of mine. Skills can be personal (~/.claude/skills/), project-level (.claude/skills/) or shipped inside plugins.

How do I install a skill in Claude Code?

For a plugin from a marketplace, add the marketplace and install the plugin: /plugin marketplace add kkuklewski/claude-plugins, then /plugin install <plugin>@kkuklewski. For a single skill, put its folder in ~/.claude/skills/ (personal) or .claude/skills/ (project).

How do I give Claude Code a skill?

Create a folder with a SKILL.md that has a name and a description in the frontmatter, then write the instructions. Put the phrases you would actually type into the description so Claude can match them. Bundle scripts and reference files next to it and point to them through the skill's base directory.

What are the top skills for Claude Code?

It depends on your work, so I will only speak for the three I use: site-audit for website QA, seo-content for Search Console based content briefs and drafts, and ladder-adoption for placing a repo on the AI adoption ladder.

What is the difference between skills and slash commands?

A skill is a folder with instructions and optional scripts, loaded when its description matches or when you call it. A custom slash command used to be a separate saved prompt; today .claude/commands/x.md and .claude/skills/x/SKILL.md both create /x, and skills add supporting files and automatic loading.

What is the difference between skills and MCP servers?

A skill tells Claude how to do a job. An MCP server gives Claude new tools to reach a system. seo-content uses both: the skill holds the procedure, the bundled server fetches the Search Console data.

Where can I find Claude Code skills?

See the section above. The short version: official docs first, GitHub topics second, and read the SKILL.md and scripts before installing anything.

Claude CodeAI WorkflowPlugins