# floodops-multi-agent-system
**Repository Path**: izxj/floodops-multi-agent-system
## Basic Information
- **Project Name**: floodops-multi-agent-system
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-10-18
- **Last Updated**: 2026-10-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# floodops — Flood Multi-Agent Orchestration System
> Production-grade multi-agent flood monitoring, prediction, and response
> platform — **8 agents** across **7 cascading phases**, **10 external data
> connectors**, **LLM-powered reasoning**, and a **real-time Google Maps
> frontend** for live flood-zone overlays, evacuation routes, sensor
> markers, and risk heatmaps.
`floodops` is a Python + LangGraph backend paired with a Vite + Google Maps
frontend. It ingests data from NOAA, USGS, ESA Copernicus, ECMWF,
HydroSHEDS, GLIMS, OSM, WorldPop, ESA CCI Soil Moisture, the Dartmouth Flood
Observatory, GDACS, ReliefWeb, and **Google's operational Flood Forecasting
API** (the Nature-2024 LSTM model behind [Flood Hub](https://g.co/floodhub));
runs a 7-phase state machine across 8 specialised agents; and surfaces the
result on a live map with an LLM chat panel for situational reasoning.
> ✅ **Built and tested.** The backend boots and demos **with no API key**
> (deterministic mock fallbacks), with **77 offline tests green**. Keys are
> additive — each one promotes a connector or the LLM from mock to live.
> See [`CLAUDE.md`](CLAUDE.md) for the engineering guide and the v2→v5
> capability log.
> 💡 Run `docker compose up` (or `make up`) for a full local demo — no API
> keys needed, all connectors fall back to deterministic mocks.
> 🔒 **Never put a real key in `.env.example`** — it is a committed template.
> Real secrets belong only in `.env` (gitignored). See *Setup & credentials*.
---
## What it does, end to end
```mermaid
flowchart TD
subgraph FE["FRONTEND — Vite + Google Maps JavaScript API"]
FEUI["live flood-zone overlays · sensor markers · evacuation routes
risk heatmap · phase indicator · LLM chat panel"]
end
subgraph BE["BACKEND — FastAPI + LangGraph + Pydantic"]
API["REST /api/v1/* · WebSocket /ws/flood · OAuth /auth/*"]
API --> ORCH["FloodOps Orchestrator (LangGraph)
7-phase state machine + LLM reasoning layer"]
ORCH --> AGENTS["8 Agents
Sentinel · GLOF · Predict · Urban
Alert · Resource · Disease · Orchestrator"]
ORCH --> CONN["10 External Connectors
NOAA · USGS · Sentinel · ECMWF · OSM
WorldPop · HydroSHEDS · GLIMS · CCI · Dartmouth"]
ORCH --> GW["Google Workspace + Gemini
Sheets · Drive · Gmail · Gemini LLM"]
end
FEUI <-->|"WebSocket — phase updates, sensor reads,
flood forecasts, alerts"| API
```
---
## The 7 cascading phases
The orchestrator is a LangGraph state machine. Every phase transition is
LLM-justified and audit-logged.
| Phase | Trigger | What runs |
|------------------|------------------------------------------------------|----------------------------------------------------------------|
| 1 · MONITOR | Default steady state | Sentinel scans gauges + satellite SAR + soil-moisture |
| 2 · WATCH | Anomaly threshold crossed | GLOF + Predict start fanning; LLM interprets anomaly |
| 3 · ELEVATED | Probabilistic flood map ≥ medium | Urban computes zone-risk + evacuation routes |
| 4 · IMMINENT | Forecast crosses high-confidence threshold | Alert composes broadcasts; Resource pre-positions supplies |
| 5 · IMPACT | Live readings confirm flooding | Alerts dispatched (cell broadcast + radio + Gmail) |
| 6 · RECOVERY | Levels recede | Disease risk map generated; Resource routes rescue/relief |
| 7 · POST-MORTEM | Event closed | Gemini synthesises the sitrep; Drive PDF; Sheets archive |
Every transition writes an `AuditEntry` (LLM-justified) and pushes a
`phase_transition` event to the WebSocket so the frontend animates the
phase indicator.
---
## The 8 agents
Each agent extends `BaseAgent`, subscribes to its triggering events on the
in-process `EventBus`, and emits structured Pydantic outputs.
| Agent | Inputs | Outputs |
|-------------------|------------------------------------------------------------------------|------------------------------------------------------|
| **Sentinel** | NOAA, USGS, Sentinel Hub SAR, ESA CCI soil moisture, GLIMS baseline | `AnomalyAlert`, `SensorReading` |
| **GLOF** | Sentinel-1 SAR coherence, GLIMS area history, HydroSHEDS DEM | `LakeHealthReport`, `ImpactZone` |
| **Predict** | ECMWF ensemble, NOAA forecast, USGS streamflow, HydroSHEDS hydrography | `ProbabilisticFloodMap`, `FloodForecast` |
| **Urban** | OSM buildings + road graph, WorldPop density, Predict probability map | `ZoneRiskReport`, `RouteSet` |
| **Alert** | Predict / Urban outputs, contact registry | `CellBroadcast`, `RadioBroadcast`, Gmail messages |
| **Resource** | Urban routes, Sentinel readings, OSM shelters/hospitals | `LogisticsOrders`, `RescueRoutes` |
| **Disease** | ECMWF temperature/humidity, post-flood standing-water polygons | `DiseaseRiskMap`, `HotspotList` |
| **Orchestrator** | All of the above | `AuditEntry`, `StateTransition`, situational reports |
---
## The 10 external connectors
Every connector extends `BaseConnector` (rate limiting, exponential
backoff retry, response caching, credential management, structured
logging).
| # | Connector | Endpoint | Auth | Format | Library |
|---|-----------------|------------------------------------------------|-----------------------|-------------------|------------------------------|
| 1 | NOAA | `api.weather.gov` + `s3://noaa-goes16/` | Open (User-Agent) | GeoJSON, NetCDF4 | `goes2go`, `requests` |
| 2 | USGS | `api.waterdata.usgs.gov` | Free API key | JSON, GeoJSON | `dataretrieval` |
| 3 | Sentinel Hub | `sh.dataspace.copernicus.eu/api/v1/` | OAuth 2.0 client | GeoTIFF, STAC | `sentinelhub` |
| 4 | ECMWF CDS | `cds.climate.copernicus.eu/api` | Personal Token | GRIB, NetCDF | `cdsapi` |
| 5 | ESA CCI SM | CEDA FTP / CDS | Open / Token | NetCDF | `esa_cci_sm`, `xarray` |
| 6 | GLIMS | `glims.org/geoserver/wfs` | Open | GeoJSON | `geopandas`, `OWSLib` |
| 7 | OSM | `overpass-api.de/api/interpreter` | Open | JSON | `osmnx`, `overpy` |
| 8 | WorldPop | `api.worldpop.org/v1/services/stats` | Open (1K/day) | GeoTIFF, JSON | `worldpoppy`, `rasterio` |
| 9 | HydroSHEDS | `hydrosheds.org` (downloads + `mghydro.com`) | Open | Shapefile, GeoTIFF| `geopandas`, `pysheds` |
| 10| Dartmouth FO | `floodobservatory.colorado.edu` | Open | CSV, Shapefile | `pandas`, `geopandas` |
Each connector implements `health_check()` so the API can report data-source
status on the dashboard.
### Google Flood Forecasting API (v5, the operational Nature-2024 model) 🔑
`connectors/googleflood.py` wraps Google's **Flood Forecasting API**
(`floodforecasting.googleapis.com/v1`) — the operational LSTM of Nearing et
al., *Nature* 627 (2024), free under CC BY 4.0. It is **key-gated and honest**:
without a key, `available` is `False` and every method returns `None` (never a
faked value). Activate by setting `FLOODS_API_KEY` (the name Google's colab/docs
use) or the legacy `GOOGLE_FLOOD_API_KEY` in `.env`.
The connector mirrors the **full surface** of Google's
`Google_Flood_Forecasting_API_Usage_Example` colab, all paginated via
`nextPageToken`:
| Method | What it returns |
|---|---|
| `get_gauges` / `get_flood_status` | gauges + latest per-gauge severity (filtered by `regionCode`, then narrowed to the basin bbox client-side) |
| `query_gauge_forecasts` | quantitative discharge/level forecasts with lead times (Hydrology Model API) |
| `get_gauge_models` | official warning / danger / extreme thresholds |
| `get_significant_events` | clustered major flood events (area + population impact) |
| `get_flash_floods` | urban flash-flood probabilities (24 h) |
| `get_serialized_polygon` | inundation / notification / event KML geometry |
In the pipeline, **Sentinel** cross-validates against it: every status →
`external_hazards` (compound fusion); a SEVERE/EXTREME status in the basin →
an independent AI-model anomaly boost. It is treated as an **independent
forecast signal — never an input** to the local runoff ensemble (paper safety
rule). Verified live against the pilot API (765 Nepal gauges → 178 in the
Bagmati bbox; all endpoints `200`).
---
## LLM reasoning layer
`backend/floodops/llm/` is the intelligence that turns raw data into
human-understandable decisions.
- **`client.py` + `providers.py`** — `FloodLLMClient` is **provider-agnostic**
via an `LLMProvider` protocol: Anthropic (`claude-opus-4-8`, structured
output via `messages.parse`), Gemini, Groq / OpenRouter / any
OpenAI-compatible endpoint, GitHub Models, and a deterministic `NullProvider`
for keyless runs. `FLOODS_LLM_PROVIDER=anthropic|gemini|groq|…|auto` selects
the chain. With no key, `available()` is `False` and every reasoning helper
returns its deterministic mock — **the LLM augments reasoning but never gates
safety decisions** (alert severity and flood probability are computed without
it). Supports structured output, ensemble voting, and reflexion.
- **`prompts.py`** — four canonical system prompts:
- **Anomaly interpreter** — explains *why* a sensor anomaly matters
given watershed context.
- **Phase transition justifier** — generates the audit-log entry for
every phase change.
- **Situational report** — concise sitrep for emergency managers.
- **Chat assistant** — answers "what's happening?", "why did we
escalate?", "what should zone 3 do?" with full state context.
- **`reasoning.py`** — `FloodReasoner` exposes
`interpret_anomaly`, `justify_transition`, `generate_sitrep`,
`chat (streaming)`, and `analyze_compound_event` (correlates multiple
simultaneous alerts).
---
## Google OAuth + Workspace integration
`backend/floodops/auth/` wires the system to Google Sheets, Drive, and Gmail.
- **`oauth.py`** — Authorization Code flow. Scopes: `spreadsheets`,
`drive.file`, `gmail.send`. Auto-refreshes access tokens; stores
refresh tokens encrypted.
- **`workspace.py`** — three integration surfaces:
- **Sheets (data logging)** — appends `SensorReading`,
`StateTransitionEvent`, `AnomalyAlert` rows. Auto-creates the
spreadsheet on first use with formatted headers.
- **Drive (report storage)** — uploads sitrep PDFs and GeoJSON
snapshots under `FloodOps/Reports/`.
- **Gmail (alert emails)** — formatted alert + sitrep email delivery.
---
## Real-time Google Maps frontend
`frontend/` is a Vite app driven by the Google Maps JavaScript API.
- **Map base** — dark-theme styled map (Map ID configured in Cloud
Console) centred on a configurable region (default Kathmandu, GLOF-prone).
- **Layer system** — toggleable overlays:
1. **Flood zones** (GeoJSON via `google.maps.Data`) — colour-coded by
probability (green / yellow / orange / red).
2. **Sensor stations** (`AdvancedMarkerElement`) — river gauges, weather
stations, SAR coverage; pulse animation on anomaly; InfoWindow with
reading + z-score.
3. **Evacuation routes** (`Polyline`) — passable / blocked / at-risk
colour-coded; animated dashes for direction.
4. **Glacial lakes** (`Polygon`) — integrity-score colours; click for
`LakeHealthReport`.
5. **Disease risk heatmap** (custom `ImageMapType`) — toggleable per
pathogen (cholera / typhoid / leptospirosis).
6. **Flood depth grid** (custom tile overlay) — blue gradient by
predicted depth (0.5 m – 5 m+).
- **WebSocket client** — connects to `/ws/flood`, dispatches updates per
message type (`phase_transition`, `sensor_update`, `flood_forecast`,
`evacuation_update`, `alert_dispatch`, `glof_emergency`,
`disease_risk`, `audit_entry`). Auto-reconnects with exponential
backoff.
- **Dashboard side panel** — phase indicator, agent statuses (running /
idle), key metrics (max probability, peak ETA, population at risk),
scrolling audit feed, layer toggles.
- **LLM chat drawer** — streams answers from `/api/v1/flood/chat`. Renders
Markdown; supports "explain", "why?", "what should X do?" queries.
---
## REST + WebSocket surface
```
GET /api/v1/flood/state current FloodSystemState
GET /api/v1/flood/phase current phase + metadata
GET /api/v1/flood/audit-log paginated audit entries
GET /api/v1/flood/agents agent statuses
POST /api/v1/flood/simulate inject mock data for testing
POST /api/v1/flood/chat LLM chat (streaming response)
GET /api/v1/flood/sitrep generate situation report
GET /api/v1/map/flood-zones probability GeoJSON
GET /api/v1/map/sensors sensor locations + latest reads
GET /api/v1/map/evacuation-routes passable / blocked routes
GET /api/v1/map/glacial-lakes lake health polygons
GET /api/v1/map/disease-risk disease risk heatmap GeoJSON
GET /api/v1/map/flood-depth predicted depth grid GeoJSON
GET /api/v1/map/urban-zones zone risk reports
GET /api/v1/verification/skill measured forecast skill (±2-day F1) or cold-start prior
GET /api/v1/basin/thresholds Weibull-fitted return-period discharge thresholds
GET /api/v1/hazards/gdacs live GDACS flood events overlay
GET /api/v1/alerts/{id}/cap.xml dispatched alert as CAP 1.2 XML
# Google Flood Forecasting API (v5, key-gated — honest available:false until keyed)
GET /api/v1/hazards/googleflood latest basin flood statuses
GET /api/v1/hazards/googleflood/forecasts quantitative discharge/level forecasts
GET /api/v1/hazards/googleflood/significant-events clustered major flood events
GET /api/v1/hazards/googleflood/flash-floods urban flash-flood probabilities
GET /api/v1/basin/google-thresholds Google's official thresholds (cross-check)
GET /auth/login Google OAuth consent redirect
GET /auth/callback exchange code, store tokens
GET /auth/status is the session authenticated?
POST /auth/logout revoke tokens
WS /ws/flood real-time updates
```
---
## Planned project structure
```
flood_multi-agent_system/
├── flood_agent_specs.jsx Agent visual spec (existing)
├── flood_multiagent_orchestration.html Standalone HTML mockup (existing)
├── implementation_plan.md v2 implementation spec
│
├── backend/
│ ├── pyproject.toml
│ ├── requirements.txt
│ └── floodops/
│ ├── config.py Thresholds, API keys, schedules
│ ├── models/ Pydantic models (state, enums, geo,
│ │ sentinel, glof, predict, urban,
│ │ alert, resource, disease, audit)
│ ├── queue/event_bus.py In-process emit / subscribe / direct
│ ├── agents/ base.py + 7 agent implementations
│ ├── orchestrator/ LangGraph graph, nodes, routing
│ ├── connectors/ base.py + 10 connectors
│ ├── llm/ Gemini client, prompts, reasoning
│ ├── auth/ Google OAuth + Workspace wrappers
│ ├── api/ FastAPI app + REST + WS + OAuth
│ └── main.py Entry point (uvicorn)
│ └── tests/ state, event bus, agents, connectors,
│ models, auth
│
├── frontend/
│ ├── package.json
│ ├── vite.config.js
│ ├── index.html
│ ├── src/
│ │ ├── main.js App entry
│ │ ├── map.js Google Maps init + layer wiring
│ │ ├── layers.js All layer systems
│ │ ├── websocket.js Live update client
│ │ ├── dashboard.js Phase + metrics + audit panel
│ │ ├── chat.js LLM chat drawer
│ │ ├── auth.js Google login flow
│ │ └── style.css Dark theme + glassmorphism
│ └── public/favicon.svg
│
├── .env.example Environment variables template
└── docker-compose.yml Optional containerisation
```
---
## Quickstart
```bash
git clone https://github.com/krishddd/floodops-multi-agent-system
cd floodops-multi-agent-system
docker compose up # full local demo — zero API keys required
```
Backend comes up on `http://localhost:8000`, frontend on `http://localhost:5173`.
Every connector and the LLM fall back to deterministic mocks until you add keys,
so the system boots and demos with nothing configured. Add live data by dropping
keys into `.env` (see *Setup & credentials* below).
Without Docker:
```bash
pip install -r backend/requirements.txt
uvicorn floodops.main:app --reload # backend
cd frontend && npm install && npm run dev # frontend
```
## Setup & credentials
You will need accounts / API keys from the following before the system runs
end to end:
0. **None, to start.** The system boots and demos with **zero keys** — every
connector and the LLM fall back to deterministic mocks. Keys below are
additive; add them as you need live data. **Put real keys only in `.env`
(gitignored), never in the committed `.env.example` template.**
1. **Google Cloud Console** — Create a project. Enable Maps JS API,
Geocoding API, Routes API, Sheets API, Drive API, Gmail API. For live AI
flood forecasts, also join the **Flood Forecasting API** pilot
([waitlist](https://support.google.com/flood-hub/answer/16364306)), enable
it, and reply to Google with your Cloud Project ID → set `FLOODS_API_KEY`.
2. **OAuth consent screen** — Configure scopes and create a Web Application
OAuth Client ID.
3. **Google AI Studio** — Get a Gemini API key.
4. **Copernicus Data Space** — Register and create OAuth client credentials
for Sentinel Hub.
5. **ECMWF CDS** — Register, copy your Personal Access Token, and
**manually accept the Terms of Use for each dataset** on the CDS site
before retrieval works.
6. **USGS** — Register at `api.waterdata.usgs.gov/signup/` for a free API
key (the legacy `waterservices.usgs.gov` endpoint is being
decommissioned Q1 2027).
`.env.example` (excerpt):
```env
# Google Cloud
GOOGLE_MAPS_API_KEY=your-maps-api-key
GOOGLE_CLIENT_ID=your-oauth-client-id
GOOGLE_CLIENT_SECRET=your-oauth-client-secret
GOOGLE_REDIRECT_URI=http://localhost:8000/auth/callback
# Gemini
GOOGLE_GENAI_API_KEY=your-gemini-api-key
# Google Flood Forecasting API (v5) — the operational Nature-2024 model.
# Free/CC BY 4.0; join the pilot waitlist, enable the API, and reply to Google
# with your Cloud Project ID. FLOODS_API_KEY is Google's canonical name;
# GOOGLE_FLOOD_API_KEY is the legacy alias (wins if both set).
FLOODS_API_KEY=your-flood-forecasting-api-key
# USGS
API_USGS_PAT=your-usgs-api-key
# Sentinel Hub (Copernicus Data Space)
SENTINEL_HUB_CLIENT_ID=your-sh-client-id
SENTINEL_HUB_CLIENT_SECRET=your-sh-client-secret
# ECMWF CDS
ECMWF_CDS_TOKEN=your-cds-personal-access-token
# Frontend
VITE_GOOGLE_MAPS_API_KEY=your-maps-api-key
VITE_WS_URL=ws://localhost:8000/ws/flood
VITE_API_URL=http://localhost:8000/api/v1
```
> The Google Maps free tier covers 10K map loads / month.
---
## Build sequence
| Step | Layer | What |
|------|--------------|-----------------------------------------------------------------------|
| 1 | Setup | `pyproject.toml`, `requirements.txt`, `.env.example`, `config.py` |
| 2 | Models | All Pydantic models + GeoJSON models |
| 3 | Queue | Event bus with WebSocket broadcast hook |
| 4 | Connectors | `BaseConnector` + all 10 data-source connectors |
| 5 | LLM | Gemini client + prompts + reasoning engine |
| 6 | Auth | OAuth flow + Workspace (Sheets / Drive / Gmail) |
| 7 | Agents | `BaseAgent` + 7 agent implementations |
| 8 | Orchestrator | LangGraph graph, nodes, conditional routing |
| 9 | API | FastAPI app, REST routes, WebSocket handler |
| 10 | Frontend | Vite app, Maps init, layers, WebSocket, dashboard, chat, styling |
| 11 | Tests | State transitions, connectors, agents, models, auth |
| 12 | Verify | Mock scenario walkthrough, visual verification, deploy |
Estimated scope: **~65 new files, 5,000–6,000 lines**.
---
## Verification plan
**Automated**
```bash
# Backend
cd backend && python -m pytest tests/ -v
```
Key test scenarios:
- Full 7-phase state traversal driven by mock connector data.
- Each connector's `health_check()` passes (requires network).
- Event bus `emit` / `subscribe` / `direct_call`.
- Pydantic model validation (probabilities ∈ [0,1], coordinate bounds).
- OAuth refresh-token flow.
- WebSocket broadcast.
**Manual**
1. Run backend (`uvicorn`) + frontend (`npm run dev`).
2. Open the browser — Google Maps should load with the dark theme.
3. Click "Login with Google" → complete OAuth.
4. `POST /api/v1/flood/simulate` to inject a mock scenario.
5. Verify map layers update in real time over WebSocket.
6. Verify the dashboard reflects phase transitions.
7. Use the LLM chat to ask "What's happening?" — expect a streaming sitrep.
8. Confirm rows appear in the linked Google Sheet and a PDF lands in Drive.
---
## Open questions (from the spec)
1. **LLM provider** — the plan defaults to Google Gemini; OpenAI /
Anthropic fallback is open.
2. **Google Earth Engine** — sources 6 (GLIMS), 9 (HydroSHEDS),
10 (Dartmouth) are easier via GEE; if no GEE account, the connectors
fall back to direct file downloads.
3. **Deployment target** — local-first today; Docker / Cloud Run
scaffolding optional.
4. **Frontend refresh rate** — plan assumes 30-second WebSocket pushes.
---
## Status
✅ **Built and operational through v5.** The backend runs keyless (mock
fallbacks) with **77 offline tests green** (`cd backend && python -m pytest
tests -q`). Capability layers, newest first:
- **v5** — Google Flood Forecasting API connector (full colab surface,
live-verified), runoff calibration, forecast skill panel.
- **v4** — multi-model LLM fleet, live hazard feeds (GDACS, ReliefWeb), real
ML (climatology, runoff ensemble, verification loop), CAP 1.2 export,
SQLite persistence, optional API-key auth.
- **v3** — per-basin return-period flood-frequency analysis, OpenAI-compatible
LLM providers (Groq / OpenRouter / local).
- **v2** — live WebSocket command deck, observability, keyless real connectors,
CI/CD.
See [`CLAUDE.md`](CLAUDE.md) for the full engineering guide. The
`implementation_plan*.md` files and the HTML/JSX artefacts capture the original
visual / UX spec.
## License
MIT