msradam/riprap

Composable, citation-grounded civic climate-exposure briefings for any US place.

0

stars

28

commits

Python

primary language

Jul 15, 2026

updated

README

Riprap dam mark

Riprap

License: Apache 2.0 Python 3.10+ CI Deployments Civic Hydrology Apache-2.0 foundation models

Citation-grounded climate-exposure briefings, city by city.

A multi-agent AI system that reads satellites, watches sensors, forecasts surges, and refuses to ship a sentence it cannot ground in a citation.

Riprap flood-exposure briefing for DUMBO, Brooklyn

Original hackathon demo (frozen at the AMD build, data probes only — inferencing disabled): https://lablab-ai-amd-developer-hackathon-riprap-nyc.hf.space. For a deployment with live inference, see the Quickstart below (Modal, a Mac Mini, or docker-compose).

Now an open-source civic-tech framework. NYC is the reference deployment. Six live deployments share the same code (NYC, Chicago, Seattle, San Francisco, Boston, Albany) — adding your city is a directory of YAML, not a fork.

  • docs/multi-city.md — six cities, three 311-platform paths (Socrata, CKAN, SeeClickFix), one codebase.
  • docs/byod.md — drop your own data in via .riprap/ auto-discovery or the RIPRAP_EXTRA_MANIFESTS env var.
  • docs/PORT-YOUR-CITY.md — walkthrough for adding a new city, using the Boston port as the worked example.
  • docs/multi-hazard.md — the same Five Stones produce a heat-exposure or air-quality briefing from a deployments/heat/ or deployments/air/ directory. Flood/NYC is the production-grade deployment (22 pebbles); heat and air are working scaffolds (3-4 pebbles) proving the architecture generalizes past flood.

The problem Riprap solves

Cities publish the hazard-exposure inputs an engineer needs. NYC alone has decades of it: Sandy 2012 inundation, NYC DEP stormwater scenarios, FloodNet sensors, NOAA tide gauges, USGS 3DEP LiDAR, 311 complaints, MTA, NYCHA, schools, hospitals — and Chicago, Seattle, San Francisco, Boston, and Albany each publish their own equivalents. The data is public. None of it composes itself.

Every engineer doing a drainage review, every resilience office siting a capital project, every climate-adaptation team prioritising blocks reassembles the same evidence by hand, per address, from a dozen agencies. A briefing that should be a tool call ends up as a half-day of manual joins. Existing tools either return opaque vendor risk scores or skip the audit trail a stamped engineering memo actually requires.

Riprap composes it. Type an address in any deployed city, get a four-section, citation-grounded briefing in about two minutes, with every claim pointing back to a [doc_id] in public-record data.


What this is. What this isn't.

Riprap is a reference dossier generator for analysts who already work with public-record climate data. It is not a stamped engineering memo, a risk score, a real-estate disclosure, or a substitute for a licensed professional.

Use Riprap if you are:

  • A climate-adaptation or resilience consultant who currently opens six tabs (NFHL, NOAA SLR, NPCC4 PDF, 311 portal, FloodNet, NWS), screenshots them into a Word memo, and cites manually. Riprap collapses that into one URL with a citation trail you can hand to a client.
  • A Phase I ESA preparer adding a Business Environmental Risk addendum under ASTM E1527-21. The compliance-audit predicates are well-aimed at that scope.
  • An investigative journalist or civic researcher who needs defensible, primary-source-linked numbers about flood-zone exposure, asset proximity, or 311 patterns.
  • A resilience-office analyst (NYC MOCEJ, Chicago CDOT, etc.) who needs to turn agency data into something a deputy commissioner reads in five minutes.

Don't use Riprap for:

  • Drainage / hydraulic design. Use HEC-RAS, SWMM, or a licensed civil engineer's full hydraulic model. Riprap is triage, not design.
  • Resident-facing flood guidance. For NYC, defer to FloodHelpNY (Center for NYC Neighborhoods, HUD CDBG-DR funded) and FloodNet NYC for sensor data.
  • Mortgage / insurance underwriting. Closed-model risk scores have regulatory acceptance Riprap doesn't claim and doesn't seek.
  • Personal property decisions or real-estate transactions. The briefing format is engineering-shaped, not consumer-shaped. Using a Riprap citation as evidence in a transaction is outside the design scope of this tool and outside the support scope of its contributors.

On FEMA determinations specifically: when FEMA proposes a change to a flood hazard determination — a Base Flood Elevation, an SFHA boundary, a floodway — federal regulation gives the affected community a 90-day appeal window, and an appeal must rest solely on scientific or technical evidence, not policy or economic argument (44 CFR Part 67). Riprap does not issue, contest, or substitute for a determination made through that process. If a decision turns on the official flood zone at a parcel, use FEMA's Flood Map Service Center or the community's Flood Zone Determination process, not a Riprap citation.


Quickstart

Four ways to use Riprap, in increasing order of self-host. Any option that clones the repo needs Git LFS first — data/ and corpus/ are LFS-tracked, and a clone without it silently checks out small pointer files instead of the real data, then the app crashes on startup trying to parse one as GeoJSON:

brew install git-lfs && git lfs install   # once per machine

(Already cloned without it? git lfs pull inside the repo fetches the real files retroactively.)

1. Try the original hackathon demo

https://lablab-ai-amd-developer-hackathon-riprap-nyc.hf.space

This is the original AMD hackathon build, frozen at its May 2026 commit. It runs the full SvelteKit shell and every deterministic data probe (Sandy, DEP, NOAA, FloodNet, 311, NPCC4, and the rest). The GPU half is offline there, so the Granite reconciler returns a graceful "inference offline" shape in place of the LLM-written prose. Methodology, evidence cards, and citations all still render.

