Cityloom

Inspiration

Cities are never designed by a single mind. Zoning wants density. Transit wants corridors. Sustainability wants parks and green floors. Economics wants buildable square footage and return. Those goals collide on the same parcel — and most tools either force one "optimal" answer or bury the trade-off in a PDF.

I wanted something different: an agent society that negotiates over real land, not a toy grid. When specialists disagree, you should see it on the map — not get a polite average. Cityloom is that commission: multi-agent urban planning with geometric conflicts, grounded tool use, and a plan you can audit.

What it does

Cityloom is a multi-agent urban planning simulator for the Qwen Cloud agent-society track.

  • Pick a real place — quick-picks in high-OSM-density cores (Berlin, London, Amsterdam, Paris, NYC) or search/draw a ~400 m study area.
  • Ingest OpenStreetMap — buildings, streets, parks, transit, POIs via Overpass (cached, rate-limited).
  • Read a site brief — green cover, density, streets, features with sources before any agent runs.
  • Start a commission — a Coordinator (Qwen) decomposes your brief; four specialists (Zoning, Transportation, Sustainability, Economic) propose on a shared parcel set.
  • Watch conflicts — typed geometric conflicts render as volumetric color-blend overlays; resolution uses rules, votes, mediation, or human council.
  • Get outcomes — before/after scores, impact pillars, MCP grounding %, decision report, certificate, PDF/CSV/GeoJSON, and a plan story page.

Live demo: cityloom.duckdns.org Health check: cityloom.duckdns.org/api/health

How I built it

Cityloom is a full-stack multi-agent system: a Next.js app that owns both the map UI and the negotiation backend, wired to Qwen Cloud, real OpenStreetMap data, and MCP tool servers.

Frontend

The map is deck.gl 9 on MapLibre. Users pick a dense neighborhood or draw a study area; Overpass layers are fetched in batches, cached in IndexedDB, and turned into parcels. Zustand keeps area/drawing state separate from negotiation UI state so the commission can stream without fighting the map. Post-commit lenses (plan, agents, hotspots, difference map, solo-vs-society) rebuild deck.gl layers carefully so production browsers don't lose WebGL contexts.

Agent society

A Coordinator (qwen-plus) decomposes the brief. Four domain agents (qwen-turbo) load role skills from lib/skills/*/SKILL.md and propose in parallel on a shared parcel set. Structured JSON, truncation repair, and optional tool-calling loops keep proposals usable. A rules engine detects geometric conflicts (same parcel, height, green space, budget, connectivity). Resolution uses vote, weighted mediation, formula, or human council. SSE pushes every event to the live map and transcript.

Tools and grounding

MCP zoning and parcel JSON-RPC servers run beside the app in Docker. Agents cite tool results; validate_grounding matches citations to a per-round ledger (with coercion for messy LLM types) so the UI can show evidence % and soft warnings instead of silent fiction.

Geo and scoring

turf.js handles clip, area, adjacency (grid-accelerated), and derived metrics (green ratio, connectivity, diversity, density). scorePlan and impact pillars compare original vs. committed parcels. Exports cover plan PDF, CSV, GeoJSON, and a browser plan-story page.

Infra and deploy

Redis write-through stores session metadata (with in-memory fallback). Production runs on Alibaba Cloud Simple Application Server: Docker Compose for the app, Redis, and both MCP services, behind Nginx, public at cityloom.duckdns.org. LLM traffic is server-side only to DashScope's OpenAI-compatible API — keys never reach the browser.

Challenges I ran into

  • Public Overpass — rate limits, timeouts, and bad geometries. Fixed with batched queries, multi-mirror failover, IndexedDB cache, and deck.gl geometry sanitization.
  • Shared jurisdiction — agents must hit the same parcel IDs as the map. I unified ingestion so server and client IDs match.
  • Grounding — LLMs cite tool results with messy types (e.g., numeric returned_value). Validation had to coerce safely without crashing domain agents.
  • Production map lenses — Diff/Compare mounted extra DeckGL instances and exhausted WebGL contexts on hosted browsers; local machines hid the bug. Fix: unmount the main deck on overlay lenses.
  • Plan story "not found" — client archives raced with SSE "complete" before scores landed; I re-archive when scores settle and slim storage payloads.
  • Docker typecheck — production next build is stricter than local dev; citation types had to stay consistent across SSE and UI.

Accomplishments that I am proud of

  • A full agent society over real OSM parcels, not synthetic blocks.
  • Geometric conflict protocol (rules → vote → formula → council) with volumetric map viz.
  • MCP + skills + grounding so claims can be checked against a real tool ledger.
  • Impact pillars that move with parcel before/after, not flat twin scores.
  • Judge-ready path: quick-picks, certificate, PDF, plan story, Alibaba deploy proof.
  • Live hosted demo on Alibaba SAS at cityloom.duckdns.org with Redis healthy.
  • Clear architecture diagrams and MIT open-source packaging.

What I learned

  • Multi-agent demos win when disagreement is first-class — map + protocol, not four chat windows.
  • Production is a different browser: WebGL limits, storage quota, and SSE ordering bite harder than localhost.
  • Grounding and types must assume messy LLM JSON (numbers, partial objects).
  • Real geo data is powerful and fragile — cache, batch, sanitize, keep study areas small for demos.
  • Splitting models by role (fast specialists, stronger coordinator) balances cost and quality on Qwen Cloud.
  • Document the deploy path early; "proof of Alibaba" is code + one solid public health URL + a short video clip.

What's next for Cityloom

  • More domain agents (heritage, flood risk, housing equity) via new SKILL.md + roster only.
  • Server-side plan archives so story pages work across devices, not only browser storage.
  • HTTPS + custom domain and lighter "review mode" for civic stakeholders.
  • Richer MCP (real municipal zoning APIs where available).
  • Offline/demo packs for regions with poor OSM or Overpass outages.

Cityloom — negotiate the city, don't flatten it.

Built With

Share this project:

Updates