Caputchin
Marketplace game development

Publish to the marketplace

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) and written its 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 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.
  2. A license on the approved list.
  3. A distribution pointer (entry, npm, or both) so the bundle resolves.

Add a marketplace.author.email if you want publish-failure emails (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 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 and re-publish. Running the engine kit's 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

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. 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:

EmailWhenWhat 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. 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.
# 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; the full code list is the publish errors reference.

See also

On this page