Inspiration
Splitting expenses is not an arithmetic problem — a calculator solved that decades ago. It is a capture problem. Nobody unlocks a phone and opens an app at a restaurant table, so the expense goes unrecorded, and a week later the evening is settled from memory and somebody quietly eats the difference.
Voice removes the capture cost: you say it while the bill is still in your hand. And Alexa is not a personal device — it sits in the kitchen and belongs to everyone in the apartment. A shared ledger on a shared device is something a per-phone app structurally cannot be.
Try it
https://tally-playground.onrender.com — press the ring and talk, or type. You are Sam in a private sandbox household with Chris and Maya.
The Alexa+ simulator is partner-only, so this page plays the device and nothing else: the browser turns speech into text, a language model routes the sentence to one of the tools the server publishes (the grey line under each sentence is that call), the real Tally MCP server runs it, and its own text is read aloud verbatim while the ui:// balance sheet updates on a mock Echo Show. The router's reply is schema-constrained to the server's published tools and their argument schemas, so it cannot call anything else; if the model is slow, a second copy of the request races the first, and if both fail a small pattern router answers and the page says so. The free instance sleeps after 15 minutes idle; the first request then takes about a minute.
What it does
Eight tools cover the whole loop: record an expense, ask who owes what, ask what you owe one person, settle up, undo a misheard entry, add someone, start a household, review recent activity.
Answers are written to be heard once — they lead with what to do, not with a table nobody can hold in their head. On a device with a screen, the same call also carries a balance sheet rendered through MCP Apps. Settling up uses the standard greedy max-debtor/max-creditor match, so it never needs more than n-1 payments against the n(n-1)/2 of paying everyone back individually.
How I built it
Three decisions shaped everything.
The spoken answer is the product; the screen is a bonus. client_supports_apps() decides only how much has to be said out loud, never whether the answer arrives. A device with no display loses the picture and nothing else, and both paths are tested.
Never guess whose money it is. Speech recognition is lossy, so names resolve exactly, then by unambiguous prefix. "An" with both Anna and Andrew in the flat does not pick one — it asks over MCP elicitation, and falls back to putting the question in the error text when the host has no back-channel.
Money is integers, end to end. Every amount is a count of minor units and floats never touch the arithmetic. A three-way split of 10.00 cannot be equal, so the odd cent rotates instead of always landing on the same person.
Challenges I ran into
Fourteen defects surfaced only under adversarial tests, and four of them would have cost real money.
parse_amount filtered out non-digits, so "1e10" silently became 11000 and "12abc34" became 123400 — a wrong number nobody would notice.
Account linking matched on a name. Anyone who guessed a flatmate's first name could attach their own Alexa to somebody else's ledger. Names are not secrets; joining now needs a single-use invite code.
A race on entry ordering meant two flatmates recording at once could make "undo the last one" delete somebody else's expense.
And a retransmitted utterance recorded a second expense, because nothing deduplicated writes. Alexa+ retries; the ledger now recognises the same utterance arriving twice.
None of these would have been found by reading the code.
Accomplishments that I'm proud of
265 tests in eight layers, including property-based tests that hold for any generated history: balances always sum to zero, the suggested transfers always clear the ledger, and there are never more than n-1 of them.
The OAuth layer is tested against the attacks it exists to stop — replayed authorization codes and forged PKCE verifiers both fail — and the concurrency tests fire two dozen simultaneous writers at one household.
What I learned
Amazon runs this hackathon to collect feedback on a new toolkit, so the depth that counts is protocol conformance, not domain exotica. Writing the friction log honestly taught me more about the SDK than the documentation did — and one entry, that live updates are unreachable at the very protocol version Alexa+ negotiates, only became visible because I tried to ship the feature rather than describe it.
What's next for Tally
Multi-currency households, leaving a household, timestamps in the activity log, and a push path for hosts on protocol 2025-11-25 — which today has none.
Log in or sign up for Devpost to join the conversation.