Hydra — the sentinel of freshwater

🐉 HYDRA

Every drop. Every angle. Watched.

Autonomous freshwater triage — a deterministic core, verified agents, zero hallucinated numbers.

Theme: Earth Forward License: MIT Python 3.11+ FastAPI 0.115 Next.js 15 Gemini 2.5 Flash Tests: 102 passed

🌐 Github Repo · 🎥 Demo Video


⚖️ The Rule

Narrative must never mutate measurement.

That is the entire architecture of Hydra in one sentence.

Environment-monitoring AI has an open secret: the model that "explains" a watershed usually also invents its risk number. A confident paragraph about a lake becomes a confident made-up score — and a municipality spends its budget on the wrong crisis.

Most projects hand the number to the LLM. Hydra refuses to.

Every claim in Hydra resolves to one of two disjoint layers:

  • 🧮 Deterministic core — pure-numpy band math on real Sentinel-2 pixels. Same input → same number, provably.
  • 🤖 Agentic narrative — five Gemini agents that plan, scout, recall, critique, and explain. They write about the number. They may not touch it.

Keep reading — the two pipelines below either satisfy the rule, or the system halts and serves a deterministic fallback. There is no third option.


🚨 The Problem: Freshwater is Dying Quietly

Freshwater is <3% of Earth's water — and most of that is trapped in ice. What remains is fought over by agriculture, industry, and billions of people — while its quality degrades invisibly, from space, week after week.

🚨 Measured reality Source
~2 billion people lack safely managed drinking water at home WHO / UNICEF JMP
~80% of global wastewater returns to nature untreated UN Water
Most lakes & rivers are never sampled at all — lab capacity is the bottleneck, not satellite coverage UN Water

The consequence: algal blooms erupt into toxic crises, turbidity spikes contaminate drinking intakes, and shoreline vegetation collapses go unseen — because field sampling doesn't scale, and satellites return pixels, not priorities.

Which leaves one hard requirement: prioritize. And a prioritized sampling plan is useless if its risk number shifts because a language model "felt like it." Hence the rule.


🔗 The Two Pipelines

Hydra passes every unit of information through exactly one of two disjoint pipelines.

===================================================================================
 [PIPELINE 1] DETERMINISTIC CORE 🛰️        │ [PIPELINE 2] AGENT LAYER 🤖           
 (Trusted Numeric Truth)                  │ (Traceable Narrative Only)            
===================================================================================
                                          │                                       
 Area of Interest (Coords/Map Input)      │ Coordinator Agent (Thinking Mode)     
          │                               │          │                            
          ▼                               │          ▼                            
 Sentinel-2 L2A Imagery Data              │ Scout Agent                           
 (Planetary Computer STAC Engine)         │ (Vision Models + Function Calling)    
          │                               │          │                            
          ▼                               │          ▼                            
 Compute 6 Spectral Indices               │ Historian Agent                       
 [NDWI · MNDWI · NDTI · NDCI · NDVI · WRI]│ (Grounding + pgvector vector store)   
          │                               │          │                            
          ▼                               │          ▼                            
 Risk Urgency Score [0–100]               │ Reporter Agent                        
 (100% Reproducible / Algorithmic)        │ (Plain-Text Citizen Summaries)        
          │                               │          │                            
          └───────────────────────┬───────┴──────────┘                            
                                  │                                               
                                  ▼                                               
                           Analyst Agent                                          
                   (Draft ➔ Critique ➔ Rewrite)                                   
                                  │                                               
                                  ▼                                               
===================================================================================
 [OUTPUT TIER] Session Detail  +  Agent Execution Trace  +  Branded Analysis PDF  
===================================================================================

✅ Pipeline 1 — summary statistics, z-scores, thresholds. Pure numpy. The risk band is computed outside any prompt context.

✅ Pipeline 2 — five Gemini agents. Every tool call, argument, result, latency, and token count is persisted to agent_traces (JSONB).

📐 Design invariant: if any agent fails, the system still terminates with a deterministic output. Degradation is structural, not silent.


🧬 The Five Agents

