Skip to content

feat: add marketplace.json for standard plugin distribution#48

Merged
taylorarndt merged 2 commits into
Community-Access:mainfrom
tesles:feat/add-marketplace-json
Mar 4, 2026
Merged

feat: add marketplace.json for standard plugin distribution#48
taylorarndt merged 2 commits into
Community-Access:mainfrom
tesles:feat/add-marketplace-json

Conversation

@tesles

@tesles tesles commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds .claude-plugin/marketplace.json to the repo root, making this repository a standard Claude Code plugin marketplace
  • Enables installation via claude plugin marketplace add Community-Access/accessibility-agents -- the official distribution path
  • Updates claude-code-plugin/README.md with standard marketplace installation instructions alongside existing install.sh method
  • Replaces the need for update.sh plugin cache mutation (lines 113-161) with native plugin update, eliminating coupling to Claude Code's internal cache structure
  • No existing functionality is removed or changed -- install.sh and update.sh remain for project-level embedding and legacy installs

Note

Scope: Claude Code Only. This PR adds native Claude Code plugin marketplace support. It does not modify any non-Claude-Code artifacts (Copilot agents, Codex config, Gemini extension, VS Code profiles). The install.sh and update.sh scripts remain unchanged for users who need those platforms.

Problem

The current install.sh script creates a temporary marketplace directory in /var/folders/.../T/tmp.../ during installation and registers it as a marketplace source in known_marketplaces.json. This causes four issues:

1. Startup warning after OS cleans /tmp

Warning: Failed to load marketplace 'community-access':
  Marketplace file not found at /var/folders/.../T/tmp.../
  accessibility-agents/community-access-plugins/
  .claude-plugin/marketplace.json

2. No auto-update path

Directory-sourced marketplaces pointing to temp paths cannot auto-update. GitHub-sourced marketplaces support native autoUpdate via the plugin system.

3. Non-standard discovery

Users cannot discover or install this plugin through Claude Code's /plugin UI or plugin marketplace add command. The only entry point is running a shell script. No marketplace.json exists on any of the repository's 12 branches.

4. update.sh couples to internal cache layout

update.sh (lines 113-161) directly writes into ~/.claude/plugins/cache/*/accessibility-agents/*/ to update the plugin. This path structure is an implementation detail of Claude Code's plugin cache. If the cache layout changes in a future Claude Code release, the update script breaks silently -- files are written to the wrong location with no error. The native plugin update command is maintained by Anthropic and insulated from these changes.

Solution

Add a marketplace.json to the repository root following the Claude Code official marketplace specification. This makes the repo itself a valid marketplace that Claude Code can register directly from GitHub.

Changes

New file: .claude-plugin/marketplace.json

{
  "$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
  "name": "community-access",
  "description": "Accessibility enforcement plugins for Claude Code",
  "owner": {
    "name": "Community Access",
    "url": "https://github.com/Community-Access"
  },
  "plugins": [
    {
      "name": "accessibility-agents",
      "source": "./claude-code-plugin",
      "description": "WCAG AA accessibility enforcement for Claude Code. 55 specialist agents, 17 commands, and enforcement hooks that delegate to accessibility-lead for UI code review.",
      "version": "1.0.0",
      "author": {
        "name": "Taylor Arndt"
      },
      "category": "accessibility",
      "homepage": "https://github.com/Community-Access/accessibility-agents"
    }
  ]
}

Modified: claude-code-plugin/README.md

 # Accessibility Agents - Claude Code Plugin
 ...
 ## How It Works
 ...

