@xbluesky/cc-marketspec
v0.12.0
Published
Headless data standard + generator for Claude Code plugin marketplace presentation. Describe a marketplace as data (entry.yaml / catalog.yaml); emit one manifest.json any site renders.
Maintainers
Readme
cc-marketspec
A headless data standard + generator for the presentation of a Claude Code plugin marketplace.
You describe a marketplace as data; cc-marketspec joins it with the native
plugin manifests, derives what's already encoded there, validates, and emits a
single manifest.json — a render-agnostic document any website can be built
from. It ships data, not design. How the site looks is the consumer's.
Mental model: native layer vs presentation layer
- Native (Claude Code defines):
marketplace.json,plugin.json,.mcp.json,skills/*/SKILL.md·commands/*.md·agents/*.mdfrontmatter,hooks/hooks.json. Identity + structure. You maintain these anyway for the plugins to work. - Presentation (this standard):
catalog.yaml(marketplace-level) +entry.yaml(per plugin). Only what native can't express.
Rule: presentation never restates native facts — it references them or adds presentation value. The generator joins the two by plugin id (= directory name).
The three files
| File | Where | Role |
|------|-------|------|
| catalog.yaml | repo root | marketplace-level data: schemaVersion, lang, group taxonomy |
| entry.yaml | each plugins/<id>/ | per-plugin presentation overlay (all optional) |
| manifest.json | generated | the consolidated consumer API — never hand-edited |
entry.yaml is optional enrichment: native alone yields a valid (plainer)
manifest via fallbacks (e.g. intro/tagline → native description, skill
description → native SKILL.md description). Authoring burden is minimal by design.
Install
npm install -D @xbluesky/cc-marketspec
# or run it without installing:
npx @xbluesky/cc-marketspecUsage
# In a marketplace repo (defaults to cwd):
npx @xbluesky/cc-marketspec
# -> writes ./manifest.json
# Validate only (CI gate) — report errors/warnings, write nothing:
npx @xbluesky/cc-marketspec --check
cc-marketspec --help # full flag list (after install, the bin is `cc-marketspec`)
cc-marketspec --versionA complete, runnable example marketplace (with its generated manifest.json)
lives in examples/marketplace/ — it's also the golden
fixture the test suite regenerates and diffs.
Programmatic:
import { generateManifest, Manifest, Entry } from '@xbluesky/cc-marketspec';
const { manifest, errors, warnings } = generateManifest(process.cwd());
// Entry / Catalog / Manifest are Zod schemas; their z.infer types are exported too.Editor support while authoring
Point your YAML language server at the published JSON Schemas:
# yaml-language-server: $schema=node_modules/@xbluesky/cc-marketspec/schemas/entry.schema.json
group: build
tagline: ...What the generator derives (so you don't restate it)
- skill autoload badge ←
user-invocable: false; bundled-resource counts ← skill dir - command argument table ← native
arguments/argument-hint;summary← first sentence of description - agent tools ← frontmatter
tools;summary← description - mcp transport + env-var keys ←
.mcp.json - hook event/matcher ←
hooks.json - plugin identity (name/version/author/license/keywords/deps) ←
plugin.json/marketplace.json - plugin category (native classification) ←
marketplace.jsonentrycategory(distinct from authoredgroup)
What you author (no native source)
entry.yaml: curated description/tagline/intro, agent returns/not,
mcp provides/install/auth/setup/env descriptions, examples, hook why,
configuration (.claude/<plugin>.local.md settings), tips / traps.
Validation (CI strict, dev degrades)
Beyond schema validation, the generator enforces referential integrity that no declarative schema can:
- plugin directory name ==
plugin.jsonname == marketplace entry name entry.yamlskill/command/agent/mcp entries must exist on disk;entryhooks must match a realevent/matcherinhooks.jsonentry.groupmust be declared incatalog.yamlgroups[]entryenv keys must exist in.mcp.json(undescribed keys → warning)
Any error fails the build (all errors are reported, not just the first).
Coverage gate
The coverage gate checks that plugins have authored enough presentation data.
Rules are addressed by <component>.<field> dot-paths (e.g. skill.trigger,
plugin.tagline). Each rule has a built-in default severity:
| Rule | Default |
|------|---------|
| skill.trigger | warn |
| skill.examples | off |
| command.description | off |
| agent.summary | warn |
| mcp.env | warn |
| mcp.provides | off |
| plugin.tagline | warn |
| plugin.group | off |
Override per-rule (or set "*" as a catch-all) in catalog.yaml:
coverage:
skill.trigger: error # promote to hard failure
plugin.group: warn # promote from off
"*": warn # default fallback for all other rules--check exits non-zero if any error-severity finding exists.
--strict-coverage additionally exits non-zero when there are any warn
findings — use this as a stricter release gate.
Getting started: npx cc-marketspec init
Scaffolds the files you need to begin authoring presentation data. It is
non-destructive: any file that already exists is reported as skipped.
npx @xbluesky/cc-marketspec initCreates:
catalog.yaml— marketplace-level metadata and group taxonomy (with a commented-outcoverage:block ready to tune).plugins/<id>/entry.yaml— per-plugin overlay stub, for each plugin found in.claude-plugin/marketplace.jsonthat has aplugin.jsonon disk.
CI
The --check flag validates without writing anything — use it on PRs.
GitHub Actions (.github/workflows/manifest.yml):
on: [pull_request, push]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npx @xbluesky/cc-marketspec --checkGitLab CI (.gitlab-ci.yml):
check:manifest:
image: node:22
script:
- npx @xbluesky/cc-marketspec --checkAdd --strict-coverage for a stricter release gate that fails on warnings too.
The generated manifest.json can be committed to the repo or uploaded as a
CI artifact — that choice is yours.
MCP
npx @xbluesky/cc-marketspec mcpStarts a stdio MCP server. Five tools:
| Tool | What it does |
|------|-------------|
| get_schema | Returns the JSON Schema for entry, catalog, or manifest |
| list_authoring_sections | Lists the entry.yaml authoring guide sections (id/title/when) |
| get_authoring_guide | Returns the full authoring guide markdown for one section |
| check_coverage | Runs the coverage gate against a plugin directory |
| scaffold_entry | Generates an entry.yaml stub for a given plugin |
Hosted MCP server
The same five MCP tools (get_schema, list_authoring_sections, get_authoring_guide,
check_coverage, scaffold_entry) are available over HTTP so contributors can query the schema
and be guided without installing anything. The handler is a platform-neutral
web-standard fetch(Request) → Response (handleHttpRequest, exported from the
package); Cloudflare Workers is the reference deployment but not a requirement.
Use it (contributors)
Add the endpoint to any Streamable-HTTP-capable MCP client:
https://cc-marketspec-mcp.xbluesky.workers.devNo credentials — the endpoint is intentionally open and read-only.
Self-host (owners)
npm install
npm run worker:dev # local: serves the handler (npx wrangler dev)
npx wrangler login # one-time Cloudflare auth (or set CLOUDFLARE_API_TOKEN)
npm run deploy # publishes the Worker; prints the public URLWrangler is not a dependency — worker:dev / deploy invoke it via npx, so
it stays out of the install tree (its platform binaries otherwise bloat npm ci).
The open/no-auth posture is deliberate (read-only tools, no secrets, file contents are passed as parameters). If you later need abuse protection, add a Cloudflare Rate Limiting rule — no code change required.
Auto-deploy from CI
.github/workflows/ci.yml deploys the Worker on every push to main (once the
validate job is green), via cloudflare/wrangler-action. To enable it, add two
GitHub repository secrets (Settings → Secrets and variables → Actions):
| Secret | Value |
|--------|-------|
| CLOUDFLARE_API_TOKEN | A Cloudflare API token scoped to Workers Scripts: Edit |
| CLOUDFLARE_ACCOUNT_ID | Your Cloudflare account ID (Workers dashboard → Account ID) |
The deploy-worker job runs in parallel with the npm release job — the Worker
going live does not wait on the npm publish, and a failed publish won't block the
deploy. Until both secrets are set the job fails loudly (never a silent skip), so
a missing secret is visible in the Actions tab.
Install as a Claude Code plugin
cc-marketspec is itself an installable Claude Code plugin. Add this repo as a marketplace and install it:
claude plugin marketplace add XBlueSky/cc-marketspec
claude plugin install cc-marketspecYou get:
- The hosted MCP tools (
get_schema,list_authoring_sections,get_authoring_guide,check_coverage,scaffold_entry) wired in automatically — no endpoint config. - Slash commands that run the generator against your current marketplace repo:
/cc-generate— writemanifest.json/cc-check— validate without writing, with errors explained/cc-init— scaffoldcatalog.yaml/entry.yamltemplates
This repo dogfoods the framework: its own manifest.json is generated by
cc-marketspec from the marketplace data in this repo.
- Showcase site —
site/is a reference Astro app that renders this repo'smanifest.jsoninto a marketplace page, live at cc-marketspec.pages.dev. It's the worked example of the "manifest → site" path: downstream marketplaces can copy it.
Versioning
The standard is semver; the manifest carries schemaVersion (MAJOR.MINOR).
Consumers gate on MAJOR; MINOR is additive / back-compatible.
Not in v1 (back-compatible additions later)
- An
x-*extension hatch (kept strict in v1 so the Zod validator and the emitted JSON Schema stay identical). lsp/output-stylescomponent types (pure-derive; additive MINOR).
