MiroShark
Documentation · v1

How MiroShark works

A deep walkthrough of the engine, by category.

MiroShark is a universal swarm-intelligence engine. You bring a scenario; it builds the world around it — a temporal knowledge graph, hundreds of grounded personas, three platforms running in lockstep, and a citing report at the end. Here is exactly how each layer is wired.

Last updated · June 4, 2026

MiroShark ships fast — this page is a snapshot, not a contract. For the latest features, env vars, model defaults and breaking changes, check the repo directly: recent commits, open & merged PRs, README and docs/. When in doubt, the code on main is the source of truth.

Contents
00Overview

The five-step pipeline

Document in, world out. Every simulation walks the same five stages: build a graph, ground the personas, run three platforms in parallel, write a citing report, and let you interact.

1 · Graph build

A document is parsed into a Neo4j knowledge graph. NER uses few-shot examples plus rejection rules to filter garbage. Chunks are processed in parallel and written in batched UNWIND transactions — ~10× faster than per-entity writes.

2 · Agent setup

Personas are generated from the graph. Each gets five layers of context: attributes, relationships, semantic search, BFS neighbours, and (for public figures or thin context) a live web research call.

3 · Simulation

Twitter, Reddit and Polymarket run simultaneously via asyncio.gather. A market-media bridge lets traders read posts and lets social agents see prices. Beliefs and trust update each round.

4 · Report

A ReACT agent writes the post-mortem using simulation_feed, market_state, graph search, belief trajectory and a Nash equilibrium tool. Every claim cites a real post or trade.

5 · Interaction

DM any agent, send a question to a group, inject breaking news, or fork the timeline with a counterfactual event. Forks are siblings; the UI diffs them.

Output surfaces

Every run yields a citing report, a trajectory chart, a signal JSON and badge, a tweet-thread export, a Jupyter notebook, an oEmbed/Frame v2 unfurl, a reproducibility bundle, and an optional DKG anchor on Base — 31 surfaces in all, each listed in /api/surfaces.json.
document  ─▶  graph build  ─▶  persona grounding  ─▶  3× platform loop  ─▶  report
                                                       │
                                                       ├─ Director Mode  (inject)
                                                       ├─ Fork           (branch)
                                                       └─ Persona Chat   (DM)
01Memory

Knowledge graph & memory pipeline

A Neo4j-backed temporal graph — NER, entity resolution, contradiction detection, fused retrieval, and Leiden community clusters — inspired by Hindsight, Graphiti, Letta and HippoRAG.

Ingestion

Text flows through NER (with an ontology) into a batched embedding call (OpenRouter text-embedding-3-large or a local Ollama equivalent). Entity resolution combines fuzzy matching, vector similarity, and an LLM reflection step — collapsing “NeuralCoin”, “Neural Coin” and “NC” into one canonical UUID. Same-endpoint relationship pairs are sent to an LLM adjudicator that invalidates the older edge instead of stacking contradictions.

text  →  NER (with ontology)
      →  batch embed (text-embedding-3-large | Ollama)
      →  entity resolve (fuzzy + vector + LLM reflection)
      →  MERGE entities (canonical UUIDs)
      →  contradiction adjudication (invalidate old)
      →  CREATE RELATION {valid_at, invalid_at, kind, source_type, source_id}

Retrieval

Each query fans out into three parallel searches — vector edge search over Neo4j HNSW, BM25 fulltext, and a BFS traversal from seed entities. The top 30 candidates are fused, filtered by valid_at / kind, and re-ranked by a BGE-reranker-v2-m3 cross-encoder on Apple MPS, CUDA or CPU.

query
  ├─ vector edge   (Neo4j HNSW)        ─┐
  ├─ BM25 edge     (Neo4j fulltext)    ─┼─ temporal + kind filters → fused top 30
  └─ BFS traversal (from seed entities) ┘
                                       ↓
                BGE-reranker-v2-m3 (MPS / CUDA / CPU)
                                       ↓
                top N tagged with _sources ("v" / "k" / "g" / combos)

Communities (zoom-out)

