Skip to main content
The WASM runtime compiles the full Meerkat agent stack to wasm32 for browser deployment. It routes through the same AgentFactory::build_agent() pipeline as all other surfaces.
This page is intentionally browser/WASM-specific rather than a cross-surface tabbed page. Use Examples: Mobpack first if you want the packaging/deployment path that usually leads into browser delivery.

Build the WASM bundle

Build a self-contained, runnable web bundle from a .mobpack artifact. --wasm points at the prebuilt meerkat-web-runtime (the wasm-pack --target web output dir, or the committed sdks/web/wasm):
rkat mob web build ./dist/my-mob.mobpack -o ./dist/web-bundle --wasm ./sdks/web/wasm
Then serve and open it: python3 -m http.server -d ./dist/web-bundle.

Initialize runtime

Use init-time credentials and provider base URLs to seed the browser runtime’s realm config. The @rkat/web RuntimeConfig is provider-specific: anthropicApiKey, openaiApiKey, geminiApiKey, and the matching provider base URL fields (anthropicBaseUrl, openaiBaseUrl, geminiBaseUrl). The old generic apiKey/baseUrl compatibility fields are deleted, and SessionConfig does not accept per-session apiKey or baseUrl.
import { MeerkatRuntime } from "@rkat/web";
import * as wasm from "@rkat/web/wasm/meerkat_web_runtime.js";

const runtime = await MeerkatRuntime.initFromMobpack(wasm, mobpackBytes, {
  anthropicApiKey: "sk-ant-...",
  model: "claude-sonnet-4-6",
});
For proxy deployments, pass a provider-specific dummy key and base URL. The proxy injects the real server-side credential.
const runtime = await MeerkatRuntime.init(wasm, {
  anthropicApiKey: "proxy",
  anthropicBaseUrl: "http://localhost:3100/anthropic",
  model: "claude-sonnet-4-6",
});

Create session and run turn

const session = runtime.createSession({
  model: "claude-sonnet-4-6",
});

const result = await session.turn("Hello");
console.log(result.text);
For OAuth or host-owned cloud credentials, register an external auth resolver and bind the session to a structural auth binding. The selected realm binding must be configured to use the WASM external-resolver credential source.
import { registerExternalAuthResolver, withAuthBinding } from "@rkat/web";

registerExternalAuthResolver(wasm, async (authBinding) => {
  const token = await hostAuth.freshAccessToken(authBinding);
  return {
    kind: "inline_secret",
    secret: token.accessToken,
    metadata: { account_id: token.accountId },
    expires_at: token.expiresAt,
  };
});

const bound = runtime.createSession(withAuthBinding(
  { realm: "team-alpha", binding: "anthropic" },
  { model: "claude-sonnet-4-6" },
));

Poll events

for (const event of session.pollEvents()) {
  if (event.type === "text_delta") {
    document.body.innerText += event.delta;
  }
}

Mob lifecycle in browser

// Create mob from definition
const mob = await runtime.createMob({
  id: "research-team",
  orchestrator: { profile: "lead" },
  profiles: {
    lead: { model: "claude-sonnet-4-6" },
    worker: { model: "claude-sonnet-4-6" },
  },
});

// Spawn members
await mob.spawn([
  { profile: "lead", agent_identity: "lead-1" },
  { profile: "worker", agent_identity: "worker-1" },
]);

// Wire peers
await mob.wire("lead-1", "worker-1");

// Inspect runtime state
const members = await mob.listMembers();
const leadStatus = await mob.memberStatus("lead-1");

Subscribe to member events

const sub = await mob.subscribeMemberEvents("lead-1");

for (const event of sub.poll()) {
  console.log(event.type, event);
}

sub.close();

Cross-mob comms

Wire ambassadors across mobs for inter-faction communication. mob.wire() accepts either a local member name or an external peer target, so trust between members of different mobs is established by wiring each ambassador to the other side’s peer identity (comms name, address, Ed25519 public key).
// Wire an ambassador to a peer in another mob
await northMob.wire("ambassador-north", {
  external: {
    name: "ambassador-south",
    address: southAddress,
    identity: { kind: "ed25519_public_key", public_key: southPublicKey },
  },
});

// Send work to a member through the canonical member path
await northMob
  .member("ambassador-north")
  .send("Send a message to the south faction proposing an alliance on the eastern front.");
Direct comms_send and comms_peers are reserved low-level placeholders rather than current wasm-bindgen exports or public @rkat/web wrapper methods. Inter-agent messaging happens through member-directed turn submission and the comms tools available to agents during their turns (send_message, send_request, send_response, and peers).

What is available on wasm32

CategoryAvailableNot available
Agent loopFull agent state machine, streaming, budget
ProvidersAnthropic, OpenAI, Gemini (browser fetch)
SessionsEphemeral sessionsPersistent sessions (filesystem)
MobsFull orchestration, flows, lifecycle
CommsIn-process (inproc) transportTCP, UDS, network transports
ToolsCustom tools, tool dispatchShell tools, filesystem tools
SkillsEmbedded skills, HTTP skillsFilesystem skill sources
HooksIn-process hooksCommand hooks, filesystem hooks
CompactionContext compaction
OtherMCP client, delegated work orchestration

Next step

  • Examples: Mobpack — the packaging/deployment path that often comes before browser delivery
  • Examples: Mobs — the multi-agent runtime model behind many WASM demos