Skip to main content
Back to Showcase

6ixPulse: An Agentic Toronto Housing Intelligence Map

Author:Daryl WanjiModel:MiniCPM4-0.5B

Agents compare Toronto neighborhoods, citing a source for every claim

6ixPulse is an agentic Toronto housing intelligence map for renters who do not want to choose a neighborhood from vibes, stale listicles, or one-off anecdotes.

It is a Build Small Hackathon entry (Backyard AI track): a personal daily-life tool for choosing where to live.

Why It Was Built​

The author is looking to move, and moving means doing a lot of research before committing to a place. Rent is only one part of the decision: you also need to understand commute time, safety signals, neighborhood feel, access to daily needs, and whether an area is getting better or just getting more expensive.

6ixPulse turns that research process into a map-first agent workflow. You can ask something like:

Plain Text
I want to move to Toronto, make $110000, work at Union Station, need safe streets,
cafes, and rent under $2600.

The app then ranks Toronto neighborhoods, animates the map to the areas it is researching, and dispatches specialized agents for affordability, commute, safety, lifestyle, future growth, and final recommendation.

What It Does​

  • Plans first. Before any agent works, the model lays out a task for each City Agent and the source it will use.
  • Discovers neighbourhoods. The agentic model picks the Toronto areas that fit the prompt and supplies their coordinates — nothing about the candidate set is hardcoded; the map draws what the model found.
  • Scores all eight dimensions — Affordability, Safety, Commute, Transit, Amenities, Lifestyle, Growth, and an overall Match — for every candidate, each computed from a real, named, no-key source.
  • Fans out a researcher per City Agent. Affordability, Commute, Safety, Lifestyle and Growth agents each reason over only their own evidence; a Recommendation agent runs last with every agent's finding and all of their sources.
  • Fails closed. The UI withholds a rent, commute, safety, growth claim, or score unless the backend can tie it to source evidence — sources are named, never "S1".
  • Shows a real Mapbox GL JS 3D map with a research tour that zooms into each area while it is being researched, then flies out-and-in to the next.
  • Reads the findings aloud. A Play button narrates a short spoken summary using Kokoro-82M neural TTS running entirely in the browser — no key, no backend.
  • Models, all under 32B. NVIDIA Nemotron Nano Omni Reasoning is the main brain (with enable_thinking); a small OpenBMB model on llama.cpp assists with summarisation; Kokoro-82M handles speech. It falls back to HF when a provider is unavailable.

Architecture​

Plain Text
Frontend · React 19 + Vite
Renter prompt (budget · commute · safety · vibe)
Mapbox GL JS + deck.gl (3D map · research tour)
Agent cards · 8-dimension scores · research brief · compare · listings
|
v
Hugging Face Space · Docker
gradio.Server (FastAPI): serves the React UI + /run_agent MCP tool
Node agent backend: POST /api/agent/run
|
v
Agentic pipeline (every step is traced)
1 Plan: intent + a task per City Agent
2 Discover neighbourhoods: model picks Toronto areas + coordinates
(nothing hardcoded; coordinates feed the map)
3 Gather official evidence (Toronto Open Data, StatCan, Wikipedia)
4 Score 8 dimensions from named sources (Toronto Police, OSM, TTC/GO, CMHC)
5 City Agent fan-out: each researches its own dimension
6 Recommendation agent: weighs every agent + all their sources
7 Evidence policy: fail-closed, no source = no claim
|
v
Results back to the frontend panels (Play button -> Kokoro-82M narration)

Models (all under 32B)
Main: NVIDIA Nemotron Nano Omni Reasoning (temp 0.6 · enable_thinking · reasoning_budget),
used for discovery, fan-out and recommendation; fallback: HF Qwen3-Coder
Assistant: OpenBMB MiniCPM via llama.cpp, summarises each agent's evidence
Voice: Kokoro-82M neural TTS, in-browser

