Inspiration
We wanted to help city planners get quicker insights, with quick iteration. We are all coders, so we use Claude Code ex-ten-sively --- and it works great for us! We are about 3x more productive with it. But it seems like in many other contexts, AI is sluggish to break in. That's where TechTO comes in.
How this works
When you use Claude Code, you start with a prompt like:

And then it will start calling tools, subagents, executing workflows, asking questions... To get to a result that looks "somewhat decent" (though not perfect - of course we still need a human in the loop).
When you use TechTO, you start with a prompt like:

And then it will start calling tools, subagents... same as Claude Code.
Now, the difference is --- this is for city planning. So you can use it to experiment, what happens to Toronto (or any other city if we added their data) when I implement a change?
More in detail...
Our city has a lot of data layers about Toronto (from open.toronto.ca), including public transit, energy, water, schools, fire, police, emergency services (just like in Cities Skylines). This way, we have a digital twin of Toronto.

Then, on this digital twin, we can do anything we want via the chat interface:

So for example for the example we had above, TechTO starts a planning orchestrator that thinks about the request (just like Claude Code):

And then calls all the relevant agents and tools:

And then gets you to a final result:

Notice how cool this is: the agent can do anything. It can choose to explore all the data about the city, for which it has a tool to execute Python code and query the data layers / run stats analysis / anything that's needed.

And then --- this is SUPER COOL --- it ACTUALLY EMULATES how people would react to the changes!!!!

