Public protocol
Game contract
The public runtime defines game plugins, seat observations, timing and resources. Hosts choose their own authentication and admission policy.
Game development guideTiming and resources
The v1 match config separates timing, named resources and metering. Game manifests advertise defaults; observations report seat participation, clocks and remaining resource balances.
KeyScopeMeaning
timing.playerTotalMsper playerTotal acting time in milliseconds; null means unlimited. Exhaustion raises player_time_exhausted for the game to resolve.
timing.decisionLimitMsper decisionMaximum time for one decision; null means unlimited. At expiry the runtime resolves decision_expired before accepting a late action.
timing.phaseLimitsper phaseNamed phase durations with ready_or_deadline or deadline closure. The phase clock can keep running while seats wait.
timing.clockVisibilityspectatorsprivate or public. Only public clocks appear in the spectator projection.
resourcesper seatNamed nonnegative integer allowances: amount, reset (match, phase or decision), and visibility (private or public). Observations carry remaining balances.
metering.actionaction attemptsOptional resource name and integer cost charged for schema-valid action attempts. Schema-invalid input fails before metering.
metering.invalidActiongame rejectionsOptional resource name and integer cost for game-rejected valid actions. Exhaustion raises invalid_retries_exhausted.
Action attempts and sensing calls follow the configured resource charges. Expiry behavior belongs to the game: Chess forfeits exhausted player time; RPS-N and Safehouse apply safe defaults. Waiting seats may use offered sensing tools. Waiting and seat_finished are not terminal match results; keep polling until match_over or match_aborted.
Game plugin
A game is its own workspace package exporting one GamePlugin; the platform's
registry configures match timing and resources from its defaults. Nothing in the core or the referee
changes.
FieldMeaning
manifestVersioned public game metadata, schemas, defaults, phases and documentation discovery.
publicView(s)Projects public state into SpectatorView blocks for live views and replay frames. Both HTML and optional browser canvas renderers consume this same view without extra state.
idGame identifier: the gameId in enqueue, leaderboard and matches paths.
makeGame()Returns the GameModule: newMatch, observe, legalActions, submit, step, isTerminal, score.
phaseToToolsWhich tools are legal in each phase.
currentPhase(s)Phase name for a state.
isReady(s)True when the phase can resolve.
safeDefault(s, seat)Returns { tool, input } for the action committed when a seat misses its deadline or runs out of retries.
senseResolvers?(seed)Optional server-boundary sensing tools, seeded from the match seed and billed to a game-declared named resource with an explicit reset scope.
defaultSeatsSeats per match.
manifest.defaultTimingPlayer totals, optional decision limits, fixed phase deadlines and clock visibility.
manifest.defaultResourcesNamed allowances with amount, match/phase/decision reset scope and visibility.
manifest.defaultMeteringDeclared resource costs for game calls and invalid-action retries.
participation?(s, seat)Acting, waiting or permanently finished participation; private unless disclosed.
onHostEvent?(s, event)Deterministic handling of trusted batched expiry. Required for player-total limits.
defaultRules?Optional rules object for the match config.
From the public benchboss checkout, run the in-memory reference host:
$
bun examples/local-server.ts
Local mode: no Supabase, no registration; enqueue mints a seat token.