Steward
An AI agent that carries one neighborhood problem from first report to verified cleanup — and a working study of where an agent's judgment should stop and the system's authority should begin.
By Elijah Leung · Updated
Why it exists
A service ticket says “completed.” A newer photo still shows a couch on the sidewalk. Reporting a problem is only the start: someone still has to connect duplicate observations, decide whether the problem persists, work out who is allowed to act, arrange the work, and check that it actually happened. A closed record and a crew's completion claim can both disagree with the physical evidence.
Steward grew out of the Good Neighbor Agents track of the AWS Agents for Humans Hackathon and one question it raised: can an agent carry that context across the whole process — including knowing when to wait and when to hand a decision back to a person — without holding authority, money, or verification it should not have?
It was also a hands-on way to go deep on Strands Agents, Amazon Bedrock, and the practical work of hosting an agent-backed application on AWS.
One couch, five decisions
The prototype is scoped to a single dumped couch in a seeded Chicago neighborhood. The small scenario is deliberate: it puts every consequential decision on screen — conflicting evidence, spending permission, failed proof, human intervention, and resolution.
- Wait — the first report scores 65 against a 70-point action threshold, and a seeded 311 record says the job is already done. Steward records the conflict and keeps watching.
- Reconcile — a second, independent report raises the score to 85. Two observations newer than the official completion confirm the dispute, and crediting the matching record brings it to 100.
- Arrange — Steward picks an eligible provider; the API checks the district's authority and budget, computes the fixed $72 quote, and reserves the funds for a simulated dispatch.
- Reject — the first completion photo scores 90 against 95 required. The API blocks payment and routes the exception to an operator.
- Resume — the operator requests completion, fresh proof scores 100, one simulated payment settles, and the case resolves. The $500 demo budget ends at $428.
The scores are explicit rules over stored evidence and structured image findings, not model confidence percentages. Every step is persisted, so the board, issue timeline, and operator inbox render what actually happened rather than an invented transcript.
Judgment versus authority
The central design problem was the line between what the model decides and what the system permits. The model interprets messy reports, proposes matches and categories, reasons about contradictions and responsibility, picks among eligible providers, and chooses its next tool. Deterministic code computes evidence scores, enforces authority and eligibility, prices the work, reserves budget, checks verification, and permits or denies every change.
- Policy at every mutation — a proposed action cannot bypass authority, budget, or completion requirements, even when the API is called directly.
- One HTTP boundary — the agent and the React app call the same actor-bound endpoints, so policy lives in exactly one service.
- Transactional money — reserve once on dispatch, consume once on settlement, release once on cancellation; retries and recovery cannot duplicate a job, a reservation, or a payment.
- No immortal session — when a decision belongs to a person, Steward persists the exception and stops. The operator's choice starts a fresh, bounded run over the saved context.
Refusing a payment, choosing to wait, and resuming after a human decision needed as much care as the successful path. Persisted records and visible evidence are what make those choices inspectable after the agent has finished running.
Proof before payment
Completion photos go to a trusted inspection service on Bedrock that returns structured, nullable findings: was the target there before, is this the same scene, was it removed, is the area clear, is there a new hazard. Unknown is never treated as true. Deterministic code combines those findings with GPS check-in and timestamp consistency into a score out of 100, and automatic payment requires 95.
Gates sit in front of the score. A reused or mismatched photo cannot pass just by scoring well, and missing or ambiguous proof routes to manual review instead of settlement. A prohibited hazard mixed into an ordinary job blocks the cleanup — picking a harmless category cannot erase the hazard.
What shipped
The repository holds the agent workflow, the policy-enforcing API, persistent storage, proof inspection, a demo driver, and five React surfaces: Operations Board, Issue Detail, Operator Inbox, Crew Form, and Resident intake. It was deployed on one EC2 instance behind CloudFront, with SQLite and evidence images on a retained volume and private S3 backups.
- Acceptance — 16/16 local API criteria in a repeated live Bedrock workflow; the hosted copy passed criteria 1–15 and kept its state through a service restart and an instance reboot.
- Tests — 706 offline tests on the clean-install candidate, none needing AWS credentials, and 68 frontend tests on the reviewed UI release.
- Vision check — 12/12 expected outcomes in a narrow, fixture-based qualification — a component check, not a general accuracy benchmark.
- Cost — about $3.75 of Bedrock inference for one complete couch walk, measured in CloudWatch; image tokens dominate.
The scope is deliberate: one seeded scenario, synthetic photos, and simulated dispatch and payment, because the point was to prove the control loop rather than move real money or authorize real municipal work. The code, tests, and dated verification receipts are public in the repository.
Where it could go
The larger idea is an operating layer for a district — its area, policy, budget, approved providers, and authority — that maintains the place through existing systems and surfaces only the decisions outside its authority. That is direction, not shipped functionality.
- Broader evaluation — varied cases and images beyond the seeded couch, then a fully browser-driven acceptance run.
- A real operator — walk an actual neighborhood operator through the demo and learn the real budgets, authorization, contracting, and verification constraints before building more.
- Managed runtime — AgentCore Runtime, Observability, and Gateway are the planned next hosting step; they would run the same agent over the same tools.
Architecture
One agent, one service, one state owner. Each accepted event starts a bounded agent run; the agent reaches the system only through typed HTTP tools; the service owns the records and decides whether each requested change is allowed.
Operations UI
five roles, one record
- Operations Board — map · budget · case status (Status: shipped)
- Issue Detail — evidence · decision timeline (Status: shipped)
- Operator Inbox — exceptions · one decision (Status: shipped)
- Crew Form — accept · check in · proof (Status: shipped)
- Resident intake — report · photo (Status: shipped)
Agent loop
one Strands agent on Bedrock
- 1 - Event starts a run — bounded · journaled (Status: shipped)
- 2 - Gather evidence — reports · 311 · geocode (Status: shipped)
- 3 - Reason, choose tools — Claude Sonnet 4.6 (Status: shipped)
- 4 - Request gated actions — dispatch · inspect · pay (Status: shipped)
- 5 - Close or hand off — persist exception · stop (Status: shipped)
Policy service
FastAPI owns every change
- Policy gates — authority · category · budget (Status: shipped)
- Evidence scoring — explicit points · 70 to act (Status: shipped)
- Proof verification — structured findings · 95 to pay (Status: shipped)
- Budget ledger — reserve · settle · release (Status: shipped)
- Trusted image inspector — Bedrock vision role (Status: shipped)
State & hosting
one durability owner
- SQLite store — cases · jobs · append-only events (Status: shipped)
- Invocation journal — resume after restart (Status: shipped)
- EC2 + CloudFront — retained volume · S3 backups (Status: shipped)
- AgentCore — runtime · observability · gateway (Status: planned)
The model never holds the pen on money or permission. It reads evidence and asks; the service checks and answers. That split is what let the agent refuse a payment, wait for a person, and pick the case back up on a fresh run without losing the thread.
Decisions
- Policy enforced at every API mutation — An instruction in a prompt is a request, not a control. Putting authority, budget, pricing, and completion checks in the service that owns the records means a model's proposed action and a direct API call get the same answer. The agent can be wrong without the system being wrong.
- Explicit evidence points over structured findings — Thresholds like 70 to act and 95 to pay only mean something if they are reproducible. Vision returns structured findings, and deterministic rules turn them into points anyone can recompute from the stored evidence. Unknown findings stay unknown, so uncertainty routes to a person instead of quietly passing.
- Cheapest model that passes each role's checks — Text reasoning and photo inspection got separately configurable models. Eight models passed a basic tool check; of the five also given the same four photo comparisons, only Claude Sonnet matched every expected outcome — three cheaper models accepted partial cleanup. Sonnet stayed the inspector until a cheaper candidate qualifies.
- Persist, stop, and resume on the next event — When a decision belongs to a person, Steward saves the exception and ends the run. The operator's choice arrives as an event that starts a fresh, bounded run over saved context. Nothing spends tokens while it waits, and a restart mid-run resumes from the journal.
- One EC2 instance behind CloudFront — SQLite and the evidence images needed durable disk, App Runner's filesystem is ephemeral, and AgentCore was optional integration work that would not change the core loop. One small instance with a retained data volume, private S3 backups, and CloudFront for HTTPS kept a single transaction owner inside a $50 spend ceiling.
Stack
- Strands Agents — Agent framework One agent with typed HTTP tools. The SDK runs the tool loop; the service keeps the authority.
- Amazon Bedrock · Claude Sonnet 4.6 — Text reasoning and image inspection Two independently configurable roles. Sonnet was the only screened model that matched every expected photo outcome, so it serves both for now.
- Python + FastAPI — Policy service and API Owns every mutation, the invocation journal, and the trusted inspector. The agent and the UI share its endpoints, so policy is never written twice.
- SQLite — Transactional state Cases, jobs, the budget ledger, and append-only events commit together under one owner, with money kept in integer cents.
- React + TypeScript + Vite — Five operations screens Board, Issue Detail, Inbox, Crew Form, and Resident intake render persisted events, typed against the API's OpenAPI schema; Leaflet draws the map.
- EC2 + CloudFront + S3 — Hosting One instance with a retained data volume, HTTPS at the edge, an instance role instead of keys, and private backups every six hours.
- pytest + Vitest — Verification 706 offline tests run without AWS credentials and 68 frontend tests cover the UI release; dated receipts record what was verified and when.