You wrote a Claude Code skill. A good one — it turns your staged diff into a proper conventional commit message, and you use it a dozen times a day.
A teammate watches you work and asks the inevitable question: "can you send me that?"
So you zip up a folder. Then someone else asks. Then you improve the skill — and now there are three copies of it in the wild, two of them stale, and nobody knows which one they have.
So you do the obvious thing: you make a repo. team-skills, one folder per skill, everyone clones it and copies what they need into their ~/.claude/. Push a fix and it's available to everybody.
This is better than the zip. It is not a solution — it's the same problem with a git remote in front of it.
The junk drawer problem
A shared repo of skills is a junk drawer, and it fails in four specific ways.
It's all-or-nothing. Clone the repo and you get all fourteen skills, including the eleven that have nothing to do with your work. And skills aren't free: each one's description competes for the agent's attention every session. Your teammate wanted one skill. Their alternative is to hand-pick files out of the clone — which is copying, which is where we came in.
Copying is still copying. The moment those files land in someone's ~/.claude/, they're a fork. No link back to the origin, no update path except "clone again and re-copy, carefully", and no way to answer the question "which version do you have?" — because there are no versions.
There's no unit. team-skills@a3f9c2 tells you nothing about the commit skill specifically. You can't say "I'm on commit-crafter 0.2.0" because commit-crafter isn't a thing that has versions; it's a folder in a repo whose history is fourteen unrelated stories braided together. Every skill's changelog is every other skill's noise.
There's no boundary of ownership. Another team publishes a genuinely good skill. Your drawer's options: copy it in and own the drift forever, or tell everyone to clone a second drawer.
What's missing are two things — and here's the part worth being clear about, because it's the actual point of this article: neither of them is an agkit invention.
The first is the plugin: the unit. A directory with a manifest that gives it an identity — a name, a version, a description, an author. Something that can be installed, updated, and uninstalled as one thing, and versioned independently of its neighbours. This is how Claude Code and GitHub Copilot already model extensions. The separation isn't tooling; it's the shape of the thing.
The second is the marketplace: the catalog. One file listing your plugins, so an agent can show them, install one by name, and know where each of them comes from — including from a repo that isn't yours.
Put those together and "can you send me that?" has a different answer:
/plugin install commit-crafter@dev-toolkit
Your teammate gets one plugin, not fourteen. It has a version. /plugin update brings them your fix. They can uninstall it cleanly. Nothing was copied by hand, and nothing drifted.
So why does anyone still keep a junk drawer? Because writing that catalog by hand — plus a manifest per plugin, plus the versioning, plus the changelogs, plus keeping the docs in step — is exactly the kind of chore that makes zipping a folder look reasonable at 6pm on a Friday.
That's the gap agkit fills. It doesn't reinvent plugins or marketplaces — it removes the reason you didn't bother. Think ng for Angular, but for agent plugin marketplaces: one command scaffolds a push-ready repository, and a handful more cover the rest of the project's life.
In this walkthrough we'll take that commit skill from "a folder on your machine" to "installable by anyone with one line". We'll scaffold a marketplace, add a plugin from a template and make it ours, catalog a second plugin that lives in someone else's repo without ever cloning it, publish to GitHub, then ship an improvement with a real version bump.
Everything below is a real terminal session against agkit 0.9.2.
The one idea to hold onto
agkit is built around a single principle: one canonical catalog.
Your repository has exactly one source of truth, .claude-plugin/marketplace.json, plus your plugins under plugins/<name>/. Claude Code and GitHub Copilot read that file as-is — no build step, no compilation. Push the repo, and it installs.
Everything else — the README plugin table, the AGENTS.md list, the registries for Codex and Cursor — is derived from that catalog. Which means it can't drift, because you never maintain it by hand.
Keep that in mind and the rest of the commands stop looking like a list of tools and start looking like one workflow.
Step 1: scaffold the marketplace
You need Node.js 22+. No install required:
npx agkit init dev-toolkit
It asks a few questions (name, owner, description, git remote, CI), or you can pass them as flags and skip the prompts entirely:
npx agkit init dev-toolkit -y \
--name dev-toolkit \
--owner "Jane Doe" \
--email jane@example.com \
--description "My personal Claude Code + Copilot plugins" \
--repo https://github.com/jane/dev-toolkit.git
┌ agkit init _
│
◇ Marketplace scaffolded
│
◇ Next steps ─────────────────────────────────────────────────────╮
│ │
│ cd dev-toolkit │
│ git remote add origin https://github.com/jane/dev-toolkit.git │
│ agkit add skill my-first-skill │
│ agkit validate │
│ git add -A && git commit -m 'feat: initial marketplace' │
│ git push -u origin main │
│ │
│ Target agents: Claude Code, GitHub Copilot CLI │
│ Native install (no build): Claude Code, GitHub Copilot CLI │
│ │
├───────────────────────────────────────────────────────────────────╯
│
└ Done ✔
Here's what landed:
dev-toolkit/
├── .claude-plugin/marketplace.json # the catalog
├── plugins/ # your plugins live here
├── AGENTS.md # repo context, read natively by most agents
├── README.md # with an install section, already filled in
├── examples/team-settings.json # drop-in config so teammates get it automatically
├── .github/workflows/validate.yml # CI gate
└── .gitignore # (git init already ran)
The catalog itself is deliberately boring:
{
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
"name": "dev-toolkit",
"owner": { "name": "Jane Doe", "email": "jane@example.com" },
"metadata": {
"description": "My personal Claude Code + Copilot plugins",
"version": "1.0.0",
"pluginRoot": "./plugins",
"targets": ["claude-code", "copilot"]
},
"plugins": []
}
Two things worth noticing. targets records which agents you serve — the default is Claude Code and Copilot, both native. And it's already a git repo with a $schema, meaning your editor autocompletes the catalog and CI can validate it from the first commit.
Serving Codex or Cursor too? Pass
--agents claude-code,copilot,codex,cursorat init. Those two install from their own registry, whichagkit buildgenerates from this same catalog. One repo, four agents, no duplicated plugin content. We'll stay native in this article.
Step 2: add the skill, then make it yours
agkit add takes a template and a name. Five built-in templates ship with the CLI — skill, command, agent, hook, mcp:
agkit add skill commit-crafter -d "Write conventional commit messages from staged changes"
◆ Created plugins/commit-crafter (built-in:skill template) and registered it in marketplace.json
│
● Edit the generated files, then test locally:
│ claude
│ /plugin marketplace add /path/to/dev-toolkit
│ /plugin install commit-crafter@dev-toolkit
Two files appear, and the catalog gains an entry pointing at them:
{
"name": "commit-crafter",
"source": "./plugins/commit-crafter",
"description": "Write conventional commit messages from staged changes",
"version": "0.1.0",
"author": { "name": "Jane Doe" }
}
Note that last hint in the output: /plugin marketplace add /path/to/dev-toolkit. A marketplace is just a directory with a catalog, so you can install from a local path and test your plugin before anything is pushed anywhere. That tightens the loop considerably.
Now the part that matters — the template is a skeleton, not a skill. Open plugins/commit-crafter/skills/commit-crafter/SKILL.md and you get scaffolding with instructions in it:
---
name: commit-crafter
description: "Write conventional commit messages from staged changes ..."
---
# Commit Crafter
Explain the knowledge or procedure this skill provides. Claude loads this
file on demand, so write it as instructions to a competent colleague.
## When to use
- Situation 1
- Situation 2
Replace it with the real thing. The description in the front matter is what Claude reads to decide whether to load the skill at all, so it's worth writing carefully:
---
name: commit-crafter
description: "Writes conventional commit messages from staged changes. Use when the user asks to commit, write a commit message, or says 'commit this'."
---
# Commit Crafter
Turn a staged diff into a Conventional Commits message.
## Instructions
1. Run `git diff --staged` to read what is actually being committed.
2. Pick the type from the change itself: `feat` for new behaviour, `fix` for
a bug, `refactor` when behaviour is unchanged, `docs`, `test`, `chore`.
3. Scope it with the package or directory touched: `feat(auth): …`
4. Subject line: imperative, lowercase, no trailing period, ≤ 72 chars.
5. If the change breaks a public contract, add a `BREAKING CHANGE:` footer.
## Examples
`feat(parser): support scoped package names`
`fix(auth): refresh the token before expiry, not after`
That's the whole shape of it: agkit gives you a valid, registered, correctly wired plugin; you supply the substance.
If you later hand-edit a manifest — a description, keywords, a homepage — remember that plugins/<name>/.claude-plugin/plugin.json is the source of truth, not the catalog. Edit it, then run agkit sync and the catalog, README table and AGENTS.md all catch up.
Step 3: catalog a plugin that lives in someone else's repo
Here's where a marketplace beats a folder of copies.
There's a public plugin you like — say a changelog generator, published in its own repository. You want it in your toolkit, but you don't want to own its code, copy it in, or track its upstream changes by hand.
So don't. Point at it:
agkit add octo-org/changelog-skill changelog \
--ref v1.2.0 \
-d "Generate a release changelog from git history"
◆ Registered changelog as a remote plugin (octo-org/changelog-skill) in marketplace.json — nothing was cloned.
│
● Claude Code fetches it from the source at install time:
│ /plugin install changelog@dev-toolkit
│ (pass --vendor to clone it into ./plugins instead)
Nothing was cloned. Your repo gained exactly one thing — an entry in the catalog:
{
"name": "changelog",
"source": {
"source": "github",
"repo": "octo-org/changelog-skill",
"ref": "v1.2.0"
},
"description": "Generate a release changelog from git history"
}
The agent resolves that source when a user installs the plugin. No vendored code, no version to keep in sync, no fork to maintain. The --ref v1.2.0 pins it to a tag so upstream can't move under your users' feet — use --sha <commit> if you want to pin harder.
This is the default for any remote git source, and the spec grammar is flexible: bare owner/repo, gh:/gl: shorthands, or a full git URL for any forge. If the plugin sits in a subdirectory of a bigger repo, point at the folder with //:
agkit add "https://gitlab.com/team/marketplace.git//my-plugin" my-plugin
And when you do want the files copied in — seeding a plugin from a shared template you intend to modify — that's what --vendor is for. It clones the repo, renders it, and drops the result into plugins/<name>/ as your code. The rule of thumb: remote sources are referenced by default; --vendor when you want to own the copy.
Step 4: validate and publish
agkit validate runs local checks — JSON validity, kebab-case names, reserved names, source resolution, manifest presence, version drift — and delegates to claude plugin validate when the Claude Code CLI is installed:
agkit validate
● Note: relative plugin sources resolve only when the marketplace is added via
Git (any forge), not via a direct URL to marketplace.json.
◆ claude plugin validate: passed
◆ .claude-plugin/marketplace.json is valid
It exits non-zero on error, which is why the CI workflow that init generated already calls it.
Publishing is the anticlimax — it's just git:
git remote add origin https://github.com/jane/dev-toolkit.git
git add -A
git commit -m "feat: initial marketplace"
git push -u origin main
That's it. That's the distribution step. No registry, no account, no publish token. Your teammate now runs:
/plugin marketplace add jane/dev-toolkit
/plugin install commit-crafter@dev-toolkit
Copilot users get the same repo through copilot plugin marketplace add jane/dev-toolkit. And because distribution is just git push, none of this is GitHub-specific — GitLab, Bitbucket, Gitea and self-hosted forges all work, agkit just emits the git URL form instead of the owner/repo shorthand.
Better still, init wrote an examples/team-settings.json with an extraKnownMarketplaces block. Drop it into .claude/settings.json in your team's repo and teammates get the marketplace automatically when they trust the repository — nobody has to add anything by hand.
Step 5: ship an improvement
This is the step neither the zip nor the drawer could ever do.
You improve the skill — it should now recognise breaking changes and add the footer. Commit it with a conventional message, scoped to the plugin:
git add plugins/commit-crafter
git commit -m "feat(commit-crafter): detect breaking changes and add a BREAKING CHANGE footer"
Preview the release before committing to it:
agkit bump commit-crafter --dry-run
● 2 commit(s) (no previous release tag):
│ minor feat(commit-crafter): detect breaking changes and add a BREAKING CHANGE footer
│ minor feat: initial marketplace
│
● [dry-run] commit-crafter: 0.1.0 -> 0.2.0 (minor) + CHANGELOG.md entry
agkit read the commits that touch that plugin's directory since its last commit-crafter@x.y.z tag — there isn't one yet, hence "no previous release tag" and the initial commit being counted too — and applied conventional-commit rules: a feat means minor, so 0.1.0 → 0.2.0. A fix would be a patch; a feat! or BREAKING CHANGE: would be major. You can always force it: agkit bump commit-crafter major.
Happy with it? Do it for real, and let agkit commit and tag the release:
agkit bump commit-crafter --tag
◆ commit-crafter: 0.1.0 -> 0.2.0 (minor)
◆ Committed and tagged commit-crafter@0.2.0 — push with: git push --follow-tags
In one command it wrote the new version into the plugin manifest, generated a changelog entry from your commit subjects, and ran sync internally so the version flowed everywhere it needs to be:
# Changelog
## 0.2.0 — 2026-07-16
- feat(commit-crafter): detect breaking changes and add a BREAKING CHANGE footer
- feat: initial marketplace
The catalog now says 0.2.0. So does the README table. So does the AGENTS.md list. You updated none of them.
git push --follow-tags
The --follow-tags matters: the tag is the boundary the next bump measures from, so it has to reach the forge. Your teammate runs /plugin update and has your fix. Versions are per plugin, by the way — each one carries its own manifest version, changelog and tags, so a busy plugin never drags a quiet one into a release.
One caveat worth knowing: you can't bump a referenced remote plugin like changelog. Its version is owned upstream and you only hold a reference. To move it forward, re-pin it: agkit add octo-org/changelog-skill changelog --ref v1.3.0.
The loop, condensed
npx agkit init dev-toolkit # scaffold a push-ready repo
agkit add skill commit-crafter # scaffold a plugin, then edit it
agkit add octo-org/changelog-skill changelog --ref v1.2.0 # reference, don't clone
agkit validate && git push -u origin main # publish
# later:
git commit -m "feat(commit-crafter): …"
agkit bump commit-crafter --tag # version + changelog + sync + tag
git push --follow-tags
Five commands to go from a folder on your laptop to something a team installs by name and updates on its own.
The genuine shift here isn't the scaffolding — it's that your skills stop being files you hand people and become software you ship: each one a plugin with a name, a version, a changelog and a release history, listed in a catalog, validated in CI. The same repo can serve Claude Code, Copilot, Codex and Cursor, from any git forge, because there's one catalog and everything else derives from it.
And notice how little of that is about agkit. The plugin and the marketplace are the platform's model — they're what let your teammate install one thing instead of fourteen, at a version, and update it without asking you. agkit's contribution is narrower and, honestly, more useful: it makes producing that structure cheap enough that you'll actually do it, instead of pushing another folder into the drawer.
Which, it turns out, was all the zip was ever missing.
agkit is MIT-licensed and unaffiliated with Anthropic, GitHub, OpenAI or Cursor.
-
npm:
agkit - Docs: agent-marketplace-kit.gitbook.io/agkit-docs
- Source: github.com/AGent-marketplace-KIT/cli
- Website: agent-marketplace-kit.github.io
If you build something with it, I'd love to see the catalog.





Top comments (0)