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:

Prompt: "Help me build a website about the negative effects of lack of sleep in hackathons"

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:

Prompt: "Help me choose the best location in the city to put a new transit stop. Also to fund this I will have to increase street parking fees somewhere in the city to save around 100k so help me find the neighborhood(s) where I can put this tax"

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.

Screen interface

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

Chatbox

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

Thinking: I need to set up two separate screening processes on the census data—one to identify underserved transit areas based on population density and transit gaps, and another to pinpoint high-income neighborhoods with strong car ownership patterns where parking fees would be viable. I'll write a Python script to run these analyses against the census profile data.

And then calls all the relevant agents and tools:

TechTO calling agents and tools

And then gets you to a final result:

Final result "Site the new stop in Milliken (116/130 corridor, code 130) — it has a large population (~24k), one of the lowest transit-commute shares in the city (14.7%), and the strongest simulated acceptance of the underserved candidates. Fund it with a street parking fee increase in The Beaches (code 063) — high income, high car-commute share, and the best-accepted of the parking-fee candidates."

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.

Agent executing code

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

Simulating acceptances

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
Share this project:

Updates