
Agents for Humans: how VolunteerShift's Strands agents staff a shift with zero clicks ?
The problem is boring on purpose. A coordinator loses 22+ hours a week matching people to shifts, chasing replies, sending reminders and finding cover. None of it needs judgement; it needs persistence.
We built VolunteerShift for the AWS Agents for Humans hackathon: an autonomous volunteer coordinator for mid-size nonprofits, live at https://volshift.xyz.
The shape of it
Five Strands agents, each with its own tool subset: Scheduler, Communicator, Recovery, Tracker, Reporter. Mistral Large 3 on Amazon Bedrock. DynamoDB for state, SES for email in both directions (a receipt rule → SNS → Lambda bridge applies YES/NO replies), CloudWatch for metrics. A background worker owns the calendar: schedule → invite → T-48h → T-2h → T+15m no-show check → hours at the end.
The two Strands features that did the most work
Hooks. A BeforeToolCallEvent hook refuses send_email/send_sms without a well-formed recipient and rejects SSN/card patterns from any tool input. An AfterToolCallEvent hook writes every call — name, input, result, timestamp — to a DynamoDB audit table. The coordinator dashboard is literally a view of that table.
A reliability hook. Agents sometimes narrate instead of act ("I would now assign…"). Ours re-prompts an agent that finishes without calling its required tool, so schedule always ends in assign_volunteers_to_shift and invite always ends in log_communication.
Give the agent the data, not the lookup
The Communicator has no query tools. Its caller pre-fetches each volunteer's address and one-tap link and hands them over in the prompt. It cannot invent an email address, and it copies the link character for character. Fewer tool round-trips, zero hallucinated recipients.
The audit table found both of our real bugs
- Our first demo take: the Scheduler ran, the matcher returned nothing, assign was called with an empty list. The audit row said: "Invalid isoformat string: '2026-09-19T09:00:00.000Z'". The server's Python 3.10 rejects a trailing Z; the dashboard now sends +00:00.
- A live test stalled: the model computed the shift's weekday itself, got it wrong, filtered the pool to zero and gave up. We routed the prompt through the matcher tool and turned on consistent reads.
Neither would have been found from the agent's own summary — it reported success both times. Trust the tool results, not the narration.
What the demo shows
A real shift posted, the worker firing 65 seconds later, 2 of 54 volunteers matched on a Spanish requirement, two SES message IDs, a confirmation from a phone updating the coordinator's screen on its own, 2/2 filled. Eight tool calls, zero coordinator actions after posting.
Code: https://github.com/Sektorial12/VolunteerShift
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article