DEV Community

Nilesh H. Thipe
Nilesh H. Thipe

Posted on AI-assisted

A Metro Closure Is a Graph Problem: Building MetroMarg with FalkorDB

TL;DR: MetroMarg is an AI agent that uses a FalkorDB graph of the Delhi Metro to answer one question: How did the closure of 45 stations on 9–10 October 2026 affect travel to Jantar Mantar? Each answer includes the route and the queries behind it.

Note on speed: responses may take a minute or more. The model can be busy, and the free hosting plan may need time to wake after inactivity.

The problem

On 9–10 October 2026, DMRC closed entry and exit at 45 Delhi Metro stations for security reasons ahead of a planned protest at Jantar Mantar. Business Today reported DMRC’s revised update; News On AIR reported that Delhi Police had proposed closures at 57 stations.

“How do I get there now?” is more than a lookup. You need to know station connections, which stations are closed, where transfers remain possible, and which open station is nearest. The answer depends on relationships—and that is what graphs represent well.

My first time with RAG, and with FalkorDB

I was new to both RAG and FalkorDB. I initially thought an AI agent needed retrieval: embed text, find similar chunks, and pass them to a model. But routes are spread across connected records, so retrieving nearby text is not enough.

Instead, I stored the connections and let the agent query them. To be precise, MetroMarg is not classic RAG or GraphRAG: it uses no embeddings or text chunks, and an LLM does not build the graph. It does share GraphRAG’s core idea of grounding answers in a graph, using fixed, human-written Cypher tools selected by the model. FalkorDB made this approach approachable for a first project.

The graph model

(:Station {name, lat, lon})-[:NEXT {line, minutes}]->(:Station)
(:Place   {name, lat, lon})-[:NEAR {walk_min}]->(:Station)
(:Closure {id, date, reason, sources})-[:CLOSES {interchange_open}]->(:Station)
Enter fullscreen mode Exit fullscreen mode
  • DMRC’s timetable from Delhi Open Transit Data (262 stations and about 550 links) becomes Station nodes and NEXT links, with ride times from the timetable.
  • Jantar Mantar is a Place, connected to nearby stations with estimated walking times.
  • The closure is also a graph node, so routing, search, and the “why were stations closed?” panel use the same record.

The reports establish two rules: passengers could not enter or exit at closed stations, but trains continued passing through. Transfers remained possible at affected stations, except New Delhi.

The model never writes Cypher

The agent uses Gemini and chooses from five fixed, human-written tools, supplying their arguments.

Tool What it does
plan_trip_to_place Compares a ride-plus-walk trip normally and during the closure
access_to_place Finds nearby stations and marks closed ones
find_route Finds the fastest ride between two stations
station_impact Finds stations within N hops and marks closures
most_connected_stations Runs FalkorDB PageRank

Three safeguards help keep answers grounded:

  1. Every station name is checked against the graph before a query runs. Unknown names are rejected.
  2. The final sentence cannot name a station the tools did not return.
  3. Each answer displays the path and queries that produced it.

The live app uses Gemini function calling. The repository also exposes the same five tools through an MCP server.

Three queries that do the real work

1. A route with a transfer rule. Trains can pass through closed stations, but transfers are allowed only where interchange remains open. This WHERE clause enforces that rule:

MATCH path = (x:Station {name: $a})-[:NEXT*1..5]->(y:Station {name: $b})
WHERE all(i IN range(0, size(relationships(path)) - 2)
          WHERE NOT (nodes(path)[i + 1].name IN $no_transfer)
             OR relationships(path)[i].line = relationships(path)[i + 1].line)
RETURN [n IN nodes(path) | n.name] AS via,
       reduce(t = 0, r IN relationships(path) | t + r.minutes) AS minutes
ORDER BY minutes
LIMIT 1
Enter fullscreen mode Exit fullscreen mode

The query returns the ordered stations and total ride time, making the route itself part of the explanation.

2. The three nearest open stations, by distance:

MATCH (o:Station {name: $name}), (s:Station)
WHERE NOT (s.name IN $closed)
RETURN s.name AS station,
       distance(point({latitude: o.lat, longitude: o.lon}),
                point({latitude: s.lat, longitude: s.lon})) AS meters
ORDER BY meters
LIMIT 3
Enter fullscreen mode Exit fullscreen mode

3. A built-in algorithm in three lines:

CALL algo.pageRank('Station', 'NEXT')
YIELD node, score
RETURN node.name AS station, score ORDER BY score DESC LIMIT 10
Enter fullscreen mode Exit fullscreen mode

PageRank measures connectivity, not route quality. It highlighted major interchanges such as Kashmere Gate, Azadpur, and Welcome.

What the graph showed

Walking times are estimated from straight-line distance. Ride times come from the 2023 timetable.

  • The 12 stations nearest to Jantar Mantar—all within about 2.5 km—were among those closed to entry and exit.
  • The nearest open station was Chandni Chowk, about 3.5 km away. Janpath is normally about 240 m away.
  • From Chandni Chowk, the trip was about 17.7 minutes normally versus about 60 minutes during the closure, largely due to the long walk. Buses and taxis are not modelled, so this measures lost metro access rather than providing a travel recommendation.
  • Six of the 10 most connected stations by PageRank were closed.
  • Trips that only passed through closed stations were unaffected because trains continued running and interchange remained open.

What I liked about FalkorDB

These features stood out while I was learning:

  • Database plus browser UI: FalkorDB Browser helped me inspect the graph before trusting my queries.
  • No schema setup: the graph exists once you first write to it.
  • Parameterized Cypher and read-only ro_query: model text is never concatenated into a query.
  • Algorithms through Cypher: PageRank took three lines. Other listed options include shortest path, BFS, centrality, connected components, and community detection.
  • Bulk loading: I loaded the network in UNWIND batches and indexed station names.
  • Multiple isolated graphs: select_graph can separate graphs in one instance. I needed only one, but this could support per-user graphs.
  • Same code locally and in the cloud: I developed with Docker, then switched to FalkorDB Cloud by changing the host, port, and credentials.

Things that went wrong, and what I learned

  • Different station names: the press called one station Seva Teerth, while the 2023 timetable lists it as Udyog Bhawan. I added aliases so the name check can resolve both.
  • Incomplete station coverage: two of the 45 closed stations were absent because they opened after the timetable was published. The graph models 43 of 45 and states this limitation.
  • An empty database after restart: the app now rebuilds the graph from the timetable at startup.
  • “Not in the graph” is a valid answer: the agent says when it cannot verify something instead of guessing. That is more useful than always producing an answer.

Graph Hacks requirements, one by one

Requirement How MetroMarg meets it
Solo or team of up to 4 Solo entry
FalkorDB as the primary database Stations, links, places, and closure records live in FalkorDB; every tool queries it with Cypher
The graph does real work Routes, transfer rules, nearest-open-station searches, and PageRank all depend on graph queries
Run FalkorDB your way Docker locally and FalkorDB Cloud Free for the demo
Name your track Track 1: Agents That Act on Connected Data
Use permitted data Public data: Delhi Open Transit Data’s timetable (copied with attribution under its terms) and press reports; no personal data
Work starts after opening Designed and built after the hackathon opened on 15 October
Frameworks and libraries allowed FastAPI, FalkorDB Python client, Gemini API, and MCP Python SDK
Public source repository https://github.com/nilesh0199/MetroMarg-GraphHacks-2026
README and graph data model Included, with a diagram
Core Cypher and algorithms Listed in a README table
Demo video https://youtu.be/gkXa_tMcAOI
Live deployment or local setup Both: Render deployment and local setup steps in the README
AI use disclosed In the README, video description, and below

Limitations

  • The timetable is from 2023; walking times are estimates.
  • There is no live train data, and buses and taxis are not included.
  • The agent is advisory: it suggests where to get off but takes no action outside the graph.
  • Responses may be slow when the model is busy.

Credits and AI disclosure

  • Data: Delhi Open Transit Data (Department of Transport, GNCTD). This project is not endorsed by DMRC or the Department of Transport.
  • Closure details: Business Today and News On AIR.
  • Design approach: WeMakeDevs’ article How to Build an Agent That Reasons Over a Graph.
  • Video: Opening footage credited to Jist News; all rights belong to the original owner. Voiceover generated with ElevenLabs.
  • AI assistants: I used Google Antigravity and Claude (Anthropic). Claude drafted most of the code through our conversations. I chose the problem, domain, and closure event; defined the neutrality rules; ran and tested the answers; and checked the sources.

MetroMarg reports what DMRC and Delhi Police said and how the closure affected metro travel. It takes no position on the event itself.

Top comments (1)

Collapse
 
maulik176 profile image
Maulik Ranadive •

Building this solo, as your first time with both RAG and FalkorDB, and landing on "the answer depends on relationships" is a great arc. Using the real 45-station closure makes it feel instantly useful. Did the closed stations stay in the graph as nodes with a status, or did you drop their links for those two days?