We generated personas of a subsample of all the citizens in Toronto --- we used the Census data and city data for that --- and we trained our custom small Qwen to be able to answer questions as if it is those people. For that, we SFT and then RL tuned the model on FreeSolo, first we used Polis data where people opine about different topics so that the model can learn to write opinions like a real human, and then we developed probes on the opinion texts to be able to predict, for instance, how happy someone would be to see a certain change implemented in the city.
How we built it
| Layer | Technology |
|---|---|
| Frontend | Next.js 14 App Router + React 18 |
| Language | TypeScript in strict mode |
| Mapping | MapLibre GL JS with OpenFreeMap |
| State and Data | Zustand + TanStack Query |
| Interface | Tailwind CSS + Framer Motion + Recharts |
| AI Orchestration | Backboard.io |
| Planning Architecture | 11 persistent Backboard assistants |
| Citizen Model | FreeSolo CitizenReactionLM |
| Database | MongoDB Atlas |
| MongoDB Features | Atlas Search, Vector Search, geospatial queries, Change Streams, time-series collections, transactions, TTL indexes, and model caching |
| Transit Data | TTC GTFS-derived routes, stops, and geometry |
| City Data | Toronto neighbourhood boundaries and Census indicators |
| Digital Twin | Toronto query, patch, snapshot, diff, scenario, and comparison layers |
| Analysis | Deterministic TypeScript simulation and read-only scientific Python |
| Backend | Next.js API routes + FastAPI transit-core service |
| Validation | Zod + Pydantic |
| Reports | Browser-generated print-ready PDF exports |
| Testing | Vitest, Testing Library, Playwright, and pytest |
The Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ User Layer │
│ │
│ Browser Client │
│ - Ask open-ended Toronto planning questions │
│ - Explore the live 2D city map │
│ - Select neighbourhoods, routes, places, and scenarios │
│ - Compare candidate interventions │
│ - Continue follow-up conversations │
│ - Export evidence-backed decision reports │
│ │
│ Flagship Demo │
│ - Ask where shared EV-charging hubs should be placed │
│ - Compare candidate areas │
│ - View apartment density and charging-access gaps │
│ - Inspect resident, equity, feasibility, and carbon impacts │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Next.js App Layer │
│ │
│ City Copilot Chat │
│ - Accept the user's planning question │
│ - Include the current conversation and map context │
│ - Stream agent and tool progress │
│ - Display evidence, candidates, KPIs, and recommendations │
│ │
│ MapLibre City Interface │
│ - Render Toronto neighbourhoods, routes, stops, and city layers │
│ - Show charging locations and apartment-density conditions │
│ - Display candidate markers, service areas, and annotations │
│ - Fly to or highlight recommended locations │
│ │
│ Next.js API Routes │
│ - Start and continue Backboard planning runs │
│ - Validate structured agent outputs │
│ - Execute safe allowlisted map actions │
│ - Persist runs, messages, evidence, and final decisions │
│ - Generate print-ready PDF reports │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Backboard Planning Council │
│ │
│ 11 Persistent Backboard Assistants │
│ - City Copilot │
│ - Planning Orchestrator │
│ - Geospatial Twin │
│ - Scenario Designer │
│ - Citizen Response │
│ - Equity Impact │
│ - Feasibility │
│ - Adversarial Reviewer │
│ - Evidence Auditor │
│ - Final Policy Judge │
│ - Explanation and Map Action Agent │
│ │
│ Backboard Orchestration │
│ - Persistent assistants and conversation threads │
│ - Assistant-specific RAG knowledge bundles │
│ - Read-only and disabled-memory controls │
│ - Capability-aware model routing │
│ - Parallel specialist-agent calls │
│ - Parallel and chained tool execution │
│ - Structured JSON outputs and validation retries │
│ - Streaming, cancellation, and run observability │
│ │
│ Planning Workflow │
│ - Understand the user's goal │
│ - Select the relevant agents, tools, and documents │
│ - Generate multiple intervention options │
│ - Challenge unsupported or unsafe recommendations │
│ - Produce the final evidence-backed decision │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ MongoDB Atlas City and Memory Layer │
│ │
│ Toronto Data Collections │
│ - Neighbourhood boundaries and Census indicators │
│ - Housing, apartment, renter, and demographic conditions │
│ - TTC routes, stops, and transportation context │
│ - EV chargers, places, parking opportunities, and city assets │
│ - Citizen cohorts, personas, events, and incidents │
│ - Scenarios, simulations, policies, evaluations, and audits │
│ │
│ Atlas Search │
│ - Resolve neighbourhoods, routes, places, and planning documents │
│ - Support natural-language and fuzzy location search │
│ │
│ Atlas Vector Search │
│ - Find neighbourhoods with similar demographic conditions │
│ - Discover areas with similar infrastructure and access gaps │
│ │
│ MongoDB Geospatial Queries │
│ - Use GeoJSON and 2dsphere indexes │
│ - Calculate hub, station, route, and service catchments │
│ - Find nearby chargers, buildings, stops, and opportunities │
│ │
│ Operational Planning Store │
│ - Persist Backboard threads, events, tool calls, and outputs │
│ - Store candidate interventions and final recommendations │
│ - Track Change Streams and time-series planning metrics │
│ - Use transactions, TTL indexes, provenance, and audit records │
│ - Cache repeated FreeSolo persona and policy evaluations │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ FreeSolo and Digital Twin Analysis Layer │
│ │
│ FreeSolo CitizenReactionLM │
│ - Evaluate simulated resident acceptance │
│ - Estimate potential behaviour or adoption responses │
│ - Use weighted cohorts instead of one call per resident │
│ - Sample representative demographic archetypes │
│ - Add samples only when initial responses disagree │
│ - Label every response as simulated │
│ │
│ Toronto Digital Twin │
│ - Query the current city state │
│ - Patch proposed infrastructure and service changes │
│ - Create snapshots and compare scenario differences │
│ - Test EV hubs, transit, energy, public space, and land use │
│ │
│ Deterministic Analysis │
│ - Calculate accessibility, equity, feasibility, and cost │
│ - Estimate utilization, adoption potential, and carbon impact │
│ - Run KPI scoring, stress tests, and bounded scenario search │
│ - Use scientific Python for quantitative analysis │
│ - Keep numerical and physical claims outside the language model │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Decision and Map Output Layer │
│ │
│ Evidence and Safety Review │
│ - Check every major claim against data, tools, or documents │
│ - Reject options that fail accessibility or safety gates │
│ - Detect severe subgroup or neighbourhood harm │
│ - Expose assumptions, uncertainty, provenance, and limitations │
│ │
│ Final Policy Decision │
│ - Compare the surviving interventions │
│ - Rank candidates using shared KPIs │
│ - Select the strongest evidence-backed option │
│ - Explain why other candidates were rejected │
│ │
│ Interactive Map Result │
│ - Fly to the recommended location │
│ - Show candidate markers, routes, catchments, and polygons │
│ - Highlight affected neighbourhoods and populations │
│ - Add annotations and open comparison panels │
│ │
│ Planning Record │
│ - Save the complete run in MongoDB │
│ - Preserve the Backboard conversation thread │
│ - Export the recommendation as a PDF decision report │
└─────────────────────────────────────────────────────────────────────────┘
Assumptions for business value breakdowns: https://onedrive.live.com/:x:/g/personal/3b95d44a0f5fc912/IQC0UnlpmTMaQLWrLjJgEhg9Ab9VtsUI7QvqpWIqO3T_EW8?rtime=0eoInJjl3kg&redeem=aHR0cHM6Ly8xZHJ2Lm1zL3gvYy8zYjk1ZDQ0YTBmNWZjOTEyL0lRQzBVbmxwbVRNYVFMV3JMakpnRWhnOUFiOVZ0c1VJN1F2cXBXSXFPM1RfRVc4
Built With
- atlas-search
- atlas-vector-search
- backboard.io
- fastapi
- framer-motion
- freesolo
- maplibre-gl-js
- mongodb
- mongodb-atlas
- next.js
- openfreemap
- playwright
- pydantic
- pytest
- python
- react
- recharts
- tailwind-css
- tanstack-query
- typescript
- vitest
- zod
- zustand



Log in or sign up for Devpost to join the conversation.