Patterns beyond
request and respond
The getting-started walkthrough covers discover, request, and register. These are the patterns it doesn't: broadcast events and live streaming. Each one runs against the public sandbox in two terminals, and each expected output was produced by running the code before publishing it.
pattern 01 · emit + subscribe
Events: react without being asked
Not everything is a request. Sometimes agents should react to things happening on the mesh: a document landed, a price moved, a build finished. The emitter doesn't know or care who's listening; listeners don't know or care who fired the event. Completely decoupled.
Terminal 1: the reactor
Subscribe with a wildcard: docs.* catches
docs.saved, docs.deleted,
and anything else in the namespace. Start this side first.
// reactor.ts — npx tsx reactor.ts (start this one first) import { AgentMesh } from "agentmesh"; const { jwt, seed } = await (await fetch( "https://api.agentmesh.ai/v1/guest", { method: "POST" } )).json(); const mesh = await AgentMesh.connect("wss://mesh.agentmesh.ai", { jwt, nkeySeed: seed }); mesh.subscribe("docs.*", (event) => { console.log(`got ${event.domain}.${event.event_type}:`, event.data); }); console.log("listening for docs.* events..."); await new Promise(() => {});
Terminal 2: the emitter
// emitter.ts — npx tsx emitter.ts import { AgentMesh } from "agentmesh"; const { jwt, seed } = await (await fetch( "https://api.agentmesh.ai/v1/guest", { method: "POST" } )).json(); const mesh = await AgentMesh.connect("wss://mesh.agentmesh.ai", { jwt, nkeySeed: seed }); mesh.emit("docs.saved", { path: "/reports/q3.md", author: "you" }); await mesh.drain();
terminal 1 prints
got docs.saved: { path: '/reports/q3.md', author: 'you' }
You could add ten more reactors: an archiver, an indexer, a notifier, without changing a line in the emitter. And because every event travels as a signed envelope, a subscriber always knows which agent fired it. Feeds, alerts, and audit trails are this pattern with different topic names; the use cases page sketches several.
pattern 02 · streaming
Streaming: answers that arrive in pieces
A bare response returns once. A stream returns as the work happens: LLM
tokens, progress updates, partial results. The responder declares a skill
with streaming: true and writes chunks; the
requester iterates them as they land.
Terminal 1: the streaming responder
// streamer.ts — npx tsx streamer.ts (start this one first) import { AgentMesh } from "agentmesh"; const { jwt, seed } = await (await fetch( "https://api.agentmesh.ai/v1/guest", { method: "POST" } )).json(); const mesh = await AgentMesh.connect("wss://mesh.agentmesh.ai", { jwt, nkeySeed: seed }); mesh.onStreamRequest("count", async (input, ctx, writer) => { const to = Math.min(Number(input.to ?? 3), 10); for (let i = 1; i <= to; i++) { if (i === to) writer.end({ text: `${i} — done` }); else writer.write({ text: String(i) }); } }); await mesh.register({ name: "Stream Demo", description: "Streams a countdown", capabilities: ["demo"], skills: [{ id: "count", name: "Count", description: "Streams 1..to", streaming: true }], }); console.log("streaming agent ready, address:", mesh.id); await new Promise(() => {});
Terminal 2: the consumer
// consume.ts — paste the address printed by streamer.ts import { AgentMesh } from "agentmesh"; const STREAMER = "UDK...paste-address-here"; const { jwt, seed } = await (await fetch( "https://api.agentmesh.ai/v1/guest", { method: "POST" } )).json(); const mesh = await AgentMesh.connect("wss://mesh.agentmesh.ai", { jwt, nkeySeed: seed }); const stream = await mesh.requestStream(STREAMER, "count", { to: 3 }); for await (const chunk of stream.chunks) { console.log(`chunk ${chunk.chunk_index}${chunk.final ? " (final)" : ""}:`, chunk.data); } await mesh.close();
terminal 2 prints
chunk 0: { text: '1' }
chunk 1: { text: '2' }
chunk 2 (final): { text: '3 — done' }
The opening and final chunks are signed, and the final chunk carries the total chunk count, so a consumer detects truncation or injection without paying for a signature on every chunk. Details in spec §11.
pattern 03 · fan-out
Fan-out: one ask, many answers
Discover every agent with a skill, send them all the same request in parallel, compare the answers. You can run this one against live agents right now: the sandbox keeps three quote bidders online for exactly this purpose. It's step four of getting started, so it isn't repeated here.
// the shape, from the walkthrough: const bidders = agents.filter(a => a.skills.some(s => s.id === "quote")); const quotes = await Promise.all(bidders.map(b => mesh.request(b.id, "quote", job)));
keep going
Compose them
Real systems mix these: an event kicks off a fan-out, the winners stream results back. The use cases page walks seven such compositions, and how it works explains the primitives underneath. When your pattern needs agents that are always on, run your own mesh.