Inspiration

Browser agents can participate in web apps, but visual automation is a poor fit for a live card game. Private information must stay private, actions depend on current state, and people need to understand and control what the agent is doing.

Card Table explores a different model: the agent joins the same product as the human through browser-native WebMCP tools.

What it does

Card Table is a live, two-player table for games played with a standard 52-card deck. A host can start from War, Crazy Eights, Go Fish, or an open table, then edit a plain-language game brief and table mechanics.

One Copy menu provides a one-use invite URL, a ready-made Codex prompt for the guest seat, and a prompt for Codex to continue the current seat.

Each player can act through the visible table, ask Codex to act for them, or let an agent play its seat. The page registers WebMCP tools that match the current table contract. A War table exposes operations such as inspect_table, play_next_card, collect_pile, announce, and react. Different contracts receive different tools.

The application enforces card ownership, private projections, available operations, revision checks, optional turns, and zone rules. People and agents interpret the plain-language game brief together, so one table can support many card games without a separate hard-coded rules engine for each one.

Why WebMCP

Without WebMCP, an agent must click pixels and infer state from screenshots or use a separate integration hidden from the player. Card Table instead gives the agent named operations, bounded schemas, and a seat-specific view of the same product the human sees.

Agents receive structured, current state instead of guessing. Private cards never appear in the other seat's DOM, WebSocket payload, HTTP response, or tool result. Tool actions animate on the felt just like direct UI actions. Room creation and game completion remain human-confirmed, users can take over through the interface at any time, and the visible WebMCP registry contracts as the table contract or game state changes.

Card Table does not call a model API. The browser agent handles judgment and strategy; the application handles authority, privacy, identity, and consistency.

How we built it

The frontend uses React, TypeScript, and Vite. A Cloudflare Worker serves the application and API from one origin. Each private room maps to a SQLite-backed Durable Object that owns authoritative state, seat sessions, invitation redemption, event history, revision replay, WebSockets, and a 24-hour expiry alarm.

Direct UI actions and WebMCP tools use the same validated HTTP action path and pure shared reducer. Every mutation carries an opaque action ID and expected revision. The reducer rejects duplicate actions, stale revisions, disabled operations, wrong turns, unknown zones, and card IDs the actor does not own. State is persisted before seat-specific updates are broadcast over hibernatable WebSockets.

Cards use cryptographically randomized opaque IDs. Separate room-and-seat-scoped secure cookies allow two Codex threads to use different seats even when they share one browser cookie jar. Guest invite tokens stay in URL fragments, are redeemed once, and are removed before room requests.

How we used Codex

Codex helped plan, implement, test, deploy, and play Card Table. The most valuable feedback came from two Codex threads joining one live War room through the page's WebMCP tools.

That playthrough exposed issues static tests missed: shared-cookie seat identity, hidden decks rendering like enormous hands, unclear guest presence, oversized action controls, and card motion that substituted a fading visual for the real card. Each finding drove a concrete product change.

Codex also wrote and ran reducer tests, Worker integration tests, WebMCP lifecycle tests, browser acceptance prompts, and deployment checks.

Features

  • Prompt-defined two-player games using a standard 52-card deck.
  • War, Crazy Eights, Go Fish, and open-table presets.
  • Browser-native tools registered with document.modelContext.registerTool.
  • Human approval before an agent-created room opens.
  • Contract-specific tools backed by one reducer and authorization path.
  • Seat-specific projections that never expose an opponent's private cards.
  • One-use fragment invitations and room-and-seat-scoped secure cookies.
  • Real-time projected updates and presence over hibernatable WebSockets.
  • Contextual controls, card motion, and reduced-motion support.
  • Host-confirmed completion followed by read-only, seat-projected revision replay.

Testing

No account or credentials are required.

Open the live URL in ChatGPT's in-app browser or Chrome with WebMCP enabled. Draft War, call start_table, approve the visible confirmation, and use inspect_table. Copy the guest Codex prompt into a second thread, confirm the guest appears online, and use play_next_card from both seats. The winning seat can use collect_pile. Direct controls and tool calls should produce the same real-time state.

Local verification uses pnpm check and pnpm deploy:dry. On September 3, 2026, all 28 unit tests and 13 Worker tests passed, along with linting, type checking, the production build, and Wrangler dry-run validation.

Known limitations

  • Players and agents referee the specific rules in the game brief.
  • Rooms support exactly two seats and one standard 52-card deck.
  • Rooms use private invitations rather than public matchmaking.
  • Rooms expire after 24 hours.
  • WebMCP requires ChatGPT's in-app browser or a compatible browser with WebMCP enabled.
  • Revision replay retains the opening state and up to 250 later snapshots.

Built With

Share this project:

Updates

Submission history