Inspiration
Small food banks run on volunteers, promised delivery windows, and one overloaded coordinator. When a municipal road-closure notice drops — on a state DOT feed nobody is watching at 7 a.m. — someone has to: notice it, work out which deliveries are actually affected, figure out whether a detour still keeps every promised window, and decide who to call. That is hours of invisible, repetitive work in the unattended hours — and it is exactly the work that breaks small community services quietly.
We built CivicRipple for the unattended hours.
What it does
CivicRipple is a community continuity agent for a small food bank's delivery operation:
- On watch, unattended. A background loop polls the real Washington State Department of Transportation RSS feed every few minutes. Each new notice runs end-to-end through the agent pipeline — no human trigger.
- Real interpretation, bounded geocoding. The extraction agent reads the notice text (no tools, schema-bound output). A deterministic geocoder maps recognized road names ("I-5 express lanes in Seattle") to approximate real corridors — the LLM never invents geometry; unmatched locations escalate to a human instead of being guessed.
- Deterministic impact. Every planned leg is tested for time AND space overlap against the disruption (half-open intervals + Shapely) — no LLM anywhere in this calculation.
- Safe rerouting. For affected routes the agent requests a detour from Amazon Location Routes with avoidance, then independently re-validates the returned geometry against the closure. Provider avoidance notices and local geometry must BOTH pass; otherwise the candidate is rejected.
- Hard-window feasibility. Arrival times are re-propagated over the detour; any hard delivery-window violation blocks automation and names the stop and the lateness in seconds.
- Three honest outcomes.
NO_IMPACT(recorded, zero interruption),AUTO_RESOLVABLE(applied automatically with a full audit trail), orHUMAN_DECISION_REQUIRED(the coordinator is interrupted with evidence). - The what-if console. During a review the coordinator doesn't just approve/reject — they negotiate: "drop this stop", "delay the departure", "shift this window". Each variant is re-run through the SAME feasibility and policy engines; the console shows the computed consequence before the human commits. An infeasible variant is refused with its computed reasons; one that passes every gate can be approved — decision, variant, and both review transitions audited.
- A ledger, not memories. Every state transition writes an append-only audit event (correlation ID, node, from/to state, structured facts, runtime mode) — queryable in the dashboard's Audit view and persisted to DynamoDB in cloud mode.
How we built it
The architecture is one thesis: LLMs interpret changing external reality; deterministic systems calculate operational impact; the orchestration layer decides when the human must return.
- Strands Agents SDK is the backbone: a ten-node Strands orchestration graph with typed conditional edges (conditional routing reads typed incident state, never string matching) and a custom offline model provider.
- Three schema-bound agents (extract, verify, options) run on Amazon Bedrock (Claude Sonnet 4.6) via Strands structured output. The extractor has no tools — browsed civic content is untrusted, and prompt-injection attempts are part of our test fixtures (they are inert by construction).
- A deterministic core — temporal overlap, Shapely intersection, arrival propagation, hard-window feasibility, fail-closed policy classification, and an explicit incident state machine — pure Python, zero LLM calls, every rule unit-tested.
- AWS: Amazon Bedrock, Amazon Location Service Routes (V2, avoidance + independent re-validation), DynamoDB (incidents + append-only audit), and the agent deployed on Amazon Bedrock AgentCore Runtime (direct-code deployment, arm64) — each replay in cloud mode is a real AgentCore invocation, proxied through the FastAPI backend via SigV4 (the browser never touches AWS).
- Dual runtime modes, visibly distinct.
MODE=awsruns everything against live AWS services.MODE=local_replayruns the identical product with a scripted offline model on cached real data — the full demo works with no AWS account, no API keys, no login. The dashboard badge shows the active mode at all times; the two modes are never silently swapped. - 192 tests, including the five acceptance scenarios executed end-to-end through the real Strands graph, plus real-AWS integration tests (gated, opt-in).
Challenges we ran into
- The Amazon Location Routes V2 response shape differs from its docs (no top-level summary; mixed vehicle/ferry legs; geometry must be explicitly requested) — we normalized against the real service, then made missing geometry fail closed.
- AWS
aws loginsessions expire every 12 hours — our watch loop reports credential failures honestly instead of pretending to work. - TLS-intercepting networks break Python's default certificate bundle — the source adapter trusts the OS certificate store directly.
- Our verifier agent twice refused synthetic fixtures as "unverifiable fiction" — correct behavior, which we honored by defining a simulation source contract in its prompt rather than weakening the check.
Accomplishments we're proud of
- The agent does real work end to end — read → verify → compute → reroute → escalate → apply — and the demo video shows it working on live public data, not canned slides.
- Every safety property is a test: unsafe detours rejected by two independent mechanisms, infeasible variants refused with computed reasons, silence is never approval, human-required incidents never expire into auto-approval.
- The what-if console: genuine human-agent collaboration where the human's intuition is checked by the same deterministic math the agent used.
What's next
- A real deployment partner (a local food bank) to validate the operation model and replace the synthetic plan with a real one.
- More municipal sources (other RSS/JSON feeds; browser automation for pages without feeds).
- Confirmed-geometry notices drawn as exact polygons; multi-route ripple handling for closures that cut several routes at once.
Built With
strands-agents-sdk, amazon-bedrock, amazon-agentcore-runtime, amazon-location-service, amazon-dynamodb, aws-cli, python, fastapi, pydantic, shapely, leaflet, playwright, kokoro-tts, pytest
Demo
- Video (2:42, narrated): https://youtu.be/u0DkOVIZ3Oc
- Repository: https://github.com/Siddhant75/civicripple
Testing instructions
No AWS account, API keys, or login are needed for the full demo — by
design. The project runs in two explicitly visible runtime modes:
local_replay (scripted offline model, deterministic) and aws (live
Amazon Bedrock + Amazon Location + DynamoDB). The dashboard badge shows the
active mode at all times; the modes are never silently swapped.
Requirements: Python 3.11+ and uv (https://docs.astral.sh/uv/).
git clone https://github.com/Siddhant75/civicripple.git
cd civicripple
uv sync --dev
MODE=local_replay uv run uvicorn civicripple.app:app --port 8000
Open http://localhost:8000 — then:
1. "Try a scenario" buttons run the four acceptance scenarios end to end
(watch the Map and Audit views for each).
2. "infeasible_reroute" lands in "Needs your decision": use the What-If
console (drop a stop / delay departure) and approve the working variant.
3. The On watch tab shows the agent's unattended activity + session report.
Optional (your own AWS account with Bedrock + Amazon Location access;
costs pennies): add WATCH_LIVE=1 MODE=aws AWS_PROFILE=<profile>
DYNAMODB_TABLE=<table> to run the same flows through live Bedrock and the
deployed Amazon Bedrock AgentCore Runtime (infra/agentcore/deploy.py).
Test suite (192 tests, no AWS required):
MODE=local_replay uv run pytest tests/unit tests/scenarios -q
Built With
- amazon-agentcore-runtime
- amazon-bedrock
- amazon-dynamodb
- amazon-location-service
- fastapi
- leaflet.js
- pydantic
- pytest
- python
- shapely
- strands-agents-sdk
Log in or sign up for Devpost to join the conversation.