🐉 HYDRA
Every drop. Every angle. Watched.
Autonomous freshwater triage — a deterministic core, verified agents, zero hallucinated numbers.
⚖️ 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.
📷 Evidence of Operation
A working deterministic core — map → satellites → indices → agents → durable PDF.
![]() |
![]() |
| Landing — the pitch, live | Dashboard — sessions, water bodies, average risk |
![]() |
![]() |
| Monitor — search / coords / map pick | Risk card — score + index deltas + AI narrative |
![]() |
![]() |
| Live session — deterministic pipeline → agent handoff | Index cards — distribution sparklines per index |
![]() |
![]() |
| Index table — full stats, one-click CSV export | Methodology — six band-math views explained |
🧱 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.
🕒 Timeline Disclosure
✅ Hydra was developed in full during the Hack-the Habitat window. All development — from core architecture and the deterministic spectral pipeline, through the five-agent workflow and pgvector memory, to the final polish — was completed.**
🐉 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









Log in or sign up for Devpost to join the conversation.