---
type: how-to
---

# Publish a game to the marketplace

Make your game discoverable in the Caputchin [marketplace](../marketplace.md). Assumes you've already built and registered a game — see [author-a-game](author-a-game.md).

## 1. Tag the GitHub repo

Add the topic `caputchin-game` to your repository on GitHub. The platform indexer queries the GitHub API for this topic; no manual submission is required.

## 2. Add `caputchin.json` at the repo root

Single game:

```json
{
  "id": "@your-org/your-game",
  "version": "1.0.0",
  "displayName": "Your Game",
  "description": "What it does in one line",
  "support": {
    "responsive": true,
    "touch": true,
    "accessible": true,
    "audio": "none",
    "languages": ["en"]
  },
  "npm": "@your-org/your-game",
  "script": "dist/your-game.js",
  "preview": "preview.gif"
}
```

Field reference: [marketplace — manifest fields](../marketplace.md#manifest-fields).

## 3. Be honest about [support flags](../marketplace.md#support-flags)

The platform never verifies them — see [ADR-0006](../adr/0006-author-declared-support-flags.md). Customers pick games based on these declarations. False claims damage your marketplace reputation.

## 4. Publishing collections

A collection has its own marketplace page plus child entries:

```json
{
  "id": "@your-org/casual-pack",
  "version": "1.0.0",
  "displayName": "Casual Pack",
  "npm": "@your-org/casual-pack",
  "script": "dist/casual-pack.js",
  "games": ["./game-a", "./game-b"]
}
```

Each path in `games` is a relative path inside the repo to a sub-`caputchin.json`. No path traversal, no external URLs.

If you don't want a collection page (you just have multiple games in one repo), omit `id` and only ship `games`. Children index, the wrapper does not.

## 5. Choose your distribution

The `script` field tells the indexer where to derive a jsDelivr CDN URL — that's the marketplace runtime path. The indexer fetches that URL, computes a SHA-384 SRI hash, and stores `{ url, integrity }` keyed by your game ID; the widget retrieves the pair from [`/games/:id/resolve`](../api.md) at mount and passes both into the sandboxed iframe. See [ADR-0015](../adr/0015-sandbox-game-iframe.md).

The `npm` field is informational only — it appears in the marketplace UI for customers who want to inspect the package. It is not a runtime distribution path; games execute inside the sandboxed iframe and are reached as a URL. If you have a customer who needs to host the game themselves (offline, regulated, or strict-CSP environments), point them at your built `script` file and let them serve it from their own static-asset directory.

## 6. Bundle for the sandbox

The marketplace runtime loads exactly one script URL. Ship a single self-contained bundle: assets inlined, no code splitting, no path-relative `fetch`, no dynamic `import`, no URL-spawned workers. See [author-a-game — bundle for the sandbox](author-a-game.md#5-bundle-for-the-sandbox) and [game-distribution](../game-distribution.md#bundle-constraint).

## 7. Verify discovery

The indexer runs on a schedule. After tagging the repo and adding the manifest, the game should appear in the marketplace browse page within the next index cycle. (Frequency will be documented when the indexer ships in [phase 4](../roadmap.md#build-phases).)

## What you don't need to do

- No code signing.
- No review submission.
- No platform CDN upload.
- No revenue-share agreement.

The marketplace is intentionally low-ceremony — see [marketplace — what's not in the manifest](../marketplace.md#whats-not-in-the-manifest).
