Case Study

Keel

My own books. 9,225 transactions. The agent found $227,736 of phantom income.

An agent-first, multi-currency, double-entry ledger I built because I hate Quicken and Firefly III's UI defeated me. Built with the harness over 26 days on my real cross-border finances, as my daily driver. This is the other end of the dial from Cleaner CRM: there the split measured 0.4% human; here it measured 2.9%, because on your own money you are the oracle. The agent did the labor. I supplied the judgment.

$227,736
Phantom Income Found
48
Stories
182
BDD Criteria
2.9%
Typed by John

What is Keel?

A double-entry ledger you talk to. Point it at your financial history and the agent proposes categorization rules, hunts down mystery transactions, reconciles transfers, and traces where money went, instead of you clicking through thousands of rows. Cross-border by design: per-currency balances, real FX, two entities, one set of books. Two personas drove the stories: the cross-border owner-operator, and the Keel Categorization Agent, an AI persona with stories of its own.

Quicken

Direct import from Quicken's internal SQLite: raw bank descriptions, native transfer links, real account types

Bank of Canada

Daily FX rates via the Valet API, cassette-recorded against the real service

MCP (anubis)

22 intent-level tools, zero CRUD: post, propose, preview, trace. Deleting is refused

Coinbase

Crypto history as asset-as-currency on the same FX engine, ACB cost basis

Postgres

A deferred sum-to-zero trigger: unbalanced transactions cannot commit, by construction

ex_money

Money as money: no floats, no cross-currency sums, custom crypto currencies

Key Features

  • Append-only double-entry core: corrections are reversing entries, the DB rejects unbalanced posts
  • Deterministic rules engine first; the LLM only ever sees the unmatched tail
  • Two-sided transfer rules: keyed exact matches, fuzzy proposals, remainder accounts that split a mortgage payment into principal and interest
  • Classification workbench: cluster the uncategorized tail, preview a rule against real data, approve, hundreds of rows clear
  • Multi-currency done right: per-currency balances, 4-leg FX transactions, never a cross-currency sum
  • Idempotent re-import: wipe and rebuild from Quicken any time, rules and links survive
  • Crypto holdings as currencies: Buys, Converts, Sells, and staking rewards on the existing FX machinery
  • Tags and forward money-tracing: ask where a wire went and get the full chain, hop by hop
  • Reports that reproduced Quicken's own P&L to the cent, then caught it double-counting

User Stories

Every story that drove this build, complete and unexcerpted: persona, Three Amigos rules with full given-when-then scenarios, acceptance criteria, and resolved questions, exported straight from the harness database. Twelve carry browser-QA passes; the rest are verified by the spex suite and real-data checks against my actual books.

48
Stories
182
Acceptance Criteria
48
With Three Amigos

Open Source Repository

Keel is public in the Code-My-Spec org. Unlike Cleaner CRM, the build transcripts stay private: they are 53MB of me discussing my actual finances with an agent. Every number in this teardown is one I approved for the public demo.

View on GitHub
Elixir / Phoenix
Language
167 green
BDD Spex
119
Unit Tests
22
MCP Tools

The Dev Story

The Good, The Bad, and The Ugly

Cleaner CRM measured what autonomy looks like: 0.4% human. Keel measured the collaborative end: 2.9%, 300 messages across 26 days, because this is my money and I am the oracle. The agent wrote 2.86 million characters and did all the labor. I supplied product decisions, accounting judgment, and the one failing test no fixture could encode: my own memory of my own finances.

  • One evening from empty repo to build-ready: personas, 37 stories, 11 ADRs, a validated architecture, Three Amigos on 14 stories, 48 BDD specs
  • 8,082 transactions of nine years of Quicken history posted as balanced double-entry in 6.7 seconds, 12 of 12 accounts reconciling to the cent
  • Keel out-audited Quicken within four days: caught its own report double-counting transactions and mislabeling a 401(k) forfeiture as a realized gain
  • The $227,736 find: 29% of recorded personal income was me moving my own money between accounts, $125k of it in a single day
  • Trial balance 0.00 in every currency, crypto included, through every import, rebuild, and recategorization: sum-to-zero is enforced by the database, not by discipline
  • Deterministic rules before any LLM: 83% of 9,073 transactions classified with 16 rules; ~130 more proposed with live previews against real data in one weekend
  • The trace answered 'where did my house money go': 120 transactions across 8 hops and 7 FX conversions, ending in 69 credit-card payments
  • An autonomous QA loop ran 10 iterations, passed 9 stories, found 2 real production bugs, and stopped itself when the remaining work needed my input

Twenty-six days, 75 commits, my real books as the test suite. 48 stories, 182 BDD criteria, 167 spex and 119 tests in a repo that started with five. 9,225 transactions balancing to the cent in every currency, $227,736 of phantom income found, one house-sale wire traced to its 69 credit-card payments. I typed 2.9% of the characters. The agent did the labor; I was the oracle. That's the pairing this whole thing is about.