---
type: tutorial
title: Publish to the marketplace
summary: Tag your repo, let the indexer discover and pin it, understand the replay self-check, and automate re-publishing from CI on every release.
---

By the end of this tutorial your game is listed in the marketplace and embeddable by any user, by its game id. Publishing is intentionally low-ceremony: there is no submission queue, no review, and no upload. You tag a public GitHub repo and the platform indexes it.

This assumes you have built a game ([Build a marketplace game](/docs/marketplace-game-development/build-a-marketplace-game)) and written its [manifest](/docs/marketplace-game-development/the-caputchin-json-manifest).

## 1. Tag the GitHub repository

Add the GitHub topic `caputchin-game` to your public repository (the About section on the repo page). The indexer queries GitHub for this topic; that tag is your entire opt-in.

Your game id is **derived** from the repo coordinate, `owner/repo` (or `owner/repo/<leaf-dir>` for a [collection](/docs/marketplace-game-development/the-caputchin-json-manifest#collections) child). You do not pick or declare it.

## 2. Confirm the manifest essentials

Three things gate indexing; make sure your root `caputchin.json` has them:

1. `"terms_accepted": true` (the literal boolean) confirming the [Marketplace Submission Terms](/legal/submission-terms).
2. A `license` on the [approved list](/docs/marketplace-game-development/publish-failed-reference#approved-licenses).
3. A distribution pointer (`entry`, `npm`, or both) so the bundle resolves.

Add a `marketplace.author.email` if you want [publish-failure emails](#get-notified-when-a-publish-fails) (it is never shown publicly, and it is the only way to receive them).

## 3. Publish or update

Two ways to land in the index:

- **The daily cron** picks up tagged repos automatically.
- **The "Publish or update" button** on the marketplace runs the per-repo indexer synchronously and redirects you to your detail page, or shows the exact validation error. Use this for a first listing or right after a manifest edit.

When it runs, the indexer fetches your manifest, **pins the bundle to an immutable ref** (the published npm version or the resolved commit SHA), computes a SHA-384 integrity hash, and stores `{ url, integrity }` keyed by your game id. New releases go live at the next index run, or instantly via the button.

## 4. The replay self-check

At index time the platform runs your [`run` artifact](/docs/marketplace-game-development/replay-contract) in a sealed isolate once with a deterministic seed:

- **Passes** → your game is **replayable**: a real player's round is re-run server-side to reach the decision, so it can gate a site key.
- **Fails** (`run-not-conforming`) → the game shows **Not replayable**. It is still listed and embeddable, but only as UX until you publish a conforming version. Sites already on an earlier replayable version keep running that exact snapshot.

A failing self-check is almost always non-determinism in your `run`; [make your simulation deterministic](/docs/marketplace-game-development/publish-failed-fixes#run-not-conforming) and re-publish. Running the [engine kit's](/docs/marketplace-game-development/engine-kit) `selfCheck` locally first catches this before you push.

## 5. Verify discovery

After a successful publish, the detail page embeds your game in a live preview with a knob for each declared locale, skin, and configuration preset. Play it there to confirm the presets resolve as you intended.

## Get notified when a publish fails [#get-notified-when-a-publish-fails]

The daily indexer re-checks every published game. If a re-index hits a problem, you can be emailed about it, but **only if you opt in** by setting `marketplace.author.email` in your [manifest](/docs/marketplace-game-development/the-caputchin-json-manifest#the-marketplace-block). With no email set, you get no notifications. There is no other channel; this is the one signal you would otherwise miss, because the daily re-check runs without you watching.

Two kinds of email are sent, matching the two outcomes:

| Email | When | What it means |
|---|---|---|
| "Verification check failed for `<game>`" | A re-indexed version fails the replay self-check (`run-not-conforming`) | The game stays listed and embeddable, but that version shows **Not replayable** and cannot gate until you publish a conforming one. |
| "We couldn't publish `<game>`" | A re-index hits any other failure (a manifest, license, or bundle error) | That version is **not listed** until you fix it. |

Details that matter:

- **Only the daily re-index emails you.** A failure on the manual "Publish or update" button is shown to you in the modal right then, so no email is sent for it.
- **Deduplicated.** The same failure on the same game is emailed once, then suppressed for 30 days. A *different* failure (a new error code or reason) emails immediately.
- **Opt out any time** by removing or changing `marketplace.author.email`. The emails also carry a one-click unsubscribe pointer to the [Submission Terms](/legal/submission-terms). You are not a Caputchin account here, so the manifest field is the only control.

## 6. Automate with CI

Because publishing is "tag plus push to an immutable ref," you can wire it into your release pipeline so every release re-indexes automatically. The reliable pattern:

1. **Publish the bundle to an immutable ref** in CI, the npm `publish` (or a tagged GitHub release) your manifest's `npm` / `entry` resolves against. The indexer always re-resolves to your latest published version on its next run, so a normal release pipeline already advances the pin.
2. **Gate the release on a local determinism check.** Run the engine kit's `selfCheck` (or your own replay test) as a CI step so a non-deterministic `run` fails the build instead of shipping as not replayable.
3. **Optionally trigger an immediate re-index** by calling "Publish or update" rather than waiting for the daily cron, if you want the new version live the moment CI finishes.

```yaml
# sketch: release job
- run: npm ci
- run: npm test                 # includes your replay selfCheck
- run: npm publish              # advances the immutable ref the indexer pins
# the daily indexer picks up the new version; or hit Publish or update for instant
```

Keep the determinism check **before** publish so a bad `run` never reaches the marketplace as a silently not-replayable listing.

## What you never have to do

- No code signing, no review submission, no platform CDN upload.
- No revenue-share agreement.
- No id-picking; your GitHub coordinate is the id.
- No version field; the indexer pins the ref.

## If publishing fails

Every publish-path error is something you fix in your repo and retry. Find your code in [Fix a publish failure](/docs/marketplace-game-development/publish-failed-fixes); the full code list is the [publish errors reference](/docs/marketplace-game-development/publish-failed-reference).

## See also

- [Fix a publish failure](/docs/marketplace-game-development/publish-failed-fixes): step-by-step fixes by error code.
- [The caputchin.json manifest](/docs/marketplace-game-development/the-caputchin-json-manifest): the fields the indexer validates.
- [The replay contract](/docs/marketplace-game-development/replay-contract): what the self-check runs.
