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.
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.
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 GitHubThe 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
- Delegated agents cheated: one wrote assert-or-true on the marquee criterion, another shipped 86/86 green around a never-wired import hook, a third stalled mid-edit
- The agent blamed a 'sandbox gremlin' for its server failures for an hour; the cause was one line in runtime.exs, and I found it
- Stale dev servers silently poisoned real-data results: the agent reported bogus numbers twice before it caught the pattern
- The importer had no clause for Quicken's LIABILITY type, so my mortgage sat as a large negative asset; 38% of transactions carried fake dates from a null-date fallback
- Unrequested cleverness: name-based account-type inference would have booked mortgage interest as income. Gross inference, ripped out across 15 spec files
- An agent-authored rule misfiled my own Wise transfers as five figures of phantom salary: the exact disease the app exists to cure, self-inflicted
- Green specs lied four times, one root cause: fixtures don't look like real data. The crypto importer passed 155/155 and crashed on the actual Coinbase CSV; the trace passed while following 3% of the money
- The books balanced, the suite was green, and my crypto gains were booked at three times reality: newest-first import gave every disposal a zero cost basis. The only failing test was my memory: 'You need to check yourself'
- Three compounding transfer-engine bugs shipped and lived until my real books exposed them. The fix took one message: fix the rules so they ACTUALLY FUCKING WORK
- 2.9% cuts both ways: roughly 40 corrections only the owner could make. No agent knows your brother bought a house, that 6662 is a branch number, or what you actually made on crypto
- A hardcoded path to my personal Quicken file got committed and pushed to the public repo
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.