website/src/content/docs/agent-os/multiplayer.mdx
All clients connected to the same actor receive broadcasted events. This enables building collaborative UIs where multiple users watch an agent work.
<CodeGroup> ```ts @nocheck client.ts import { createClient } from "rivetkit/client"; import type { registry } from "./server";// Client A: creates the session and sends prompts const clientA = createClient<typeof registry>("http://localhost:6420"); const agentA = clientA.vm.getOrCreate(["shared-agent"]);
agentA.on("sessionEvent", (data) => { console.log("[A]", data.event.method); });
const session = await agentA.createSession("pi", { env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! }, }); await agentA.sendPrompt(session.sessionId, "Build a REST API");
// Client B: observes the same session (in a separate process) const clientB = createClient<typeof registry>("http://localhost:6420"); const agentB = clientB.vm.getOrCreate(["shared-agent"]);
agentB.on("sessionEvent", (data) => { console.log("[B]", data.event.method); });
// Client B sees the same events as Client A
```ts @nocheck server.ts
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { vm } });
registry.start();
All clients receive process output events from the same VM.
<CodeGroup> ```ts @nocheck client.ts import { createClient } from "rivetkit/client"; import type { registry } from "./server";const client = createClient<typeof registry>("http://localhost:6420"); const agent = client.vm.getOrCreate(["shared-agent"]);
// All connected clients see process output
agent.on("processOutput", (data) => {
const text = new TextDecoder().decode(data.data);
console.log([pid ${data.pid}] ${data.stream}: ${text});
});
// All connected clients see shell data agent.on("shellData", (data) => { const text = new TextDecoder().decode(data.data); process.stdout.write(text); });
```ts @nocheck server.ts
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { vm } });
registry.start();
One client acts as the driver (sending prompts), while others observe.
<CodeGroup stacked> ```ts @nocheck server.ts import { agentOs } from "rivetkit/agent-os"; import { setup } from "rivetkit"; import common from "@rivet-dev/agent-os-common"; import pi from "@rivet-dev/agent-os-pi";const vm = agentOs({ onSessionEvent: async (c, sessionId, event) => { // Server-side hook runs once per event, even with multiple clients console.log("Session event:", sessionId, event.method); }, options: { software: [common, pi] }, });
export const registry = setup({ use: { vm } }); registry.start();
```ts @nocheck client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
// Driver client
const driver = createClient<typeof registry>("http://localhost:6420");
const driverAgent = driver.vm.getOrCreate(["shared-agent"]);
const session = await driverAgent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
// Observer client (different user, same actor)
const observer = createClient<typeof registry>("http://localhost:6420");
const observerAgent = observer.vm.getOrCreate(["shared-agent"]);
observerAgent.on("sessionEvent", (data) => {
console.log("[observer]", data.event.method, data.event.params);
});
// Driver sends a prompt. Observer sees the streaming response.
await driverAgent.sendPrompt(session.sessionId, "Refactor the auth module");
When a client reconnects, use getSequencedEvents to replay missed events and catch up.
const client = createClient<typeof registry>("http://localhost:6420"); const agent = client.vm.getOrCreate(["shared-agent"]);
// On reconnect, replay events from the last known sequence number const lastSeq = 42; // Track this on the client side const missedEvents = await agent.getSequencedEvents("session-id", { since: lastSeq, }); for (const event of missedEvents) { console.log("Replaying:", event.sequenceNumber, event.notification.method); }
// Resume live streaming agent.on("sessionEvent", (data) => { console.log("Live:", data.event.method); });
```ts @nocheck server.ts
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({
options: { software: [common, pi] },
});
export const registry = setup({ use: { vm } });
registry.start();
["shared-agent"]) for all clients that should share the same VM.getSequencedEvents to replay missed events.onSessionEvent hook for logic that should run once per event regardless of connected clients.