# Agent Action Capability
1 🧭 Coordinator plans the workflow Gemini thinking mode
2 🔭 Scout picks the satellite scene Function calling + Gemini Vision on the real RGB tile
3 📚 Historian pulls trends & grounded context History + Google Search grounding + URL Context + code execution + pgvector memory
4 ✍️ Analyst writes & self-critiques the brief Structured output + critique-then-rewrite loop
5 📣 Reporter writes the citizen summary Structured response schema (deterministic fallback)

Every agent operates under a defined contract — structured output, bounded tools, persisted trace. Mediator of record: Gemini 2.5 Flash, with deterministic fallbacks on all five. Each run lands in the Agentic Workflow card with tool calls, JSON outputs, latency, and token usage — the same colour vocabulary across the UI and the branded PDF:

  • 🧭 Coordinator — aqua · 🔭 Scout — sky · 📚 Historian — amber · ✍️ Analyst — violet · 📣 Reporter — emerald

Deep dive: docs/agent_layer.md


🧠 The Memory

Hydra exhibits cross-session learning — verified deterministically.

🗄️ PostgreSQL 16 + PostGIS stores geometry and spectral risk, cross-referenced by AOI.

🧬 agent_memory embeds sessions with text-embedding-004 into a pgvector 768-dim HNSW cosine index — the Historian recalls prior states by similarity, not string match.

📈 Recurring water bodies accumulate history. Repeat visits are quantified via index deltas — the trace records when memory informed the narrative, and when it was intentionally skipped.


🛡️ The Safety Net

Every layer has a deterministic fallback — a session always produces a usable brief:

💥 Failure ✅ Fallback
Gemini key 429 / quota Roll over to GOOGLE_API_KEY_FALLBACK[_2]
Coordinator parse error Baseline plan: Scout + Analyst + Reporter (+ Historian if history exists)
Scout vision timeout Freshest STAC candidate under the cloud-cover ceiling
Historian failure Analyst runs without the briefing; memory write skipped
Analyst failure Deterministic narrator (reasoning._fake_bundle)
Reporter failure Deterministic citizen summary (citizen_summary.py)
AOI = land / mixed Pipeline 2 skipped entirely (zero Gemini cost); UI shows Not water
WeasyPrint error 500 with original message; cached PDFs never served stale

Degraded behaviour is never silent — all failures are recorded in the per-session trace. Determinism isn't just robustness. It's a safety property: degraded behavior can't produce a wrong number confidently written.


🧪 Verification Report

# Backend — 102 tests in <10s, fully deterministic CI
cd backend && .venv/bin/python -m pytest -q
.venv/bin/ruff check . && .venv/bin/black --check app/ tests/ alembic/

# Frontend
cd frontend && pnpm typecheck && pnpm lint && pnpm test && pnpm e2e

✔ 102 backend tests pass in < 10 s with zero mocks — deterministic CI; HYDRA_FAKE_GEMINI=1 enforces offline reproducibility.

✔ CI gates — pytest + ruff + black on backend; typecheck + lint + Vitest + Playwright on frontend + a WeasyPrint PDF smoke test on each PR.

✔ Reproducibility — same AOI, same indices, same score. The safety property is a test, not a claim.


🧱 Technical Composition

Layer Technology
🎨 Frontend Next.js 15 App Router · React 19 · Tailwind CSS 4 · TypeScript strict · MapLibre GL · SWR live polling · shadcn/ui · Vitest + Playwright
⚙️ Backend FastAPI 0.115 · Python 3.11+ · SQLModel · Pydantic v2 · Alembic migrations · structured logging
🗄️ Data PostgreSQL 16 + PostGIS (geometry) + pgvector (768-dim HNSW cosine index)
🛰️ Satellite Microsoft Planetary Computer STAC API · Sentinel-2 L2A COGs · pure-numpy band math
🤖 AI Google Gemini 2.5 Flash (chat + Vision + thinking mode + embeddings text-embedding-004) · 5-agent orchestrator with key rollover
📄 Reports Jinja2 + WeasyPrint branded PDFs (regenerated per-download — never stale)
🐳 Infra Docker Compose · Render blueprint · Vercel frontend