For the full LLM and specialist path, run the inference stack yourself. Three options — see docs/DEPLOY.md for the full walkthrough of each:

  • Modal (scale-to-zero, recommended). modal deploy two apps from msradam/riprap-inference — the ML specialists (the same LitServe backend the Mac Mini path below runs natively) and Granite 4.1 via vLLM, each its own scale-to-zero app since they run on different GPU tiers. Both cost nothing while idle and wake on the first request; a warm query returns a full cited briefing in about a minute. See docs/DEPLOY.md for the full setup.
  • Mac Mini / Apple Silicon, fully local. No cloud, no GPU rental — Ollama-served Granite 4.1 plus every ML specialist run on one box, with real measured power draw via powermetrics instead of a data-sheet estimate. This is the reference "clone it and it just works" deployment.
  • Local Ollama (granite4.1:8b pulled), for CPU-only development with no GPU at all.

The three NYC fine-tunes were trained on an AMD Instinct MI300X via the AMD Developer Cloud; RIPRAP_HARDWARE_LABEL="AMD MI300X" swaps the energy ledger back to MI300X figures if you deploy to your own AMD GPU box (docker-compose --profile with-models). See docs/DEPLOY.md.

2. Run locally with Docker

git clone https://github.com/msradam/riprap
cd riprap
cp .env.example .env
# edit .env to point RIPRAP_LLM_BASE_URL / RIPRAP_ML_BASE_URL at
# a Modal deployment or your own self-hosted instance
docker compose up

Visit http://localhost:7860.

The GPU inference half lives in a companion repo, msradam/riprap-inference — ML specialists and Granite 4.1 (vLLM), deployable to Modal (as two apps) or run natively on a Mac Mini, same codebase either way (or point at any other OpenAI-compatible vLLM endpoint). Point this app at them via RIPRAP_LLM_BASE_URL / RIPRAP_ML_BASE_URL. See docs/DEPLOY.md for every deployment shape.

3. Develop

# Python 3.12 venv via uv
uv venv && uv pip install -r requirements.txt

# SvelteKit frontend (committed pre-built; only rebuild if sources change)
cd web/sveltekit && npm ci && npm run build && cd ../..

# Local server (Ollama primary)
.venv/bin/uvicorn web.main:app --host 127.0.0.1 --port 7860

# Local server pointed at a remote GPU backend (Modal, or your own
# vLLM box), vLLM primary with Ollama fallback
RIPRAP_LLM_PRIMARY=vllm \
RIPRAP_LLM_BASE_URL=<your backend's OpenAI-compatible URL> \
RIPRAP_LLM_API_KEY=<token> \
.venv/bin/uvicorn web.main:app --host 127.0.0.1 --port 7860

# End-to-end address suite (5 NYC addresses, intent-aware checks)
.venv/bin/python scripts/probe_addresses.py

4. Run with your city's data

Riprap ships with six working deployments (deployments/{nyc,chicago, seattle,sf,boston,albany}/). Each is a directory of YAML pebble manifests plus a stones.yaml. Switch deployments with one env var:

# Brief 233 S Wacker Dr, Chicago — no code changes, real upstream data
RIPRAP_DEPLOYMENT=deployments/chicago RIPRAP_RECONCILER_TIER=no_llm \
.venv/bin/python -c "import riprap.core.burr.app as a; \
  print(a.run('233 S Wacker Dr, Chicago, IL')['paragraph'])"

Layer your own data on top of any deployment via docs/byod.md:

# .riprap/ in your CWD is auto-discovered
mkdir -p .riprap && cp examples/byod/fdny_firehouses.{yaml,csv} .riprap/

# Same effect via env var (a colon-separated list of dirs or yaml files)
RIPRAP_EXTRA_MANIFESTS=examples/byod \
RIPRAP_DEPLOYMENT=deployments/nyc \
.venv/bin/uvicorn web.main:app --port 7860

Add your own city: see docs/PORT-YOUR-CITY.md.


How Riprap works: the Five Stones

Behind every briefing, a couple dozen atomic data probes (pebbles) fan out across NYC datasets, satellite imagery, sensors, and forecasts. Each pebble is one YAML manifest plus a small adapter; the framework loads them from a deployment directory and groups them into five legible roles, the Five Stones:

Cornerstone remembers. Keystone tallies. Touchstone watches. Lodestone projects. Capstone writes it all down with citations.

StoneRoleWhat fires
CornerstoneThe Hazard Reader. What the ground remembers.Sandy 2012 inundation extent, NYC DEP stormwater scenarios, 2021 Ida USGS high-water marks, baked Prithvi-EO Ida-attributable polygons, USGS 3DEP DEM + HAND/TWI
KeystoneThe Asset Register. What's exposed.MTA subway entrances, NYCHA developments, NYC DOE schools, NYS DOH hospitals, TerraMind-NYC Buildings LoRA
TouchstoneThe Live Observer. Current state of the city.FloodNet ultrasonic depth sensors, NYC 311 flood complaints, NWS hourly METAR, NOAA tide-gauge water levels, Prithvi-EO 2.0 NYC-Pluvial v2, TerraMind-NYC LULC LoRA
LodestoneThe Projector. What's coming.NWS public flood alerts, Granite TTM r2 surge nowcast (zero-shot, 6-min cadence, 9.6 h horizon), per-address 311 weekly forecast, FloodNet sensor recurrence forecast, Granite-TTM-r2-Battery-Surge fine-tune (96 h hourly horizon)
CapstoneThe Synthesiser. Citation-grounded briefing.Granite 4.1 + Mellea rejection sampling

Each Stone fans its pebbles out in parallel as a Burr MapActions group; the Capstone then reconciles their documents into one cited briefing. Adding a data source is a new manifest in the deployment directory, not a code change.


The Five Stones beyond NYC

The Five Stones taxonomy is a city-agnostic template for any flood-vulnerable region with the right data scaffolding. The five roles generalise; only the probes plugged into each Stone change.

StoneRoleWhat you replace
CornerstoneHazard memoryLocal historical inundation extents, regional DEM, regulatory floodplain maps
KeystoneAsset registersThe transit, housing, education, and healthcare polygons your jurisdiction publishes
TouchstoneLive observationWhatever live sensors and complaint streams the city or region exposes (FloodNet has analogues in Houston, Boston, Miami)
LodestoneForecastsLocal NWS forecast office output, regional surge or hydrologic models, time-series fine-tunes for your tide gauge
CapstoneCitation-grounded synthesisSame

The architectural commitments transfer unchanged: a Burr FSM that fans pebble manifests out per Stone, Granite-native role="document" reconciliation, Mellea four-check grounding, SSE streaming to a SvelteKit map UI, every claim cited to its source. To port Riprap to a new city you write a deployment directory of manifests against local data and, for the satellite and time-series layers, retrain the EO and TTM fine-tunes on your jurisdiction's imagery and gauges. The agentic shell stays the same. See docs/PORT-YOUR-CITY.md.


NYC-specialised foundation models (Apache 2.0)

Three NYC-specific fine-tunes built on AMD Instinct MI300X via AMD Developer Cloud, published under permissive licence.

msradam/TerraMind-NYC-Adapters. LoRA family on TerraMind 1.0 base. LULC mIoU 0.5866 (+6.13 pp over full-FT baseline), TiM 0.6023, Buildings 0.5511. Trained in around 18 minutes on a single MI300X.

msradam/Prithvi-EO-2.0-NYC-Pluvial. NYC pluvial-flood fine-tune of Prithvi-EO 2.0. Test flood IoU 0.5979 vs 0.10 on the Sen1Floods11 base, a 6× lift. Lovász-Softmax loss with copy-paste augmentation.

msradam/Granite-TTM-r2-Battery-Surge. NYC Battery storm-surge nowcast fine-tune of Granite TimeSeries TTM r2. Test MAE 0.1091 m, 41% better than persistence and 25% better than zero-shot.

All three are loaded at runtime by their respective FSM probes in app/context/ and app/live/. Reproduction recipes live under experiments/18..21/.


Architecture

Address ──► Granite 4.1 3B planner ──► Plan{intent, targets, specialists}
                                                  │
                                                  ▼
                  Five-Stone Burr FSM (manifest pebbles, MapActions fan-out)
                            ┌───────────┬───────────┬───────────┬──────────┐
                            ▼           ▼           ▼           ▼          ▼
                       Cornerstone  Keystone   Touchstone   Lodestone  (cont.)
                       (hazard)    (assets)    (live)       (forecast)
                            │           │           │           │
                            └───────────┴─────┬─────┴───────────┘
                                              ▼
                         build_documents() — Granite-native
                         role="document <doc_id>" messages
                                              ▼
                  Capstone: Granite 4.1 8B + Mellea rejection sampling
                  ──► 4-check grounding loop, surgical feedback rerolls
                                              ▼
                       Four-section briefing with [doc_id] citations
                                              ▼
                       SSE stream → SvelteKit UI (briefing, trace, map)

The runtime is the manifest-driven framework under riprap/core/. A deployment is a directory of YAML pebble manifests plus a stones.yaml; the registry loads them and the Burr app fans each Stone's pebbles out in parallel. Adding a data source, or a whole new city, is configuration, not code. The legacy app/ modules remain for the register and multi-intent paths the framework has not yet absorbed.

LLM inference is dispatched through app/llm.py, a LiteLLM Router shim with two backends: Ollama (local dev, CPU) and vLLM (OpenAI-compatible, on Modal or a cloud GPU). Same chat() signature in both directions; vLLM is primary when configured, Ollama is the auto-failover.

Specialist ML inference (Prithvi-EO, TerraMind, TTM, GLiNER, Granite Embedding) goes over HTTP to a bearer-authenticated proxy, which stamps real GPU/Apple-Silicon power readings onto every response (see the energy section below). The specialist server is msradam/riprap-inference (LitServe) — one codebase, deployable to Modal (scale-to-zero, $0 idle) or run natively on a Mac Mini / Apple Silicon for MPS access. Granite 4.1 via vLLM is the same repo's second Modal app (its own GPU tier, its own image); any other OpenAI-compatible vLLM endpoint works too. See docs/DEPLOY.md for every combination.

Source-of-truth pointers:

  • riprap/core/pebbles/: the pebble framework — manifest schema, registry, and the adapters / shapers that normalize each source.
  • riprap/core/burr/: the Burr application — intake, per-Stone MapActions fan-out, and the reconciler tiers (llm / no_llm).
  • deployments/<city>/: the manifests, stones.yaml, data, and corpus that define one deployment.
  • riprap/core/compliance/: briefing-quality predicates audited per run.
  • web/main.py: FastAPI + SSE. The stream emits plan / step / token / mellea_attempt / final events plus the stone_start / stone_done envelope around each Stone group.
  • riprap/mcp/server.py: MCP server (python -m riprap.mcp.server) — lets an agent call Riprap as a tool: get_briefing, list_sources, get_citation.
  • web/sveltekit/: primary UI (SvelteKit + adapter-static).
  • app/llm.py: LiteLLM Router shim (Ollama / vLLM).
  • app/emissions.py: per-query Tracker + hardware profiles. Records every LLM and ML inference call with measured: bool.

For the long-form architecture document, see docs/ARCHITECTURE.md. Methodology and civil-engineering framing in docs/METHODOLOGY.md. Lit review in docs/RESEARCH.md. Deploy topology in docs/DEPLOY.md. Live measurements (wall-clock, real NVML energy, Mellea grounding pass-rate) in docs/BENCHMARKS.md.


Inference energy — measured, not estimated

Riprap reports the energy and token cost of every inference call it makes during a briefing. The status row on the Findings region displays a single chip:

✓ 1.4 Wh / 6.9K tok inference

The icon means every recorded call came back with a real reading off the inference GPU via nvmlDeviceGetPowerUsage. The proxy runs a 100 ms-cadence NVML sampler and stamps X-GPU-Power-W / X-GPU-Energy-J on every response; the LLM client brackets each completion with two GETs to /v1/power because LiteLLM hides response headers. When the proxy is unreachable, the chip shows ~ or and the row falls back to a data-sheet sustained- power estimate.

Per-call records carry prompt_tokens, completion_tokens, duration_s, power_w, joules, and a measured: bool flag. The full ledger is shipped on the SSE final event under emissions.calls, so any consumer (dashboard, billing model, reproducibility check) can reuse the data.

Detailed pipeline + verification recipe in docs/EMISSIONS.md.


Data sources

Riprap contacts only public-record federal, state, and city sources at runtime. No commercial APIs, no proprietary scores, no opaque aggregators.

SourceHosting agencyUsed for
Hurricane Sandy 2012 inundation zoneNYC OTI / NOAA Office for Coastal ManagementCornerstone hazard memory
NYC DEP Stormwater Flood MapsNYC Department of Environmental ProtectionDEP modeled-scenario layers
Hurricane Ida 2021 USGS high-water marksUSGS Short-Term NetworkEmpirical validation points
FloodNet ultrasonic sensor networkNYU CUSP / FloodNetHistorical flood-event log (labeled events, peak depths)
NYC 311 flood complaintsNYC Open DataEmpirical complaint history
NOAA tide gauge, The BatteryNOAA CO-OPSLive tide and surge level
NWS METARNational Weather ServiceHourly precipitation
NWS public flood alertsNational Weather ServiceActive warnings and watches
MTA subway entrancesMTA / NYC Open DataTransit asset register
NYCHA developmentsNYC Housing AuthorityPublic-housing exposure
NYC DOE schoolsNYC Department of EducationEducation-asset exposure
NYS DOH hospitalsNew York State Department of HealthCritical-facility exposure
USGS 3DEP 1 m DEMUSGS National MapHAND / TWI microtopography
NYC DOB filingsNYC Department of BuildingsDevelopment-check intent
NPCC4 SLR projectionsNYC Mayor's Office of Climate & Environmental JusticePolicy-context corpus (RAG)
Sentinel-2 MSI imageryESA / CopernicusPrithvi + TerraMind inputs

The full data licence map and vintage table is enumerated in docs/ARCHITECTURE.md.


Repository structure

riprap/core/               The manifest-driven framework (current runtime)
├── pebbles/               Pebble schema, registry, adapters, shapers
├── burr/                  Burr app: intake, per-Stone MapActions, reconcilers
└── compliance/            Briefing-quality predicates (FEMA / IPCC / TCFD / …)

riprap/mcp/                MCP server — Riprap as an agent-callable tool

deployments/               One directory per deployment
├── nyc/                   Reference: manifests, stones.yaml, data, corpus
└── chicago, seattle, sf, boston, …    Same shape, different city

app/                       Legacy modules still used by register + intent paths
├── llm.py                 LiteLLM Router shim (Ollama / vLLM)
├── emissions.py           Per-query energy + token ledger (real NVML)
└── geocode.py, registers/, intents/, context/, flood_layers/, live/

web/                       FastAPI + SvelteKit
├── main.py                FastAPI app, SSE streaming, layer endpoints
└── sveltekit/             Primary UI (adapter-static; build committed)

modal/                     Modal deploy of this app (CPU, scale-to-zero)
scripts/                   Probes, register builders, deploy commands
experiments/               Reproduction recipes for the three NYC fine-tunes
docs/                      ARCHITECTURE · DEPLOY · multi-city · PORT-YOUR-CITY · …
tests/                     pytest (pebbles, stones, routing) + vitest (UI)

The GPU/ML-specialist inference stack lives in a separate repo, msradam/riprap-inference (LitServe specialists + Granite 4.1 via vLLM, deployable to Modal as two apps, or a Mac Mini). inference/ and services/riprap-models/ in this repo are lighter self-host sidecars that predate it — see docs/DEPLOY.md.

CONTRIBUTING.md covers dev setup, the probe scripts, and house style. CHANGELOG.md tracks changes since the v0.5.0 hackathon submission.


Citation

If you reference Riprap in academic or professional work:

@software{riprap_2026,
  author       = {Rahman, Adam Munawar},
  title        = {Riprap: Composable, Citation-Grounded Civic Climate-Exposure Briefings for Any US Place},
  year         = {2026},
  url          = {https://github.com/msradam/riprap},
  version      = {v0.6.0},
  note         = {Originated as the AMD x lablab.ai Developer Hackathon submission; evolved into a multi-city, multi-hazard open-source framework}
}

License

Apache 2.0. See LICENSE and NOTICE.

The three NYC-specialised fine-tunes above are also Apache 2.0; underlying upstream models retain their own permissive licences (see each MODEL_CARD.md). Public-record data sources retain their own access terms; the licence map is in docs/ARCHITECTURE.md.


Acknowledgments

  • AMD Developer Cloud, MI300X compute that made the three Apache-2.0 NYC fine-tunes feasible.
  • AMD × lablab.ai Developer Hackathon, the venue.
  • IBM Research, Granite 4.1, Granite Embedding 278M, Granite TTM r2, Mellea, and the rest of the open-source Granite ecosystem.
  • NASA / IBM Prithvi-EO 2.0 and IBM / ESA TerraMind 1.0, the geospatial foundation models behind the NYC fine-tunes.
  • NYU CUSP / FloodNet, the public sensor network whose data Riprap reads live.
  • Andrew Hicks, civil-engineering review of the methodology.
  • The Riprap dam mark, "Dam" by Chintuza via the Noun Project, licensed CC-BY 3.0. The original SVG embedded the attribution as on-canvas text; Riprap's assets/logo*.svg strips the embedded text and carries the credit here in body copy instead, per the Creative Commons attribution requirement.

Contributors

msradam

28 commits

msradam/riprap

Composable, citation-grounded civic climate-exposure briefings for any US place.

0

stars

28

commits

Python

primary language

Jul 15, 2026

updated

README

Riprap dam mark

Riprap

License: Apache 2.0 Python 3.10+ CI Deployments Civic Hydrology Apache-2.0 foundation models

Citation-grounded climate-exposure briefings, city by city.

A multi-agent AI system that reads satellites, watches sensors, forecasts surges, and refuses to ship a sentence it cannot ground in a citation.

Riprap flood-exposure briefing for DUMBO, Brooklyn

Original hackathon demo (frozen at the AMD build, data probes only — inferencing disabled): https://lablab-ai-amd-developer-hackathon-riprap-nyc.hf.space. For a deployment with live inference, see the Quickstart below (Modal, a Mac Mini, or docker-compose).

Now an open-source civic-tech framework. NYC is the reference deployment. Six live deployments share the same code (NYC, Chicago, Seattle, San Francisco, Boston, Albany) — adding your city is a directory of YAML, not a fork.

  • docs/multi-city.md — six cities, three 311-platform paths (Socrata, CKAN, SeeClickFix), one codebase.
  • docs/byod.md — drop your own data in via .riprap/ auto-discovery or the RIPRAP_EXTRA_MANIFESTS env var.
  • docs/PORT-YOUR-CITY.md — walkthrough for adding a new city, using the Boston port as the worked example.
  • docs/multi-hazard.md — the same Five Stones produce a heat-exposure or air-quality briefing from a deployments/heat/ or deployments/air/ directory. Flood/NYC is the production-grade deployment (22 pebbles); heat and air are working scaffolds (3-4 pebbles) proving the architecture generalizes past flood.

The problem Riprap solves

Cities publish the hazard-exposure inputs an engineer needs. NYC alone has decades of it: Sandy 2012 inundation, NYC DEP stormwater scenarios, FloodNet sensors, NOAA tide gauges, USGS 3DEP LiDAR, 311 complaints, MTA, NYCHA, schools, hospitals — and Chicago, Seattle, San Francisco, Boston, and Albany each publish their own equivalents. The data is public. None of it composes itself.

Every engineer doing a drainage review, every resilience office siting a capital project, every climate-adaptation team prioritising blocks reassembles the same evidence by hand, per address, from a dozen agencies. A briefing that should be a tool call ends up as a half-day of manual joins. Existing tools either return opaque vendor risk scores or skip the audit trail a stamped engineering memo actually requires.

Riprap composes it. Type an address in any deployed city, get a four-section, citation-grounded briefing in about two minutes, with every claim pointing back to a [doc_id] in public-record data.


What this is. What this isn't.

Riprap is a reference dossier generator for analysts who already work with public-record climate data. It is not a stamped engineering memo, a risk score, a real-estate disclosure, or a substitute for a licensed professional.

Use Riprap if you are:

  • A climate-adaptation or resilience consultant who currently opens six tabs (NFHL, NOAA SLR, NPCC4 PDF, 311 portal, FloodNet, NWS), screenshots them into a Word memo, and cites manually. Riprap collapses that into one URL with a citation trail you can hand to a client.
  • A Phase I ESA preparer adding a Business Environmental Risk addendum under ASTM E1527-21. The compliance-audit predicates are well-aimed at that scope.
  • An investigative journalist or civic researcher who needs defensible, primary-source-linked numbers about flood-zone exposure, asset proximity, or 311 patterns.
  • A resilience-office analyst (NYC MOCEJ, Chicago CDOT, etc.) who needs to turn agency data into something a deputy commissioner reads in five minutes.

Don't use Riprap for:

  • Drainage / hydraulic design. Use HEC-RAS, SWMM, or a licensed civil engineer's full hydraulic model. Riprap is triage, not design.
  • Resident-facing flood guidance. For NYC, defer to FloodHelpNY (Center for NYC Neighborhoods, HUD CDBG-DR funded) and FloodNet NYC for sensor data.
  • Mortgage / insurance underwriting. Closed-model risk scores have regulatory acceptance Riprap doesn't claim and doesn't seek.
  • Personal property decisions or real-estate transactions. The briefing format is engineering-shaped, not consumer-shaped. Using a Riprap citation as evidence in a transaction is outside the design scope of this tool and outside the support scope of its contributors.

On FEMA determinations specifically: when FEMA proposes a change to a flood hazard determination — a Base Flood Elevation, an SFHA boundary, a floodway — federal regulation gives the affected community a 90-day appeal window, and an appeal must rest solely on scientific or technical evidence, not policy or economic argument (44 CFR Part 67). Riprap does not issue, contest, or substitute for a determination made through that process. If a decision turns on the official flood zone at a parcel, use FEMA's Flood Map Service Center or the community's Flood Zone Determination process, not a Riprap citation.


Quickstart

Four ways to use Riprap, in increasing order of self-host. Any option that clones the repo needs Git LFS first — data/ and corpus/ are LFS-tracked, and a clone without it silently checks out small pointer files instead of the real data, then the app crashes on startup trying to parse one as GeoJSON:

brew install git-lfs && git lfs install   # once per machine

(Already cloned without it? git lfs pull inside the repo fetches the real files retroactively.)

1. Try the original hackathon demo

https://lablab-ai-amd-developer-hackathon-riprap-nyc.hf.space

This is the original AMD hackathon build, frozen at its May 2026 commit. It runs the full SvelteKit shell and every deterministic data probe (Sandy, DEP, NOAA, FloodNet, 311, NPCC4, and the rest). The GPU half is offline there, so the Granite reconciler returns a graceful "inference offline" shape in place of the LLM-written prose. Methodology, evidence cards, and citations all still render.

For the full LLM and specialist path, run the inference stack yourself. Three options — see docs/DEPLOY.md for the full walkthrough of each:

  • Modal (scale-to-zero, recommended). modal deploy two apps from msradam/riprap-inference — the ML specialists (the same LitServe backend the Mac Mini path below runs natively) and Granite 4.1 via vLLM, each its own scale-to-zero app since they run on different GPU tiers. Both cost nothing while idle and wake on the first request; a warm query returns a full cited briefing in about a minute. See docs/DEPLOY.md for the full setup.
  • Mac Mini / Apple Silicon, fully local. No cloud, no GPU rental — Ollama-served Granite 4.1 plus every ML specialist run on one box, with real measured power draw via powermetrics instead of a data-sheet estimate. This is the reference "clone it and it just works" deployment.
  • Local Ollama (granite4.1:8b pulled), for CPU-only development with no GPU at all.

The three NYC fine-tunes were trained on an AMD Instinct MI300X via the AMD Developer Cloud; RIPRAP_HARDWARE_LABEL="AMD MI300X" swaps the energy ledger back to MI300X figures if you deploy to your own AMD GPU box (docker-compose --profile with-models). See docs/DEPLOY.md.

2. Run locally with Docker

git clone https://github.com/msradam/riprap
cd riprap
cp .env.example .env
# edit .env to point RIPRAP_LLM_BASE_URL / RIPRAP_ML_BASE_URL at
# a Modal deployment or your own self-hosted instance
docker compose up

Visit http://localhost:7860.

The GPU inference half lives in a companion repo, msradam/riprap-inference — ML specialists and Granite 4.1 (vLLM), deployable to Modal (as two apps) or run natively on a Mac Mini, same codebase either way (or point at any other OpenAI-compatible vLLM endpoint). Point this app at them via RIPRAP_LLM_BASE_URL / RIPRAP_ML_BASE_URL. See docs/DEPLOY.md for every deployment shape.

3. Develop

# Python 3.12 venv via uv
uv venv && uv pip install -r requirements.txt

# SvelteKit frontend (committed pre-built; only rebuild if sources change)
cd web/sveltekit && npm ci && npm run build && cd ../..

# Local server (Ollama primary)
.venv/bin/uvicorn web.main:app --host 127.0.0.1 --port 7860

# Local server pointed at a remote GPU backend (Modal, or your own
# vLLM box), vLLM primary with Ollama fallback
RIPRAP_LLM_PRIMARY=vllm \
RIPRAP_LLM_BASE_URL=<your backend's OpenAI-compatible URL> \
RIPRAP_LLM_API_KEY=<token> \
.venv/bin/uvicorn web.main:app --host 127.0.0.1 --port 7860

# End-to-end address suite (5 NYC addresses, intent-aware checks)
.venv/bin/python scripts/probe_addresses.py

4. Run with your city's data

Riprap ships with six working deployments (deployments/{nyc,chicago, seattle,sf,boston,albany}/). Each is a directory of YAML pebble manifests plus a stones.yaml. Switch deployments with one env var:

# Brief 233 S Wacker Dr, Chicago — no code changes, real upstream data
RIPRAP_DEPLOYMENT=deployments/chicago RIPRAP_RECONCILER_TIER=no_llm \
.venv/bin/python -c "import riprap.core.burr.app as a; \
  print(a.run('233 S Wacker Dr, Chicago, IL')['paragraph'])"

Layer your own data on top of any deployment via docs/byod.md:

# .riprap/ in your CWD is auto-discovered
mkdir -p .riprap && cp examples/byod/fdny_firehouses.{yaml,csv} .riprap/

# Same effect via env var (a colon-separated list of dirs or yaml files)
RIPRAP_EXTRA_MANIFESTS=examples/byod \
RIPRAP_DEPLOYMENT=deployments/nyc \
.venv/bin/uvicorn web.main:app --port 7860

Add your own city: see docs/PORT-YOUR-CITY.md.


How Riprap works: the Five Stones

Behind every briefing, a couple dozen atomic data probes (pebbles) fan out across NYC datasets, satellite imagery, sensors, and forecasts. Each pebble is one YAML manifest plus a small adapter; the framework loads them from a deployment directory and groups them into five legible roles, the Five Stones:

Cornerstone remembers. Keystone tallies. Touchstone watches. Lodestone projects. Capstone writes it all down with citations.

StoneRoleWhat fires
CornerstoneThe Hazard Reader. What the ground remembers.Sandy 2012 inundation extent, NYC DEP stormwater scenarios, 2021 Ida USGS high-water marks, baked Prithvi-EO Ida-attributable polygons, USGS 3DEP DEM + HAND/TWI
KeystoneThe Asset Register. What's exposed.MTA subway entrances, NYCHA developments, NYC DOE schools, NYS DOH hospitals, TerraMind-NYC Buildings LoRA
TouchstoneThe Live Observer. Current state of the city.FloodNet ultrasonic depth sensors, NYC 311 flood complaints, NWS hourly METAR, NOAA tide-gauge water levels, Prithvi-EO 2.0 NYC-Pluvial v2, TerraMind-NYC LULC LoRA
LodestoneThe Projector. What's coming.NWS public flood alerts, Granite TTM r2 surge nowcast (zero-shot, 6-min cadence, 9.6 h horizon), per-address 311 weekly forecast, FloodNet sensor recurrence forecast, Granite-TTM-r2-Battery-Surge fine-tune (96 h hourly horizon)
CapstoneThe Synthesiser. Citation-grounded briefing.Granite 4.1 + Mellea rejection sampling

Each Stone fans its pebbles out in parallel as a Burr MapActions group; the Capstone then reconciles their documents into one cited briefing. Adding a data source is a new manifest in the deployment directory, not a code change.


The Five Stones beyond NYC

The Five Stones taxonomy is a city-agnostic template for any flood-vulnerable region with the right data scaffolding. The five roles generalise; only the probes plugged into each Stone change.

StoneRoleWhat you replace
CornerstoneHazard memoryLocal historical inundation extents, regional DEM, regulatory floodplain maps
KeystoneAsset registersThe transit, housing, education, and healthcare polygons your jurisdiction publishes
TouchstoneLive observationWhatever live sensors and complaint streams the city or region exposes (FloodNet has analogues in Houston, Boston, Miami)
LodestoneForecastsLocal NWS forecast office output, regional surge or hydrologic models, time-series fine-tunes for your tide gauge
CapstoneCitation-grounded synthesisSame

The architectural commitments transfer unchanged: a Burr FSM that fans pebble manifests out per Stone, Granite-native role="document" reconciliation, Mellea four-check grounding, SSE streaming to a SvelteKit map UI, every claim cited to its source. To port Riprap to a new city you write a deployment directory of manifests against local data and, for the satellite and time-series layers, retrain the EO and TTM fine-tunes on your jurisdiction's imagery and gauges. The agentic shell stays the same. See docs/PORT-YOUR-CITY.md.


NYC-specialised foundation models (Apache 2.0)

Three NYC-specific fine-tunes built on AMD Instinct MI300X via AMD Developer Cloud, published under permissive licence.

msradam/TerraMind-NYC-Adapters. LoRA family on TerraMind 1.0 base. LULC mIoU 0.5866 (+6.13 pp over full-FT baseline), TiM 0.6023, Buildings 0.5511. Trained in around 18 minutes on a single MI300X.

msradam/Prithvi-EO-2.0-NYC-Pluvial. NYC pluvial-flood fine-tune of Prithvi-EO 2.0. Test flood IoU 0.5979 vs 0.10 on the Sen1Floods11 base, a 6× lift. Lovász-Softmax loss with copy-paste augmentation.

msradam/Granite-TTM-r2-Battery-Surge. NYC Battery storm-surge nowcast fine-tune of Granite TimeSeries TTM r2. Test MAE 0.1091 m, 41% better than persistence and 25% better than zero-shot.

All three are loaded at runtime by their respective FSM probes in app/context/ and app/live/. Reproduction recipes live under experiments/18..21/.


Architecture

Address ──► Granite 4.1 3B planner ──► Plan{intent, targets, specialists}
                                                  │
                                                  ▼
                  Five-Stone Burr FSM (manifest pebbles, MapActions fan-out)
                            ┌───────────┬───────────┬───────────┬──────────┐
                            ▼           ▼           ▼           ▼          ▼
                       Cornerstone  Keystone   Touchstone   Lodestone  (cont.)
                       (hazard)    (assets)    (live)       (forecast)
                            │           │           │           │
                            └───────────┴─────┬─────┴───────────┘
                                              ▼
                         build_documents() — Granite-native
                         role="document <doc_id>" messages
                                              ▼
                  Capstone: Granite 4.1 8B + Mellea rejection sampling
                  ──► 4-check grounding loop, surgical feedback rerolls
                                              ▼
                       Four-section briefing with [doc_id] citations
                                              ▼
                       SSE stream → SvelteKit UI (briefing, trace, map)

The runtime is the manifest-driven framework under riprap/core/. A deployment is a directory of YAML pebble manifests plus a stones.yaml; the registry loads them and the Burr app fans each Stone's pebbles out in parallel. Adding a data source, or a whole new city, is configuration, not code. The legacy app/ modules remain for the register and multi-intent paths the framework has not yet absorbed.

LLM inference is dispatched through app/llm.py, a LiteLLM Router shim with two backends: Ollama (local dev, CPU) and vLLM (OpenAI-compatible, on Modal or a cloud GPU). Same chat() signature in both directions; vLLM is primary when configured, Ollama is the auto-failover.

Specialist ML inference (Prithvi-EO, TerraMind, TTM, GLiNER, Granite Embedding) goes over HTTP to a bearer-authenticated proxy, which stamps real GPU/Apple-Silicon power readings onto every response (see the energy section below). The specialist server is msradam/riprap-inference (LitServe) — one codebase, deployable to Modal (scale-to-zero, $0 idle) or run natively on a Mac Mini / Apple Silicon for MPS access. Granite 4.1 via vLLM is the same repo's second Modal app (its own GPU tier, its own image); any other OpenAI-compatible vLLM endpoint works too. See docs/DEPLOY.md for every combination.

Source-of-truth pointers:

  • riprap/core/pebbles/: the pebble framework — manifest schema, registry, and the adapters / shapers that normalize each source.
  • riprap/core/burr/: the Burr application — intake, per-Stone MapActions fan-out, and the reconciler tiers (llm / no_llm).
  • deployments/<city>/: the manifests, stones.yaml, data, and corpus that define one deployment.
  • riprap/core/compliance/: briefing-quality predicates audited per run.
  • web/main.py: FastAPI + SSE. The stream emits plan / step / token / mellea_attempt / final events plus the stone_start / stone_done envelope around each Stone group.
  • riprap/mcp/server.py: MCP server (python -m riprap.mcp.server) — lets an agent call Riprap as a tool: get_briefing, list_sources, get_citation.
  • web/sveltekit/: primary UI (SvelteKit + adapter-static).
  • app/llm.py: LiteLLM Router shim (Ollama / vLLM).
  • app/emissions.py: per-query Tracker + hardware profiles. Records every LLM and ML inference call with measured: bool.

For the long-form architecture document, see docs/ARCHITECTURE.md. Methodology and civil-engineering framing in docs/METHODOLOGY.md. Lit review in docs/RESEARCH.md. Deploy topology in docs/DEPLOY.md. Live measurements (wall-clock, real NVML energy, Mellea grounding pass-rate) in docs/BENCHMARKS.md.


Inference energy — measured, not estimated

Riprap reports the energy and token cost of every inference call it makes during a briefing. The status row on the Findings region displays a single chip:

✓ 1.4 Wh / 6.9K tok inference

The icon means every recorded call came back with a real reading off the inference GPU via nvmlDeviceGetPowerUsage. The proxy runs a 100 ms-cadence NVML sampler and stamps X-GPU-Power-W / X-GPU-Energy-J on every response; the LLM client brackets each completion with two GETs to /v1/power because LiteLLM hides response headers. When the proxy is unreachable, the chip shows ~ or and the row falls back to a data-sheet sustained- power estimate.

Per-call records carry prompt_tokens, completion_tokens, duration_s, power_w, joules, and a measured: bool flag. The full ledger is shipped on the SSE final event under emissions.calls, so any consumer (dashboard, billing model, reproducibility check) can reuse the data.

Detailed pipeline + verification recipe in docs/EMISSIONS.md.


Data sources

Riprap contacts only public-record federal, state, and city sources at runtime. No commercial APIs, no proprietary scores, no opaque aggregators.

SourceHosting agencyUsed for
Hurricane Sandy 2012 inundation zoneNYC OTI / NOAA Office for Coastal ManagementCornerstone hazard memory
NYC DEP Stormwater Flood MapsNYC Department of Environmental ProtectionDEP modeled-scenario layers
Hurricane Ida 2021 USGS high-water marksUSGS Short-Term NetworkEmpirical validation points
FloodNet ultrasonic sensor networkNYU CUSP / FloodNetHistorical flood-event log (labeled events, peak depths)
NYC 311 flood complaintsNYC Open DataEmpirical complaint history
NOAA tide gauge, The BatteryNOAA CO-OPSLive tide and surge level
NWS METARNational Weather ServiceHourly precipitation
NWS public flood alertsNational Weather ServiceActive warnings and watches
MTA subway entrancesMTA / NYC Open DataTransit asset register
NYCHA developmentsNYC Housing AuthorityPublic-housing exposure
NYC DOE schoolsNYC Department of EducationEducation-asset exposure
NYS DOH hospitalsNew York State Department of HealthCritical-facility exposure
USGS 3DEP 1 m DEMUSGS National MapHAND / TWI microtopography
NYC DOB filingsNYC Department of BuildingsDevelopment-check intent
NPCC4 SLR projectionsNYC Mayor's Office of Climate & Environmental JusticePolicy-context corpus (RAG)
Sentinel-2 MSI imageryESA / CopernicusPrithvi + TerraMind inputs

The full data licence map and vintage table is enumerated in docs/ARCHITECTURE.md.


Repository structure

riprap/core/               The manifest-driven framework (current runtime)
├── pebbles/               Pebble schema, registry, adapters, shapers
├── burr/                  Burr app: intake, per-Stone MapActions, reconcilers
└── compliance/            Briefing-quality predicates (FEMA / IPCC / TCFD / …)

riprap/mcp/                MCP server — Riprap as an agent-callable tool

deployments/               One directory per deployment
├── nyc/                   Reference: manifests, stones.yaml, data, corpus
└── chicago, seattle, sf, boston, …    Same shape, different city

app/                       Legacy modules still used by register + intent paths
├── llm.py                 LiteLLM Router shim (Ollama / vLLM)
├── emissions.py           Per-query energy + token ledger (real NVML)
└── geocode.py, registers/, intents/, context/, flood_layers/, live/

web/                       FastAPI + SvelteKit
├── main.py                FastAPI app, SSE streaming, layer endpoints
└── sveltekit/             Primary UI (adapter-static; build committed)

modal/                     Modal deploy of this app (CPU, scale-to-zero)
scripts/                   Probes, register builders, deploy commands
experiments/               Reproduction recipes for the three NYC fine-tunes
docs/                      ARCHITECTURE · DEPLOY · multi-city · PORT-YOUR-CITY · …
tests/                     pytest (pebbles, stones, routing) + vitest (UI)

The GPU/ML-specialist inference stack lives in a separate repo, msradam/riprap-inference (LitServe specialists + Granite 4.1 via vLLM, deployable to Modal as two apps, or a Mac Mini). inference/ and services/riprap-models/ in this repo are lighter self-host sidecars that predate it — see docs/DEPLOY.md.

CONTRIBUTING.md covers dev setup, the probe scripts, and house style. CHANGELOG.md tracks changes since the v0.5.0 hackathon submission.


Citation

If you reference Riprap in academic or professional work:

@software{riprap_2026,
  author       = {Rahman, Adam Munawar},
  title        = {Riprap: Composable, Citation-Grounded Civic Climate-Exposure Briefings for Any US Place},
  year         = {2026},
  url          = {https://github.com/msradam/riprap},
  version      = {v0.6.0},
  note         = {Originated as the AMD x lablab.ai Developer Hackathon submission; evolved into a multi-city, multi-hazard open-source framework}
}

License

Apache 2.0. See LICENSE and NOTICE.

The three NYC-specialised fine-tunes above are also Apache 2.0; underlying upstream models retain their own permissive licences (see each MODEL_CARD.md). Public-record data sources retain their own access terms; the licence map is in docs/ARCHITECTURE.md.


Acknowledgments

  • AMD Developer Cloud, MI300X compute that made the three Apache-2.0 NYC fine-tunes feasible.
  • AMD × lablab.ai Developer Hackathon, the venue.
  • IBM Research, Granite 4.1, Granite Embedding 278M, Granite TTM r2, Mellea, and the rest of the open-source Granite ecosystem.
  • NASA / IBM Prithvi-EO 2.0 and IBM / ESA TerraMind 1.0, the geospatial foundation models behind the NYC fine-tunes.
  • NYU CUSP / FloodNet, the public sensor network whose data Riprap reads live.
  • Andrew Hicks, civil-engineering review of the methodology.
  • The Riprap dam mark, "Dam" by Chintuza via the Noun Project, licensed CC-BY 3.0. The original SVG embedded the attribution as on-canvas text; Riprap's assets/logo*.svg strips the embedded text and carries the credit here in body copy instead, per the Creative Commons attribution requirement.

Contributors

msradam

28 commits

Languages

Python

50.8%

Jupyter Notebook

20.7%

TypeScript

9.5%

Svelte

8.4%

JavaScript

5.0%

CSS

2.8%

HTML

1.9%