Sankalp.irl_new: LokAyukt: The Open-Source Civic OS That Tries to Prove a Complaint Was Actually Fixed
A multimodal grievance platform pairs LangGraph agents, PostGIS routing, and AI verification to turn municipal complaints into a traceable, spatially aware workflow.
- LokAyukt is less a complaint app than a verification system for public work, because it tries to make closure auditable instead of merely fast.
- Its most distinctive move is a two-step trust gate that screens suspicious images before asking vision models to judge before-and-after evidence.
- PostGIS is not a side feature here, because ward geometry, routing, and heatmaps turn geography into operational data.
- The repo looks structurally serious, but it still reads as an early-stage prototype with little external adoption.
Why municipal software usually fails at the last mile
Most grievance systems are optimized for intake. They make it easy to file a ticket, assign a number, and move on. The weak point is closure, because the easiest thing in the world is to mark an issue resolved without proving that anything changed.
That is the problem LokAyukt targets. Its core idea is not “AI for civic support.” It is a trust machine for government work, built around the uncomfortable question that most portals avoid: how do you know the job was actually done?
| System | What it optimizes | What it misses |
|---|---|---|
| Traditional grievance portal | Ticket creation and status updates | Whether the issue was genuinely fixed |
| Basic AI chatbot frontend | Faster intake and conversational UX | Routing quality, spatial context, proof of resolution |
| LokAyukt | Verified closure and spatially aware escalation | It still depends on adoption and disciplined field execution |
LokAyukt’s real innovation: resolution has to survive verification
The interesting part is the trust loop. A citizen can submit text, voice, or image. But a resolution does not become real just because a ward officer says it is done. LokAyukt tries to verify the claim with evidence.
The repo’s verification flow uses a cheap first pass, then a more expensive judgment. First, it checks whether an image looks suspiciously flat or synthetic. Then it compares before and after evidence with vision reasoning. That ordering matters. It avoids spending model effort on images that already look wrong.
How the verification layer works
The repo’s AI layer, in `Unified-AI/ai_models.py`, combines two different checks. One is statistical: `detect_fake_image` looks at pixel variation and flags images that are too smooth to be believable. The other is semantic: Groq’s Llama 3 Vision compares before and after images to judge whether the reported repair holds up.
That pairing is the key. The statistical check is cheap and blunt. The vision model is slower and smarter. Together they create a practical filter for a municipal setting where bad actors could try to fake evidence of work.
def verify_issue(before_image, after_image):
if detect_fake_image(after_image):
return {
'status': 'flagged',
'reason': 'suspicious image texture'
}
result = vision_model.compare(
before=before_image,
after=after_image,
task='verify whether the issue was actually resolved'
)
return result
How the complaint becomes a routed municipal task
LokAyukt’s intake path is multimodal by design. Citizens can submit text, voice, or image. The FastAPI service in `Unified-AI/main.py` normalizes that input into structured issue data, then routes it into the workflow that follows.
The point is not just conversion. It is classification with enough confidence to support action. A complaint has to become a department-ready object, with issue type, confidence, and location attached, before anyone can do anything useful with it.
POST /classify/audio
POST /classify/image
# Core path
transcribe_audio() -> classify_text() -> issue_type, department, confidence
# Agent layer
citizen_agent
ward_agent
admin_agent
| Stage | What gets added | Why it matters |
|---|---|---|
| Text, voice, image intake | Raw complaint content | Lets citizens report in the format they already have |
| Normalization | Transcript, label, confidence | Turns messy reports into structured tasks |
| Agent routing | Role-specific action | Keeps citizens, ward officers, and admins in separate lanes |
| Verification | Before/after proof, fraud screening | Makes closure harder to fake |
Why geography is treated as data, not decoration
The spatial layer is one of the repo’s strongest choices. `Backend/services/geoService.js` and `wardService.js` use PostGIS to locate a complaint inside a ward polygon, so routing is based on geometry rather than manual lookup.
That changes the whole feel of the system. A map is no longer just a dashboard skin. It becomes part of the workflow, because geometry determines where the complaint goes, how it is visualized, and how patterns get aggregated across the city.
The database schema treats wards as polygons and complaints as points, which is exactly the kind of data model a civic system needs if it wants location-aware prioritization and accurate heatmaps.
| Map as UI | Map as system |
|---|---|
| Shows where something happened | Helps decide who owns the task |
| Useful for browsing | Useful for routing and escalation |
| Decorative layer | Operational layer |
The priority engine does more than sort by urgency
Priority in LokAyukt is not a simple severity label. In `Backend/services/priorityService.js`, the score combines hardcoded issue weights, complaint volume over the last 48 hours, and recurrence over a 7-day history. The result is a rough model of systemic failure, not just complaint intensity.
That matters because repeated leaks, contamination, or waste issues are not isolated events. They are signals. A good civic system should surface that pattern and push it up the queue before the situation turns into a citywide problem.
function calculatePriority(issue, count48h, recurrence7d) {
const urgency = ISSUE_WEIGHTS[issue] || 50;
const impact = Math.log10(count48h + 1) * 20;
const recurrence = recurrence7d * 5;
return Math.min(100, urgency + impact + recurrence);
}
| Signal | What it captures | Why it helps |
|---|---|---|
| Issue weight | Intrinsic severity | Keeps obviously dangerous problems near the top |
| 48-hour volume | Local clustering | Surfaces bursts of neighborhood-level failure |
| 7-day recurrence | Chronic repetition | Distinguishes one-off noise from structural breakdown |
From chatbot to agents: three roles, three different kinds of intelligence
LokAyukt does not treat every user as the same kind of actor. The system defines separate citizen, ward, and admin agents with different responsibilities. That is a better fit for government work than a single catch-all assistant.
The citizen agent is there to help file and clarify. The ward agent is there to manage action. The admin agent is closer to a strategic analyst, because it can synthesize city-wide patterns, spot clusters, and support planning rather than just answering questions.
That separation is subtle but important. It keeps the interface simple for residents while giving officials a more serious operational layer underneath.
What LokAyukt gets right, and what remains unresolved
The repo is structurally thoughtful. The split between Node, Python, and PostGIS is sensible. The use of agents, geometry, and verification shows real product intent, not just demo code.
But the public footprint is thin. There is no visible ecosystem around it, and the project still reads like an early-release prototype. That does not weaken the idea, but it does put the burden of proof back on future adoption.
| Strength | Open question |
|---|---|
| Strong architecture across intake, routing, and verification | Will field teams actually use the verification loop? |
| Clear spatial model | How much manual cleanup will real municipal data need? |
| Serious anti-fraud logic | Can the system avoid becoming too complex for daily operations? |
LokAyukt is trying to make municipal closure trustworthy, not just efficient. That is a meaningful shift, because it changes the unit of value from “ticket created” to “work proven.”