Inspiration
Inspiration
Growing up, my mother was the treasurer of her chama, an informal savings group common across Kenya and much of Africa under different names: stokvels in South Africa, esusu in Nigeria, iqub in Ethiopia, tontines in West Africa. Every month, I watched her wait for M-Pesa confirmation messages to trickle into a WhatsApp group, then cross-check every single one by hand against a notebook. She'd chase down members who "forgot" to pay, and settle arguments about whose turn it was for the payout. It looked like love. It was also unpaid, exhausting admin work.
That scene isn't unique to my family. In Kenya alone, there are over 300,000 chamas managing roughly KSh 300 billion (about $3.4B) in combined assets, and for the 6.4 million Kenyans who remain unbanked, chamas are often their only point of access to a financial system. But the trust these groups run on is fragile: research from FSD Kenya found that 13% of chama funds are lost to theft or embezzlement, and most chamas don't survive past two years, largely because manual, error-prone record-keeping erodes trust faster than the group can rebuild it.
I built Chama Keeper for the tool I wished my mother had.
What it does
Chama Keeper is an autonomous AI agent that takes the manual reconciliation burden off a chama treasurer's hands, without replacing her judgment. It:
- Reconciles M-Pesa contribution confirmations automatically, matching sender to member and updating balances
- Nudges members who are behind, sending a warm, non-shaming reminder rather than a robotic one
- Flags disputes it genuinely can't resolve on its own (an unmatched sender name, an unexplained overpayment) for a human treasurer to review, instead of guessing
- Calculates the payout rotation once every member's balance clears
- Lets the treasurer resolve disputes directly, which unblocks the payout once she's made the call
Everything runs through a Flask dashboard where the treasurer can see member status, the disputes queue, and the payout rotation at a glance, instead of a scattered mix of WhatsApp screenshots and a notebook.
How I built it
The core of Chama Keeper is a single reasoning agent built with the Strands Agents SDK, running on Claude via Amazon Bedrock. Rather than a rigid rules engine, the agent reasons over each incoming M-Pesa message and decides which of five tools to invoke: reconcile_payment, flag_dispute, send_nudge, calculate_payout, and resolve_dispute. All five tools read and write to one shared state object (members, disputes, activity log), which a Flask backend exposes through a REST API and serves to a browser dashboard.
For the demo's messaging layer, I integrated Twilio's WhatsApp Sandbox so nudges are delivered as real WhatsApp messages, not just simulated console output.
Challenges I ran into
Judgment over automation. Early on, every payment mismatch, including simple partial payments, was treated as a dispute. That was wrong: someone paying Ksh300 against a Ksh500 obligation isn't a problem, it's just not finished yet. I reworked the logic so partial payments update a running balance automatically, and disputes are reserved for cases the agent genuinely can't resolve, like a sender name close enough to a real member's that it could be a nickname, a family member, or something else entirely. Watching the agent flag exactly that case, reasoning through the ambiguity out loud instead of guessing, was the moment the project clicked.
Bedrock model access. My first run threw a ResourceNotFoundException. First-time AWS accounts have to submit a short use-case form to Anthropic before invoking a model at all, separate from the standard model access toggle, with roughly a 15 minute wait after submission.
Twilio sandbox limits. Twilio's trial account only delivers messages to numbers that have explicitly joined the sandbox, so my sample member phone numbers could never receive real messages. I routed the demo's outgoing nudges to a verified test number while keeping the member's name in the activity log, so the underlying send_nudge logic stays accurate to how it would work in production.
Environment friction. A fair amount of time went into Windows-specific quirks: PowerShell versus Git Bash syntax differences, missing Unix utilities throwing cosmetic (but alarming-looking) warnings, and remembering that a terminal-run script and a running Flask dashboard don't share memory unless you design them to.
Accomplishments that I'm proud of
The agent's dispute-flagging logic is the part I'm most proud of. It isn't just pattern-matching on amounts, it's making a real judgment call about when a human needs to be in the loop, and explaining its reasoning when it defers. That distinction, between what an agent can safely automate and what it should hand back to a person, is the actual hard problem in building trustworthy financial agents, and I think Chama Keeper handles it well for a hackathon timeline.
What I learned
I learned the Strands Agents SDK from scratch over the course of this build, and came away with a much clearer sense of how to design tool boundaries so an agent's autonomy matches the actual stakes of a decision. I also learned, again, that sandbox and trial-account limitations (Twilio, Bedrock approval) are a normal part of building fast under a deadline, not a sign something is broken, and that routing around them for a demo is often the right call rather than blocking on making them production-perfect.
What's next for Chama Keeper
- Real M-Pesa integration via Safaricom's Daraja API, replacing sample data with live transactions
- USSD support so members on feature phones, not just smartphones, can participate
- Multi-group support for treasurers who manage more than one chama
- Expanding the dispute-resolution flow with a lightweight chat interface so treasurers can resolve issues in natural language instead of structured forms
Log in or sign up for Devpost to join the conversation.