Local-only personal finance for Israeli bank accounts. Encrypted. AI-categorized. Yours.
[!WARNING] Personal, local-only tool. Scraping financial institutions may violate their Terms of Service. Use only for your own accounts on your own machine. Do not deploy as a hosted service.

Israeli banks have terrible exports, YNAB doesn't speak ILS gracefully, and every "cloud finance" app wants you to hand over your bank password. Spent is the answer for people who'd rather just run something on their own laptop.
Your transactions get pulled directly from your bank with israeli-bank-scrapers, stored in a local SQLite file you can cp and back up like any other file, and categorized by an AI provider you choose: paid Claude, free local Ollama, or nothing at all.
The trade-off is honest: you self-host, you trust the scraper, and you accept that banks may not love automation. In return you get a fast, beautiful, fully offline dashboard that never phones home.
| ### 🏦 Israeli bank integration Isracard, Bank Hapoalim, and Max work out of the box. Visa Cal and Bank Leumi are on the roadmap. | ### 🤖 AI categorization Choose Claude (Anthropic) for best accuracy, Ollama for fully local LLMs, or skip and categorize manually. | ### 🔒 Local-only & encrypted Credentials encrypted with AES-256-GCM. Server binds to `127.0.0.1` only — never reachable from your LAN or the internet. |
| ### 📊 Budgets with pacing Hierarchical categories, monthly targets, "ahead of pace" hero card, and per-category drilldown. | ### 🌓 Light & dark theme Polished buttercream-and-sage palette in light mode, warm charcoal in dark. System-aware by default. | ### 🍎 Menu bar / tray app Optional native companion lives in your menu bar (macOS) or notification area (Windows) — one click to open the dashboard or trigger a sync. |
| ### 🎯 Auto-detected transfers Credit card payments and inter-account moves are recognized and excluded from spending totals. | ### 📅 Multi-month history Pull up to 3 months of transactions per sync (configurable). Most banks support 12 months total. | ### 🔍 Merchant memory Once you correct an AI categorization, Spent remembers — same merchant goes to the right category next time. |
| Dashboard — light | Dashboard — dark |
![]() |
![]() |
| Transactions | Setup wizard |
![]() |
![]() |
| Categories | AI provider |
![]() |
![]() |
| Bank accounts | |
![]() |
flowchart LR
Bank["🏦 Israeli bank
(Isracard / Hapoalim / Max)"]
Scraper["Puppeteer scraper
(israeli-bank-scrapers)"]
DB[("📦 SQLite
data/spent.db
(WAL mode)")]
AI{"🤖 AI provider
Claude · Ollama · None"}
UI["🖥 Dashboard
http://spent.local:41234"]
Bank -->|HTTPS
credentials encrypted| Scraper
Scraper -->|new transactions| DB
DB -->|uncategorized batch| AI
AI -->|category proposals| DB
DB --> UI
subgraph local["🔒 Your machine — 127.0.0.1 only"]
Scraper
DB
UI
end
Everything inside the dashed box stays on your laptop. The only outbound traffic is to your bank (for scraping) and optionally api.anthropic.com (if you chose Claude) or localhost:11434 (if you chose Ollama).
| Bank | Type | Status |
|---|---|---|
| Isracard | Credit card | ✅ Supported |
| Bank Hapoalim (incl. Poalim wallets) | Bank | ✅ Supported |
| Max (formerly Leumi Card) | Credit card | ✅ Supported |
| Visa Cal | Credit card | 🚧 Planned |
| Bank Leumi | Bank | 🚧 Planned |
Don't see your bank? Adding a scraper is a small wrapper around israeli-bank-scrapers — see Contributing.
| Claude (Anthropic) | Ollama (local) | None | |
|---|---|---|---|
| Cost | ~₪0.004 per sync | Free | Free |
| Accuracy | Best | Good (depends on model) | Manual |
| Network | api.anthropic.com |
localhost:11434 |
Offline |
| Setup | API key | Install Ollama + pull a model | Nothing |
Default model when Claude is selected: claude-haiku-4-5 (cheap, fast, accurate for categorization). For Ollama, llama3.2:3b is the recommended default.
You can change providers any time from Settings → AI provider. Existing categorizations are kept.
git clone https://github.com/Shaya16/Spent.git
cd spent
npm install
npm run build
npm run service:install
service:install registers an auto-start unit (LaunchAgent on macOS / systemd on Linux / Task Scheduler on Windows) and adds 127.0.0.1 spent.local to your hosts file. The hosts edit is the only step that asks for sudo / Administrator.
Open http://spent.local:41234 and bookmark it.
Menu bar / tray app (optional) — native status icon with one-click open, sync, and start/stop. Pre-built binaries are attached to every release, so no toolchain needed.
macOS (Spent.app.zip):
unzip Spent.app.zip -d ~/Applications/
xattr -dr com.apple.quarantine ~/Applications/Spent.app # if Gatekeeper complains
open ~/Applications/Spent.app
Windows (Spent.exe):
mkdir $env:LOCALAPPDATA\Programs\Spent
Move-Item .\Spent.exe $env:LOCALAPPDATA\Programs\Spent\
# SmartScreen on first launch: "More info" → "Run anyway"
# For auto-start: drop a shortcut to Spent.exe into shell:startup
First launch on either platform shows an unsigned-binary warning. That's expected for an open-source project without paid code-signing certificates.
In the browser:
| What you want | Run |
|---|---|
| Just use the app (no coding) | Open http://spent.local:41234 |
| Code and see changes instantly | npm run dev → http://127.0.0.1:3000 |
| Update the always-on app after editing | npm run service:reload |
Rare cases:
npm run service:uninstall && npm run service:install.| Command | What it does |
|---|---|
npm run service:status |
Running? Bound to loopback? |
npm run service:start / :stop |
Start/stop now |
npm run service:reload |
Rebuild and restart |
npm run service:logs |
Tail server logs |
npm run service:open |
Open the app in your browser |
npm run service:uninstall |
Remove auto-start and hosts entry. data/ is untouched. |
| Concern | Defense |
|---|---|
| Credentials at rest | AES-256-GCM, encryption key file mode 0600 (server refuses to start otherwise) |
| Network exposure | Bound to 127.0.0.1 only — not reachable from your LAN or the internet |
| Browser CSRF | Origin / Referer validation on every mutation |
| Bot detection | Chromium sandbox on by default (SPENT_DISABLE_CHROMIUM_SANDBOX=1 to opt out) |
| Bundle integrity | israeli-bank-scrapers, better-sqlite3, and @anthropic-ai/sdk pinned to exact versions |
| Browser hardening | Strict CSP, X-Frame-Options: DENY, Permissions-Policy locks down camera/mic/geo/payment |
Turn on full-disk encryption (FileVault / BitLocker / LUKS). The encryption key file sits next to the database, so disk-level protection is your last line of defense if the laptop is lost.
Full threat model and responsible-disclosure policy → SECURITY.md.
data/spent.db — transactions, categories, budgets, settingsdata/.encryption-key — 32-byte AES key, mode 0600~/Library/Logs/Spent/ (macOS) / ~/.local/state/spent/log/ (Linux) — service logsBack up data/ like any other folder. To migrate to a new machine, copy data/ over and run npm run service:install.
spent/
├── src/
│ ├── app/ Next.js App Router (routes + API)
│ │ ├── (dashboard)/ Dashboard, transactions, settings pages
│ │ ├── api/ Sync (SSE), summary, transactions, setup
│ │ └── setup/ First-run wizard
│ ├── components/
│ │ ├── dashboard/ Hero card, category grid, budget drawer
│ │ ├── setup/ Bank, AI, target, budgets steps
│ │ └── settings/ Per-tab settings panels
│ ├── lib/ Shared client-side types and helpers
│ └── server/
│ ├── ai/ Claude + Ollama provider implementations
│ ├── db/ SQLite singleton, migrations, query helpers
│ ├── lib/ Encryption, dedup, transfer detection, pace
│ └── scrapers/ Wrapper around israeli-bank-scrapers
├── menubar/ Optional tray companions
│ ├── mac/ Swift MenuBarExtra app
│ └── windows/ C# WPF NotifyIcon app
├── scripts/service/ LaunchAgent / systemd installer
└── data/ SQLite + encryption key (gitignored)
lsof -nP -iTCP:41234 -sTCP:LISTEN (Unix) or netstat -ano | findstr :41234 (Windows). Kill the offender and re-run install.Spent.app → right-click → Open → Open. One-time.loginctl enable-linger $USER.SPENT_DISABLE_CHROMIUM_SANDBOX=1 to let Puppeteer use a real Chrome profile.Spent is built for personal use first, open-source second. PRs welcome for:
BANK_PROVIDERS in src/lib/types.ts, map to CompanyTypes in src/server/scrapers/index.ts, flip enabled: true.AIProvider interface from src/server/ai/types.ts, register in src/server/ai/factory.ts, and add an option to the setup wizard.Conventions:
any without a comment.feat:, fix:, chore:, docs:, refactor:.End users should grab the prebuilt binaries from Releases. Local builds are only needed when you're changing the menubar app itself:
```bash
npm run menubar:install # builds + copies to ~/Applications/
npm run menubar:build:windows Copy-Item menubar\windows\build\Spent.exe $env:LOCALA
$ claude mcp add Spent \
-- python -m otcore.mcp_server <graph>