Reconciled financial truth for complex households.
Most personal finance apps stop at "the aggregator says your balance is $X." That's a feed, not a ledger. When the aggregator drops a statement, miscategorizes a transfer, or fails silently for a week, the user is the last to know — and there's no second source to verify against.
Mahi Kala treats every fact in the ledger as a claim that needs evidence. Bank-side data flows in through one or more aggregators. Statement-side data flows in through user-uploaded PDFs, CSVs, and email attachments — extracted, validated, and reconciled before it touches the ledger. The two sides have to agree, and when they don't, the user sees exactly which account, which period, and which side disagrees.
Aggregator data is checked against statement evidence on every close period. Gaps surface as actionable exceptions, not silently wrong totals.
Five distinct dates per source — attempt, success, data-as-of, next-expected, user-acknowledged — drive a single derived status that doesn't lie about how current a number is.
"Delete my data" leaves zero residue across database, disk, and aggregator-side connections. The wipe is tested with an assertion that every household-scoped table comes back empty.
The system on one page
Four kinds of source feed one reconciled ledger. The ledger powers the user views — net worth, reconciliation report, freshness dashboard. Every workflow below is a slice of this picture.
Core workflows
Users see one "Connect a bank" affordance. Mahi Kala routes the link to the aggregator with better coverage and pricing for that institution — Teller's per-enrollment economics for major US banks, Plaid for the long tail.
Every enrollment is signed by the aggregator with Ed25519 over a server-issued nonce. Replay attacks where a stolen token gets POSTed to plant a ghost connection are rejected before they reach the ledger.
A scheduler runs sync per source on its expected cadence. last_attempt_at stamps every run; last_success_at and data_as_of only move forward when real data arrived — a webhook firing doesn't qualify.
The distinction drives one derived freshness_status: healthy, waiting, missing-statement, stale, needs-reauth, failed-transient, failed-permanent, manual, paused, or setup-needed. Every account carries the status as a colored pill.
The wedge. For institutions where the aggregator is unreliable or unsupported, the user uploads a statement — PDF, CSV, OFX, or screenshot. Deterministic parsers handle structured files; vision and document AI handle the rest.
The extractor produces a candidate statement, never a ledger write. Candidates go through hard validation (totals match, period exists, opening + flows = closing) and reconciliation against the existing ledger. The user reviews before any row hits production. No LLM output writes directly to financial data.
The single screen that answers: do my balances tie to source evidence, and where don't they? Per-account balance tie-out, transfer-matching state, missing-statement recommendations, source health, and open exceptions — all in one scorecard with a "fully reconciled" boolean for the headline.
This is the surface that justifies a premium price tag — no aggregator-only app gives it.
Financial data is sensitive by definition. Three deletion paths ship: reset (clear data, keep account), delete-household, and delete-account. Each runs leaf-first through every household-scoped table, removes uploaded documents from disk, and revokes aggregator-side connections so the bank stops sharing.
The wipe is tested with an assertion that verify_zero_residue() returns an empty dict — every table, every file. The only thing retained is a single audit row saying "this household wiped on date X."
Architecture
Four kinds of data source share one ledger. The connector layer normalizes each provider's shape into the same internal rows — Plaid items, Teller enrollments, document-fed sources, and manual entries all hit the same write path. A source can have multiple roles per account over time and the system tracks each independently.
What's different
Most personal finance apps optimize for aggregator coverage breadth. Mahi Kala optimizes for whether the user can trust the number on screen. That's a different bet.
| Capability | Aggregator-first apps | Mahi Kala |
|---|---|---|
| Aggregator coverage | Broader (13k+) | Major US + statement-fed long tail |
| Statement reconciliation | Not supported | Per-account tie-out vs evidence |
| Document ingestion | CSV only, if at all | PDF · CSV · OFX · vision |
| Explicit freshness state | One timestamp | Five dates · derived enum |
| Transfer matching state | Heuristic only | Matched · pending · inferred · external · review |
| Verifiable data deletion | Unclear scope | Zero-residue + revoke + unlink |
| AI-native context | Rule-based | Anthropic + OpenAI across extraction · categorization · queries |
Status
Mahi Kala is in private beta. The architecture above is shipped: multi-aggregator linking, statement ingestion, reconciliation report, freshness layer, assets registry, and the verifiable-wipe data-deletion paths all run in production today. Onboarding is founder-led; the design partner cohort is small and intentional.
Built in Honolulu under Tax Accountability Services, LLC. Household-scoped, web app, US-only, no data resale.