Volunteers run on their inbox. Nobody has time for it.
Small organizations (food pantries, shelters, parish offices) lose hours to the same emails: are you open Thursday, can I donate furniture, how do I start volunteering. The usual chatbot answer is to hand the inbox to an LLM and hope. Verger does the work, but a human holds the send button.
What it does
Verger is a front-desk agent that reads the organization inbox end to end. For every message it drafts a reply and queues it for the trustee's explicit yes, declines politely, or stays silent. Every autonomous action lands in a hash-chained receipt ledger a human can audit.
The gate. A Strands BeforeToolCallEvent hook checks every tool call against the allowlist and raises an interrupt before anything leaves the agent. Approving sends bit-for-bit what was reviewed; denying retires the paused session. Nothing is sent without the trustee. Watch it happen in the demo video.
The receipts. An append-only sha256 hash chain, self-verifying on every append. The desk shows the ledger's own verdict and never re-derives hashes client-side.
The desk. One screen for the trustee: a decision bell that swings when a send is waiting, one-click approve or deny, and the full chain verdict in view.
How we built it
- Strands Agents SDK (TypeScript,
@strands-agents/sdk): the Agent class,tool()helpers, and interrupt-based human-in-the-loop as enforcement, not decoration. - Serverless rounds: one inbox message per function invocation, chained by the desk client, with a single-flight lock so an unattended cron tick and the trustee can never double-hold the same message.
- Netlify Blobs holds all state: mailbox, sent folder, receipt ledger, pending decisions. No server, no disk.
- gpt-oss-20b on Groq's OpenAI-compatible endpoint as the demo brain.
Try it
The live desk ships with a seeded demo mailbox: run a round, the agent works the inbox, the bell rings, you decide. Source is on GitHub.
Challenges
- Fresh agent per chunk: shared conversation state made the model answer the previous sender. Zero cross-chunk state fixed it.
- Every "just let the model decide" shortcut failed the trust bar. The gate is real because the trustee's decision executes deterministically.
- Status chrome must never lie: the receipt chain verdict comes from the writer, never from a stale cache re-derivation.
Built With
- groq
- netlify
- netlify-blobs
- netlify-functions
- nextjs
- sha256
- strands-agents-sdk
- typescript
Log in or sign up for Devpost to join the conversation.