Inspiration
In May 2016, floods and landslides hit the Kelani basin in Sri Lanka. In a disaster like that, the hardest problem isn't a shortage of boats. It's information. Reports arrive by Telegram, phone and web forms, in Sinhala, Tamil and English. They are duplicated, unverified and out of date, and someone has to decide which one gets the single boat.
We wanted a system that turns that flood of reports into one ranked, checked dispatch plan, while keeping a human in charge of every decision that sends a crew.
What it does
ResQ-Mesh is a situational-intelligence and dispatch engine for floods and landslides.
Reports in: citizens report through a web form, with GPS or a map pin, or through a Telegram bot, in Sinhala, Tamil or English. Personal details are redacted before the text is read. Fusion: reports are located against a gazetteer of 757 Grama Niladhari divisions and fused into incidents. One source alone never dispatches a crew, and it takes two independent sources to cross the confidence floor. Hazard model: flood extent is modelled from SRTM terrain and rainfall, and the model marks which roads are impassable. Triage and dispatch: a scoring step ranks incidents, and a constraint solver proposes which boats and trucks go where, along routes that avoid flooded roads. Guardrail and human gate: a guardrail checks every plan, including that destinations exist, that none sits in a no-go zone, and that capacity and confidence hold. A commander then approves, modifies or rejects it. Publishing a public alert is a separate decision. Crews and public: crews get a single-use link to their own dispatch page. The public reads approved bulletins in three languages, and they expire when stood down. Record: every approval records who gave it. There is an audit trail, situation-report PDFs, and an emergency halt.
How we built it
We built it in Jac, one language for the agents, the graph, the server endpoints and the console. The incident is a node in a persistent graph, and the agents are stations on it, so every transition is stored.
Agents: a supervisor and six agents for ingest, hazard, triage, optimiser, guardrail and communications. Each piece of shared state has exactly one writer. Language models: a chain of Gemini, then Groq, then DeepSeek, then a deterministic rules extractor, so extraction degrades instead of stopping. Optimiser: Google OR-Tools CP-SAT, with a greedy fallback if the solver fails. Geospatial: SRTM terrain, OpenStreetMap roads, rasterio and Shapely, with flood extent computed from terrain. Console: Jac client with Mantine, Leaflet and MapLibre, with a 2D and a 3D map. The console calls the server's endpoints as typed functions. Deployment: Docker on Coolify. The app is sealed at build time so it starts in well under 1 GB. Challenges we ran into Being honest about the model. Against WFP's flood extent for May 2016, the hazard model flags 166 of 177 flooded divisions (recall 0.938). Its precision is 0.455, so it over-warns. We chose to say so rather than tune it away. A scenario that can't be solved. At the 2016 peak, the model cuts 11,406 road segments and marks 87 divisions no-go, and no crew can reach any incident. We report that instead of hiding it. The default replay is two days earlier, with 96 mm of rain, about 4,950 cut segments and 35 no-go divisions. False dispatches. One uncorroborated report scored 0.40, below our 0.50 floor, so a single prank call can't send a boat. A report also had to be read in the light of its incident, or a message about a flood could start a second, unrelated incident. Routes that disappeared after restarts, and an app that needed over 2 GB of memory to compile on every start. We fixed these by keeping routing graphs where a restart finds them, and by sealing the app at image build. A young toolchain. Several Jac client and server behaviours took time to learn. Accomplishments that we're proud of A working system, deployed and live, with every role served from one address: citizen, crew, public and commander. A human gate that is real. Nothing moves without an approval, and every approval records who gave it. 537 automated tests, including adversarial cases for the guardrail. Honest evaluation, with limits stated alongside the headline numbers. A recurring cost of US$0, because every component is open source or on a permanent free tier, with no GPU.
What we learned
Safety rules belong in the structure, not in a prompt. A guardrail that checks a plan against a gazetteer and no-go zones is more trustworthy than asking a model to be careful. A graph is a good model for an incident. The audit trail and replay come for free. Degrading gracefully matters more than being clever. The rules fallback means extraction never fully stops. Reporting what the system can't do builds more trust than a clean headline number. What's next for ResQ Mesh Tamil place names. The gazetteer indexes English and Sinhala names, but Tamil place names don't yet resolve. Boats on water. Boats are currently routed over the road graph. Routing them along waterways would fix the biggest gap in the plan. Real validation. We have one real-event accuracy number for the hazard model and none for triage. We want real field-report logs from an actual event to measure it properly. More ways to reach people. Public delivery is partial today: bulletins and a Telegram channel. We want SMS and radio. Partners. Work with Sri Lankan disaster-response agencies on live trials and local data. Try it: https://resqmesh.silham.dev Code: https://github.com/silham/resqmesh
Built with: Jac, Google OR-Tools, Gemini, Groq, DeepSeek, SRTM, OpenStreetMap, rasterio, Shapely, Mantine, Leaflet, MapLibre, Telegram Bot API, Docker, Coolify
Built With
- jac
Log in or sign up for Devpost to join the conversation.