Version: 1.0.0 Last Updated: 2025-12-16 Audience: Marketplace operators, infrastructure architects, package publishers
- Overview
- Architecture
- Infrastructure Requirements
- Registry Setup
- Hosting Options
- Discovery Protocol
- Package Distribution
- Security Considerations
- Step-by-Step Setup Guide
- Multi-Registry Support
- Monitoring & Maintenance
- Troubleshooting
- Advanced Topics
A Claude Code marketplace is a discoverable registry of skills, agents, and commands that users can install via the /plugin command. This guide explains how to create and operate your own marketplace.
By following this guide, you'll create:
- A registry.json file describing available packages
- Package distribution infrastructure
- Discovery endpoints for Claude Code integration
- Version management system
- Publisher verification (optional)
- Marketplace operators - Setting up internal/public marketplaces
- Enterprise admins - Deploying private package registries
- Package publishers - Understanding marketplace infrastructure
- Platform developers - Building marketplace tooling
- Git repository (GitHub, GitLab, Bitbucket, or self-hosted)
- Basic understanding of JSON and HTTP
- Text editor or IDE
- (Optional) Web hosting or CDN
┌─────────────────────────────────────────────────────────────┐
│ Claude Code CLI │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ /plugin marketplace add <owner>/<repo> │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────┘
│
│ 1. Discovery Request
▼
┌─────────────────────────────────────────────────────────────┐
│ Marketplace Registry (HTTP/HTTPS) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ GET /docs/registries/nuget/registry.json │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────┘
│
│ 2. Registry Response
▼
┌─────────────────────────────────────────────────────────────┐
│ registry.json │
│ { │
│ "marketplace": { "name": "...", "version": "..." }, │
│ "packages": { │
│ "package-name": { │
│ "version": "1.0.0", │
│ "path": "packages/package-name", │
│ "artifacts": { ... } │
│ } │
│ } │
│ } │
└────────────────────────┬────────────────────────────────────┘
│
│ 3. Package Installation
▼
┌─────────────────────────────────────────────────────────────┐
│ Package Artifacts │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ GET /packages/package-name/manifest.yaml │ │
│ │ GET /packages/package-name/commands/cmd.md │ │
│ │ GET /packages/package-name/agents/agent.md │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
│ 4. Installation
▼
┌─────────────────────────────────────────────────────────────┐
│ User's .claude/ Directory │
│ .claude/ │
│ ├── commands/ │
│ │ └── package-cmd.md │
│ ├── agents/ │
│ │ └── package-agent.md │
│ └── skills/ │
│ └── package-skill/SKILL.md │
└─────────────────────────────────────────────────────────────┘
- Discovery: User runs
/plugin marketplace add owner/repo - Registry Fetch: Claude Code fetches
registry.jsonfrom known path - Package Browse: User browses packages via
/pluginUI - Installation: User selects package, Claude Code fetches artifacts
- Deployment: Artifacts copied to user's
.claude/directory
Claude Code resolves marketplace URLs using this pattern:
Input: /plugin marketplace add randlee/synaptic-canvas
Resolves to:
1. https://raw.githubusercontent.com/randlee/synaptic-canvas/main/docs/registries/nuget/registry.json
2. (If 404) https://raw.githubusercontent.com/randlee/synaptic-canvas/master/docs/registries/nuget/registry.json
3. (If 404) https://randlee.github.io/synaptic-canvas/registries/nuget/registry.json
Required:
- ✅ GitHub repository (public or private)
- ✅
docs/registries/nuget/registry.jsonfile - ✅ Package directories with manifest.yaml files
No additional infrastructure needed!
GitHub raw URLs serve files automatically:
https://raw.githubusercontent.com/owner/repo/main/docs/registries/nuget/registry.json
Adds:
- ✅ GitHub Pages for better caching
- ✅ Custom domain (optional)
- ✅ HTTPS by default
- ✅ CDN distribution
Benefits:
- Faster downloads
- Better availability
- Professional URLs
- Lower rate limits
Required:
- ✅ Web server (nginx, Apache, Caddy)
- ✅ HTTPS certificate
- ✅ Version control system
- ✅ CI/CD pipeline for registry updates
Optional:
- CDN (Cloudflare, CloudFront)
- Authentication layer
- Usage analytics
- Package signing infrastructure
The registry.json file is the heart of your marketplace. It describes all available packages.
Location: docs/registries/nuget/registry.json
Why this path?
- Claude Code expects this specific path
nugetrefers to the registry format version- Multiple registries can coexist in subdirectories
{
"$schema": "https://yourcompany.github.io/schemas/package-registry.schema.json",
"version": "2.0.0",
"generated": "2025-12-16T00:00:00Z",
"repo": "your-org/your-marketplace",
"marketplace": {
"name": "Your Marketplace Name",
"version": "1.0.0",
"status": "stable",
"url": "https://github.com/your-org/your-marketplace"
},
"packages": {
"example-package": {
"name": "example-package",
"version": "1.0.0",
"status": "stable",
"tier": 0,
"description": "A sample package demonstrating basic functionality",
"github": "your-org/your-marketplace",
"repo": "https://github.com/your-org/your-marketplace",
"path": "packages/example-package",
"readme": "https://raw.githubusercontent.com/your-org/your-marketplace/main/packages/example-package/README.md",
"license": "MIT",
"author": "Your Name",
"tags": ["example", "demo"],
"artifacts": {
"commands": 1,
"skills": 1,
"agents": 2,
"scripts": 0
},
"dependencies": [],
"changelog": "https://raw.githubusercontent.com/your-org/your-marketplace/main/packages/example-package/CHANGELOG.md",
"lastUpdated": "2025-12-16",
"dependents": []
}
},
"metadata": {
"registryVersion": "2.0.0",
"schemaVersion": "1.0.0",
"totalPackages": 1,
"totalCommands": 1,
"totalSkills": 1,
"totalAgents": 2,
"totalScripts": 0,
"categories": {
"examples": ["example-package"]
}
},
"versionCompatibility": {
"marketplace": "1.0.0",
"minimumPackageVersion": "1.0.0",
"maximumPackageVersion": "1.x.x",
"note": "Stable release with long-term support"
}
}| Field | Type | Required | Description |
|---|---|---|---|
$schema |
string | No | JSON Schema URL for validation |
version |
string | Yes | Registry format version (e.g., "2.0.0") |
generated |
string | Yes | ISO 8601 timestamp of last update |
repo |
string | Yes | GitHub repo path (owner/repo) |
marketplace |
object | Yes | Marketplace metadata |
packages |
object | Yes | Package definitions (key = package name) |
metadata |
object | Yes | Registry statistics and categorization |
versionCompatibility |
object | Yes | Version constraints |
publishers |
object | No | Publisher verification info |
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Display name of marketplace |
version |
string | Yes | Marketplace platform version |
status |
string | Yes | "beta", "stable", or "deprecated" |
url |
string | Yes | Homepage URL |
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Package identifier (kebab-case) |
version |
string | Yes | SemVer version (e.g., "1.0.0") |
status |
string | Yes | "beta", "stable", "deprecated" |
tier |
integer | Yes | 0 (no deps), 1 (tokens), 2 (runtime deps) |
description |
string | Yes | One-line package description |
github |
string | Yes | GitHub repo path |
repo |
string | Yes | Full repo URL |
path |
string | Yes | Path to package directory |
readme |
string | Yes | URL to README.md |
license |
string | Yes | License identifier (e.g., "MIT") |
author |
string | Yes | Author name or organization |
tags |
array | Yes | Search tags |
artifacts |
object | Yes | Count of each artifact type |
dependencies |
array | Yes | Runtime dependencies (empty for Tier 0) |
changelog |
string | Yes | URL to CHANGELOG.md |
lastUpdated |
string | Yes | ISO 8601 date |
dependents |
array | Yes | Packages that depend on this one |
variables |
object | No | Token substitution variables (Tier 1) |
"artifacts": {
"commands": 2, // Number of slash commands
"skills": 1, // Number of skills
"agents": 5, // Number of agents
"scripts": 1 // Number of helper scripts
}Tier 0: Direct Copy
- No token substitution
- No external dependencies
- Works immediately after installation
{
"tier": 0,
"dependencies": [],
"variables": {} // Omit entirely
}Tier 1: Token Substitution
- Requires variable substitution at install time
- Auto-detected from environment
{
"tier": 1,
"dependencies": ["git >= 2.27"],
"variables": {
"REPO_NAME": {
"auto": "git-repo-basename",
"description": "Repository name from git toplevel"
}
}
}Tier 2: Runtime Dependencies
- External tools required before use
{
"tier": 2,
"dependencies": [
"python3 >= 3.12",
"gh >= 2.0"
]
}Step 1: Initialize the file
mkdir -p docs/registries/nuget
cat > docs/registries/nuget/registry.json <<'EOF'
{
"version": "2.0.0",
"generated": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"repo": "your-org/your-marketplace",
"marketplace": {
"name": "Your Marketplace",
"version": "1.0.0",
"status": "stable",
"url": "https://github.com/your-org/your-marketplace"
},
"packages": {},
"metadata": {
"registryVersion": "2.0.0",
"totalPackages": 0
}
}
EOFStep 2: Add your first package
{
"packages": {
"my-first-package": {
"name": "my-first-package",
"version": "1.0.0",
"status": "stable",
"tier": 0,
"description": "My first Claude Code package",
"github": "your-org/your-marketplace",
"repo": "https://github.com/your-org/your-marketplace",
"path": "packages/my-first-package",
"readme": "https://raw.githubusercontent.com/your-org/your-marketplace/main/packages/my-first-package/README.md",
"license": "MIT",
"author": "Your Name",
"tags": ["utility", "automation"],
"artifacts": {
"commands": 1,
"skills": 0,
"agents": 1,
"scripts": 0
},
"dependencies": [],
"changelog": "https://raw.githubusercontent.com/your-org/your-marketplace/main/packages/my-first-package/CHANGELOG.md",
"lastUpdated": "2025-12-16",
"dependents": []
}
}
}Step 3: Validate JSON
# Check JSON syntax
python3 -m json.tool docs/registries/nuget/registry.json > /dev/null && echo "Valid JSON" || echo "Invalid JSON"
# Or use jq
jq empty docs/registries/nuget/registry.json && echo "Valid JSON"Pros:
- ✅ Zero setup required
- ✅ Free forever
- ✅ Works immediately
- ✅ Automatic versioning (git branches/tags)
Cons:
- ❌ Rate limiting (5,000 requests/hour for authenticated)
- ❌ No custom domain
- ❌ Slower than CDN
- ❌ No analytics
Setup:
# 1. Commit your registry
git add docs/registries/nuget/registry.json
git commit -m "Add marketplace registry"
git push
# 2. Test access
curl https://raw.githubusercontent.com/your-org/your-marketplace/main/docs/registries/nuget/registry.json
# 3. Users add marketplace
/plugin marketplace add your-org/your-marketplaceURL Pattern:
https://raw.githubusercontent.com/{owner}/{repo}/{branch}/docs/registries/nuget/registry.json
Pros:
- ✅ Free for public repos
- ✅ Custom domain support
- ✅ HTTPS by default
- ✅ CDN-backed (Fastly)
- ✅ Better rate limits
- ✅ Professional appearance
Cons:
- ❌ 1 GB repository size limit
- ❌ 100 GB/month bandwidth soft limit
- ❌ Public repos only (unless GitHub Pro)
Setup:
Step 1: Enable GitHub Pages
# In your repo: Settings → Pages
# Source: Deploy from branch
# Branch: main
# Folder: /docsStep 2: Update file structure
# Move registry to web-accessible path
mkdir -p docs/registries/nuget
# registry.json already at correct locationStep 3: Create index page (optional)
cat > docs/index.html <<'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Your Marketplace</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Your Claude Code Marketplace</h1>
<p>Add this marketplace to Claude Code:</p>
<pre><code>/plugin marketplace add your-org/your-marketplace</code></pre>
<h2>Registry</h2>
<p><a href="registries/nuget/registry.json">registry.json</a></p>
</body>
</html>
EOFStep 4: Test deployment
# Wait 1-2 minutes for deployment
curl https://your-org.github.io/your-marketplace/registries/nuget/registry.jsonStep 5: Custom domain (optional)
# Add CNAME file
echo "marketplace.yourcompany.com" > docs/CNAME
git add docs/CNAME
git commit -m "Add custom domain"
git push
# Configure DNS:
# Add CNAME record: marketplace.yourcompany.com → your-org.github.ioURL Pattern:
https://{owner}.github.io/{repo}/registries/nuget/registry.json
# or
https://marketplace.yourcompany.com/registries/nuget/registry.json
Pros:
- ✅ Ultra-fast global distribution
- ✅ DDoS protection
- ✅ Free tier available (Cloudflare)
- ✅ Advanced caching control
- ✅ Analytics included
Cons:
- ❌ Requires setup and configuration
- ❌ Potential costs at scale
Setup (Cloudflare Pages):
Step 1: Connect repository
# 1. Login to Cloudflare Dashboard
# 2. Pages → Create a project
# 3. Connect to Git → Select your repoStep 2: Configure build
Build command: (leave empty)
Build output directory: /docs
Branch: mainStep 3: Deploy
# Automatic deployment on every push
# URL: https://your-marketplace.pages.devStep 4: Custom domain
# Cloudflare Pages → Custom domains → Add domain
# DNS automatically configuredURL Pattern:
https://your-marketplace.pages.dev/registries/nuget/registry.json
# or
https://marketplace.yourcompany.com/registries/nuget/registry.json
Pros:
- ✅ Full control
- ✅ Private/internal only
- ✅ Custom authentication
- ✅ Compliance-friendly
- ✅ No external dependencies
Cons:
- ❌ Requires infrastructure
- ❌ Ongoing maintenance
- ❌ Uptime responsibility
Setup (nginx):
Step 1: Install nginx
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install nginx
# RHEL/CentOS
sudo yum install nginxStep 2: Configure site
# /etc/nginx/sites-available/marketplace
server {
listen 80;
server_name marketplace.yourcompany.com;
root /var/www/marketplace;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location /registries/ {
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
add_header Cache-Control "public, max-age=300";
}
}Step 3: Deploy files
# Create web root
sudo mkdir -p /var/www/marketplace/registries/nuget
# Copy registry
sudo cp docs/registries/nuget/registry.json /var/www/marketplace/registries/nuget/
# Set permissions
sudo chown -R www-data:www-data /var/www/marketplace
sudo chmod -R 755 /var/www/marketplaceStep 4: Enable SSL
# Install Certbot
sudo apt-get install certbot python3-certbot-nginx
# Get certificate
sudo certbot --nginx -d marketplace.yourcompany.comStep 5: Enable and test
# Enable site
sudo ln -s /etc/nginx/sites-available/marketplace /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
# Test
curl https://marketplace.yourcompany.com/registries/nuget/registry.jsonAutomation (CI/CD):
# .github/workflows/deploy-registry.yml
name: Deploy Registry
on:
push:
branches: [main]
paths:
- 'docs/registries/**'
- 'packages/**'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to server
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_KEY }}
REMOTE_HOST: marketplace.yourcompany.com
REMOTE_USER: deploy
SOURCE: "docs/registries/"
TARGET: "/var/www/marketplace/registries/"When a user runs /plugin marketplace add owner/repo, Claude Code follows this discovery process:
Step 1: Parse input
Input: your-org/your-marketplace
Parsed:
- owner: your-org
- repo: your-marketplace
Step 2: Attempt primary URL
GET https://raw.githubusercontent.com/your-org/your-marketplace/main/docs/registries/nuget/registry.json
Status: 200 OK
└─> Success! Registry loaded.
Status: 404 Not Found
└─> Try fallback...Step 3: Fallback to master branch
GET https://raw.githubusercontent.com/your-org/your-marketplace/master/docs/registries/nuget/registry.json
Status: 200 OK
└─> Success! Registry loaded.
Status: 404 Not Found
└─> Try GitHub Pages...Step 4: Fallback to GitHub Pages
GET https://your-org.github.io/your-marketplace/registries/nuget/registry.json
Status: 200 OK
└─> Success! Registry loaded.
Status: 404 Not Found
└─> Error: Marketplace not foundFor self-hosted marketplaces, Claude Code may support custom URLs:
# Full URL format (future feature)
/plugin marketplace add https://marketplace.yourcompany.com/registries/nuget/registry.json
# Short alias (future feature)
/plugin marketplace add mycompany
# Maps to configured URL in ~/.claude/config.yamlClaude Code caches registry data to reduce network requests:
- Cache Duration: 5 minutes (default)
- Cache Location:
~/.claude/cache/registries/ - Force Refresh:
/plugin marketplace refresh
Cache invalidation:
# Manual cache clear
rm -rf ~/.claude/cache/registries/your-org-your-marketplace.json
# Or refresh via CLI
/plugin marketplace refresh your-org/your-marketplaceEach package must follow this structure:
packages/your-package/
├── manifest.yaml # Required: Package metadata
├── README.md # Required: Package documentation
├── CHANGELOG.md # Required: Version history
├── LICENSE # Required: License text
├── USE-CASES.md # Recommended: Usage examples
├── TROUBLESHOOTING.md # Recommended: Common issues
├── commands/ # Optional: Slash commands
│ └── your-command.md
├── skills/ # Optional: Workflow orchestrations
│ └── your-skill/
│ └── SKILL.md
├── agents/ # Optional: Isolated executors
│ └── your-agent.md
└── scripts/ # Optional: Helper scripts
└── helper.sh
name: your-package
version: 1.0.0
description: >
A comprehensive package that demonstrates
best practices for Claude Code extensions.
author: Your Name
license: MIT
tags:
- automation
- productivity
- example
# Files to install (relative to package root)
artifacts:
commands:
- commands/your-command.md
skills:
- skills/your-skill/SKILL.md
agents:
- agents/your-agent.md
scripts:
- scripts/helper.sh
# Token substitution (Tier 1 only)
variables:
REPO_NAME:
auto: git-repo-basename
description: Repository name from git toplevel
# Runtime requirements (Tier 2 only)
requires:
- git >= 2.27
- python3 >= 3.10When a user installs a package:
1. User runs: /plugin install your-package@your-marketplace
2. Claude Code:
a. Reads registry.json
b. Finds package entry
c. Fetches manifest.yaml from package path
d. Downloads all artifacts listed in manifest
e. Performs token substitution (Tier 1)
f. Validates dependencies (Tier 2)
g. Copies artifacts to ~/.claude/ or ./.claude/
3. Result:
.claude/
├── commands/
│ └── your-command.md
├── agents/
│ └── your-agent.md
└── skills/
└── your-skill/
└── SKILL.md
Follow semantic versioning (SemVer):
Version Format: MAJOR.MINOR.PATCH
- MAJOR: Breaking changes, incompatible API changes
- MINOR: New features, backward-compatible
- PATCH: Bug fixes, no API changes
Example progression:
1.0.0 → Initial stable release
1.0.1 → Bug fix (patch)
1.1.0 → New feature (minor)
2.0.0 → Breaking change (major)
Pre-release versions:
0.1.0 → Early development
0.9.0 → Feature-complete beta
1.0.0-rc.1 → Release candidate (avoid in registry)
1.0.0 → First stable release
Registry version synchronization:
All three layers must match:
- Marketplace version (registry.json → marketplace.version)
- Package version (registry.json → packages.your-package.version)
- Artifact versions (frontmatter in .md files)
# Verify version consistency
grep -r "version:" . | grep -E "(registry.json|manifest.yaml|\.md)"1. HTTPS Only
✅ GOOD: https://raw.githubusercontent.com/...
✅ GOOD: https://marketplace.yourcompany.com/...
❌ BAD: http://marketplace.yourcompany.com/... (No encryption)
2. Integrity Verification
Add checksums to registry.json (future feature):
{
"packages": {
"your-package": {
"version": "1.0.0",
"integrity": {
"algorithm": "sha256",
"hash": "a3c2f1e9b...",
"signatures": [
{
"signer": "your-gpg-key-id",
"signature": "base64-encoded-sig"
}
]
}
}
}
}3. Rate Limiting
Protect your registry from abuse:
# nginx rate limiting
http {
limit_req_zone $binary_remote_addr zone=registry:10m rate=10r/s;
server {
location /registries/ {
limit_req zone=registry burst=20 nodelay;
}
}
}4. Access Control
For private marketplaces:
# nginx basic auth
location /registries/ {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
}Or use token-based auth:
# nginx token validation
location /registries/ {
if ($http_authorization != "Bearer your-secret-token") {
return 403;
}
}1. Code Review
All packages should be reviewed before adding to registry:
# Review checklist
- [ ] No hardcoded secrets or credentials
- [ ] Input validation on all external data
- [ ] No arbitrary code execution
- [ ] Dependencies are pinned versions
- [ ] License is compatible
- [ ] Documentation is complete2. Dependency Scanning
# Scan for known vulnerabilities
npm audit # If Node.js dependencies
pip-audit # If Python dependencies3. Sandboxing
Agents run in isolated contexts by default. Ensure packages don't:
- Access files outside workspace
- Make unauthorized network requests
- Execute arbitrary commands without user approval
4. Publisher Verification
Implement publisher verification:
{
"publishers": {
"your-org": {
"name": "Your Organization",
"github_handle": "your-org",
"github_url": "https://github.com/your-org",
"verification": {
"level": 2,
"method": "domain_verification",
"verified_date": "2025-12-16T00:00:00Z",
"domain": "yourcompany.com"
},
"packages": ["package1", "package2"],
"total_packages": 2
}
}
}Verification levels:
- Level 0: Unverified (default)
- Level 1: GitHub organization verified
- Level 2: Domain ownership verified
- Level 3: Code signing with GPG
- Never commit secrets to registry or packages
- Use HTTPS for all distribution
- Pin dependencies to specific versions
- Audit code before publishing
- Sign releases with GPG (future feature)
- Monitor access logs for unusual patterns
- Keep packages updated with security patches
- Document security policies in SECURITY.md
Goal: Create a public marketplace hosted on GitHub Pages
Time Required: 30 minutes
# Create new repo on GitHub: your-org/claude-marketplace
git clone https://github.com/your-org/claude-marketplace.git
cd claude-marketplace# Create required directories
mkdir -p docs/registries/nuget
mkdir -p packages
# Create README
cat > README.md <<'EOF'
# Claude Code Marketplace
A marketplace for Claude Code skills, agents, and commands.
## Installation
```bash
/plugin marketplace add your-org/claude-marketplaceSee docs/registries/nuget/registry.json for available packages. EOF
#### Step 3: Create Registry
```bash
cat > docs/registries/nuget/registry.json <<'EOF'
{
"$schema": "https://your-org.github.io/claude-marketplace/schemas/registry.schema.json",
"version": "2.0.0",
"generated": "2025-12-16T00:00:00Z",
"repo": "your-org/claude-marketplace",
"marketplace": {
"name": "Your Company Marketplace",
"version": "1.0.0",
"status": "stable",
"url": "https://github.com/your-org/claude-marketplace"
},
"packages": {},
"metadata": {
"registryVersion": "2.0.0",
"schemaVersion": "1.0.0",
"totalPackages": 0,
"totalCommands": 0,
"totalSkills": 0,
"totalAgents": 0,
"totalScripts": 0,
"categories": {}
},
"versionCompatibility": {
"marketplace": "1.0.0",
"minimumPackageVersion": "1.0.0",
"maximumPackageVersion": "1.x.x",
"note": "Stable release"
}
}
EOF
# Create package directory
mkdir -p packages/hello-world/{commands,agents}
# Create manifest
cat > packages/hello-world/manifest.yaml <<'EOF'
name: hello-world
version: 1.0.0
description: A simple hello world package
author: Your Name
license: MIT
tags:
- example
- demo
artifacts:
commands:
- commands/hello.md
agents:
- agents/hello-agent.md
EOF
# Create command
cat > packages/hello-world/commands/hello.md <<'EOF'
---
name: hello
description: Print a friendly greeting
version: 1.0.0
---
Print "Hello from Claude Code Marketplace!"
EOF
# Create agent
cat > packages/hello-world/agents/hello-agent.md <<'EOF'
---
name: hello-agent
description: Generate friendly greetings
version: 1.0.0
---
You are a friendly greeting generator. When invoked, generate a warm, personalized greeting.
EOF
# Create README
cat > packages/hello-world/README.md <<'EOF'
# hello-world
A simple example package demonstrating Claude Code marketplace basics.
## Installation
```bash
/plugin install hello-world@your-org/claude-marketplace/helloEOF
cat > packages/hello-world/CHANGELOG.md <<'EOF'
- Initial release
/hellocommand- hello-agent for greeting generation EOF
#### Step 5: Update Registry with Package
```bash
# Update registry.json to include the package
cat > docs/registries/nuget/registry.json <<'EOF'
{
"$schema": "https://your-org.github.io/claude-marketplace/schemas/registry.schema.json",
"version": "2.0.0",
"generated": "2025-12-16T00:00:00Z",
"repo": "your-org/claude-marketplace",
"marketplace": {
"name": "Your Company Marketplace",
"version": "1.0.0",
"status": "stable",
"url": "https://github.com/your-org/claude-marketplace"
},
"packages": {
"hello-world": {
"name": "hello-world",
"version": "1.0.0",
"status": "stable",
"tier": 0,
"description": "A simple hello world package",
"github": "your-org/claude-marketplace",
"repo": "https://github.com/your-org/claude-marketplace",
"path": "packages/hello-world",
"readme": "https://raw.githubusercontent.com/your-org/claude-marketplace/main/packages/hello-world/README.md",
"license": "MIT",
"author": "Your Name",
"tags": ["example", "demo"],
"artifacts": {
"commands": 1,
"skills": 0,
"agents": 1,
"scripts": 0
},
"dependencies": [],
"changelog": "https://raw.githubusercontent.com/your-org/claude-marketplace/main/packages/hello-world/CHANGELOG.md",
"lastUpdated": "2025-12-16",
"dependents": []
}
},
"metadata": {
"registryVersion": "2.0.0",
"schemaVersion": "1.0.0",
"totalPackages": 1,
"totalCommands": 1,
"totalSkills": 0,
"totalAgents": 1,
"totalScripts": 0,
"categories": {
"examples": ["hello-world"]
}
},
"versionCompatibility": {
"marketplace": "1.0.0",
"minimumPackageVersion": "1.0.0",
"maximumPackageVersion": "1.x.x",
"note": "Stable release"
}
}
EOF
# Commit everything
git add .
git commit -m "Initial marketplace setup with hello-world package"
git push origin main
# Enable GitHub Pages:
# 1. Go to repo Settings → Pages
# 2. Source: Deploy from branch
# 3. Branch: main
# 4. Folder: /docs
# 5. Save
# Wait 1-2 minutes for deployment# Verify registry is accessible
curl https://raw.githubusercontent.com/your-org/claude-marketplace/main/docs/registries/nuget/registry.json
# Or via GitHub Pages (after deployment)
curl https://your-org.github.io/claude-marketplace/registries/nuget/registry.json
# In Claude Code:
/plugin marketplace add your-org/claude-marketplace
/plugin install hello-world
/hello# Create another package
mkdir -p packages/another-package/{commands,agents,skills}
# Create manifest, artifacts, documentation
# Update registry.json with new package entry
# Commit and pushCongratulations! You now have a working Claude Code marketplace.
Goal: Create a private marketplace for internal use
Requirements:
- Self-hosted server or private GitHub Enterprise
- Authentication system
- Internal network only
# Create private GitHub repo
# Or use GitLab/Bitbucket/self-hosted Git
git clone https://github.yourcompany.com/internal/claude-marketplace.git
cd claude-marketplace# Same structure as public marketplace
mkdir -p docs/registries/nuget
mkdir -p packages
# Create registry.json
# (Same format as public marketplace)Option A: GitHub Private Repo
# Users must authenticate with GitHub
# Claude Code will prompt for credentials
# Configure in ~/.gitconfig
git config --global credential.helper store
git config --global credential.https://github.yourcompany.com.username your-usernameOption B: Self-Hosted with nginx
# /etc/nginx/sites-available/marketplace
server {
listen 443 ssl;
server_name marketplace.internal.company.com;
ssl_certificate /etc/nginx/ssl/marketplace.crt;
ssl_certificate_key /etc/nginx/ssl/marketplace.key;
root /var/www/marketplace;
# IP whitelist (internal network only)
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
# Basic auth
auth_basic "Internal Marketplace";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
try_files $uri $uri/ =404;
}
location /registries/ {
add_header Content-Type application/json;
}
}# ~/.claude/config.yaml (future feature)
marketplaces:
- name: internal
url: https://marketplace.internal.company.com/registries/nuget/registry.json
auth:
type: basic
username: your-username
password: ${MARKETPLACE_PASSWORD} # Environment variable# Option A: Distribute via internal docs
# Create setup guide for employees
# Option B: Automate via MDM/configuration management
# Use Ansible/Puppet/Chef to deploy config
# Option C: Docker image with pre-configured Claude Code
docker build -t internal/claude-code:latest .Claude Code supports multiple registries simultaneously.
# Add public marketplace
/plugin marketplace add randlee/synaptic-canvas
# Add company marketplace
/plugin marketplace add yourcompany/internal-marketplace
# Add team marketplace
/plugin marketplace add yourteam/team-tools
# List all marketplaces
/plugin marketplace listWhen a package exists in multiple registries:
- Explicit registry specified by user takes priority
- First-added marketplace is default
- User can choose during installation
# Install from specific marketplace
/plugin install package-name@synaptic-canvas
# Install from default marketplace
/plugin install package-name
# Claude Code will prompt if ambiguous# ~/.claude/marketplaces.yaml (future)
registries:
- name: synaptic-canvas
owner: randlee
repo: synaptic-canvas
url: https://raw.githubusercontent.com/randlee/synaptic-canvas/main/docs/registries/nuget/registry.json
priority: 1
enabled: true
- name: internal
owner: yourcompany
repo: internal-marketplace
url: https://github.yourcompany.com/internal/marketplace/registries/nuget/registry.json
priority: 2
enabled: true
auth:
type: token
token: ${INTERNAL_MARKETPLACE_TOKEN}To avoid conflicts, use namespaced package names:
company-package-name
team-specific-tool
sc-delay-tasks (Synaptic Canvas prefix)
Track these metrics:
- Download counts (if using analytics)
- Popular packages (installation frequency)
- Error rates (404s, timeouts)
- Geographic distribution (CDN stats)
- Version adoption (which versions are installed)
Option 1: Server logs
# Parse nginx access logs
tail -f /var/log/nginx/access.log | grep "registry.json"
# Count unique IPs
cat /var/log/nginx/access.log | grep "registry.json" | awk '{print $1}' | sort | uniq -cOption 2: CloudFlare Analytics
Dashboard → Analytics → Traffic
- Page views: registries/nuget/registry.json
- Unique visitors
- Bandwidth usage
- Geographic distribution
Option 3: Google Analytics
<!-- docs/index.html -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>Create a health check endpoint:
// docs/registries/nuget/health.json
{
"status": "healthy",
"timestamp": "2025-12-16T12:00:00Z",
"registry_version": "2.0.0",
"total_packages": 10,
"last_updated": "2025-12-15T08:30:00Z"
}Monitor script:
#!/bin/bash
# scripts/health-check.sh
URL="https://your-org.github.io/claude-marketplace/registries/nuget/health.json"
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$RESPONSE" -eq 200 ]; then
echo "✅ Marketplace is healthy"
exit 0
else
echo "❌ Marketplace is down (HTTP $RESPONSE)"
exit 1
fiSet up monitoring:
# .github/workflows/health-check.yml
name: Marketplace Health Check
on:
schedule:
- cron: '*/15 * * * *' # Every 15 minutes
jobs:
health-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check marketplace health
run: |
bash scripts/health-check.shWeekly:
- Review package updates
- Check for broken links
- Validate JSON schema
- Review access logs
Monthly:
- Update marketplace version
- Audit package versions
- Review security advisories
- Update documentation
- Clean up deprecated packages
Quarterly:
- Performance review
- User feedback analysis
- Infrastructure optimization
- Disaster recovery test
Auto-update registry timestamps:
#!/bin/bash
# scripts/update-registry-timestamp.sh
REGISTRY="docs/registries/nuget/registry.json"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
jq ".generated = \"$TIMESTAMP\"" "$REGISTRY" > "$REGISTRY.tmp"
mv "$REGISTRY.tmp" "$REGISTRY"
echo "Updated registry timestamp to $TIMESTAMP"Validate all packages:
#!/bin/bash
# scripts/validate-packages.sh
for package in packages/*; do
echo "Validating $package..."
# Check required files
[ -f "$package/manifest.yaml" ] || echo "❌ Missing manifest.yaml"
[ -f "$package/README.md" ] || echo "❌ Missing README.md"
[ -f "$package/CHANGELOG.md" ] || echo "❌ Missing CHANGELOG.md"
# Validate manifest
python3 -c "import yaml; yaml.safe_load(open('$package/manifest.yaml'))" || echo "❌ Invalid YAML"
doneSymptoms:
Error: Marketplace not found
Failed to fetch: https://raw.githubusercontent.com/your-org/your-marketplace/main/docs/registries/nuget/registry.json
Diagnosis:
# Check if file exists
ls docs/registries/nuget/registry.json
# Check if committed
git ls-files docs/registries/nuget/registry.json
# Test URL
curl -I https://raw.githubusercontent.com/your-org/your-marketplace/main/docs/registries/nuget/registry.jsonSolutions:
- File not committed:
git add docs/registries/nuget/registry.json
git commit -m "Add registry"
git push- Wrong branch:
# If your default branch is 'master' not 'main'
git branch --show-current
# Update URL or rename branch- Wrong path:
# Verify exact path
find . -name "registry.json"
# Move to correct location if needed
mkdir -p docs/registries/nuget
mv registry.json docs/registries/nuget/Symptoms:
Error: Failed to parse registry
Invalid JSON at line 42
Diagnosis:
# Validate JSON syntax
python3 -m json.tool docs/registries/nuget/registry.json
# Or with jq
jq empty docs/registries/nuget/registry.jsonCommon errors:
- Trailing comma in last array/object element
- Missing quotes around strings
- Unescaped special characters
- Wrong field types (string vs number)
Solution:
# Use a JSON formatter/validator
# Fix syntax errors
# Validate again before committingSymptoms:
Error: Failed to install package 'your-package'
Could not fetch artifacts
Diagnosis:
# Check package path in registry
cat docs/registries/nuget/registry.json | jq '.packages["your-package"].path'
# Verify package directory exists
ls packages/your-package/
# Check manifest.yaml
cat packages/your-package/manifest.yamlSolutions:
- Path mismatch:
// registry.json
"path": "packages/your-package" // Must match actual directory- Missing manifest:
# Create manifest.yaml
cat > packages/your-package/manifest.yaml <<EOF
name: your-package
version: 1.0.0
# ...
EOF- Artifact paths wrong:
# manifest.yaml
artifacts:
commands:
- commands/cmd.md # Must exist: packages/your-package/commands/cmd.mdSymptoms:
Error: API rate limit exceeded
Retry after: 3600 seconds
Solution:
Switch from raw.githubusercontent.com to GitHub Pages:
# Enable GitHub Pages (see Hosting Options)
# Updates distribution URL to:
# https://your-org.github.io/your-marketplace/registries/nuget/registry.json
# Or use authenticated requests (future feature)Symptoms:
Error: CORS policy blocked request
Solution:
Add CORS headers to nginx:
location /registries/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type";
}While Claude Code expects the standard format, you can maintain internal registries in different formats and convert them:
# scripts/convert-registry.py
import yaml
import json
# Read internal YAML registry
with open('internal-registry.yaml') as f:
internal = yaml.safe_load(f)
# Convert to standard format
standard = {
"version": "2.0.0",
"packages": {}
}
for pkg in internal['packages']:
standard['packages'][pkg['name']] = {
"name": pkg['name'],
"version": pkg['version'],
# ... map fields
}
# Write standard registry.json
with open('docs/registries/nuget/registry.json', 'w') as f:
json.dump(standard, f, indent=2)GitHub Actions workflow:
# .github/workflows/publish-package.yml
name: Publish Package
on:
push:
tags:
- 'v*.*.*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Extract version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Update registry
run: |
python3 scripts/add-to-registry.py \
--package ${{ github.event.repository.name }} \
--version ${{ steps.version.outputs.VERSION }}
- name: Commit registry update
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add docs/registries/nuget/registry.json
git commit -m "chore: publish ${{ github.event.repository.name }} v${{ steps.version.outputs.VERSION }}"
git pushCreate a meta-marketplace that aggregates multiple registries:
// docs/registries/nuget/federated-registry.json
{
"version": "2.0.0",
"type": "federated",
"sources": [
{
"name": "synaptic-canvas",
"url": "https://raw.githubusercontent.com/randlee/synaptic-canvas/main/docs/registries/nuget/registry.json",
"priority": 1
},
{
"name": "internal",
"url": "https://internal.company.com/registries/nuget/registry.json",
"priority": 2
}
],
"packages": {
// Merged packages from all sources
}
}Sign packages with GPG for verification:
# Generate GPG key
gpg --full-generate-key
# Sign package
cd packages/your-package
tar czf ../your-package-1.0.0.tar.gz .
gpg --armor --detach-sign ../your-package-1.0.0.tar.gz
# Add signature to registry
{
"packages": {
"your-package": {
"version": "1.0.0",
"signature": {
"type": "gpg",
"key_id": "ABCD1234",
"signature": "base64-encoded-signature"
}
}
}
}Mirror external registries for reliability:
#!/bin/bash
# scripts/mirror-registry.sh
SOURCE="https://raw.githubusercontent.com/randlee/synaptic-canvas/main/docs/registries/nuget/registry.json"
DEST="docs/mirrors/synaptic-canvas/registry.json"
# Fetch upstream registry
curl -s "$SOURCE" > "$DEST"
# Validate
jq empty "$DEST" && echo "✅ Mirror updated" || echo "❌ Invalid JSON"Now that you understand marketplace infrastructure:
- Create your registry - Follow the step-by-step guide
- Add packages - Start with a simple example package
- Test installation - Verify everything works end-to-end
- Document usage - Create clear instructions for users
- Gather feedback - Learn what users need
- Iterate - Improve based on real-world usage
- Synaptic Canvas Registry: registry.json
- Example Packages: packages/
- Architecture Guidelines: claude-code-skills-agents-guidelines-0.4.md
- Contributing Guide: CONTRIBUTING.md
- Questions: Open a discussion in your marketplace repo
- Bug reports: File an issue
- Feature requests: Start a discussion
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2025-12-16 | Initial comprehensive guide |
Marketplace infrastructure is the foundation of the Claude Code ecosystem. Build thoughtfully, document thoroughly, and maintain diligently.