{"slug": "i-built-a-25-agent-polish-parliament-that-drafts-bills-with-real-legal-citations", "title": "I Built a 25-Agent Polish Parliament That Drafts Bills With Real Legal Citations", "summary": "A developer built a 25-agent AI system that simulates the Polish Parliament, generating bills with real legal citations in under two minutes. The system, called Virtual Parliament, uses Hermes agents to represent a Speaker, 19 ministries, and five political parties, producing vote tallies, social impact analyses, and side-by-side comparisons of current law versus proposed amendments. Each clause in the output is cited to an actual Polish statute, making the normally invisible legislative editing process visible to non-lawyers.", "body_md": "*This is a submission for the Hermes Agent Challenge*\n\nTL;DR— Type a one-line bill topic. Twenty-five Hermes agents (1 Speaker, 19 ministries, 5 parties) run a full Polish legislative session in 2 minutes. Vote tally, social impact, party tweets — and a side-by-side\"current law vs proposed amendment\"with every clause cited to a real statute. Built on`delegate_task`\n\nfor parallel ministry consultation.\n\n🌐 **Live:** [https://web-production-53027.up.railway.app/](https://web-production-53027.up.railway.app/)\n\n🎥 **Walkthrough:** [https://www.loom.com/share/92cdac7da31c471088a4e569b0cfe1ed](https://www.loom.com/share/92cdac7da31c471088a4e569b0cfe1ed)\n\n📦 **Repo:** [https://github.com/monsad/ai-politics](https://github.com/monsad/ai-politics) (MIT)\n\nWatch a politician debate a new tax law on TV. They argue whether it's fair, whether it'll work, whether the other side is lying. **Nobody ever shows you the diff** — *which paragraph of which statute* actually changes, and from what to what. The conversation is theatre on top of an invisible legal document.\n\nSo I built the theatre AND the legal document.\n\n**Virtual Parliament** is a multi-agent simulation of the Polish Sejm. You type something like *\"four-day work week\"* or *\"flat income tax\"*, and 25 Hermes agents run a full legislative session:\n\n`delegate_task`\n\nThe frontend surfaces the diff as a **Current law vs proposed change** panel. Left column: what's in force today, quoted from the statute. Right column: what the AI just proposed. A non-lawyer can finally see the actual edit.\n\nThis is the part of legislation that's normally invisible. **The whole point is to make it visible.**\n\n🎥 **Video walkthrough (~2 min):** [https://www.loom.com/share/92cdac7da31c471088a4e569b0cfe1ed](https://www.loom.com/share/92cdac7da31c471088a4e569b0cfe1ed)\n\n🌐 **Live URL:** [https://web-production-53027.up.railway.app/](https://web-production-53027.up.railway.app/)\n\nTwo buttons:\n\n`google/gemini-3.1-flash-lite`\n\ncalls.Try **\"four-day work week\"** (Demo) — it's the demo fixture I ship in the Docker image. Lewica and Konfederacja vote on opposite sides (pro-labour vs free-market), which is the political-coherence check I built into the acceptance tests.\n\n**Local one-command run:**\n\n```\ngit clone https://github.com/monsad/ai-politics && cd ai-politics && make setup && parliament \"four-day work week\"\n```\n\n📦 **Repo:** [https://github.com/monsad/ai-politics](https://github.com/monsad/ai-politics) (MIT)\n\n```\nskills/                         # 25 Hermes Agent skills, validated by skills-ref\n  marszalek-sejmu/              # the orchestrator — owns the bill-drafting template\n  ministry-finansow/            # 19 ministry experts (Finance, Health, Climate, ...)\n  ...\n  party-ko/                     # 5 party agents (KO, PiS, TD, Konfederacja, Lewica)\nparliament/\n  session.py                    # subprocess launcher around `hermes chat -s <skill>`\n  transcript_parser.py          # splits orchestrator stdout into per-speaker utterances\n  citation_validator.py         # every [node:...] must resolve back to a real statute\n  api.py                        # FastAPI: POST /sessions, polling SSE /stream/{id}\n  cli.py                        # `parliament \"<topic>\"` (typer)\nweb/                            # Next.js 16 static export, served by FastAPI\ndeploy/                         # Dockerfile entrypoint + Hermes config + demo fixture\n```\n\n| Layer | Tech | Notes |\n|---|---|---|\nAgent framework |\nhermes-agent 0.14.0 |\nthe load-bearing piece — `pip install hermes-agent==0.14.0`\n|\nSkills spec |\nAnthropic Agent Skills + `skills-ref@0.1.5`\n|\n25 skills, lowercase-hyphen, validated in CI |\nRAG |\nPageIndex Cloud via MCP |\nvectorless retrieval over Polish Constitution + ~50 statutes; every citation traces to a real document |\nModels |\n`google/gemini-3.1-flash-lite` via OpenRouter |\n~$0.04 per full session, fast enough for live demo |\nOrchestrator |\nPython 3.11 + FastAPI + uvicorn | subprocess launcher around `hermes chat`\n|\nStream |\nsse-starlette + polling SQLite | per-speaker utterances pushed as `event: utterance`\n|\nFrontend |\nNext.js 16 (App Router, static export) + Tailwind | served from `/app/*` by the same FastAPI |\nDeploy |\nRailway (single Docker container) | public HTTPS, ~$5/month |\n\nThere's one Hermes property the whole project is built on:\n\n`delegate_task`\n\nlets a parent skill fan out to N child skills in parallel as a single tool call.\n\nWithout that, this project isn't tractable. With it, the entire 25-agent pipeline is **24 LLM calls in a tight DAG**, runs in 2 minutes, and the orchestrator never has to manage thread pools or async gathers itself.\n\nHere's the shape:\n\n```\n                  ┌─────────────────────────────┐\n                  │  marszalek-sejmu (skill)    │\n                  │  Topic → ministry selection │\n                  └──────────────┬──────────────┘\n                                 │ delegate_task(tasks=[...])  ← Hermes batch mode\n                ┌────────────────┼────────────────┐\n                ▼                ▼                ▼\n       ┌────────────────┐ ┌────────────────┐ ┌────────────────┐\n       │ ministry-      │ │ ministry-      │ │ ministry-      │\n       │ finansow       │ │ klimatu        │ │ rodziny-pracy  │\n       └────────┬───────┘ └────────┬───────┘ └────────┬───────┘\n                │  PageIndex RAG   │   (cite real statutes)\n                └────────┬─────────┴─────────┬───────┘\n                         ▼                   ▼\n                  Synthesized findings → Marszałek\n                         │\n                         ▼   5 × party debate, ×2 readings\n                  ┌──────────────┐\n                  │ KO  PiS  TD  │\n                  │ Konf  Lewica │\n                  └──────┬───────┘\n                         ▼\n                  Seat-weighted vote → Draft bill\n```\n\n`delegate_task`\n\nwas the right primitive\n`ThreadPoolExecutor`\n\nto spawn `AIAgent`\n\nchildren. I don't have to mix asyncio with hermes-agent's threaded subagents — a known foot-gun if you roll your own.`pageindex-rag`\n\n). The Marszałek doesn't pollute their context.**Skills as the unit of expertise.** Every agent is one `SKILL.md`\n\n. The Marszałek has the bill-drafting template (`assets/bill-draft-template.md`\n\n). The parties have their actual policy positions. None of this fits in one big system prompt — but as 25 separate skills, it's maintainable. I can rewrite Lewica's economic stance without touching Konfederacja.\n\n**MCP toolsets for retrieval.** Every skill that cites Polish law declares `toolsets: [\"pageindex-rag\"]`\n\nand gets retrieval for free. Zero Python integration code. The PageIndex MCP server is one config-yaml entry.\n\n**Subprocess as the integration surface.** Hermes is a CLI first. The cleanest way to embed it in FastAPI is `subprocess.Popen([\"hermes\", \"chat\", \"-s\", skill, \"-q\", topic, \"-Q\", \"--accept-hooks\", \"--yolo\"])`\n\n. My `session.py`\n\nis essentially that subprocess launcher plus a stdout parser that splits the result into per-speaker utterances for SSE streaming.\n\n**Bake-time config for the container.** For Railway, the Dockerfile copies `hermes-config.yaml`\n\nto `/root/.hermes/config.yaml`\n\nand `skills/*`\n\nto `/root/.hermes/skills/`\n\n. An entrypoint script materializes `OPENROUTER_API_KEY`\n\ninto `~/.hermes/.env`\n\nat boot. Crucially: ** disabled_toolsets: [browser, computer-use, voice, terminal-modal]** — otherwise Hermes hangs at startup looking for a Chromium binary that isn't in\n\n`python:3.11-slim`\n\n. I only found that via a `/diag`\n\nendpoint I added to introspect the running container.If I had to write the parallel fan-out + tool registry + skill loader by hand, I'd still be debugging deadlocks instead of arguing with my own bill drafts.\n\nHermes let me spend my time on **the simulation design** (how does a Marszałek pick ministries? what does each party's house style sound like? how do you parse \"Article 129 §1 is amended to read…\" out of free-form markdown?) and **the legal-diff UX** (the Current law vs proposed change panel) — not on the orchestration framework.\n\nThat's the right division of labour for a 5-day contest project, and frankly for most agent projects.\n\n`gemini-flash-lite`\n\n↔ `llama-3.3-70b`\n\nchanges vocabulary, barely changes the structure of the debate.`Czas pracy nie może przekraczać 8 godzin na dobę i przeciętnie 40 godzin…`\n\n\"🇵🇱 Built in Żory. MIT-licensed. Educational simulation only — no real Members of Parliament are represented, no hate speech is produced, and a disclaimer is emitted at the top and bottom of every session.", "url": "https://wpnews.pro/news/i-built-a-25-agent-polish-parliament-that-drafts-bills-with-real-legal-citations", "canonical_source": "https://dev.to/msadlok/i-built-a-25-agent-polish-parliament-that-drafts-bills-with-real-legal-citations-45h7", "published_at": "2026-05-30 21:59:57+00:00", "updated_at": "2026-05-30 22:11:19.115167+00:00", "lang": "en", "topics": ["ai-agents", "ai-policy", "large-language-models", "natural-language-processing", "ai-tools"], "entities": ["Hermes", "Polish Sejm", "Virtual Parliament", "Railway", "Loom", "GitHub", "MIT"], "alternates": {"html": "https://wpnews.pro/news/i-built-a-25-agent-polish-parliament-that-drafts-bills-with-real-legal-citations", "markdown": "https://wpnews.pro/news/i-built-a-25-agent-polish-parliament-that-drafts-bills-with-real-legal-citations.md", "text": "https://wpnews.pro/news/i-built-a-25-agent-polish-parliament-that-drafts-bills-with-real-legal-citations.txt", "jsonld": "https://wpnews.pro/news/i-built-a-25-agent-polish-parliament-that-drafts-bills-with-real-legal-citations.jsonld"}}