Leiden community detection (via igraph) groups entities. An LLM writes a 2-sentence summary and title per cluster; clusters persist as :Community nodes with MEMBER_OF edges. Semantic search over cluster summaries is exposed as the browse_clusters agent tool.

Reasoning memory

Every report generation persists its full ReACT trace as a traversable subgraph: (:Report)-[:HAS_SECTION]->(:ReportSection)-[:HAS_STEP]->(:ReasoningStep). Step kinds are thought, tool_call, observation, conclusion — so a future operator can ask “why did the agent conclude X?” and walk the trace.

What it buys you

Multi-hop queries land facts that single-hop RAG misses. Temporal queries (as_of="2026-04-10T14:00Z") return the world as known at that moment. Epistemic filtering separates ground-truth facts from agent beliefs. First-call recall is high enough that the report agent's 5-call budget actually goes somewhere.
02Agents

Persona generation & grounding

Each agent is built from five layers of context — graph attributes, relationships, semantic neighbours, BFS context and (optionally) live web research — then anchored to Nemotron demographics.

Five layers of grounding

For every entity that becomes an agent, the generator pulls: (1) the node's attributes, (2) its first-degree relationships, (3) a semantic vector search over the rest of the graph, (4) related nodes via BFS, and (5) — when the graph context is thin (< 150 chars) or the entity looks like a public figure — a live web-research LLM call. The five layers fuse into a single persona prompt.

Individual vs institutional

The system distinguishes a person (“Vitalik Buterin”) from an institution (“Ethereum Foundation”) via keyword and ontology rules, and switches the persona schema accordingly — institutions speak in press-release voice, individuals in first person with personality variance.

Web enrichment

When enabled, set WEB_SEARCH_MODEL=perplexity/sonar-pro in .env. The grounding call goes through OpenRouter and returns citation-backed snippets that get folded into the prompt — so a CEO persona reflects the actual last-week-of-news version of the CEO, not a stale training snapshot.

Demographic anchoring (Nemotron)

Non-named agents inherit demographic features (age bracket, region, education, profession, online platform mix) from a Nemotron-aligned population sample. The result is a swarm that mirrors a realistic population distribution rather than a sea of identical Reddit-shaped archetypes.
entity ─┬─ attrs            (Neo4j properties)
        ├─ relationships   (1-hop edges)
        ├─ semantic        (vector neighbours)
        ├─ BFS context     (multi-hop)
        └─ web enrichment  (Perplexity / Sonar — public figures only)
                  ↓
        persona prompt  ─▶  Wonderwall agent loop
03Engine

Cross-platform simulation engine

Twitter, Reddit and a Polymarket-style prediction market run simultaneously every round. Belief states track stance, confidence and trust; a sliding-window memory keeps prompts compact.

┌──────────────────────────────────────────────────────────┐
│        Round Memory (sliding window)                     │
│  Old rounds:        LLM-compacted summaries              │
│  Previous round:    full action detail                   │
│  Current round:     live (partial)                       │
└────┬─────────────┬─────────────┬─────────────────────────┘
     │             │             │
┌────▼────┐   ┌────▼────┐   ┌────▼──────────┐
│ Twitter │   │ Reddit  │   │ Polymarket    │
│ Posts   │   │ Comments│   │ Trades (AMM)  │
│ Likes   │   │ Upvotes │   │ Single market │
│ Reposts │   │ Threads │   │ Buy/Sell/Wait │
└────┬────┘   └────┬────┘   └────┬──────────┘
     │             │             │
┌────▼─────────────▼─────────────▼─────────────────────────┐
│        Market-Media Bridge                               │
│  Social sentiment   → trader prompts                     │
│  Market prices      → social media prompts               │
│  Social posts       → trader observation                 │
└────┬─────────────┬─────────────┬─────────────────────────┘
     │             │             │
┌────▼─────────────▼─────────────▼─────────────────────────┐
│        Belief State (per agent)                          │
│  Positions:   topic → stance (-1 to +1)                  │
│  Confidence:  topic → certainty (0 to 1)                 │
│  Trust:       agent → trust level (0 to 1)               │
└──────────────────────────────────────────────────────────┘

Three platforms, one round

All three platforms execute concurrently each round via asyncio.gather. Twitter and Reddit generate posts, replies and reactions; Polymarket runs a constant-product AMM with a single LLM-framed market.

Market-Media Bridge

Traders see actual posts in their observation prompt. Social agents see market prices in theirs. Cross-platform context is the difference between simulating a crowd and simulating a market.

Prediction market

The market title is generated through the Smart model slot — phrasing has to be sharp, time-bound and resolvable, because it frames the entire run. Initial price is the LLM's probability estimate (non-50/50). Pricing is constant-product AMM.

Belief states

Each agent carries a per-topic stance ∈ [-1, +1], a confidence ∈ [0, 1], and a per-agent trust level. Heuristic updates each round capture exposure, agreement, and trusted-source weighting.

Sliding-window memory

Old rounds are LLM-compacted to summaries on a background thread. Previous round stays as full detail; current round is live. The window keeps prompts compact while preserving narrative continuity.

Per-round frame API

GET /api/simulation/<id>/frame/<round> returns a compact snapshot — actions, active-agent count, market prices, belief state. Query params: platforms, include_belief, include_market. Powers the replay scrubber and the CLI frame subcommand.

Performance numbers (vs. naive baseline)

Neo4j writes        1 tx per entity      →  batched UNWIND      (10×)
Chunk processing    sequential           →  ThreadPoolExecutor (3×)
Config generation   sequential batches   →  parallel batches   (3×)
Platform execution  partial concurrency  →  all 3 in parallel
Memory compaction   blocking             →  background thread
04Interaction

Live interaction — Director, chat, forks

Inject breaking news mid-run, fork the timeline with a counterfactual event, or DM any agent. Forks are first-class siblings; comparisons are diffable.

Director Mode (inject)

Drop a breaking-news payload into the current timeline. Active agents observe it in their next round, beliefs shift, the market reprices. No fork — the same run continues with new information.

Counterfactual Branching (fork)

Pick any round, inject an event (“CEO resigns in round 24?”), and MiroShark forks the simulation. The parent keeps running; the child runs independently. The UI shows the two side-by-side so you can read the divergence.

Persona chat

Click any agent to open a DM. The chat uses the agent's current belief state and full posting history — it answers in character, not as a stateless LLM. Group sends route the same prompt to a selected cohort.

Lineage navigator

Forks aren't flat: every branch knows its parent, its sibling branches, and the round at which it split. The lineage navigator renders the whole tree so you can compare across counterfactual paths, not just two-by-two.
05Reports

Reports, signals & analytics

A ReACT report agent cites real posts and trades. Trajectory chart, signal JSON, peak-round analytics, per-agent sparklines, consensus badge, Nash equilibrium tool.

ReACT report agent

The report agent runs a tool-calling loop with simulation_feed (real posts / comments / trades), market_state (prices, P&L), graph search, belief_trajectory, and a Nash equilibrium tool. Every claim is grounded in a citation. A Regenerate Report button re-runs the agent on demand and mints a fresh report_id.

Signal JSON & direction

signal.json distils the final belief split into a direction — bullish > bearish > neutral — using a plurality rule with a deterministic tie-break. Same rule drives the platform aggregate.

Trajectory chart (SVG)

A purely stdlib SVG of per-round belief means, deltas and confidence bands. Drops straight into oEmbed unfurls, Discord embeds and static-site exports — no JS, no Recharts, no PNG roundtrip.

Consensus badge (SVG)

A Shields.io-compatible 20-pixel pill — green / grey / red by direction. One Markdown line turns any README into a live consensus indicator.

Peak-round analytics

Identifies the round where belief variance, market velocity or comment volume peaks. Lets a reader jump straight to the inflection moment instead of scrubbing the whole timeline.

Belief volatility

/volatility is the turbulence counterpart to peak-round — it describes the distribution of round-over-round belief swings: mean_delta_pct, std_dev_delta_pct, a volatility_index (0–100) and a trend of stable / converging / contested.

Per-agent sparklines

One inline SVG per agent shows that agent's belief trajectory across the run. Click through to the full persona profile + simulation history.

Agent roster (agents.json)

/agents.jsonis the “who they were” export — name, bio, a truncated persona preview, demographics (age / gender / MBTI / country / profession / interests), karma, and each agent's final stance and rounds participated. Sparklines show how a belief moved; this shows whose it was.

Polymarket-ready prediction

/polymarket.json is the first integrator-shaped surface: a direction-aware yes_probability / no_probability pair (summing to 1.0), a four-bucket confidence_tier, risk tier and a suggested market title. Emits only once a run is completed — a stricter gate than signal.json.

Platform & project stats

/api/stats aggregates consensus distribution, average confidence and surface views across every public completed sim, with a Shields.io /api/stats/badge.svg pill. /api/project/<id>/stats scopes the same numbers to one workspace and adds a per-project quality_distribution.

Predictive accuracy ledger

Cross-references published predictions with later ground truth, so the system tracks (and exposes) how often the swarm was right.

Quality diagnostics

A per-run quality score covers entity coverage, graph density, agent activity dispersion, and belief movement — flagging runs where the input was too thin or the swarm was inert.
06Inputs

Inputs — Smart Setup, Just Ask, Trending

Drop a doc, type a question, pick from RSS-driven trending news, or use one of six preset templates. Shareable links land readers on a pre-filled form.

Smart Setup

Drop in a document → three auto-generated Bull / Bear / Neutral scenarios in ~2s. Pick one to seed the run.

What's Trending

A live RSS pane shows current news items. One click pre-fills the scenario from the headline, with the source URL captured for citation.

Just Ask

Type a question with no document. MiroShark routes through the Smart slot to research and write the seed briefing itself.

Preset templates

Six benchmarked scenarios — crypto launch, corporate crisis, political debate, product announcement, campus controversy, historical what-if — each tuned for the right preset size, market framing and persona mix.

Shareable links

?scenario=…&url=… or ?template=<slug> land a reader on a pre-filled New Sim form. Round-trips through tweets and Substack posts without losing context.

Live Oracle data (FeedOracle MCP)

Opt-in. 484 grounded feed tools — markets, on-chain data, news, social — exposed via the FeedOracle MCP. Seeds get anchored in current state, not in stale training data.

Per-agent MCP tools

Personas can invoke real MCP tools during the simulation — web search, on-chain reads, your in-house APIs. The Wonderwall loop treats them as first-class actions alongside posting and trading.

Locale

Top-right 中 / EN toggle persists per-browser and is reflected in the public gallery cards. API consumers negotiate the same en / zh-CN locales over HTTP by precedence: ?lang= > X-MiroShark-Locale > Accept-Language > en — localizing error messages, template metadata, feed copy and report narration.
07Models

Model routing — six slots, one key

LLM / Smart / Wonderwall / NER / Embedding / Reranker. One OpenRouter key, five env slots, full freedom to mix providers — including self-hosted vLLM or Claude Code with no API key.

MiroShark splits work across six independent model slots, so you can keep the cheap loop cheap and spend on the few prompts that actually steer the run.

LLM (default)

Profiles, sim config, memory compaction. Default: xiaomi/mimo-v2-flash.

Smart

Reports, ontology, graph reasoning, market-question phrasing. #1 quality lever. Default: google/gemini-3-flash-preview.

Wonderwall

The agent simulation loop — the most expensive surface by token volume. #1 cost driver, use the cheapest viable model. Optionally point at a self-hosted vLLM, Modal endpoint, or fine-tune via WONDERWALL_BASE_URL / WONDERWALL_API_KEY.

NER

Entity extraction. Needs reliable JSON and no hidden chain-of-thought. Default: google/gemini-3-flash-preview.

Embedding

OpenRouter text-embedding-3-large or a local Ollama embedding endpoint.

Reranker

BGE-reranker-v2-m3 cross-encoder, ~1GB one-time download. Runs on Apple MPS, CUDA or CPU.

One key, five slots

The recommended path is a single OpenRouter key pasted into the five API-key env vars (LLM_API_KEY, SMART_API_KEY, NER_API_KEY, OPENAI_API_KEY, EMBEDDING_API_KEY). First run is ~10 min and ~$1.

Claude Code mode

