06-reference/research

claude code plugin private distribution

2026-06-10·research-brief·source: deep-research
claude-codepluginsmarketplaceprivate-distributionphdata

Private Claude Code Plugin Distribution: Marketplace.json, Versioning, and Access Control

The question

How are teams distributing proprietary Claude Code plugins via private marketplaces (Bitbucket / self-hosted git) — versioning, access control, gated update flows?

What we already know (from the vault)

What the web says

marketplace.json schema (confirmed against docs.claude.com/en/plugin-marketplaces)

Top-level required fields:

Top-level optional fields:

Reserved marketplace names (cannot be used): claude-code-marketplace, claude-plugins-official, anthropic-marketplace, and ~12 others impersonating Anthropic.

Per-plugin entry fields (key ones):

Plugin source types:

Source type Key fields Notes
Relative path "./path" string Plugin lives in same repo as marketplace; resolves from marketplace root
github repo (owner/repo), ref?, sha? GitHub shorthand or full URL
url url (full git URL), ref?, sha? GitLab, Bitbucket, any git host
git-subdir url, path, ref?, sha? Sparse-clone a subdirectory; bandwidth-efficient for monorepos
npm package, version?, registry? Supports private npm registries

When both ref and sha are set, sha is the effective pin — install succeeds even if the branch is deleted, as long as the commit is reachable.

Private / Bitbucket distribution (confirmed against docs)

Version pinning and update flow (confirmed against docs)

Version resolution order (first match wins):

  1. version in plugin.json
  2. version in marketplace entry
  3. Git commit SHA of the plugin's source

Key rule: if version is set in plugin.json, pushing new commits without bumping that string does nothing for existing users — they keep the cached copy. Bump version on every release, or omit it to use commit SHA as auto-versioning. [1]

Avoid setting version in both plugin.json and the marketplace entryplugin.json always wins silently; a stale marketplace-entry version can mask your intended pin. [1]

CLI update commands:

Release channels: two separate marketplaces pointing to ref: "stable" and ref: "latest" of the same repo, assigned to different user groups via managed settings. Each channel must resolve to a different version string (or omit version and rely on distinct commit SHAs). [1]

Team-enforced plugins and trust flow (confirmed against docs, with known bug)

extraKnownMarketplaces in .claude/settings.json auto-prompts teammates to install the marketplace when they trust the project folder:

{
  "extraKnownMarketplaces": {
    "company-tools": {
      "source": {
        "source": "url",
        "url": "https://bitbucket.org/company/plugins.git"
      }
    }
  },
  "enabledPlugins": {
    "caf@caf-marketplace": true
  }
}

Known issue (GitHub issue #32606): extraKnownMarketplaces + enabledPlugins in project-level .claude/settings.json does not currently trigger the install prompt reliably — reported as a bug. Also does not work in headless/-p mode (issue #13096). Verify current behavior before relying on it for automated rollout. [2][3]

strictKnownMarketplaces in managed settings — enterprise lockdown:

Container / CI pre-population: CLAUDE_CODE_PLUGIN_SEED_DIR points at a pre-built ~/.claude/plugins directory baked into an image. Seed is read-only; auto-updates are disabled for seed marketplaces. Build via CLAUDE_CODE_PLUGIN_CACHE_DIR=/opt/claude-seed claude plugin install ... at image-build time. [1]

Org-managed plugins via Claude.ai admin console (separate surface from self-hosted)

For teams using Claude.ai enterprise (not self-hosted marketplace), admins set four distribution levels per plugin: Required (auto-deploy, no uninstall), Installed by default (auto-deploy, can uninstall), Available for install (self-service), Not available (hidden). Group-level overrides apply; most-permissive setting wins when a user is in multiple groups. Max 500 plugins per marketplace via GitHub sync (private/internal repos only). [4]

This is a separate surface from the self-hosted marketplace.json approach — applies when using the Claude.ai managed product, not to self-hosted Claude Code installations.

Convergences and contradictions

Convergences:

Contradictions / gaps:

Synthesis for RDCO

CAF on phData Bitbucket — recommended setup:

Create a single Bitbucket repo caf-marketplace with the structure from [[2026-06-09-caf-restructure-proposal]] Move 1. The .claude-plugin/marketplace.json catalogs the caf plugin with a relative-path source ("./plugins/caf"). Version lives exclusively in plugins/caf/.claude-plugin/plugin.json — never set version in the marketplace entry to avoid the silent-wins footgun. Bump version (semver: 4.1.0, 4.2.0, etc.) on every meaningful release; commit-SHA auto-versioning works for internal rollout but gives worse UX in /plugin list output.

For access control: the Bitbucket repo's visibility and branch permissions ARE the access gate — restrict write access to the plugins engineering team, read access to all phData consultants who install Claude Code. For background auto-updates on consultant machines, have IT or onboarding docs set BITBUCKET_TOKEN (app password scoped to repository:read) in shell config. For CI/sandbox environments, use the CLAUDE_CODE_PLUGIN_SEED_DIR container pattern. Do NOT rely on extraKnownMarketplaces auto-prompting — use a documented onboarding step (claude plugin marketplace add <url>) until bug #32606 is confirmed fixed.

For gated updates: the recommended CAF update cadence is explicit version bumps with a changelog entry. Use a stable branch (pinned in the marketplace source.ref) for the production marketplace and a dev branch for a test marketplace consultants can optionally add. This gives a stable/latest channel split without requiring separate marketplace repos. Only promote to stable after a verified pilot engagement.

RDCO ray-plugins — recommended setup:

The existing RayDataCo/ray-plugins setup is already correctly structured. Reinforce two rules from vault memory: (1) only plugin.json version field triggers updates — marketplace.json plugin entries stay version-less; (2) sha-pin any plugin entries pointing to external repos if stability matters. For the phData port, strip any RDCO-internal path references and confirm all plugin sources are self-contained (relative paths within the plugin dir, no ../ escapes). The monorepo git-subdir source type is worth adopting as ray-plugins grows — it enables sparse-clone fetches so consultants don't pull the full repo when installing a single plugin.

For ray-plugins specifically, add a .claude/settings.json at repo root with extraKnownMarketplaces pointing back to RayDataCo/ray-plugins once bug #32606 is confirmed resolved — this closes the "clone the repo and trust the folder" auto-registration loop for contributors.

Schema validation gate: run claude plugin validate . in CI (GitHub Actions for ray-plugins, Bitbucket Pipelines for phData) on every PR that touches marketplace.json or plugin.json. This is a one-line gate that catches structural errors before consultants encounter broken installs.

Open follow-ups

Related

Sources

Vault:

Web (confirmed against docs.claude.com):

  1. Create and distribute a plugin marketplace — Claude Code Docs — primary source; all marketplace.json schema, source types, versioning, private repo auth, strictKnownMarketplaces
  2. extraKnownMarketplaces + enabledPlugins never prompts user to install — GitHub Issue #32606
  3. Support extraKnownMarketplaces in headless/print mode — GitHub Issue #13096
  4. Manage plugins for your organization — Claude Help Center — org-managed admin console (separate claude.ai surface)
  5. claude-plugins-official marketplace.json — GitHub — reference schema from Anthropic's official marketplace
  6. Build a Private Claude Code Plugin Marketplace in 90 Minutes — Automation Labs / Medium
  7. Building a Private Claude Code Plugin Marketplace for Your Team — Dominic Böttger