DEV Community

Cover image for Building The Rumor Machine: making the spread of belief visible
Harish Kotra (he/him)
Harish Kotra (he/him)

Posted on

Building The Rumor Machine: making the spread of belief visible

A technical note for developers who want to build simulations where information—not resource management—is the mechanic.

The design constraint

The central constraint was conceptual, not visual: reality must not move. The interesting system is every version of that reality that people form and transmit.

So the app begins with one protected record:

const event = 'A dragon attacked the eastern farm at dawn.';
Enter fullscreen mode Exit fullscreen mode

The map is then a readout of thirty separate interpretations. A farmer can speak from proximity, a scholar can hesitate, and a child can leap to a dramatic conclusion. The user sees the social network rather than being asked to micromanage it.

The browser architecture

The browser architecture

React owns the exhibit state. The provider adapter is deliberately separate from the rumour orchestrator: the adapter knows how to call an endpoint; the orchestrator knows the information rules. That boundary lets the same citizen workflow run against a hosted model, a local model, or an Agno agent.

A provider-neutral model adapter

Most model servers now implement OpenAI-style chat completions. One small function can therefore cover OpenAI, gateways, Ollama’s compatibility server, and LM Studio:

const response = await fetch(`${baseUrl}/chat/completions`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
  body: JSON.stringify({
    model,
    temperature: 0.7,
    response_format: { type: 'json_object' },
    messages,
  }),
});
Enter fullscreen mode Exit fullscreen mode

The Agno citizen service takes a different route. It accepts a run for one named citizen, so the orchestration and role rules remain inside real Agno agents:

await fetch(`${agentOsUrl}/agents/${agentId}/runs`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
  body: JSON.stringify({ message: prompt, stream: false }),
});
Enter fullscreen mode Exit fullscreen mode

The workflow: model output as a constrained simulation input

The prompt mirrors a small agent workflow: observe the permanent record, retrieve current memory, reason through a role, converse, then reflect. The response is constrained to a compact JSON payload.

const value = JSON.parse(match[0]) as BeliefUpdate;
if (!value.belief || !Number.isFinite(value.confidence)) {
  throw new Error('The model response was missing a belief or confidence.');
}
return { ...value, confidence: Math.max(0, Math.min(100, Math.round(value.confidence))) };
Enter fullscreen mode Exit fullscreen mode

This detail matters. A model is not authoritative simply because it returns prose. The simulation treats every model answer as untrusted input, parses it, clamps its numeric ranges, and only then adds it to a citizen state.

Why the map uses CSS and SVG

The brief calls for a miniature village, but a full 3D scene is not automatically the better first implementation. The map’s job is to show relationships, distance, and transmission. CSS buildings and an SVG network do that at a tiny payload and make the flow lines easy to inspect.

The visual direction is closer to a field notebook than an AI dashboard: muted terrain, editorial type, old-paper profile cards, and one warm highlight for the active thread. The interface’s signature is the glowing rumor line—the visual equivalent of a sentence moving from person to person.

The current model consultation is intentionally individual and opt-in. A deeper version should add first-class rumours, a maximum memory queue, trust deltas, deterministic scheduled encounters, and replayable seeds. Once those pieces exist, model calls can be used selectively—for example only when a novel rumour reaches a high-influence citizen—while the majority of the simulation remains cheap, traceable, and reproducible.

For a public deployment, move the model calls behind a server-side proxy. A browser should never be the long-term home of a paid provider credential.

Code & more: https://www.dailybuild.xyz/project/213-the-rumor-machine

Top comments (0)