Inspiration
Every Delhi resident has the same story: you file a complaint about a pothole, and three months later MCD tells you it's a PWD road. The complaint didn't fail because Delhi doesn't listen — it failed because Delhi has 11 governing bodies and nobody knows which one owns the pothole. Roads split by width (under 60 ft = MCD, over = PWD), drains belong to MCD but sewers to DJB, DDA colonies are half-handed-over to MCD, and Lutyens Delhi is a different government entirely. This jurisdiction maze is the single biggest reason civic complaints die, and no tool existed to solve it. So we built one.
What it does
Kiski Galti? ("Whose fault is it?") takes a civic grievance typed in Hindi, Hinglish, or English — "mere ghar ke saamne 3 mahine se gaddha hai, Lajpat Nagar" — and returns three things:
- A jurisdiction verdict — the agency actually responsible, with the specific rule cited (not vibes: "roads under 60 ft vest with MCD"). If you complained to the wrong agency, it tells you why your complaint died.
- A filed-ready complaint — drafted for the correct channel (MCD 311, PWD 1076, DJB 1916, PGMS), with the right category keywords so it doesn't get auto-routed to a dead queue.
- A pre-loaded escalation ladder — Day 0 file, Day 15 reminder + PGMS re-file, Day 30 the nuclear option: a ready-to-paste RTI application asking what action was taken on your complaint number. RTIs create personal accountability, and officers know it.
How we built it
- Elasticsearch (Elastic Cloud) is the knowledge backbone: a hand-curated index of Delhi jurisdiction rules, locality-to-agency mappings, complaint channels, and escalation chains. Retrieval is hybrid — BM25 + ELSER semantic search fused with RRF. This matters because Hinglish grievances ("nali choke ho gayi") share zero keywords with English rule text ("blocked storm drain") — the semantic leg carries those, while BM25 nails exact tokens like road and portal names.
- Gemini powers the agent: intent extraction from messy multilingual input, tool-calling against three Elastic-backed tools (
resolve_jurisdiction,get_channel,get_escalation_path), and drafting the formal complaint + RTI in the user's own language. - OpenAI as a transparent fallback: Gemini is called through its OpenAI-compatible endpoint, so both providers share one SDK and one tool-calling code path — if Gemini rate-limits mid-demo, the loop reruns on GPT with zero format translation.
- Streamlit for the chat UI, built in the final stretch.
The LLM never guesses law or process — it only narrates what Elastic retrieved. Keyword filters on doc_type and agency make each tool call a precise lookup, so verdicts are checkable, not hallucinated.
Challenges we ran into
- Encoding Delhi's jurisdiction rules was the real work. The road-width split, the drain-vs-sewer divide, the DDA handover limbo — this knowledge lives in scattered notifications and residents' scar tissue, not in any API. We hand-authored the entire knowledge base under time pressure, which turned out to be a feature: clean curated docs beat scraped noise for retrieval quality.
- Hinglish retrieval. Pure keyword search returned nothing for half our test grievances. Getting the hybrid RRF retriever right — and proving it outperformed BM25-only — took real tuning within the four-hour window.
- Agent discipline. Early versions asked too many clarifying questions or invented agencies when retrieval was thin. We had to prompt-engineer a strict contract: ask at most one question, ground every claim in retrieved docs, admit uncertainty otherwise.
Accomplishments that we're proud of
- A working end-to-end agent — multilingual input to grounded verdict to drafted RTI — built inside the event window.
- The DDA handover gotcha firing correctly on a live Dwarka park grievance: the system flags that internal roads/parks may still be DDA's even though sanitation is MCD's, and drafts a complaint naming both so it can't be bounced. That's the exact ping-pong failure mode we set out to kill.
- Deterministic verdicts: the jurisdiction logic lives in the index, not the model's memory — swap the LLM and the answers don't change.
What we learned
- Hybrid search isn't a checkbox — it's the difference between working and not working for code-mixed Indian language input. Watching "gaddha" retrieve a rule that only says "pothole" was the moment ELSER earned its place.
- A small, structured, hand-curated knowledge base beats a large scraped one for agentic RAG — the agent's answers are only as crisp as the docs behind them.
- The OpenAI-compatible endpoint pattern is the cheapest multi-provider resilience available: one code path, ordered fallback list, done.
What's next for Kiski Galti?
- Deterministic road ownership: index the published PWD road lists so "Press Enclave Road → PWD" is a lookup, not an inference.
- Community layer: write every grievance into a second Elastic index —
more_like_thissurfaces "3 similar complaints from your area this month," and aggregations power a live "Delhi grievance pulse" dashboard in Kibana. - Photo and voice input: point a camera at the pothole, or speak the complaint in Hinglish — Gemini's multimodality feeds the same pipeline.
- Ward-level precision: all 250 MCD wards with councillor and zone office details, so the verdict names the exact human accountable.
- SLA tracking: store complaint dates, auto-remind on Day 15, auto-draft the RTI on Day 30 — turning a one-shot answer into a companion that follows the complaint until it's fixed.
Built With
- claude
- elastic
- python
Log in or sign up for Devpost to join the conversation.