Set LLM_PROVIDER=claude-code and MiroShark drives Claude through the Code CLI — no API key required.

Local Ollama

Docker + local Ollama, or a fully manual Ollama wiring — both are first-class install paths.

CoT toggle

DISABLE_COT=trueon reasoning-capable OpenRouter models (Qwen3-Flash, Gemini-3-Flash) drops latency by ~3× for slots that don't need it.
08Integrations

MCP, webhooks, notifications

MCP server for Claude Desktop / Cursor / Windsurf / Continue. Signed webhooks with delivery log. Channel-native completion notifications on Discord, Slack, Email and Telegram. PWA push.

MCP server

A first-party MCP server exposes the simulation surface to Claude Desktop, Cursor, Windsurf, and Continue (VS Code / JetBrains). Spin up sims, fetch frames, query the belief trajectory, and invoke the report agent's tools — all from your editor.

Webhooks

Per-simulation webhooks fire on lifecycle events (run start, fork, round, completion, report). Set WEBHOOK_SECRET and every payload is HMAC-signed in the X-MiroShark-Signature header (Stripe / GitHub scheme). Event filtering and a delivery log come built-in.

Webhook event filter

WEBHOOK_EVENTS is an optional comma-separated allow-list that filters completion webhooks before dispatch (blank = fire on everything). Tokens combine OR within a category and AND across them — e.g. bullish,bearish,high_confidencemeans “(bullish OR bearish) AND high confidence.” simulation.failed always bypasses the filter.

WaybackClaw archive

The IPFS + Nostr sibling of the DKG citation. One opt-in POST to api.waybackclaw.space pins the run snapshot (scenario, agent count, consensus, quality, lineage, reproduce.json SHA-256) to IPFS and broadcasts a NIP-01 note to Nostr relays. Free, no on-chain cost — run it alongside DKG for triple-redundant provenance. Configure with WAYBACKCLAW_AGENT_TOKEN.

Private share links

The first “third-state” sharing primitive, between fully public and fully private. Mint a 192-bit token (POST /api/simulation/<id>/share-link, default 30-day expiry) and hand out /preview/<token> — a noindex, no-OG, no-referrer landing page. Revoke any time; the per-sim REST surfaces keep their public gate. Admin actions need MIROSHARK_ADMIN_TOKEN.

Discord

DISCORD_WEBHOOK_URL → MiroShark posts a native rich-embed: stance-coloured side border, scenario title, belief-percent fields, share-card thumbnail, deep link. Pure stdlib, opt-in, fire-and-forget.

Slack

SLACK_WEBHOOK_URL→ a native Block Kit message with title block, Unicode block-character belief bars, quality / scale / outcome fields, and an “Open simulation” action button.

Email (SMTP)

SMTP_HOST + comma-separated SMTP_TO → a multipart/alternative email per completion. Subject is [MiroShark] Bullish: <scenario>, so a single Gmail filter routes by direction. STARTTLS on 587; STARTTLS-failure with credentials refuses to send cleartext.

Telegram

TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID→ a Bot-API message with HTML parse mode, a stance-coloured headline, Unicode belief bars, and an inline “View simulation” button.

PWA push

Browser push notifications via the PWA shell — opt-in per device, fires on completion and on Director-Mode events you subscribed to.

History database

Local SQLite-backed history of every run, fork, report and chat. Acts as the source of truth for the gallery, the lineage view, and the per-agent profile timelines.
09Export

Export, embed & provenance

31 published surfaces — reproducibility JSON, BibTeX, Jupyter, oEmbed/Frame v2, archive bundle, clone inputs, a self-describing /api/surfaces.json catalog — plus on-chain DKG and WaybackClaw IPFS/Nostr provenance.

Reproducibility JSON

reproduce.json carries every parameter — seed, model slots, persona list, prediction-market framing — needed for a second operator to re-run the simulation bit-for-bit. The canonical bytes are stable.

Clone inputs (clone.json)

The first share surface that returns a sim's inputs rather than its outputs. /clone.json ships a clone_payload that is wire-compatible with POST /api/simulation/create — drop it straight back in to spin up the same scenario against fresh agents.

On-chain provenance (DKG)

The OriginTrail DKG citation anchors reproduce.json's SHA-256 on Base as a Knowledge Asset. A reviewer can fetch the UAL years later and verify the local file still hashes to the recorded digest — DOI-grade provenance, no publishing-house intermediary.

BibTeX

GET /api/simulation/<id>/cite.bib returns a @misc{…}entry that drops straight into a LaTeX source or imports cleanly into Zotero / Mendeley via “Import from URL”. The note field carries the reproduce.json SHA-256 and the annote carries the DKG UAL when present.

Jupyter notebook

A notebook.ipynbper run drops the full trajectory — beliefs, market series, action stream — into a researcher's IDE for direct slicing in pandas / numpy.

Archive bundle

A single ZIP capturing every artifact in one download: report, reproduce.json, notebook, badge SVGs, trajectory SVG, share card, DKG citation, transcript. Cold-storage-friendly.

Tweet thread export

A pre-formatted X / Twitter thread with the headline takeaway, peak rounds, belief deltas and the share card. Built so an operator can ship the run to their audience in one paste.

oEmbed auto-unfurl

One /oembed endpoint covers Notion, Ghost, Substack and WordPress. Paste the sim URL into any of them and the embed renders the trajectory chart, headline, and consensus badge inline.

Farcaster Frame v2

The same sim URL is a valid Frame v2. Cast it on Farcaster and the recipient gets an interactive belief-trajectory card with deep links back to the live run.

Public gallery feeds

/feed.rss and /feed.atom for the public gallery, plus a /sitemap.xml and /robots.txt — so every published simulation is crawlable, citeable and subscribable.

Live watch page

A spectator broadcast surface: a public, read-only live view of a running simulation, suitable for sharing during press cycles or streamed events.

Surface catalog (surfaces.json)

The surface that lists the surfaces. GET /api/surfaces.json is a self-describing catalog of all 31 published surfaces on a deployment — each with its endpoint, method, type (analytics / visualization / export / embed / integration / platform / discovery), description and a ready-to-run example_curl. An integrator answers “what can this host do?” with one call.

Every export surface listed here is built on pure stdlib — no extra dependencies — and is opt-in via env flag. See the full reference in docs/FEATURES.md.

10Ecosystem

Ecosystem & integrators

Projects, agents and tools built on MiroShark — a human-readable ECOSYSTEM.md and a machine-readable /api/ecosystem.json catalog that integrators and registries crawl.

ECOSYSTEM.md (human-readable)

The curated index of projects, agents and products built on top of MiroShark — alphabetized, with a logo column and an “Add your project” PR guide. Linked from the README in both EN and 中文. Browse it on the Ecosystem page.

/api/ecosystem.json (machine-readable)

The crawlable counterpart. Each entry carries name, url, description, category (product / tool / integration / agent / benchmark), x_handle and repo. ETag-cached and exposed as a discovery surface in /api/surfaces.json.

Who's building on it

Discovery registries (Sparkleware), synthetic-user research (SyntheticsAI), integration specs (Capacitr), local-first agent dashboards (HivemindOS), and Telegram/web prediction agents (ZER0) all run real MiroShark simulations.

Drive it from anywhere

Noelclaw ships MiroShark as an MCP server (@noelclaw/mcp) — its miroshark_simulate / miroshark_status tools wrap the full create → prepare → start → poll flow, so any Claude / Cursor / Windsurf session can launch a swarm. AntFleet runs the first integrator benchmark against the engine.
GET /api/ecosystem.json
{ "success": true,
  "data": {
    "schema_version": "1",
    "count": 14,
    "ecosystem": [
      { "name": "Sparkleware", "category": "integration",
        "x_handle": "…", "repo": "https://github.com/…" },
      …
    ] } }

Add your project with a PR to ECOSYSTEM.md — a square 40 px logo, one-line description, category, and links. The machine-readable catalog stays in lockstep via a drift-guard test.

Run it

Your first simulation takes ~10 min and ~$1.

One OpenRouter key, one launcher. Clone, drop the key into the five slots, run ./miroshark, openlocalhost:3000.