| name | nsheaps-claude-marketplaces |
| description | Use this skill to understand the claude marketplaces in the nsheaps github org: the plugin marketplace build, release, and propagation pipeline.
Recall this skill when working on CI/CD workflows, mise tasks, plugin versioning, marketplace updates,
or when asked how plugins get from source code to a user's Claude Code installation.
Also recall when debugging version bumps, marketplace.json drift, or plugin cache issues.
|
How the nsheaps/ai-mktpl Plugin Marketplace Works
This skill documents the full lifecycle of a Claude Code plugin in the nsheaps/ai-mktpl repository (local clone at ~/src/nsheaps/ai-mktpl/), from source code to installation on a user's machine.
Repository: nsheaps/ai-mktpl on GitHub
Tooling Stack
The repository relies on these tools, all managed by mise (see mise.toml):
| Tool | Purpose |
|---|
mise | Polyglot tool version manager + task runner |
yarn (v4, via corepack) | JS dependency management (workspace root) |
release-it + @release-it/bumper | Automated SemVer version bumps in plugin.json |
prettier | Linting and formatting |
node (LTS) | Runtime for yarn/release-it |
jq | JSON processing in scripts |
gh | GitHub CLI for CI interactions |
Run mise run setup to bootstrap: it calls mise install -y then yarn install.
Repository Layout
~/src/nsheaps/ai/
.claude-plugin/marketplace.json # Central plugin registry (auto-generated)
mise.toml # Tool versions
.release-it.base.json # Shared release-it config (no git ops, patch increment)
mise/tasks/ # Build tasks
package.json # Root workspace (yarn 4, release-it devDeps)
plugins/<name>/ # One directory per plugin
.claude-plugin/plugin.json # Plugin manifest (name, version, description, author)
.release-it.js # Extends base config, points bumper at plugin.json
commands/ # Slash command definitions (*.md with YAML frontmatter)
skills/ # Agent skill definitions (SKILL.md with YAML frontmatter)
README.md
CHANGELOG.md # Auto-generated by release-it
.github/workflows/
ci.yaml # Lint + validate on PRs and main
cd.yaml # Version bump + marketplace update on main
claude-code-review.yaml # AI-powered PR review
claude-agent.yaml # Claude agent workflow
claude-agent-trigger.yaml # Claude agent trigger
.github/actions/
detect-plugin-changes/ # Composite action: diff plugins vs base ref
update-marketplace/ # Composite action: run mise run update-marketplace
lint-files/ # Composite action: prettier check/fix
validate-plugins/ # Composite action: claude plugin validate
Build Process (Mise Tasks)
Local Development
| Task | What it does |
|---|
mise run setup | Install mise tools + yarn dependencies |
mise run lint | Run prettier check; auto-fix if errors found |
mise run validate | Validate marketplace.json + every plugin.json via claude plugin validate |
mise run check | Run lint then validate (the full local CI equivalent) |
mise run update-marketplace | Regenerate .claude-plugin/marketplace.json from all plugins/*/plugin.json files |
mise run release -- --dry-run | Preview which plugins would get version bumps |
mise run detect-plugin-changes [base-ref] | Output JSON listing plugins with code changes vs a base ref |
Version Bumping
Each plugin has a .release-it.js that extends .release-it.base.json:
module.exports = {
extends: "../../.release-it.base.json",
plugins: {
"@release-it/bumper": {
in: ".claude-plugin/plugin.json",
out: ".claude-plugin/plugin.json",
},
},
};
The base config disables all git operations (no commit, no tag, no push) because CI handles those separately. It applies a patch increment by default and runs prettier --write on the plugin.json after bumping.
Bumping a single plugin: cd plugins/<name> && yarn exec release-it --ci
CI Pipeline (ci.yaml)
Triggers: PRs, pushes to main, manual dispatch.
Jobs
-
check-version-files (PRs only) -- Fails if plugin.json or marketplace.json were manually changed. These files are auto-generated; manual edits in PRs are rejected.
-
lint -- Runs mise run lint via the lint-files composite action. If files change, it auto-commits the fixes via git-auto-commit-action and fails the check (so a re-run picks up the committed fixes).
-
validate -- Runs mise run validate via the validate-plugins composite action. Uses claude plugin validate against the marketplace and each plugin manifest.
CD Pipeline (cd.yaml)
Triggers: Pushes to main or PRs that touch plugins/** (excluding plugin.json and marketplace.json to prevent loops).
On Pull Requests: Preview Only
The version-preview job runs mise run auto-bump-plugins against the PR base branch in the working tree only — nothing is committed or pushed. It then surfaces the preview two ways:
- A sticky PR comment (header
plugin-versions) with a table of each plugin's base → pending version.
- A GitHub
::notice annotation on each affected plugin.json showing the pending bump (e.g. my-plugin: 1.2.3 → 1.2.4 will be applied on merge).
The PR branch is never modified — bumping versions and regenerating the shared marketplace.json inside PR branches caused constant cross-PR merge conflicts, so the real bump happens once on merge to main.
On Push to Main: Bump + Update
The bump-and-update-marketplace job performs these steps in sequence:
- Detect + bump changed plugins --
mise run auto-bump-plugins (base: the cd/last-release tag) identifies plugins with code changes (excluding CHANGELOG.md and plugin.json from the diff) and patch-bumps each via yarn exec release-it --ci, unless already manually bumped to a higher version.
- Lint -- Runs
mise run lint to ensure formatting is clean after bumps.
- Commit version bumps -- Auto-commits with
chore: bump plugin versions [skip ci].
- Update marketplace -- Runs
mise run update-marketplace, which iterates all plugin dirs, reads each plugin.json, and rebuilds .claude-plugin/marketplace.json (sorted by name, with category/tag inference).
- Lint again -- Ensures marketplace.json is formatted.
- Commit marketplace -- Auto-commits with
chore: update marketplace metadata [skip ci].
- Push -- Single
git push sends both commits. The [skip ci] tag prevents infinite loops.
Authentication uses a GitHub App (not GITHUB_TOKEN) to allow the push to trigger downstream workflows if needed.
From Marketplace JSON to User Installation
Marketplace Registration
Nathan's ~/.claude/settings.json registers the marketplace as a directory-type source:
{
"extraKnownMarketplaces": {
"nsheaps-claude-plugins": {
"source": {
"source": "directory",
"path": "/Users/nathan.heaps/src/nsheaps/ai"
}
}
}
}
Because the source type is "directory", Claude Code reads marketplace.json directly from the local filesystem at ~/src/nsheaps/ai/.claude-plugin/marketplace.json. A git pull on that clone is sufficient to get the latest marketplace state.
For remote users, the marketplace can also be configured as a GitHub source ("source": "github", "repo": "nsheaps/ai-mktpl"), and Claude Code fetches the marketplace.json from the repo.
Plugin Enable/Disable
Plugins are toggled in settings.json under enabledPlugins using the format <plugin-name>@<marketplace-name>:
{
"enabledPlugins": {
"scm-utils@nsheaps-claude-plugins": true,
"git-spice@nsheaps-claude-plugins": true
}
}
This can be set at the user level (~/.claude/settings.json) or project level (.claude/settings.json).
Plugin Cache
When claude plugin install runs (or Claude Code auto-resolves an enabled plugin), the plugin contents are cached to:
~/.claude/plugins/cache/<marketplace-name>/<plugin-name>/<version>/
For example: ~/.claude/plugins/cache/nsheaps-claude-plugins/scm-utils/0.1.5/
Multiple versions may coexist in the cache. Claude Code uses the version declared in marketplace.json to determine which cache entry to load.
Full Propagation Path
Here is the complete path a plugin change takes from developer to user:
1. Developer edits files in plugins/<name>/
2. Developer commits and pushes to a feature branch
3. PR is opened -> ci.yaml runs lint + validate
-> cd.yaml posts version bump preview comment
4. PR is merged to main
5. cd.yaml triggers on main push:
a. detect-plugin-changes finds changed plugins
b. release-it bumps plugin.json version (patch)
c. Commits version bumps [skip ci]
d. mise run update-marketplace rebuilds marketplace.json
e. Commits marketplace update [skip ci]
f. Pushes both commits
6. User pulls main (or Claude Code fetches from GitHub)
7. marketplace.json now lists the new version
8. Claude Code resolves the plugin from marketplace -> source path
9. Plugin is cached in ~/.claude/plugins/cache/
10. On next Claude Code session, the updated plugin is active
For Nathan specifically (local directory marketplace), step 6 is git pull in ~/src/nsheaps/ai/. Claude Code reads the updated marketplace.json directly from that path.
Local Development Workflow
mise run setup
vim plugins/my-plugin/skills/my-skill/SKILL.md
mise run check
mise run release -- --dry-run
claude
git add -A && git commit -m "feat(my-plugin): add new skill"
git push
References
Deep-Dive References
These reference documents provide detailed analysis on specific design decisions:
- Plugin Env Vars Tradeoff — Tradeoffs between writing env vars to
settings.local.json vs CLAUDE_ENV_FILE in SessionStart hooks, including dynamic reloading behavior, scope, persistence, security, and when to use each approach.
- Marketplace to User Settings — How plugins propagate from marketplace.json to user installations.
- CI/CD Pipeline Details — Detailed CI/CD pipeline behavior and conventions.