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), or HUMAN_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=aws runs everything against live AWS services. MODE=local_replay runs 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 login sessions 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

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

Share this project:

Updates

Submission history