Tech Stack​

  • Frontend: React 19, TypeScript, Vite
  • Map: Mapbox GL JS, custom Mapbox style, deck.gl
  • UI: custom CSS, lucide-react icons, map-matched monochrome palette
  • Backend: Node HTTP server
  • Space wrapper: gradio.Server on FastAPI, Docker Space
  • Agent orchestration: plan → discover → research → score → fan-out → recommend, fully traced
  • Data: Toronto Open Data, Toronto Police, OpenStreetMap (Overpass), CMHC, StatCan, Wikipedia — all no-key
  • Models (all under 32B):
    • Main agentic brain: nvidia/nemotron-3-nano-omni-30b-a3b-reasoning (build.nvidia.com)
    • Summarisation assistant: OpenBMB MiniCPM via llama.cpp (openbmb/MiniCPM4-*-GGUF)
    • Speech: hexgrad/Kokoro-82M neural TTS in the browser (transformers.js)
    • Fallback: Qwen/Qwen3-Coder-30B-A3B-Instruct on the HF Router

Runtime Flow​

  1. The user writes a housing prompt in the Ask 6ixPulse composer; the frontend calls POST /api/agent/run.
  2. Plan — the model parses intent (budget, commute cap, priority weights) and lays out a task for each City Agent.
  3. Discover — the model names the Toronto neighbourhoods that fit and supplies their coordinates. No candidate list is hardcoded; the map renders what the model returns.
  4. Gather evidence — official Toronto data is pulled per area: Toronto Police crime rates, building permits, TTC GTFS, StatCan, and Wikipedia coordinates.
  5. Score — for every candidate, all eight dimensions are computed from named sources and combined into a weighted Match.
  6. Fan-out — each City Agent reasons over only its dimension's evidence; the Recommendation agent runs last with every finding and all sources, using the reasoning model's thinking mode.
  7. Evidence policy — any claim without a matched source or computed fact is hidden ("needs source").
  8. The map, agent cards, 8-dimension scores, research brief, and comparison all update from the same structured, source-cited result.

Source-Backed Display Policy​

6ixPulse intentionally fails closed.

Local neighborhood rows seed the workflow, but they are not treated as truth. The app does not present a rent range, commute score, safety claim, growth claim, or final agent score unless the backend can connect that category to source evidence or computed facts.

This matters because housing decisions are high-stakes. A pretty map with fake confidence is worse than a map that admits where research is incomplete.

Data Sources & Scoring​

Every dimension shown in the UI is computed from a real, no-key source and labelled with that source's name:

DimensionSource
SafetyToronto Police Service — Neighbourhood Crime Rates (Toronto Open Data)
CommuteDistance to Union Station over the TTC + GO (Metrolinx) network
TransitTTC stops & stations via OpenStreetMap
Amenities · Lifestyle · GrowthOpenStreetMap (Overpass) — cafés, restaurants, parks, groceries, construction sites
AffordabilityCMHC rental-market context + a distance-to-core / density model
MatchWeighted blend of the above, against the renter's stated priorities
CoordinatesWikipedia REST (for placing discovered areas on the map)

These are all official public APIs, so the hosted Space runs without any scraping or bypass tooling. Optional keyed web search (Google CSE, SerpAPI, Brave, Tavily) can be enabled for extra context, but it is off by default and never required.

Models​

Two tiers, both under 32B parameters:

Bash
# Main agentic brain: NVIDIA Nemotron Nano Omni Reasoning (build.nvidia.com).
# Used for discovery, the per-agent findings, and the final recommendation (with thinking).
AGENT_MODEL_PROVIDER=auto # tries Nemotron first, then HF
NVIDIA_API_KEY=your_nvapi_key
NVIDIA_MODEL=nvidia/nemotron-3-nano-omni-30b-a3b-reasoning
NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
NVIDIA_ENABLE_THINKING=1 # temperature 0.6, top_p 0.95, reasoning_budget

# Summarisation assistant: small OpenBMB model through the llama.cpp runtime.
LLAMACPP_ENABLED=1
LLAMACPP_MODEL=openbmb/MiniCPM4-0.5B # or MiniCPM4-8B-GGUF for stronger summaries
AGENT_SUMMARIZER_PROVIDER=llamacpp

