Inspiration
New York City files roughly 200,000 tree removal permits each year. On paper, each permit can look small: one street tree outside a construction site, a few more cleared for a curb cut, another group removed for redevelopment. But those individual losses add up. They are part of why cities keep falling short of their 30% canopy goals.
What bothered us most was the accountability gap. A developer can promise to plant 12 replacement trees after removing 10, but there is no simple public way to check whether those trees were ever planted, whether they survived, or whether the same developer has failed to meet similar promises before.
The data exists in fragments. Parks has inspection records. DOB has permit records. Residents see the trees disappear. But nothing connects those pieces into a clear history at the developer level.
ROOT was built to close that gap. Instead of treating every permit like an isolated case, ROOT creates a living accountability record that follows a developer across every tree removal permit they file. The goal is simple: make tree replacement promises measurable, public, and harder to forget.
What it does
ROOT assigns a persistent guardian agent to every street tree affected by a removal permit.
When a permit is filed, the agent activates and runs a five-part pipeline in under 90 seconds.
First, it maps the full group of threatened trees within the removal radius and calculates their combined ecosystem value, including stormwater interception, carbon storage, cooling benefit, and air quality impact. It also identifies heat-vulnerable residents in the surrounding block.
Next, it checks the developer’s replacement history through the accountability ledger. ROOT looks at previous permits, promised replacement trees, verified surviving trees, and trees that were never accounted for.
Then, it searches a corpus of prior permit cases using MongoDB Atlas Vector Search, surfacing similar situations where public comments led to enforceable conditions.
After that, it selects the most relevant city policies based on the specific permit impact: canopy targets, heat resilience rules, replacement ratios, and environmental review thresholds.
Finally, Gemini 2.5 Flash turns the evidence into a legally grounded 500 to 750 word public comment draft with specific conditions the agency can actually impose.
We intentionally designed ROOT as human-in-the-loop rather than fully autonomous. In a civic and legal context, the agent should gather evidence, surface patterns, and help residents write stronger comments, but the decision to file should stay with the person affected. Public comments carry real names, real legal weight, and real community consequences, so ROOT never submits anything on its own. The resident reads the draft, edits it, and chooses whether to file.
After a comment is filed, ROOT opens a five-year monitoring case with checkpoints at day 90, month 12, month 36, and year 5. At each milestone, the guardian checks whether the replacement trees were planted, whether they survived, and whether the permit conditions were actually met. Everyone who filed a defense receives an email update.
How we built it
ROOT’s backend is a FastAPI service deployed on Render, with Motor as the async MongoDB driver.
The system is organized around four specialized agents: Coalition, Developer Ledger, Precedent, and Policy. Each agent owns a distinct responsibility, and together they run a coordinated pipeline. In production, the pipeline can be orchestrated by Google ADK’s LlmAgent with Vertex AI. For local development, we also built a deterministic Python pipeline that produces the same output without requiring cloud credentials.
MongoDB Atlas is the core of the system. We use geospatial queries with $geoWithin and $centerSphere to find threatened trees by radius, Atlas Vector Search with gemini-embedding-001 768-dimensional cosine embeddings for precedent retrieval, and MongoDB’s document model to store tree records, ecosystem valuations, environmental justice scores, permit outcomes, and developer histories.
In production, the agents call MongoDB through the official @mongodb-js/mongodb-mcp-server MCP protocol.
The frontend is built with Next.js 14 and the App Router. MapLibre GL and deck.gl power the WebGL map layer, while react-leaflet handles the guardian overlay. Agent progress streams live to the browser through Server-Sent Events using sse-starlette.
For long-term monitoring, APScheduler runs hourly checkpoint checks and sends email updates through Mailjet, with Brevo and Resend as fallbacks. Our data ingestion pipelines pull from NYC Open Data, EPA EJScreen, and USDA i-Tree methodology to seed real street tree records with ecosystem valuations.
Challenges we ran into
The hardest part was the developer identity layer.
Tree removal permits often list an applicant name, but the same developer may file under shell companies, subsidiaries, abbreviations, or slightly different names across different projects. We needed entity matching that could connect related filings without incorrectly merging unrelated developers. That balance was harder than expected because a false positive could unfairly damage a developer’s record.
Another challenge was output reliability. Early versions of the pipeline produced strong drafts most of the time, but under load they could occasionally end mid-sentence or miss a required section. We added a Release Polish Agent as a final quality gate. It evaluates the draft against a rubric and falls back to a deterministic professional filing template if anything is incomplete.
We also had to make the live progress stream reliable. The full pipeline can take long enough that a silent browser would feel broken, especially on Render where request timeouts matter. Coordinating ADK tool call events with the SSE channel took careful work so the user sees continuous progress instead of waiting on a blank screen.
Accomplishments that we're proud of
The Developer Accountability Ledger is the part we are most proud of.
As far as we could find, there is no public system that permanently attaches a developer’s verified tree replacement survival rate to their future permit activity. ROOT turns past compliance into present evidence. If a developer has promised replacement trees before and failed to maintain them, that history can now appear in every relevant future public comment.
We are also proud of the five-year guardian architecture. Most civic tools stop once a comment is submitted. ROOT is designed to keep checking long after the hearing ends. The checkpoint system, email cascade, and outcome verification agent make accountability persistent rather than temporary.
Finally, we are proud that the full evidence-to-draft pipeline runs in under 90 seconds. A resident can click an amber permit marker on the map and receive an evidence-backed public comment before they have even finished reading the permit details. That speed matters because public participation often depends on timing.
What we learned
We learned that MongoDB’s geospatial and vector search capabilities are especially powerful when they live in the same database.
ROOT can run a radius query to find threatened trees, then immediately use vector search to retrieve similar precedent cases without syncing data across a separate vector store. That simplified the architecture and removed a lot of potential failure points.
We also learned that the dual-mode pipeline was one of our best technical decisions. The production path lets Gemini and ADK dynamically coordinate tools, while the deterministic local path gives every developer a stable baseline for testing and debugging. That made the system easier to build, easier to test, and easier to trust.
Most importantly, we learned that human-in-the-loop design needs to be enforced in the architecture itself. ROOT cannot file a public comment without the resident reading it and choosing to send it. We built the submission flow around real civic infrastructure links, including pre-filled mailto links for NYC Parks, DOB links, and 311 links. In a civic and legal context, that guardrail is not just a design choice. It is necessary.
What's next for ROOT
We want to expand beyond New York. The architecture is city-agnostic, and we already have an ingestion path for Portland tree inventory data. The main challenge is mapping each city’s permit schema and parks inspection records into the ROOT data model. Los Angeles, Chicago, and Seattle are strong candidates because they have comparable open data infrastructure.
The developer identity system also needs to become more sophisticated. The current version relies heavily on name similarity. A stronger version would cross-reference business registration records, filing histories, addresses, and corporate relationships to build a more complete developer graph.
Long term, the ledger becomes more valuable as it ages. A developer with five years of verified replacement history has a very different risk profile than a new applicant. Our goal is for ROOT’s ledger to become something city agencies themselves can consult when evaluating tree replacement commitments, not just a tool for residents.
Built With
- apscheduler
- brevo-api
- deck.gl
- docker
- epa-ejscreen
- eslint
- fastapi
- gemini-2.5-flash
- gemini-embedding-001
- gmail-smtp
- google-adk
- google-cloud
- groq
- hatchling
- javascript
- leaflet.js
- llama-3.3-70b
- mailjet
- maplibre-gl
- mongodb-atlas
- mongodb-atlas-vector-search
- mongodb-mcp-server
- motor
- next.js-14
- nyc-open-data
- postcss
- pytest
- pytest-asyncio
- python-3.11
- react-18
- react-leaflet
- react-map-gl
- render
- resend-api
- ruff
- secret-manager
- server-sent-events
- socrata-api
- sse-starlette
- tailwind-css
- typescript
- usda-i-tree
- uvicorn
- vercel
- vertex-ai
Log in or sign up for Devpost to join the conversation.