Inspiration
There are times when a friend covers your dinner or your Uber and you genuinely forget to pay them back, not because you don’t care, but because life moves fast and nobody keeps track, and those small forgotten moments add up into silent resentments that slowly change how friendships feel without anyone ever saying a word. Money is one of the hardest things to talk about with people we’re close to, and surveys show it, with two-thirds of Americans skipping a social plan they couldn’t afford and more than half of them never telling anyone the real reason. We kept asking ourselves two questions we couldn’t answer, how much do our friends cost us, and how much do we cost them, and we realized that our bank statements, calendars and messages already held the answer, it just wasn’t connected anywhere.
What it does
Even Stevens looks at your transactions, your calendar and your messages together, works out which friends you were with each time you spent money, and shows you how much you spend with each person, what you usually do together and how that’s changing over time. It also catches the moments your bank can’t see, like the dinner where a friend quietly covered you, by spotting hangouts that clearly happened but have no matching charge from you, and it compares what you paid against what that outing usually costs per person to tell whether you paid your share, covered someone else, or got covered. Everything works from one person’s data, so your friends never have to sign up, and the dollar amounts stay private to you.
How we built it
Even Stevens is a TypeScript monorepo with a React Native app built on Expo, a Fastify backend, and Postgres on Tiger Data with pgvector, all sharing one set of zod schemas. The pipeline turns data from Capital One’s Nessie API, message exports and calendars into events, links them across days so Tuesday’s plan connects to Friday’s dinner, and uses Meta’s Muse Spark to read the chats for signals like who’s going, who said “I got it,” and whether a plan was cancelled.
Those signals feed a two-stage multinomial logistic regression that decides whether an event never happened, was solo, or was social, and then whether you paid your share, covered others, or got covered, while a separate model estimates who was actually there. When nobody states a price, RAG over your messages with Gemini embeddings finds what people said a place cost, and the same retrieval surfaces shared interests so SerpApi can price new things to do together when you owe someone. All money math happens in code, and LangSmith traces every step so we can see where a wrong number came from.
Challenges we ran into
The hardest problem was deciding what counts as truth, because a transaction proves you spent money but nothing in your own data proves a friend paid for you, so we treated transactions as the anchor, used calendar and chat as supporting evidence, and let user confirmations settle the cases nothing else could. Our first version used a fixed rule that only counted events with at least two people, a payment and two sources of evidence, which was reliable but threw away real outings that only one source captured, and replacing it with a trained classifier meant building a synthetic dataset large enough to learn from without losing an honest evaluation. Getting message data was its own challenge, since no Meta API exposes personal chats, which pushed us toward exports and screenshots instead.
Accomplishments that we're proud of
We’re proud that the system answers a question nobody could answer before, how much you actually spend with each friend, automatically and without asking anyone else to install anything, and that every number it shows can be traced back to its evidence. We’re also proud of how much the idea grew, from a spreadsheet of costs into something that helps people keep their friendships even and keep showing up for each other.
What we learned
We learned that the best split of work between a language model and code is to let the model read and let the code decide, since an LLM that extracts signals and a regression that weighs them is easier to debug, cheaper to run, and more consistent than asking a model for the final answer. We also learned that evaluating a chain of model calls means tracing the whole run rather than testing prompts one at a time, and that synthetic data with known ground truth is what makes it possible to train and measure a system like this before it has real users.
What's next for SARK
Next, we want one-tap connection to Instagram and Messenger through Meta’s data portability program, a review queue ranked by how many dollars each answer would fix, and group plans that fit everyone’s budget without anyone having to say what they can afford.
Built With
- embeddings
- expo.io
- fastify
- gemini
- langsmith
- muse
- pglite
- pgvector
- postgresql
- react-native
- serpapi
- tanstack
- tiger
- typescript
- vitest
Log in or sign up for Devpost to join the conversation.