Inspiration

In the Eaton fire, the people most at risk were the ones who couldn't report: no signal, no car, no one answering the door. 911 asks "who are you and are you sure?" We wanted a layer beside 911 that asks the world instead of the witness, lets anyone call for anyone, and gets a neighbor moving before the engine arrives. And if drones can drop water on a fire head in minutes, the only thing standing between a report and a swarm should be one human click.

What it does

Dragonfly is a neighborhood wildfire response layer. Anyone reports a fire, for themselves or for a neighbor who may need help leaving. Thirteen real Claude agents take it from there: intake structures the story, a sentinel flags prompt injection as a signal, and a verifier checks the world (satellite hotspots, weather, other reports) without ever seeing the text or the person. Corroborated incidents get a full staged response from seven more agents: spread forecast, perimeter, station and apparatus, evacuation orders, helper matching, a public alert, and a drone plan. Nothing is sent and no drone flies until a dispatcher clicks "Approve." Then simulated phones light up, opted-in helpers walk to opted-in neighbors, people move out of the fire's path, and up to 500 drones cycle between base and the fire head. The dashboard shows people saved, people overrun, acres burned versus acres without drones, and the cost of every agent run.

How we built it

Python 3.12, FastAPI, pydantic v2, the Anthropic SDK and httpx. Nothing else at runtime. The world is a deterministic simulation: a fire circle that grows and drifts downwind, a satellite that only sees it after it reaches 100 m, scripted citizens with opt-in flags, and a drone fleet with real cycle times. The agents are real. Each run is a headless Claude Code session with built-in tools disabled and our read-only tools served over a 60-line hand-written MCP endpoint, scoped per run to that agent's allow-list, so XO Space records one session, one cost and one tool trace per run. Verdict labels are computed by code from the verifier's tool results; the model writes only the evidence prose. Every agent has a deterministic mock twin, so the eval and 19 tests run without a key. A plain HTML and SVG dashboard polls one JSON endpoint.

Challenges we ran into

Seven hard invariants had to live in types and single code paths, not prompts: the verifier signature is exactly (lat, lon, tick, hazard); incident status is a Literal with no "dismissed"; grep for the outbox append res degrade to "unverifiable" and a human lane instead of aguess. Making the invariance test hold with a non-deterministic model meant moving the label decision out of the model entirely. XO Space observes Claude Code sessions, not raw API calls, so we rebuilt the agent runnwith an MCP tool server at hour three. And the first invariancetest was wrong: shuffling reporter ids also moved their locations, so we pinned locations and shuffled identity alone.

Accomplishments that we're proud of

The eval passes with real agents on all four scenarios for undnce test shows identical verifier labels when every reporteridentity is shuffled. Twelve reports collapse to two incidents; the downtown prank never gets dismissed, it just waits for a human. A tool outage produces "unverifiable", never a crash. Approve at minute six with 500 ead of 840, zero people overrun. And in the observer's sessionlist, the verifier's session title is only a location and a tick, which is the blindness rule visible to anyone.

What we learned

Uncertainty is information: three labels and no "false" change Safety claims are cheap unless a test can fail; we measuredeverything we claimed. A model should write prose, not policy. And the fastest responder in a wildfire is the neighbor 60 metres away, if someone asks them.

What's next for Dragonfly

Live mode is code-complete against NASA FIRMS and Open-Meteo but untested without a key. Next: helpers who say no and re-matching, re-planning when a merged report raises the stakes, a real spread model and terrarift, and an MCP server so other dispatch tools can call thesame read-only world.

Share this project:

Updates

Submission history