Inspiration
The Youth Code Foundation, which runs this hackathon, is itself a small nonprofit. So somewhere a treasurer is doing what every small-org treasurer does in the last week of a quarter: sitting at a kitchen table, surrounded by receipts and an open Venmo app, trying to remember if the $67.43 Staples charge was reimbursed via the bank or via P2P. Or both.
I kept thinking about that scene while I was sketching ideas. Budgeting apps don't help here. QuickBooks assumes clean entry. Monarch assumes one linked account. None of them ingest a folder of Venmo screenshots and ask the question that actually matters: does any of this match the ledger?
So I built Ledgerline for that treasurer.
What it does
You drop in the shoebox - bank CSV, receipt photos, P2P screenshots, the treasurer's spreadsheet - and a swarm of four agents reconciles it. You watch them work in real time: four lanes, messages flowing between them. At the end you get a board-ready PDF with every anomaly explained in plain English and every decision logged with provenance.
On the demo dataset Ledgerline finds three things a tired treasurer would absolutely miss:
- A duplicate reimbursement. A $67.43 Staples charge appears in both the bank CSV and a Venmo reimbursement screenshot - same merchant, same amount, different sources within a week. Classic double-claim pattern.
- A category mismatch hiding in program supplies. Spotify Premium ($49.99), filed under
program_supplies. Personal subscription, not a program expense. - A $240 ledger entry with no corroborating receipt or bank line. Neighborhood Hardware, above the documentation threshold. Disallowable without backup.
The Skeptic agent flags these with evidence and confidence scores. The report is marked Review Required until a human acknowledges the high-severity flags.
How I built it
The architecture is three layers: deterministic engine, agent swarm, UI. I built the engine first so the math was provably correct before the agents touched it.
Layer 1 - the engine. Pure TypeScript. Three anomaly checks as concrete functions, not vibes: findDuplicatePayments, findCategoryMismatches, findMissingDocumentation, plus evaluateLedger which recomputes totals in code. A test harness (npm run test:engine) asserts the planted 3-anomaly dataset is caught with exactly three flags and zero spurious types.
Layer 2 - the swarm. Four agents - Ingestion, Matcher, Skeptic, Reconciler - communicating through a typed in-process message bus with trace + provenance snapshots. The Matcher proposes pairwise cross-source matches with a transparent confidence score (amount + merchant + date proximity). The Skeptic challenges proposals below 75% confidence and drops them. It also runs the full anomaly taxonomy independently. The Reconciler recomputes ledger math from scratch - it never trusts agent prose for numbers.
Layer 3 - the UI. Landing page at /, workspace at /audit. Three columns: transactions on the left, live agent trace in the center, anomaly report on the right. The trace replays event-by-event with deliberate delays. Anomaly cards appear when the Skeptic flags them. Ink-on-paper design - warm cream, near-black ink, surgical red for evidence only.
Ingestion: CSV, JSON, text, and images. Receipt photos are OCR'd in-browser via Puter.js (no API key), then structured on the server with Groq text parsing; vision fallback (Groq Llama 4 Scout or Anthropic) for hard scans. Sample books in public/sample-books/ regenerate from the same mock dataset.
Challenges I ran into
The hardest part was signal-to-noise on duplicates. A naive check flags any two lines with the same merchant and amount. In real nonprofit books, the same expense legitimately appears in multiple sources - bank charge, receipt photo, spreadsheet row. The fix that shipped: only flag cross-source pairs (never same source), same normalized merchant, same amount, within a configurable day window. That catches the Staples double-claim without flagging every legitimate bank↔ledger mirror.
The other trap was demo reliability. Live OCR on stage is a single point of failure. Load sample books runs the real ingest pipeline on bundled files; the swarm always finds the same three planted anomalies. That's the honest demo path.
Accomplishments I'm proud of
- Engine + swarm tests pass on every build (
test:engine,test:swarm). - The live agent trace shows real propose→challenge events from the message bus - not a pre-rendered animation.
- Board-ready PDF: cover, executive summary, anomaly evidence, provenance trail (client-side jsPDF).
- Deployed and runnable: ledgerline-cyan.vercel.app/audit.
- Design that reads like a forensic document, not another fintech dashboard.
What I learned
AI proposes, code verifies. I use LLMs to structure messy OCR text into rows; they don't score matches or flag anomalies in my build. Every match score and every anomaly is deterministic TypeScript. Every total in the PDF is recomputed in code.
Provenance is the product. Treasurers and CPAs don't trust a black-box "AI found problems." They trust a trail: which agent, which evidence, which transaction IDs, what action to take. That's what I optimized for.
What's next for Ledgerline
- Round-number anomaly check (in the original design, not yet in the engine).
- Bounded multi-round Matcher↔Skeptic re-match (today: challenge drops weak pairs; no iterative re-score loop).
- Native Excel (
.xlsx) ingestion - landing mock shows it; parser not built yet. - Multi-org dashboard for fiscal sponsors.
The version I'm submitting already does the core thing: it finds the catches a tired treasurer would miss, with evidence you can defend.
Built With
- anthropic
- date-fns
- eslint
- github
- groq
- jspdf
- next.js
- node.js
- puter.js
- react
- react-icons
- typescript
- vercel

Log in or sign up for Devpost to join the conversation.