+## Installation
+
+### Standard (Recommended)
+
+Register the marketplace and install the plugin:
+
+```bash
+claude plugin marketplace add Community-Access/accessibility-agents
+claude plugin install accessibility-agents@community-access
+```
+
+Or interactively via `/plugin` in Claude Code.
+
+**Scopes:**
+- `--scope user` (default) -- personal, all projects
+- `--scope project` -- team-shared via `.claude/settings.json` (committed to git)
+- `--scope local` -- personal per-project via `.claude/settings.local.json` (gitignored)
+
+For team projects, add to `.claude/settings.json`:
+
+```json
+{
+  "extraKnownMarketplaces": {
+    "community-access": {
+      "source": {
+        "source": "github",
+        "repo": "Community-Access/accessibility-agents"
+      }
+    }
+  },
+  "enabledPlugins": {
+    "accessibility-agents@community-access": true
+  }
+}
+```
+
+Team members are auto-prompted to install when they open the project.
+
+**Updating:**
+
+```bash
+claude plugin update accessibility-agents@community-access
+```
+
+**Offline install** from a local clone:
+
+```bash
+claude plugin marketplace add ./path/to/local/clone
+claude plugin install accessibility-agents@community-access
+```
+
+### Alternative: install.sh
+
+For embedding agents directly into a project directory
+(self-contained, zero network dependency):
+
 ```bash
 # Install to your project
 bash install.sh --project

 # Install globally
 bash install.sh --global

### Repository layout (after change)

This change adds a `.claude-plugin/` directory at the repo root containing `marketplace.json`. All existing files and directories remain unchanged.

accessibility-agents/ (repo root = marketplace root)

  • .claude-plugin/
  • marketplace.json NEW -- marketplace definition
    claude-code-plugin/ unchanged -- the actual plugin
    .claude-plugin/
    plugin.json unchanged -- plugin manifest
    agents/ 55 agent .md files
    commands/ 17 skill commands
    hooks/
    hooks.json plugin hook configuration
    scripts/
    a11y-enforce-edit.sh PreToolUse enforcement
    a11y-mark-reviewed.sh PostToolUse session marker
    a11y-team-eval.sh UserPromptSubmit detection
    CLAUDE.md decision matrix + standards
    README.md modified -- adds marketplace install
    install.sh unchanged
    update.sh unchanged
    uninstall.sh unchanged
    docs/ unchanged

## Before / after comparison

| Feature | Before: install.sh only | After: Marketplace + install.sh |
|---|---|---|
| Marketplace source | `/tmp/` (OS-cleaned) | GitHub repo (persistent) |
| Auto-update | Not supported | `plugin update` |
| Discovery | Shell script only | `/plugin` UI + CLI |
| Update mechanism | Mutates internal cache | Native plugin system |
| install.sh | Works | Still works (unchanged) |

## install.sh step-by-step mapping

Every Claude Code step of `install.sh` maps to a native plugin mechanism:

| install.sh step | Plugin equivalent | Status |
|---|---|---|
| Copy agents to `~/.claude/agents/` | Plugin `agents/` dir auto-loaded on install | Covered |
| Copy skills to `~/.claude/skills/` | Plugin `commands/` + `skills/` auto-loaded | Covered |
| Merge CLAUDE.md snippet | Plugin `CLAUDE.md` at root loaded per session | Covered |
| Create temp marketplace dir + register | `marketplace.json` in repo + `plugin marketplace add` | Covered (this PR) |
| Register 3 global hooks | Plugin `hooks/hooks.json` loaded on enable | Covered |
| Copy hook scripts to `~/.claude/hooks/` | Plugin `scripts/` via `${CLAUDE_PLUGIN_ROOT}` | Covered |
| Auto-update via LaunchAgent/cron | GitHub marketplace `autoUpdate` | Covered |
| File manifest tracking | Plugin cache at `~/.claude/plugins/cache/` | Covered |
| Project-level embedding (`--project`) | `extraKnownMarketplaces` + auto-prompt | Different model* |

> [!NOTE]
> **\*Project-level distribution.** `install.sh --project` copies agent files directly into the project's `.claude/` directory -- self-contained, version-controlled, zero network dependency. The marketplace `--scope project` approach uses `extraKnownMarketplaces` in `.claude/settings.json` to auto-prompt teammates to install. Both achieve team distribution. `install.sh --project` is better for air-gapped or offline environments. The marketplace approach is better for keeping plugins updated across teams.

## Update lifecycle: update.sh vs native plugin updates

`update.sh` (388 lines) manages updates for Claude Code by directly writing into the plugin cache. With a marketplace, the Claude Code-specific update path is replaced by the native `plugin update` command.

| update.sh section | What it does | Marketplace equivalent |
|---|---|---|
| Lines 89-108 | Clone/pull repo to local cache dir | `plugin marketplace update community-access` |
| Lines 113-161 | Diff + copy files into `~/.claude/plugins/cache/` | `plugin update accessibility-agents@community-access` |
| Lines 353-378 | Update global hook scripts in `~/.claude/hooks/` | Plugin hooks auto-update with the plugin |
| Lines 163-234 | Legacy file-based install update (agents/commands) | No equivalent -- `update.sh` only |

> [!WARNING]
> **Cache mutation.** The `update.sh` plugin cache update (lines 113-161) clones the repo, diffs files, then copies them directly into `~/.claude/plugins/cache/*/accessibility-agents/*/`. The native `plugin update` command produces the same result -- updated plugin files -- but through Claude Code's own internal process rather than a third-party script reaching into an undocumented path. If Anthropic changes the cache layout, the native command adapts; the script does not.

> [!TIP]
> **What update.sh still covers.** The legacy file-based update path (lines 163-234) remains necessary for users who installed via `install.sh --project`, where agents live directly in the project's `.claude/` directory rather than the plugin cache.

## Hook enforcement: plugin vs global

<details>
<summary>Hook enforcement architecture decision</summary>

The project's architecture docs state:

> "Plugin hooks can only inject text instructions. They cannot block tool calls."

The [official Anthropic Claude Code plugin reference](https://code.claude.com/docs/en/plugins-reference) describes plugin hooks and global hooks using the same `hooks.json` schema. The plugin already ships `hooks/hooks.json` with three hook entries and references the enforcement scripts in `scripts/`. These are loaded when the plugin is enabled.

This PR does not change the hook mechanism. The plugin's built-in `hooks.json` provides the enforcement layer through the native plugin system. The `install.sh` global hook registration provides an additional layer for users who prefer belt-and-suspenders enforcement.

**Both approaches coexist.** This PR is not a replacement.

</details>

## Distribution paths after this PR

| Use case | Method | Scope |
|---|---|---|
| Individual user, all projects | `plugin install --scope user` | User (default) -- `~/.claude/settings.json` |
| Team project, shared via git | `plugin install --scope project` or `extraKnownMarketplaces` | Project -- `.claude/settings.json` (committed) |
| Personal per-project, not shared | `plugin install --scope local` | Local -- `.claude/settings.local.json` (gitignored) |
| Team project, self-contained | `bash install.sh --project` | Project (files copied into repo) |
| Air-gapped / offline | `plugin marketplace add ./local-clone` or `bash install.sh --project` | User or Project |
| Update (marketplace installs) | `plugin update accessibility-agents@community-access` | User / Project / Local |
| Update (project-embedded installs) | `bash update.sh --project` | Project |

## Test plan

- [ ] Run `claude plugin validate .` from repo root -- confirms marketplace.json + plugin.json are valid
- [ ] Run `claude plugin marketplace add ./` from local clone -- confirms marketplace registers without errors
- [ ] Run `claude plugin install accessibility-agents@community-access --scope user` -- confirms plugin installs, agents load, hooks fire
- [ ] Verify `install.sh --global` still works independently -- no regressions
- [ ] Verify `install.sh --project` still works independently -- no regressions

## References

- [Create and distribute a Claude Code plugin marketplace](https://code.claude.com/docs/en/plugin-marketplaces): official marketplace specification
- [Claude Code plugins reference](https://code.claude.com/docs/en/plugins-reference): plugin.json schema, hooks.json schema, component paths
- [Discover and install prebuilt Claude Code plugins](https://code.claude.com/docs/en/discover-plugins): user-facing install flow
- [Create Claude Code plugins](https://code.claude.com/docs/en/plugins): plugin directory structure
- [Reference marketplace.json from anthropics/claude-plugins-official](https://github.com/anthropics/claude-plugins-official/blob/main/.claude-plugin/marketplace.json): reference implementation

Adds .claude-plugin/marketplace.json to the repo root, making this
repository a standard Claude Code plugin marketplace. Users can now
install via `claude plugin marketplace add` instead of only through
install.sh. Updates claude-code-plugin/README.md with marketplace
install instructions alongside the existing install.sh method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@taylorarndt taylorarndt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Verified against official Claude Code docs

I checked every URL, CLI command, and JSON field in this PR against the official Claude Code plugin documentation at code.claude.com/docs/en/plugin-marketplaces and code.claude.com/docs/en/discover-plugins.

What checks out

The core approach is solid. The marketplace system works exactly as described:

  • .claude-plugin/marketplace.json location is correct
  • /plugin marketplace add owner/repo syntax is correct
  • /plugin install plugin-name@marketplace-name syntax is correct
  • extraKnownMarketplaces and enabledPlugins JSON structures match the docs
  • Relative path source "./claude-code-plugin" is valid for git-based marketplaces
  • --scope user/project/local flags are documented
  • Offline local clone install path is documented
  • Marketplace name community-access is not on the reserved names list

Issues to fix before merge

1. $schema URL is fabricated
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json" does not appear anywhere in the official docs or examples. No marketplace example in the docs uses a $schema field. This URL likely does not resolve. Recommend removing it.

2. Top-level description is in the wrong location
The docs define three top-level required fields: name, owner, plugins. A marketplace description belongs under metadata.description, not as a top-level description field. From the docs:

Field Type Description
metadata.description string Brief marketplace description

Either move it to "metadata": { "description": "..." } or remove it.

3. owner.url is not a documented field
The docs say owner supports name (required) and email (optional). There is no url field:

Field Type Required Description
name string Yes Name of the maintainer or team
email string No Contact email for the maintainer

Either change to "email" with a contact address, or remove the field.

4. claude plugin update command is not documented
The README adds claude plugin update accessibility-agents@community-access. The official docs do not show a /plugin update command for individual plugins. Plugin updates are handled through:

  • /plugin marketplace update marketplace-name (refreshes marketplace listings)
  • Auto-update at startup (when enabled for the marketplace)

Recommend replacing with the documented update path or verifying this command exists in the current CLI.

Summary

The marketplace concept and structure are correct. Four fields/commands need cleanup to match the actual spec. None are blocking (Claude Code likely ignores unknown fields silently), but they could confuse users who cross-reference the docs.

@taylorarndt taylorarndt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes Requested: 4 issues found against official Claude Code docs

Verified every URL, CLI command, and JSON field against the official docs at code.claude.com/docs/en/plugin-marketplaces and code.claude.com/docs/en/discover-plugins. The core marketplace approach is correct and well-structured, but 4 fields/commands need cleanup to match the spec.

1. Remove fabricated $schema URL

"$schema": "https://anthropic.com/claude-code/marketplace.schema.json" does not appear in any official doc or example. This URL likely does not resolve. No marketplace example in the docs uses a $schema field. Remove it.

2. Move description under metadata

Top-level "description" is not a documented top-level field. The docs define three top-level required fields: name, owner, plugins. A marketplace description belongs under metadata.description:

"metadata": {
  "description": "Accessibility enforcement plugins for Claude Code"
}

3. Fix owner.url — not a documented field

The docs say owner supports name (required) and email (optional). There is no url field. Either change to "email" with a contact address, or remove it.

4. Verify claude plugin update command

The README adds claude plugin update accessibility-agents@community-access. The official docs do not show a /plugin update command for individual plugins. Updates are handled through:

  • /plugin marketplace update marketplace-name (refreshes listings)
  • Auto-update at startup (when enabled)

Replace with the documented path or confirm this command exists in the current CLI.

What checks out

Everything else is correct: marketplace location, install commands, extraKnownMarketplaces/enabledPlugins structures, relative path source, scopes, offline install, and the marketplace name is not reserved. Good PR — just needs these 4 items cleaned up.

@tesles tesles left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Darn, was trying to go 3-for-3! Implemented 3 of the 4 corrections and included supporting verification for #4.

See the plugins-reference entry for plugin update:

claude plugin update <plugin> [options]

Arguments:
  <plugin>    Plugin name or plugin-name@marketplace-name

Options:
  -s, --scope <scope>    Scope to update: user, project, local, or managed (default: user)
  -h, --help             Display help for command

There is also a separate command for refreshing marketplace listings: /plugin marketplace update marketplace-name. The two serve different purposes — one updates an installed plugin, the other refreshes the marketplace catalog.

  1. $schema -- Fixed. Removed. Not in the official spec, URL was hallucinated. 😓
  2. description -- Fixed. Moved to metadata.description per the documented schema:
    "metadata": {
      "description": "Accessibility enforcement plugins for Claude Code"
    }
  3. owner.url -- Fixed. Removed. Only name (required) and email (optional) are documented on the owner object.

Remove $schema (not in spec), move description to metadata.description,
remove undocumented owner.url field.

Addresses review feedback items 1-3 from #48.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@taylorarndt taylorarndt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

Verified all fields and CLI commands against the official Claude Code docs:

  • marketplace.json — all fields match the marketplace schema. No undocumented fields remain after the fixes.
  • claude plugin update — confirmed documented in the plugins-reference CLI commands.
  • README instructionsmarketplace add, plugin install, extraKnownMarketplaces, scopes, and offline install all match the official docs.

All 4 requested changes from the previous review are resolved. Clean PR, ready to merge.

@taylorarndt taylorarndt merged commit e0e23a1 into Community-Access:main Mar 4, 2026
3 checks passed
@tesles tesles deleted the feat/add-marketplace-json branch March 5, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants