A Fetch.ai multi-agent system for anyone running for office (school board, city council, state house, federal). Upload a policy → simulate how every demographic actually reacts → talk to constituents in character → draft and post your position → measure real engagement against the simulated predictions.
Twelve discoverable agents on Agentverse, one chat entry point on ASI:1, two transports (mailbox + HTTP A2A), one shared envelope (SharedAgentState).
The whole flow is driven through one ASI:1 chat — the orchestrator dispatches everything else.
Type something like:
"simulate a 5% minimum wage increase in San Jose, 5 personas per cluster and 2 rounds"
You'll get back, in one reply: a markdown decision brief with verdicts and quotes per cluster, a 3D Mapbox impact globe URL, chat handles for each cluster persona to drill into, and pre-loaded social-media drafts ready to post via Stripe-gated Composio.
The orchestrator chains six phases through these agents — each with its own discoverable Agentverse profile:
| # | Agent | Role | Profile |
|---|---|---|---|
| 0 | policy-orchestrator | Chat entry point. Coordinates all phases. | Profile → |
| 1 | graphrag-agent | Extracts entities / relationships / affected populations from policy text | Profile → |
| 2 | env-config-agent | Picks which clusters to simulate + persona/round counts | Profile → |
| 3a | cluster-low_income_renters | Demographic simulator + in-character chat persona | Profile → |
| 3b | cluster-homeowners_middle_class | Demographic simulator + in-character chat persona | Profile → |
| 3c | cluster-small_business_owners | Demographic simulator + in-character chat persona | Profile → |
| 3d | cluster-young_professionals | Demographic simulator + in-character chat persona | Profile → |
| 3e | cluster-seniors_retirees | Demographic simulator + in-character chat persona | Profile → |
| 3f | cluster-families_with_kids | Demographic simulator + in-character chat persona | Profile → |
| 3g | cluster-low_income_workers | Demographic simulator + in-character chat persona | Profile → |
| 4 | report-agent | Synthesizes the markdown decision brief | Profile → |
| 5 | map-agent | Builds the 3D Mapbox impact globe (FastAPI service — local-only, not on Agentverse) | local FastAPI on :8888 |
| 6 | drafts pushed | Orchestrator pushes platform drafts to social-media-agent's /draft sidecar |
— |
These aren't part of the simulation pipeline itself — they're the act and measure half of the campaign workflow:
| Agent | Role | Profile |
|---|---|---|
| social-media-agent | Pay-to-post via Stripe + Composio. Posts to Twitter / Reddit / Facebook on the user's authorized accounts after $1 payment confirmation. Pre-loaded with drafts from the orchestrator. | Profile → |
| comparison-agent | Reality-check agent. Takes simulated cluster reports + actual replies on a published post, classifies each reply into its closest cluster, and produces a "predicted vs actual" delta brief. | Profile → |
USER (chat or web)
│
▼ Phase 1: graphrag-agent extract entities + relationships + populations
▼ Phase 2: env-config-agent pick clusters + persona/round counts
▼ Phase 3: 7 cluster-* agents parallel sentiment simulations (asyncio.gather)
▼ Phase 4: report-agent markdown decision brief
▼ Phase 5: map-agent 3D Mapbox impact globe
▼ Phase 6: drafts pushed tweet / reddit / facebook drafts pre-loaded
│ onto social-media-agent's sidecar
▼
RESULT: brief + map URL + 7 cluster chat handles + social drafts ready
THEN — separately, after the politician posts a position:
USER → social-media-agent → Stripe checkout → Composio post (Twitter / Reddit / Facebook)
THEN — once replies accumulate on the post:
USER / dashboard → comparison-agent → predicted-vs-actual reality-check brief
The system is built around a few deliberate engineering choices:
Instead of typed request/reply pairs per agent (which would mean 10+ message classes), every inter-agent message uses the same Pydantic model. Each sub-agent reads what it needs, fills its slice, and returns the whole envelope. The orchestrator's chat handler is one ~50-line linear async function — no event machine, no state DB.
Default Fetch transport (mailbox websocket polling) was 60-90s per hop in our tests — fatal for a 6-phase pipeline. Workers expose /process REST endpoints; orchestrator calls them via httpx.post. Latency drops from minutes to ~1s per hop. Mailbox is reserved for ASI:1 user-facing chat — orchestrator + cluster agents + social-media-agent + comparison-agent all keep mailbox=True for that.
We use register_chat_agent from uagents_core.utils.registration with the AGENTVERSE_API_KEY to register every agent at module load — before agent.run(). Bypasses the manual "Connect Mailbox" inspector click. Mailbox client finds the bound mailbox on first connect.
social-media-agent runs a uagent on its main port (chat + payment protocols) AND a FastAPI server on port+1 for the orchestrator's draft push. Daemon thread, same process. Avoids forcing the orchestrator into the chat protocol just to send context.
Each cluster-* agent serves both: (a) the orchestrator's /process REST for full simulations, and (b) AgentChatProtocol/0.3.0 for direct user chat. In chat mode, the agent generates a single composite persona on first message and stays in character with per-sender history.
social-media-agent includes both chat_protocol_spec and payment_protocol_spec (seller role). On chat, it creates a Stripe Checkout session and ships the client_secret in RequestPayment.metadata["stripe"]. ASI:1's chat UI renders the embedded checkout. On CommitPayment, the agent verifies via stripe.checkout.Session.retrieve and only then dispatches to Composio.
| Layer | Tech |
|---|---|
| Agent framework | Fetch.ai uagents 0.24.2, uagents-core 0.4.4 |
| LLM | ASI:1 (OpenAI-compatible, Fetch-hosted) |
| Inter-agent transport | HTTP A2A via httpx (workers) + Agentverse mailbox (user-chat) |
| Discovery | Programmatic Almanac registration via register_chat_agent |
| Payments | Stripe Checkout (embedded_page) wrapped in payment_protocol_spec |
| Tool integrations | Composio (Twitter / Reddit / Facebook) with dangerously_skip_version_check |
| Visualization | Mapbox GL JS 3D globe + D3.js force-directed knowledge graph |
| Geocoding | Nominatim (free, no API key) |
| Web frontend | Vite + React 19 + TypeScript + Tailwind |
.
├── policy_simulator/
│ ├── orchestrator.py # chat-protocol entry; pipeline coordinator + web API on :8000
│ ├── graphrag_agent.py # Phase 1
│ ├── env_config_agent.py # Phase 2
│ ├── cluster_agent.py # Phase 3 — generic, picked per `CLUSTER` env
│ ├── report_agent.py # Phase 4
│ ├── map_agent.py # Phase 5 — pure FastAPI, serves /map/<id> + 3D globe
│ ├── social_media_agent.py # post-pipeline action — Stripe + Composio
│ ├── comparison_agent.py # post-pipeline measurement — predicted-vs-actual
│ ├── composio_socials.py # Composio wrappers (Twitter/Reddit/Facebook)
│ ├── personas.py / simulation.py / clusters/definitions.py
│ └── static/map.html # forked MiroFish 3D globe UI
├── shared/
│ ├── models.py # SharedAgentState + ClusterReport + ComparisonRequest etc.
│ ├── chat_proto.py # AgentChatProtocol/0.3.0 helpers
│ ├── registration.py # programmatic Agentverse registration
│ └── asi_one.py # ASI:1 client
├── twitter_agent/ # standalone Twitter assistant (legacy, separate use)
├── website/ # Vite + React frontend (Stump)
└── scripts/run_swarm.py # spawns all sub-agents
# 0. setup
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .env # then fill in ASI_ONE_API_KEY, AGENTVERSE_API_KEY, COMPOSIO_API_KEY,
# STRIPE_SECRET_KEY/STRIPE_PUBLISHABLE_KEY, MAPBOX_TOKEN
# 1. spawn all sub-agents (graphrag + env_config + report + map + social_media +
# comparison + 7 cluster agents)
.venv/bin/python scripts/run_swarm.py
# 2. spawn the orchestrator (chat on :8002, web API on :8000)
.venv/bin/python -m policy_simulator.orchestrator
# 3. (optional) spawn the website
cd website && npm install && npm run dev # http://localhost:5173Once everything's up, all twelve agents auto-register on Agentverse via API key — they show up under your "My Agents" dashboard within a few seconds. From there you can chat the orchestrator (or any sub-agent) directly via ASI:1.
ChatGPT can roleplay one voter. This system coordinates 140 across seven demographics, runs six rounds of opinion drift between them, takes real actions in the world (Stripe payments + OAuth-authorized social posts), and leaves each cluster as a discoverable agent you can drill into. Each agent is its own process with isolated state. Each posts a manifest on Agentverse. Each is callable programmatically by other agents.
"One prompt is a tool. An agent system is a product."
MIT — built on Fetch.ai for the campaign toolbox demo.