# Fallback when no key/runtime is available, so the app always responds.
HF_TOKEN=your_hugging_face_token
HF_MODEL=Qwen/Qwen3-Coder-30B-A3B-Instruct
  • Summarisation assistant: OpenBMB's MiniCPM4-0.5B runs through llama.cpp and summarises each agent's evidence; MiniCPM4-8B-GGUF can be swapped in for stronger summaries.
  • Reasoning model: uses the Nemotron recipe (matching ChatNVIDIA): temperature=0.6, top_p=0.95, chat_template_kwargs={"enable_thinking": true}, and a reasoning_budget; its <think> reasoning is captured separately from the JSON answer. Thinking is enabled only for the decisions (discovery, recommendation, synthesis), and the per-agent fan-out runs in parallel on hosted APIs, so a full run stays within the response budget.
  • Speech: the Play button uses hexgrad/Kokoro-82M neural TTS via transformers.js, running fully in the browser (ONNX/WASM). It is lazy-loaded — the ~80 MB model only downloads on the first Play, then is cached — and falls back to the browser's built-in speech while it loads or where it can't run. No key, no backend, 82M parameters.

Gradio Space​

The project is deployed as a Docker-backed Gradio Space using gradio.Server, which is designed for custom frontends like React while still providing Gradio's API engine, queuing, MCP support, and Hugging Face Spaces hosting. The entrypoint is app.py, which:

  • starts the Node agent backend on 127.0.0.1:8787
  • serves the built React app from dist/
  • injects runtime Mapbox config from Space secrets
  • proxies the frontend calls to /api/agent/run
  • exposes a Gradio API endpoint and MCP tool named /run_agent

Required Space secrets:

Bash
VITE_MAPBOX_TOKEN=your_mapbox_token
NVIDIA_API_KEY=your_nvidia_api_key

Recommended Space variables (the Docker image already sets these):

Bash
AGENT_MODEL_PROVIDER=auto
NVIDIA_MODEL=nvidia/nemotron-3-nano-omni-30b-a3b-reasoning
NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
NVIDIA_ENABLE_THINKING=1
AGENT_DISCOVER=1
AGENT_FANOUT=1
SEARCH_PROVIDER=disabled # official-data-only; no scraping on the hosted Space
OFFICIAL_DATA_ENABLED=1

To run it Space-style locally, then open http://127.0.0.1:7860/:

Bash
npm install
npm run build
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python app.py

Running Locally​

Bash
npm install
cp .env.example .env
npm run dev:full

Open http://127.0.0.1:5173/. Set your Mapbox token before running:

Bash
VITE_MAPBOX_TOKEN=your_token_here
VITE_MAPBOX_STYLE_URL=mapbox://styles/ownpath/cmqe4wg8h005001s4bjx9461m

You can also run the services separately and check their health:

Bash
npm run dev:api
npm run dev

curl http://127.0.0.1:8787/api/agent/health
curl http://127.0.0.1:8787/api/agent/search/health

Project Structure​

Plain Text
app.py Gradio Server wrapper for the Space runtime
Dockerfile Docker Space image with Node + Python
src/App.tsx app shell, agent panels, scores, listings
src/components/MapCanvas.tsx Mapbox/deck.gl map + research tour
src/lib/agentApi.ts frontend API client types
src/lib/tts.ts Kokoro-82M in-browser narration
server/index.mjs agent API server; orchestrates the pipeline
server/discover.mjs model-driven neighbourhood discovery (+ coordinates)
server/score-tools.mjs 8-dimension scoring from named no-key sources
server/agent-fanout.mjs per-agent City Agents + Recommendation agent
server/model-chat.mjs provider routing: main brain vs. summariser
server/agent-core.mjs plan, trace, and the fail-closed evidence policy
server/research-tools.mjs Toronto Open Data + crime rates + coordinates
server/nvidia-client.mjs NVIDIA Nemotron (reasoning) client
server/llamacpp-client.mjs llama.cpp / OpenBMB client
server/hf-client.mjs Hugging Face Router fallback client
scripts/dev-full.mjs starts frontend and backend together
scripts/llama-server.sh launches a local OpenBMB GGUF via llama.cpp

Development Notes​

The project was developed with assistance from OpenAI Codex for implementation, debugging, verification, and repository preparation. Product direction, final decisions, and submission review remain human-owned.

Project info

Author
Daryl Wanji