InspiraBUNQSY — Project Story
Inspiration
Most finance apps are rear-view mirrors. They tell you what you spent last month, show you a chart, and suggest you "spend less on coffee." By the time you open the app, the damage is done.
We wanted to build the opposite: a system that watches your money in real time, reasons about risk before you notice a problem, and acts — with your consent — before it's
too late.
The bunq API made this possible. Real-time webhook hooks, programmable cards, JAR accounts, sandbox top-ups — it's the only consumer banking API expressive enough to
actually do something, not just read.
What We Built
BUNQSY is an autonomous AI financial guardian with a 60-second heartbeat. Every tick, 7 specialized Claude agents run concurrently and vote on the state of your finances:
┌───────────────────┬────────────────────────────────┐
│ Agent │ Responsibility │
├───────────────────┼────────────────────────────────┤
│ Fraud Detection │ Anomalous transaction patterns │
├───────────────────┼────────────────────────────────┤
│ Cashflow Monitor │ Runway and liquidity risk │
├───────────────────┼────────────────────────────────┤
│ Spending Patterns │ Drift from baseline behaviour │
├───────────────────┼────────────────────────────────┤
│ Savings Optimizer │ Goal progress velocity │
├───────────────────┼────────────────────────────────┤
│ Anomaly Detector │ Statistical outliers │
├───────────────────┼────────────────────────────────┤
│ Tax Compliance │ VAT exposure and deductibility │
├───────────────────┼────────────────────────────────┤
│ Goal Tracker │ Milestone proximity │
└───────────────────┴────────────────────────────────┘
Each agent is bounded — 800 token input, 200 token output, no side effects, returns a typed JSON vote. The Risk Oracle aggregates votes into a single health score:
$$S = \sum_{i=1}^{7} w_i \cdot v_i \cdot c_i$$
where $w_i$ is the agent weight, $v_i \in [0, 100]$ is the vote score, and $c_i \in [0, 1]$ is the confidence. If $S$ drops below a threshold, BUNQSY generates an
Intervention.
Every intervention follows a hard constitutional rule: Plan → Confirm → Execute. Claude narrates exactly what will happen in plain English. You say yes or no — by voice or
tap. Only then does a single write gateway touch the bunq API.
On top of this: full double-entry bookkeeping (every transaction auto-categorized, deductibility scored, VAT tracked), a 30-day cashflow forecast, and Dream Mode — a nightly worker process that builds a Financial DNA card while you sleep.
How We Built It
The stack is a Turborepo monorepo with three packages:
- daemon — Fastify + TypeScript + SQLite. The heartbeat loop, Oracle, bookkeeping engine, voice pipeline (Whisper STT → Claude → ElevenLabs TTS), and the single bunq write
gateway - frontend — React + Vite. Four dashboard tabs, live WebSocket feed, Voice Orb with push-to-talk and conversation mode
- shared — Zod schemas shared between packages; every external API response validated before use
We wrote constitutional rules directly into CLAUDE.md as law — the coding agent enforced them throughout the session. No file other than execute.ts could make a write to
bunq. No sub-agent could call another sub-agent. No phase could be scaffolded before the previous one passed.
The bookkeeping engine runs double-entry ledger logic in SQLite with journal entries, debit/credit accounts, and Dutch BTW VAT computation:
$$\text{VAT Net Due} = \text{VAT Collected} - \text{VAT Paid (input)}$$
A negative result means a refund owed by the tax authority — something most apps silently hide.
Challenges
The hardest problem was consent without friction. Making an AI that acts on your money is easy. Making one that acts correctly, explainably, and only with permission —
without making the UX feel like signing a legal document every 60 seconds — took most of our time. The Plan → Confirm → Execute flow went through several iterations before
it felt natural.
Two copies of React nearly sank the presentation package. A monorepo with separate node_modules trees caused Recharts to resolve a different React instance than the
renderer, producing a cryptic dispatcher.useContext null crash. One dedupe: ['react', 'react-dom'] line in the Vite config fixed it.
ElevenLabs in real-time conversation is trickier than it looks. The silence detector — an RMS analyser running on a requestAnimationFrame loop — had to be tuned carefully.
Too sensitive and it fires mid-sentence; too slow and conversation mode feels laggy. The final values ($\text{threshold} = 12\ \text{RMS}$, $\text{hold} = 2400\ \text{ms}$,
$\text{min} = 1500\ \text{ms}$) were found empirically.
SQLite schema migrations in a live daemon. Because the daemon runs without restarting, adding new columns (categorized_at, journal_entry_id) required runtime PRAGMA
table_info checks and ALTER TABLE ADD COLUMN migrations — not just schema changes.
What We Learned
That constraints breed clarity. The constitutional rules felt restrictive at first. By the end, they were the reason the system stayed coherent across 72 hours of iteration.
A single write gateway means you can audit every bunq API call in one file. Bounded sub-agents mean you can reason about Oracle outputs without reading 7,000 lines of
entangled logic.
And that the bunq API is genuinely one of the most builder-friendly banking APIs in existence. The sandbox is real, the endpoints are expressive, and the fact that you can
programmatically freeze cards, move money between JARs, and receive webhook events in a test environment — without a compliance review — is remarkable.tion
Built With
- better-sqlite3-ai-&-voice-anthropic-claude-api-(claude-sonnet-4-5)
- card-management
- elevenlabs-(tts-?-eleven-turbo-v2-5)-banking-api-bunq-api-(sandbox)-?-payments
- fastify
- github-web-apis-web-audio-api
- goals
- intervention-log
- jar-accounts
- journal-entries
- languages-typescript
- localhost-daemon-(node.js)
- mediarecorder-api
- node.js
- openai-whisper-(stt)
- recharts
- score-log
- speech
- sql-frameworks-&-runtime-react-19
- tailwind-css-v4
- turborepo
- user-profile-platform-&-deployment-github-pages-(presentation)
- vite
- web
- webhook-events-database-sqlite-(via-better-sqlite3)-?-transactions
- websocket
- zod
Log in or sign up for Devpost to join the conversation.