Skip to content

Players come from agentenv-game-env's lobby, and its match grades them - #19

Merged
earakely-scale merged 2 commits into
mainfrom
feat/game-env
Oct 12, 2026
Merged

earakely-scale merged 2 commits into
mainfrom
feat/game-env

Conversation

@earakely-scale

Copy link
Copy Markdown
Owner

Stacked on #18: merge that first.

OpenCiv3's env becomes an agentenv-game-env game env. This tests how well game-env generalizes beyond Warcraft III: OpenCiv3 is turn-based, has many players and has human players.

What changes

  • The lobby says who plays. urn:game:lobby/v1 takes:

    • the game's settings: seed, size, difficulty, barbarians, landform, ocean, turn_limit, human_turn_seconds, min_turn_seconds and broadcast;
    • one player slot per civilization, played by an agent, a person or the game's AI.

    An agent's or person's slot takes a civ, and the next free one is used when it names none. The engine picks the AI's civs. Closing the lobby creates the game.

  • Routing by address, not header. An agent plays at /players/<player_id>/mcp, which add_player_slot registers with it. X-OpenCiv3-Seat is gone from the env and from the player agents. In a lobby game, the env's own /mcp plays no one.

  • A person's token is the slot's secret. It is passed through game-env 0.6.0's new @player_slot_headers hook. add_player_slot puts it in the page link's fragment, and the play page reads it from there.

  • The match (urn:game:match/v1) reports:

    • the turns;
    • each player's outcome, by the game's own rules (see below);
    • scores: score, cities, population and techs;
    • moves: turns a player ended itself, and turns the env ended for it.
  • Outcome rules:

    • A defeated civilization has lost.
    • A conquest, domination, culture or score victory goes to its civ, and every other player loses.
    • At the turn limit, a tie on top is no one's victory.
  • Finishing and files. finish_match plays a match out by ending every remaining player's turn. The match keeps its recording as files, by kind: map_video, html_replay, last_turn and client_video. Its spectator view is /live.

  • Tasks.

    • The ten multi-agent tasks and human-vs-ai use open_lobby, add_player_slot, close_lobby, finish_match (with await_match first in a person's game), grade_match and save_match_files.
    • grade_match uses max_missed: 0.1, the victor verifier's rule for an agent that sat out.
    • human-vs-agents grades the person in a second step, without the gate.
  • Removed: the openciv3_match and openciv3_await_game steps and the victor verifier.

  • Kept on the default game: new-game keeps the single-civilization default game. smoke, play and full-game stay on it, with their baseline verifiers and save_env_recording.

  • Broadcast. It stays OpenCiv3's own, now set through the lobby, and agent-env openciv3 stream is unchanged. Banner logos must now be https:// URLs or data: URIs, which the env fetches as the lobby closes.

  • Image. The env image installs game-env from the archive that pyproject.toml pins; setup passes it in.

Behaviour changes to know about

  • Each agent gets its own grade: 1 for a win, 0.5 for a draw, 0 for a loss. The victor verifier graded the match once.
  • An AI civilization's score victory at the turn limit now means every agent lost. The victor verifier ignored AI scores. This applies to sol-vs-opus, which has three AI civs.

Verification

  • Local tests: 408 pass. The 93 failures and 22 errors are the same set as on Players survive a long broadcast; a five-model war task; sponsor banners on the stream #18; they need the real engine, which can't run on a Mac without .NET. Ruff is clean.
  • Real engine, EC2 Linux, image built from this branch: 493 pass, 20 skipped, none failed. That includes the multi-player seat and HTTP routing tests.
  • Real runs (env openciv3-port, Claude Haiku 4.5 players). In every run each agent played at its own slot address and the match files were kept.
    • three-agents-quick, 10 turns: each agent ended 10 of 10 turns itself, and both gates passed. At turn 10, two players tied on top, so no one won, and each agent got 0.5.
    • human-vs-ai, 4 turns: a scripted person played through the play page's API.
      • The link added by add_player_slot served the page.
      • The API refused calls without the token, and accepted them with it.
      • The person ended 4 turns, await_match returned at the end, and the full-game verifier graded it 0.42.
    • showmatch-quick, 6 turns: played with agent-env openciv3 stream --record --offline. The casters commented over the whole game, and the recording is a 32 MB video. Each agent got 0.5 for a three-way tie.
    • playtest/bots.py, 3 seats, 5 turns: 84 tool calls, none failed.

Not in this pass

Casters in game-env's broadcast, so Warcraft III gets casters back.

🤖 Generated with Claude Code

Base automatically changed from fix/claude-player-silent-model to main October 12, 2026 01:28
earakely-scale and others added 2 commits October 11, 2026 18:30
OpenCiv3's env is an agentenv-game-env game env (AgentEnvGameEnv), to see how game-env generalizes beyond Warcraft III:
- The lobby (urn:game:lobby/v1) takes the game's settings (seed, size, difficulty, barbarians, landform, ocean,
  turn_limit, human_turn_seconds, min_turn_seconds and the broadcast) and a player slot per civilization: an agent's,
  a person's or the game's AI, each agent or person with its civ (the next free one when it names none; the engine
  picks the AI's). Closing it creates the game.
- An agent plays at its player slot's address, /players/<player_id>/mcp, which add_player_slot gives it: no more
  X-OpenCiv3-Seat header, in the env or the player agents. A person's slot gets its play token as the slot's secret
  headers (@player_slot_headers), which add_player_slot puts in the page link's fragment, and the play page reads.
- The match (urn:game:match/v1) reports the turns, each player's outcome by the game's own rules (a defeated civ has
  lost; a conquest, domination, culture or score victory is its civ's, every other player's a loss, an AI civ's
  included; a tie on top at the turn limit is no one's), scores (score, cities, population, techs) and moves (turns a
  player ended itself, and those the env ended for it). finish_match plays a match out, ending every player's turn.
- The match's files are its recording by kind (map_video, html_replay, last_turn, client_video); its spectator view
  is /live.
- The broadcast stays OpenCiv3's own, now a lobby setting; the env fetches banner logos (https URLs or data: URIs) as
  the lobby closes.

The ten multi-agent tasks and human-vs-ai use open_lobby, add_player_slot, close_lobby, finish_match (await_match for
a person's game), grade_match with max_missed 0.1 (the victor verifier's sat-out rule) and save_match_files. The victor
verifier, and the openciv3_match and openciv3_await_game steps, are gone. new-game keeps the default game, one
civilization at the env's own address, for smoke, play and full-game, which keep their baseline verifiers and
save_env_recording. The env image installs game-env from the archive pyproject.toml pins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lane

README, docs (play, tools, protocol, recording, viewer), the bundle's README and the playtest README describe the
lobby, player slots, the match and grade_match in place of openciv3_match, the seat header and the victor verifier.
playtest/bots.py starts its matches through the lobby and plays each seat at its player slot's address. data/reset
and data/add start a default game after a lobby game, without the lobby's keys, as new-game does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale merged commit 93a8553 into main Oct 12, 2026
5 checks passed
@earakely-scale
earakely-scale deleted the feat/game-env branch October 12, 2026 01:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant