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 toapplication/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
Log in or sign up for Devpost to join the conversation.