TAB.
The expense agent in your iMessage conversation.
A HackNC 2026 expense agent that turns iMessage conversations and receipt photos into trip ledgers, dispute workflows, and Solana devnet settlements.
HackNC team · Ayug Poudel, Prasun Sapkota & Amit Khanal
HackNC 2026 / Messaging agent + ledger + devnet settlement
Built collaboratively at HackNC 2026 by Ayug Poudel, Prasun Sapkota, and Amit Khanal. The case study describes the complete team application verified in the supplied public repository; it does not assign every subsystem to one contributor.
Inside this case file 12 sections
Product Overview
TAB is an AI-powered expense agent with an iMessage entry point. Friends create or join trips, text expenses or receipt photos, inspect balances, dispute a charge, and request settlement. A mobile trip page provides the line items and transfer history behind the conversation.
The product includes participant registration, multiple open trips, equal and itemized splits, balance explanations, disputes and their resolution, reminders, trip closure, and devnet payment execution. The central interface is the conversation; the web experience supports onboarding and transparent inspection of the ledger.
Problem and Solution
On a shared trip, the hard part is not simply dividing a total. People participate in different purchases, receipts arrive later, two people may owe each other, and a disputed item should not silently remain payable.
TAB makes the trip ledger accessible through natural language and gives each balance a traceable set of expense shares and transfers. Questions such as who participated, which trip an expense belongs to, and why a person owes an amount become part of the application workflow.
Messaging and Product Flow
Photon Spectrum supplies inbound iMessages and attachments through its SDK stream and sends outbound responses. The shared-number setup uses individual conversations and project-user registration; the application does not claim native group-chat participation.
The adapter merges text and image messages from the same sender over a short window so a receipt and its instructions can be processed together. The agent maintains per-sender queues and persisted pending conversation states for follow-up questions, names, trip selection, item assignments, and dispute answers.
- 01
Register a participant, create a trip, and share its invitation.
- 02
Receive a natural-language purchase or receipt image through Photon.
- 03
Resolve the trip, payer, amount, and intended participants.
- 04
Compute and persist the expense and shares; notify the people involved.
- 05
Expose balances, explanations, disputes, and settlement through messages and the trip page.
System Architecture
The inspected application runs TypeScript on Node.js with Hono for web routes and SQLite through better-sqlite3 for persistence. Messaging, AI interpretation, ledger calculations, storage, and chain operations sit behind distinct interfaces.
Gemini reads language and receipt content into a bounded intent or receipt shape. The agent resolves that interpretation against real participants and trips before invoking deterministic operations. The model does not calculate trusted balances, produce arbitrary messages to friends, or execute an unrestricted tool loop.
Receipt Processing and Exact Splits
Gemini’s receipt path requests structured JSON containing merchant, date, item amounts, subtotal, tax, tip, and total. The image-processing helper resizes inputs for the model; receipt consistency checks compare item and total arithmetic before the result is described as matched.
Financial values are represented as integer cents. Equal splits and weighted allocation use a largest-remainder method so the allocated shares sum back to the total. Itemized splitting distributes each item among its participants, then allocates tax, tip, and rounding differences proportionally.
Unspecified participants, missing totals, or unresolved item assignments trigger follow-up questions. Failed receipt interpretation becomes a request for clarification instead of an invented amount.
Trips, Disputes, and Transaction History
A participant can belong to several trips. Named-trip matching, active-trip context, and explicit clarification handle ambiguous messages. The same persisted expenses, shares, and transfers power running balances, line-by-line explanations, reminders, and the trip page.
The current code logs shares as active immediately and supports a dispute-first workflow. Disputing a share removes it from payable calculations. A payer can supply a receipt to restore the contested share or agree to remove the participant and re-split the expense among those remaining.
Settlement uses pairwise netting so the person named in a balance explanation is also the person paid. A separate global-netting helper exists, but the active trip ledger prefers understandable creditor relationships over routing money through unrelated participants to reduce transfer count.
Backend and Data Architecture
SQLite stores users, trips, membership, expenses, per-person shares, transfers, pending conversations, and payment nudges. Expenses retain receipt metadata and active/deleted state; shares retain participation and dispute state. Related expense-and-share changes use store transactions.
Hono serves organizer registration, invitation acceptance, per-trip pages, manifests, and generated preview-card assets. The trip page uses server-rendered HTML plus browser JavaScript to display people, expense details, balances, and on-chain transfer links. It is not a React frontend in the reviewed repository.
Railway is documented as a long-lived container with persistent SQLite storage. That deployment shape supports the Photon stream, timer, and database file in one process; it is a hackathon-scale operating model rather than a claim of distributed infrastructure.
Solana Devnet Settlement
The chain adapter creates per-member custodial wallets and encrypts their secret material with AES-256-GCM. A treasury sponsors fees and funds the custom devnet mint. Transfers use the SPL checked-transfer instruction and convert cents to the token’s six-decimal base units with integer arithmetic.
A payment action derives debts from the ledger, checks the sender’s available token balance, and transfers to the recorded counterparties. Successful signatures are stored with the transfer history and linked to the devnet explorer. If a batch transfer fails, later transfers stop and the application reports the partial result.
A per-user in-process payment guard prevents overlapping payment execution within the running process. This is not a claim of crash-safe, distributed exactly-once settlement. Production custody, real-value tokens, broader authentication, and reconciliation would require additional engineering.
Identity and Access Model
The messaging adapter uses the sender identity provided by Photon, and trip membership scopes the agent’s operations. Joining and registration are application workflows, with private conversations carrying personalized links.
The web viewer token is an HMAC-derived shortcut for choosing the initial member view. The source explicitly describes it as view selection, not authentication. This case study therefore does not describe the trip page as a securely authenticated financial dashboard.
Custodial devnet keys are an MVP tradeoff. A production design would need a stronger identity and authorization model, a reviewed custody approach, and durable transaction recovery beyond the current single-process guards.
Testing and Reliability
The public Vitest suites cover equal and itemized splits, rounding, tax and tip allocation, ledger calculations, trip stories, multiple-trip routing, joining, disputes, and personalized viewer links. Fake messenger and chain implementations allow conversational and settlement behavior to be exercised without live providers.
Gemini has model fallback and keyword-based interpretation when unavailable. Photo failures ask for a usable amount, provider registration has bounded retries, and deterministic message formatting keeps model prose out of the outbound financial explanation.
The repository’s tests were inspected rather than rerun as part of this portfolio build. No new test count, coverage percentage, real receipt accuracy metric, or live transaction success is claimed.
Challenges & solutions
The most important separation is between understanding a person and mutating a financial record. Typed intents constrain the AI layer; explicit agent branches resolve context; domain functions own the split and ledger arithmetic.
Receipts arrive separately from text
The Photon adapter merges nearby attachment and text events from the same sender before routing the combined expense context.
Several trips can be open
Trip names, active context, persisted pending state, and clarification questions keep expenses and disputes attached to the intended trip.
A dispute changes who owes what
The ledger excludes disputed shares and handles payer agreement and receipt-backed restoration through explicit state changes and notifications.
Outcomes and Lessons
TAB connects iMessage onboarding, natural-language entry, receipt interpretation, exact splitting, multi-trip ledgers, dispute resolution, transparent histories, and devnet settlement in one application. The public repository, video, and documented deployment make the product and its architecture inspectable.
The main lesson is to use AI for interpretation and conventional code for accounting, state transitions, and execution. A second is to choose an architecture that fits the operating environment: a long-lived messaging stream and local database favor a simple persistent service for this prototype.
The ADR contains earlier approval-oriented design notes. The case study follows the current implementation’s dispute-first behavior where those notes and the source differ.
Evidence & scope
Reviewed the public README and ADR alongside the agent router, Gemini adapter, Photon adapter, SQLite store, split and settlement logic, Hono pages, wallet adapter, and Vitest suites. The demo video and documented deployment responded successfully during review.