---
type: reference
---

# Marketplace

The discoverable default for [game distribution](game-distribution.md). Authors publish a GitHub repo; the platform indexes it; customers browse and pick games.

## Discovery

The platform indexer queries the GitHub API for repos tagged with the topic `caputchin-game`. There is no manual submission, no review, no signing. Author chooses to be discovered by adding the topic to their repo.

## Manifest

A `caputchin.json` file at the repo root. The manifest is **pure metadata for the marketplace UI and the resolver** — the runtime never reads it directly. The actual game contract is the [SDK `register()` call](game-sdk.md), not the manifest. The indexer reads the manifest, fetches the built JS at the derived jsDelivr URL, computes a SHA-384 integrity hash, and stores the `{ url, integrity }` pair under the game ID. The widget reaches that pair through [`/games/:id/resolve`](api.md) at mount time and passes it into the sandboxed iframe via `<script src integrity>`. See [ADR-0015](adr/0015-sandbox-game-iframe.md).

### Single game

```json
{
  "id": "@cooperative-games/bubble-pop",
  "version": "1.2.0",
  "displayName": "Bubble Pop",
  "description": "Pop the floating bubbles",
  "support": {
    "responsive": true,
    "touch": true,
    "accessible": false,
    "audio": "optional",
    "languages": ["en", "es"]
  },
  "npm": "@cooperative-games/bubble-pop",
  "script": "dist/bubble-pop.js",
  "preview": "preview.gif"
}
```

### Collection (first-class with a marketplace page)

```json
{
  "id": "@cooperative-games/casual-pack",
  "version": "2.0.0",
  "displayName": "Casual Pack",
  "npm": "@cooperative-games/casual-pack",
  "script": "dist/casual-pack.js",
  "games": ["./bubble-pop", "./memory-match", "./color-sort"]
}
```

### Unnamed multi-game wrapper (no collection identity)

```json
{
  "games": ["./bubble-pop", "./memory-match"]
}
```

## Manifest fields

| Field | Required | Purpose |
|---|---|---|
| `id` | for indexed games / collections | Author-declared, conventionally `@org/name`. Format-validated only. |
| `version` | yes | Display only — not enforced |
| `displayName` | yes | Marketplace UI |
| `description` | yes | Marketplace UI |
| `preview` | recommended | Path or URL to a preview image / GIF |
| `support` | recommended | Author-declared compatibility flags — see [below](#support-flags) |
| `npm` | optional | Informational only. Indexed for marketplace UI display. Not a runtime distribution path — games execute inside a sandboxed iframe and must reach it as a URL. Customer-bundled games are loaded via `game-src` on the [widget](widget.md), not by importing the npm package. |
| `script` | optional | Path inside the repo; the indexer derives the jsDelivr CDN URL |
| `games` | optional | Sub-manifest paths for collections / multi-game repos |

## Indexer rules

- Fetch the **root manifest only**; for collections, follow the paths in `games` to read sub-manifests.
- Compute the SHA-384 SRI hash of the built JS pointed at by `script` (jsDelivr URL). Store `{ url, integrity }` keyed by game ID for the resolver endpoint.
- `id` + `games` → indexed as a **collection** (gets its own marketplace page plus child entries).
- `games` only → unbundled multi-game repo; child games index, the wrapper does not.
- `id`, no `games` → single game.
- No path traversal — `games` paths must stay inside the repo.
- No external URLs in `games`.
- Sane size cap on manifests.
- Skip broken sub-manifests; do not fail the whole repo.
- **No deduplication of conflicting IDs across repos.** Customers choose. See [game-distribution](game-distribution.md#collisions-are-the-customers-problem).

## Support flags

All author-declared, **never verified** by the platform. The marketplace surfaces them as filters and badges so customers can pick games matching their site's needs. See [ADR-0006](adr/0006-author-declared-support-flags.md) for why honesty beats fake validation.

| Flag | Type | Meaning |
|---|---|---|
| `responsive` | bool | Adapts to container size |
| `touch` | bool | Works with touch input |
| `accessible` | bool | Screen-reader and keyboard navigable |
| `audio` | `"none"` / `"optional"` / `"required"` | Sound design |
| `languages` | `string[]` | Language codes; empty / omitted = English-only or no text |

## What's *not* in the manifest

- **No code signing.** Out of scope at MVP. SRI on the indexer's stored hash protects against jsDelivr tampering between index time and load time, not against author-side malice. Sandbox isolation is what bounds malicious-author blast radius — see [ADR-0015](adr/0015-sandbox-game-iframe.md).
- **No revenue share.** [Deferred entirely](roadmap.md#whats-deferred-entirely).
- **No platform-hosted CDN.** Games ship via jsDelivr (marketplace), customer's host (self-hosted), or bundled. No platform-side asset delivery.
- **No review process.** Discovery is open; quality is conveyed via the [support flags](#support-flags) and customer choice.

## Authoring a manifest

See the [publish-to-marketplace guide](guides/publish-to-marketplace.md).
