# App Manifest reference

The App Manifest is `gamestage.yaml`: one file describing the whole game. It is
not an App Spec and it is not a general configuration file.

Fetch the machine-readable contract:

```sh
curl https://gamestage.ai/schemas/app-manifest/1.0
```

Validate a local file:

```sh
gamestage manifest validate gamestage.yaml
gamestage manifest validate gamestage.yaml --level L2
```

## Metadata

`manifest` holds metadata about the file rather than a reviewable product
section.

| Field | Type | Meaning |
| --- | --- | --- |
| `schema_version` | string | Manifest language version, currently `1.0` |
| `revision` | non-negative integer | Creator-controlled revision |
| `conformance` | `L0` to `L5` | The level the author claims; validation computes the evidenced level and refuses a claim above it |

## Sections

The ten sections below carry their own `status` and `provenance`.

### `app`

Identity and ownership of the game.

* **`id`**: stable game id, also used as the Engine tenant and URL key.

* **`title` and `summary`**: creator-facing name and optional description.

* **`source`**: canonical repository URL and branch. This is distinct from repository evidence attached to one value.

* **`owners`**: optional IP, delivery and platform owners.

### `experience`

The fan-facing shape.

* **`surfaces`**: places the game renders, such as `web-embed`.

* **`container_label`**: what this game calls one go, such as Round, Voting window or Tournament. Defaults to Round.

* **`screen_graph`**: optional path to the experience's screen graph.

* **`design`**: optional Figma file, version, token reference and design build stage.

### `backend`

The authority model.

* **`route`**: `managed_runtime`. Every game runs on our Engine, so this is the
  only value a manifest can carry. The schema still names three others,
  `bring_your_own`, `manifest_driven` and `dedicated_engine`, because `inspect`
  uses them to describe a game it found before you migrate it. A manifest that
  declares one is refused, and the refusal says which value to use.

* **`archetype`**: the declared rule set.

* **`component`, `version` and `variant`**: the pinned Proxima implementation where known.

* **`configuration`**: additional component configuration.

* **`round`**: the current Preview container specification. See [Game formats](/docs/game-formats).

### `studio_app`

