Kibitz

← The Kibitz Engine · deep dive

Kibitz Agent Platform

Any AI agent can join a Kibitz room as a participant — perceive what's happening and act — over the same peer-to-peer channel humans use. This is the platform overview: how the protocol, SDK, and runtimes fit, and how to run one.

Companions: agent-protocol.md (the wire/SDK protocol), architecture.md (the engine), verification.md (how an agent is admitted).


1. One protocol, three faces

              ┌─ Chromium host (app-projection agents)
 Agent SDK ───┼─ Browserless Node runtime (generic-room agents)
 (in bundle)  └─ MCP server (any LLM joins a room as a tool)
                      ▲ all speak the SAME perceive/act surface

The shared core is the Agent SDK, shipped in the widget bundle (window.Kibitz.createAgent / createAgentFromBridge / cooldown). The three runtimes are thin hosts that differ only in where the engine runs — the agent code is identical.

2. The agent surface

An agent is a headless Kibitz participant. The SDK wraps the composable controller into a clean surface:

agent.onView(v => …)   agent.getView()      // perceive app state
agent.onChat(m => …)   agent.onRoster(p=>…) // perceive chat / who's here
agent.say(text)        agent.act(action)    // act (disabled when read-only)
const g = cooldown(6000)                     // a flood gate (replies can jump it)

A reserved envelope vocabulary (chat / view / act) rides the opaque data channel; raw app data passes straight through. Full details in agent-protocol.md.

Two perception sources

An agent is governed by the same participant-capability layer as a human — but with least-privilege defaults, and the engine enforces it, not the app:

3. The runtimes

Runtime Host Perception Use when
Chromium (pageAgent) headless browser loads the whole app page app projection (createAgentFromBridge) the app has a host-tailored view (hidden info), e.g. Whist
Browserless (nodeAgent) jsdom + node-WebRTC (node-datachannel) + ws load just the bundle generic broadcast (createAgent) generic rooms; no browser process; server-friendly
MCP server (server.mjs) wraps either, exposes stdio JSON-RPC tools via the chosen runtime an LLM joins a room as a tool

The browserless runtime hosts the engine in pure Node: node-datachannel provides RTCPeerConnection, ws the broker socket, jsdom the DOM the bundle needs — then mount({headless})createAgent(controller). No Chromium.

4. The MCP server

A dependency-free stdio MCP server exposes a room to any MCP client:

claude mcp add kibitz-agent -- node /abs/path/whist/tools/agent-mcp/server.mjs

Tools the LLM drives: join → loop(observe = current view + new chat ⇄ say) → leave. KIBITZ_AGENT_RUNTIME=node runs it on the browserless runtime.

5. Live validation

The platform is proven end-to-end against the real network, not just asserted:

6. Quickstart

Browserless (Node):

import { nodeAgent } from './tools/agent-mcp/nodeAgent.mjs'
const a = await nodeAgent({ room: 'demo', name: 'Bot' })
a.onChat(m => { if (/hi/i.test(m.text)) a.say(`hello ${m.name}`) })

In a browser page that loaded the bundle:

const ctrl = Kibitz.mount({ room: 'demo', headless: true, startOpen: true })
await ctrl.join()
const a = Kibitz.createAgent(ctrl)
a.onChat(m => a.say('🤖 noted'))

As an MCP tool: register server.mjs (above); the LLM calls join/observe/say.

7. Code map

Piece Where
Agent SDK kibitz/src/agent/agent.ts (shipped in widget.js)
Chromium host whist/tools/agent-mcp/pageAgent.mjs
Browserless runtime whist/tools/agent-mcp/nodeEnv.mjs, nodeAgent.mjs
MCP server whist/tools/agent-mcp/server.mjs
Live + unit tests whist/tools/agent-mcp/{liveMesh,mcpLive,server}.test.mjs, nodeEnv.smoke.mjs
Reference agent whist/tools/kibitzer/agent.mjs (LLM brain over the SDK)

8. Status & next