Inspiration

Hydropower runs 6% of the US grid and blocks 17 ESA-listed salmon populations from spawning. Designing a fish ladder to fix it takes a senior CFD engineer weeks, and most small fisheries can't afford one. I wanted to collapse that to 30 seconds.

My mom works on hydroelectric and fish-passage projects. She's the reason I knew this problem existed at all, and when I hit a wall mid-build searching for the right regulatory sources, she pointed me at the references that ground every verdict.

What it does

Upload an STL + species + life stage. FishFlow runs a full CFD simulation on AWS, checks the result against published USFWS fish-passage criteria, and returns a regulator-grade PDF verdict in ~30 seconds. ~$0.20 a run, zero at idle.

How we built it

  • Architecture: CloudFront → API Gateway → Lambda → S3 events → Router Lambda → transient Fargate task running OpenFOAM from ECR.
  • Six steps, two AI calls: translate (Sonnet 4.5), mesh, solve, render, assess (Sonnet 4.5), report. Both LLM calls run on AWS Bedrock in us-west-2.
  • LLM narrates, engine decides: a deterministic engine checks $\text{EDF} \leq 200~\text{W/m}^3$ and $v_{\max} \leq 2.4~\text{m/s}$. The LLM only writes the prose around the verdict; it cannot override pass/fail.

Challenges we ran into

  • OpenFOAM on serverless. Needed Fargate (Lambda won't run it), pinned by ECR digest.
  • Presigned URL signature mismatch. S3 V4 signs Content-Type; backend and frontend now both lock to application/octet-stream.
  • Sandbox carbon data trap. ElectricityMap's free key returns intentionally wrong numbers (30 vs ~140 gCO₂/kWh) with a buried _disclaimer. We built a three-tier live, regional stub, hardcoded fallback to catch it.

Accomplishments that we're proud of

  • 30-second end-to-end pipeline: CFD plus two LLM calls plus regulator-grade PDF.
  • LLM cannot override a failing verdict; the result is auditable line-by-line.
  • A carbon-data fallback that refuses to ship wrong-but-plausible numbers.
  • AWS-native LLM serving via Bedrock in us-west-2. Every translate and assess call originates from the same BPAT-region AWS infrastructure as the CFD compute. OpenRouter remains a one env-var rollback.
  • ~$0.20 a run, zero at idle.
  • 150+ passing tests across the Python services and TypeScript frontend, including paid end-to-end smokes.

What we learned

  • The "LLM narrates, engine decides" split generalizes to any regulated context: medical, financial, safety-critical.
  • Scale-to-zero is an access-equity choice. A small fisheries office can run this on a grant.

What's next for FishFlow

  • Autonomous design. Go from "verify a human-designed ladder" to "synthesize the ladder from constraints" (species, life stage, head drop, footprint) and verify against the deterministic engine in the same loop.

Built With

  • amazon-api-gateway
  • amazon-bedrock
  • amazon-cloudfront
  • amazon-cognito
  • amazon-ecr
  • amazon-web-services
  • anthropic
  • aws-cloudformation
  • aws-fargate
  • aws-lambda
  • aws-sam
  • claude
  • docker
  • electricitymap
  • graphviz
  • jinja
  • matplotlib
  • openfoam
  • pytest
  • python
  • react
  • tailwindcss
  • typescript
  • vite
  • vitest
  • weasyprint
Share this project:

Updates