The registered [Monterosa](https://www.monterosa.co/) Studio App Spec:
`spec_url` and `version`.

### `studio_surface`

The operator surface: `family`, `version` and `configuration_schema`.
Gamestage has no content editor. Paid content operations belong in Monterosa
Studio.

### `interaction_cloud`

The platform mapping: `project_template`, `project_id`, `events` and `elements`.
A game maps to a
[project](https://products.monterosa.co/mic/creator-guide/projects), an edition
maps to an
[event](https://products.monterosa.co/mic/core-concepts/schedule-and-events) and
a container maps to an
[element](https://products.monterosa.co/mic/reference/core-platform/elements).

The pairing ids are stored end to end: a deploy writes `platformProject`,
`platformEvent` and `platformElement` back onto the game record, and the next
deploy reads them rather than searching by name (GS-259). Do not mark this
section verified because provisioning returned ids once: verify that a second
deploy found the same project rather than creating another.

### `identity`

Player identity and consent policy.

* **`provider`**: `anonymous`, `jwt`, `identify` or `custom`.

* **`jwt`**: `issuer`, `jwks_uri` and optional `audience` when provider is `jwt`.

* **`require_authenticated_writes`**: whether production writes require an identified player.

* **`age_gate`**: `required`, `minimum_age`, `method` and an optional named verifier.

* **`consent`**: whether analytics needs consent and which provider owns the choice.

Gamestage issues signed anonymous sessions. It does not provide a login system
for identified fans at any plan. A game that needs identity names its own JWT
issuer and public key set.

The JWT validator and `gamestage dev --as` harness exercise that contract. The
deployed Engine validates a presented token against the issuer and JWKS
configured on that deployment; a deployment with neither set still refuses
every token rather than trusting one. `create` and `inspect` also still propose
`identity.provider: identify`; review that generated value rather than treating
it as a product default. Use `jwt` only after a person has confirmed the
external issuer and keys.

### `measurement`

Declared event routing.

* **`destinations`**: ordered declarations for `monterosa`, `posthog`, `ga4` or `webhook`.

* **`trusted_events`**: events emitted after an Engine commit.

* **`signal`**: optional Fantenna Signal declaration and public identifiers.

Keys and tokens never belong in the manifest. The schema accepting a
destination is not evidence that a production service has provisioned it. The
launch plan records that production ingestion and Studio visibility are still
dependencies, so a declared destination alone is not proof that analytics is
flowing.

### `deployment`

Hosting and environments.

* **`hosting`**: named host or strategy.

* **`space_spec`**: Proxima space specification when one exists.

* **`environments`**: any of `local`, `playground`, `staging`, `production`.

### `operations`

Support and promotion controls.

* **`support_tier`**: stored plan key, one of `runtime`, `live` or `enterprise`.

* **`runbook`**: operator runbook reference.

* **`promotion`**: whether the game offers a prize, its terms, jurisdictions, free entry route and skill position.

The stored plan keys are not creator-facing labels. Surfaces show Starter,
Publisher and Enterprise.

### `assurance`

Record the accessibility, security, secrets and privacy checks you ran on your
game. Gamestage suggests a check for each and shows your record on the game's
page in Stage. It does not run them, and it does not certify the result: the
record is yours. Nothing here affects `verify`, `deploy` or the build stage.

```yaml
assurance:
  accessibility:
    tool: addyosmani/web-quality-skills@accessibility
    ran_at: 2026-09-28
    result: issues_fixed
    owner: Jo Bloggs
    evidence: reports/accessibility-2026-09-28.md
  secrets:
    tool: gitleaks
    ran_at: 2026-09-28
    result: passed
```

| Check | Suggested | Run it with |
| --- | --- | --- |
| `accessibility` | A WCAG 2.2 audit skill | `npx skills add addyosmani/web-quality-skills@accessibility` |
| `security` | Sentry's security review skill | `npx skills add getsentry/skills@security-review` |
| `secrets` | The gitleaks scanner | `gitleaks detect --source .` |
| `privacy` | A GDPR skill | `npx skills add wshobson/agents@gdpr-data-handling` |

Each check you record takes these fields:

| Field | Type | Required | What it holds |
| --- | --- | --- | --- |
| `tool` | string | yes | The skill or tool that ran |
| `ran_at` | date, `YYYY-MM-DD` | yes | The day it ran |
| `result` | `passed`, `issues_fixed` or `issues_open` | yes | What it found, after any fixes |
| `owner` | string | no | The person answerable for the result |
| `evidence` | string | no | A link or repo path to the report |
| `note` | string | no | Anything a reviewer should know |

A check with no `ran_at`, a date in another format or an unknown `result` is
not counted: `verify` names the field to fix and Stage shows it as not
counted. It never makes the manifest invalid, so a typo here cannot stop a
deploy. A check you have not run is left out, and `verify` suggests it after
its verdict.

## Beside the manifest: `gamestage.settings.json`

The manifest describes the game and carries no content. The words and colours
a fan sees by default go in `gamestage.settings.json` next to it, keyed by the
Studio field keys: `display_name`, `strapline`, `how_to_play`, the button
labels, `primary_colour` and the `css_variables_*` palette.

```json
{
  "display_name": "Wages",
  "how_to_play": "Pick one player from each line. Stay under the cap.",
  "play_button_label": "Select Player"
}
```

A deploy writes each value into the game's Studio project where that field is
empty, and never over a producer's edit. `manifest validate` and `deploy` refuse
a key Studio does not have and list the ones it does. The file is never
published with the game.

## Status

| Status | Meaning |
| --- | --- |
| `missing` | The section does not exist yet. This is normal until it is needed. |
| `proposed` | An agent wrote it and nothing has tested it. |
| `confirmed` | Checked and it holds. |
| `verified` | Proved by evidence rather than inspection. |
| `approved` | A person signed it off. |

An inferred value is `proposed`. An agent must not turn its own inference into a
human decision.

## Provenance

Each section carries a list showing where its values came from.

| Kind | Required fields | Use |
| --- | --- | --- |
| `human_decision` | `owner`, `date` | A person made the decision |
| `generated_proposal` | `tool` | An agent or tool proposed it |
| `repository_evidence` | `file` | Source code or repository state supports it |
| `platform_evidence` | `system`, `id` | A platform record exists |
| `external_evidence` | `supplier` | A supplier, licence or dataset supports it |

Optional detail includes notes, commits, packages, model names, source context,
licences and dataset versions.

## Build stages

The CLI works out the highest stage supported by the evidence. Setting
`conformance` above that stage is a validation error.

| Level | Build stage |
| --- | --- |
| L0 | Concept |
| L1 | Experience built |
| L2 | Wired to the platform |
| L3 | Ready to deploy |
| L4 | Production ready |
| L5 | Operating live |

Never use the L number alone in creator-facing output.

## Cross-section rules

Structural JSON Schema validation is necessary but does not cover every rule.
The CLI also checks:

* **Signal and consent**: Signal cannot be enabled while analytics consent is disabled.

* **Prize declarations**: a prize needs terms, jurisdictions and either a free entry route or a declared skill basis.

* **JWT identity**: `provider: jwt` needs an issuer and JWKS URI. Deployed URLs must use HTTPS and cannot point at loopback.

* **Age gates**: a required gate needs a minimum age, and a verified method needs a named verifier.

* **Container integrity**: each built game format has reachability, uniqueness and ordering checks described in the game formats guide.

## Where a round's content comes from

Today both the local path and a deploy read `backend.round` from the manifest.
Keep the manifest as the source for `dev`, `verify` and deploy.