🔬 Reproduce the Result

cp .env.example .env

docker compose up --build
# → frontend http://localhost:3000 · backend http://localhost:8000

# or without docker
cd backend && python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]" && alembic upgrade head
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

cd frontend && pnpm install && pnpm dev

Requirements: DATABASE_URL, GOOGLE_API_KEY (free tier fine), NEXT_PUBLIC_API_URL.

Optional: GOOGLE_API_KEY_FALLBACK[_2] for quota rollover · HYDRA_AGENTIC_MODE=false to skip the agent layer · HYDRA_FAKE_GEMINI=1 for fully deterministic offline CI.


🧾 Project Assessment & Technical Provenance

📊 Hydra System Performance Summary

💡 Originality

  • Fuses a provably-deterministic spectral core with a self-critiquing agent team.
  • Replaces standard static dashboards entirely.
  • Separates raw numbers from narrative as its core contribution.

🌱 Earth Forward Adherence

  • Delivers freshwater triage focused on conservation, ecosystem monitoring, and community resilience.
  • Scales via satellite to reach areas where traditional lab budgets fall short.
  • Serves as the primary thematic driver for the project.

✅ Completion

  • Operates as a full-stack working product: map → satellite → six indices → five agents → PDF.
  • Maintained by 102 passing backend tests and CI gates.
  • Secured by a robust technical fallback matrix.

🧠 Learning

  • Implements advanced geospatial pipelines including STAC/COG and PostGIS geometry.
  • Integrates pgvector HNSW and Gemini's function calling, Vision, and thinking modes.
  • Mastered WeasyPrint for dynamic report generation.

🎨 Design

  • Built with a live agent trace UI styled in a dark system aesthetic.
  • Features integrated sparklines and direct CSV export tools.
  • Styled with custom branded PDFs and an animated SVG crest.

🛡️ Technology

  • Ensures the LLM can never manipulate the risk metrics.
  • Utilizes Numpy for data decisions while agents strictly handle narration.
  • Powered by six indices, five agents, and a unified vector-backed memory with full trace persistence.

🛠️ The Stack Behind the Invariant

Hydra’s architecture is built on three layers: compute, data, and agentic AI – each chosen to enforce the rule that the math measures, the model narrates.

Layer Technology Role
Compute Engine Python 3.11+ · NumPy · FastAPI · Pydantic Deterministic math + API layer
Data & Geospatial PostgreSQL 16 · PostGIS · pgvector (HNSW) · Alembic Geometry, vectors, migrations
Satellite Pipeline Microsoft Planetary Computer STAC · Sentinel‑2 L2A COGs · h5wasm Raw pixel access, server‑side
Agentic AI Gemini 2.5 Flash (thinking, vision, function‑calling, embeddings) · LangChain 5‑agent orchestration
Reports Jinja2 · WeasyPrint Branded PDF (never stale)
Frontend Next.js 15 · React 19 · Tailwind CSS 4 · MapLibre GL · shadcn/ui Live dashboard, trace UI
Infra Docker Compose · Render · Vercel One‑command local + cloud deploy

Key design decisions:

  • Pure NumPy band math – risk score is computed outside any LLM context.
  • Deterministic fallbacks – every agent has a hard‑coded safety net.
  • 102 tests, zero mocks – CI proves reproducibility.

No external AI API for the numbers. No black‑box risk. Just math you can audit.


🐉 Many heads. One invariant: the model writes about the water. The math measures it. 💧

Built With

  • alembicmicrosoft-planetary-computer
  • dockerrender
  • fastapi
  • gemini-2.5-flash
  • h5wasm
  • jinja
  • langchainnextjs
  • maplibre-gl
  • numpy
  • pgvector
  • postgis
  • postgresql
  • pydantic
  • python
  • react
  • sentinel-2
  • shadcn-ui
  • stac
  • tailwind-css
  • vercel
  • weasyprint
Share this project:

Updates

Submission history