Inspiration
India processes over 200 million civic complaints annually — broken water mains, power outages, road hazards, illegal dump sites. Most go unresolved for weeks, not because governments lack the will, but because the system is broken at the intake layer: complaints arrive in 22+ languages, through fragmented channels, with no routing logic, no accountability, and no way to measure impact.
The moment that crystallised this for us was watching a neighbour spend three days trying to report a burst water pipe — calling wrong departments, being redirected, filling paper forms — while an estimated 21,600 litres of clean drinking water drained into the street. The problem wasn't the pipe. It was the process.
We asked: what if a citizen could describe a problem in their own language, and an AI system would instantly know exactly which department owns it, how urgent it is, and what happens if it isn't fixed in time?
What it does
CivicSense AI is an end-to-end multilingual civic grievance platform with four layers:
1. Citizen Interface Any citizen submits a complaint in any Indian language — typed, with a photo, and a map pin. No forms, no department knowledge required.
2. AI Triage Engine A multi-agent system (Google ADK + Gemini 2.5 Flash) processes each complaint:
- Detects language and translates semantics internally
- Classifies into one of 8 civic categories
- Geocodes the location via OpenStreetMap Nominatim
- Scores priority on a 1–10 scale using:
$$P = P_{base} + 1.5 \cdot \mathbb{1}{children} + 1.2 \cdot \mathbb{1}{elderly} + 2.0 \cdot \mathbb{1}{hazard} + 1.5 \cdot \mathbb{1}{corruption} + \min\left(\frac{n_{affected}}{200}, 1.5\right)$$
- Assigns SLA deadlines (4h for public safety → 120h for social welfare)
- Auto-escalates CRITICAL tickets that breach SLA
3. Officer Dashboard A real-time Kanban board with AI-generated action plans, a live issue heatmap, and per-ticket evidence logging.
4. Eco-Impact Dashboard Quantifies the environmental benefit of rapid response:
$$W_{saved} = R_{leak} \times T_{response} \quad \text{where } R_{leak} \approx 900 \text{ L/hr (avg municipal pipe)}$$
How we built it
Agent layer — Built with Google ADK as a single-file multi-agent system. Four specialist sub-agents (intake, tracker, resolver, analytics) are orchestrated by a root agent. Calendar events, officer tasks, and resolution notes are handled by a custom MCP (Model Context Protocol) stdio server, giving the agents structured tool access without subprocess overhead.
Database — Neon PostgreSQL (serverless) stores tickets, events, tasks, calendar entries, and notes. All writes go through Pydantic validation before hitting the DB.
Frontend — Next.js 16 with TypeScript and Tailwind CSS. Server Actions connect directly to the DB and the ADK agent API. Leaflet renders the interactive map and issue heatmap. The Eco-Impact dashboard runs entirely server-side with no external API calls.
Deployment — Both the web app and the ADK agent run on Google Cloud Run (europe-west1), deployed via gcloud run deploy --source.
Challenges we ran into
Mixed-case status values — The ADK agent writes statuses as OPEN/RESOLVED (uppercase) while the web app writes open/resolved (lowercase). The eco-impact calculator was doing strict string matching and silently treating all agent-created resolved tickets as active, producing 0.0 savings. Fixed with .toLowerCase() normalisation.
Timestamp type inconsistency — PostgreSQL's created_at column (typed TEXT) was returning raw ISO strings from the agent but Date objects from the pg Node.js driver depending on the query path. Subtracting a string from a Date produces NaN silently in JavaScript. Fixed with a parseDate() helper that handles both.
Seed data with zero response time — The resolved electricity ticket had created_at and updated_at set to the same moment (seeded simultaneously), giving hoursElapsed = 0 and therefore 0.0 kWh saved. Fixed by falling back to sla_hours as a proxy when the measured response time is under 1 hour, and correcting the seed record directly.
MCP on Cloud Run — The MCP server runs as a stdio subprocess spawned by the agent. On Cloud Run, the Python executable path and working directory differ from local. Solved by using sys.executable (the exact active venv Python) and Path(__file__).parent for absolute path resolution.
Multilingual geocoding — Location strings in Hindi or Tamil passed directly to Nominatim returned no results. Solved by appending , India to every query and using the countrycodes=in filter, which dramatically improved match rates for transliterated place names.
Accomplishments that we're proud of
- A fully deployed, end-to-end working system — not a prototype, not a mockup. Real DB, real AI, real Cloud Run URLs.
- The Eco-Impact dashboard — we believe this is the first civic grievance platform to quantify environmental savings from response speed. The formula is grounded in published Indian municipal engineering data.
- 22+ language support with zero translation APIs — Gemini 2.5 Flash handles semantic understanding natively, which means no latency penalty and no per-character cost for multilingual input.
- MCP integration in a production agent — using the Model Context Protocol for calendar, task, and note tools rather than hardcoding them as function tools, making the tool layer swappable and inspectable.
- Clean separation between the citizen experience (simple, language-agnostic) and the officer experience (data-dense, AI-assisted) in a single codebase.
What we learned
- Multi-agent systems need strict contracts. When agents hand off data between each other, even a single field name mismatch (
location_latvslatitude) causes silent failures. Pydantic validation at the DB boundary caught dozens of these. - "It works locally" is not enough. Cloud Run's ephemeral filesystem, different Python paths, and cold-start behaviour each broke something that worked perfectly in dev. Systematic environment parity matters.
- Environmental impact is measurable. We assumed the eco-impact numbers would be too rough to be useful. Researching actual Indian municipal leak rates, streetlight wattages, and dump-site emission factors showed the estimates are defensible and meaningful — and they make the platform's value tangible in a way that "tickets resolved" never could.
- Status normalisation is infrastructure. Mixed-case strings across two systems writing to the same DB is a class of bug that appears trivial and costs hours. Normalise at the boundary, always.
What's next for CivicSense AI
Push notifications — SMS/WhatsApp alerts to citizens when their ticket status changes, using Twilio or MSG91.
Predictive SLA breach detection — Train a lightweight model on historical ticket data to predict which tickets are likely to breach SLA before they do, enabling proactive officer assignment.
Expanded eco-metrics — Add air quality index improvement estimates for environment category tickets, and water quality risk scores for sewage-adjacent complaints.
Panchayat / ward-level routing — Integrate India's local government hierarchy so tickets route not just to state departments but to the specific ward officer responsible for that GPS coordinate.
Citizen reputation system — Score complaint quality over time to deprioritise repeat false reports while surfacing high-credibility citizens whose complaints get fast-tracked.
Open API — Expose a public REST API so NGOs, journalists, and civic tech organisations can query anonymised grievance data for research and accountability reporting.
Built With
- adk
- css
- gemini
- leaflet.js
- next.js
- node.js
- nominatim
- openstreetmap
- postgresql
- python
- react
- tailwind
- typescript
Log in or sign up for Devpost to join the conversation.