Hon (Hebrew: הוֹן, "wealth") is a private, local-first personal finance dashboard for Israeli households. It logs into your banks, credit cards, pension funds, brokerages, and loyalty/gift-card programs, pulls everything into one SQLite database on your own machine, and shows you net worth, cash flow, budgets, and trends — without sending a byte to anyone's cloud.
Privacy model in one line: all data lives on your machine; the only outbound traffic is the bank/financial logins you explicitly configure (plus optional FX rates and, if you turn it on, an LLM API).
# From the repo root:
npm install # first time only
npm run dev # starts the sidecar engine + opens the web appnpm run dev boots the local engine (the "sidecar") and the web UI together.
It prints a URL like:
Hon engine starting — web app at http://127.0.0.1:4000/#token=<uuid>
Open that URL (the launcher opens it for you). The token in the URL fragment authenticates your browser to the loopback-bound engine.
Prerequisites: Node 20+ and Google Chrome (Hon drives Chrome for the bank and pension scrapers — see How Hon finds Chrome).
The engine listens on 127.0.0.1 only. Nothing is exposed to your LAN unless
you deliberately run it as a server (see
Run it — NAS or home server).
Hon is browser-based — there's no desktop app to install. The engine serves the web UI; you open it in the browser you already use.
A complete walkthrough for a non-technical Windows user — from a blank PC to a running Hon.
- Install Node.js. Go to nodejs.org and download the
LTS installer. Run it, accept the defaults. This gives you
nodeandnpm. - Install Google Chrome if it's not already on the machine.
- Download Hon. Either
git clonethe repo (if you have Git) or use the green Code → Download ZIP button on GitHub and unzip it somewhere likeC:\Hon. - Open a terminal in the Hon folder. In File Explorer, navigate into the
Honfolder, then click the address bar, typecmd, and press Enter. - Install and run:
npm install npm run dev - First run installs everything (a few minutes), then Hon opens in your browser automatically.
If a Windows Firewall prompt appears, you can safely Cancel/Deny — Hon
only talks to 127.0.0.1 (your own machine), so it doesn't need any firewall
permission.
- better-sqlite3 fails to build. You need the Visual Studio Build Tools
with the "Desktop development with C++" workload. Install from
visualstudio.microsoft.com/visual-cpp-build-tools,
then re-run
npm install. - "npm is not recognized." Reopen the terminal after installing Node so the new PATH takes effect.
- Chrome not found. Install Chrome, or set
PUPPETEER_EXECUTABLE_PATH— see How Hon finds Chrome.
Two packages in one repo:
Hon/
├── sidecar/ the local engine — Fastify HTTP API, scrapers, SQLite, vault,
│ on-device LLM. This is where most of the code lives. It also
│ serves the built web UI.
└── web/ the React app (Vite) you see in the browser, built to web/dist.
The sidecar is the product; web/ is its face. There's one moving part at
runtime: the engine. It serves the React build at / and exposes the API
under /api/* on the same loopback port — no separate web server, no CORS.
How the UI is served. npm run dev's launcher (sidecar/web.mjs) builds
web/dist when it's missing or stale, then starts the engine. The engine
serves web/dist/index.html at / and the hashed assets under /assets/.
The React client calls /api/<route>; the engine strips the /api prefix and
routes to its handlers (the production equivalent of Vite's dev proxy), with
the bearer token enforced on every API call. In development you can instead run
Vite directly (cd web && npm run dev, on :5173) for hot-reload, with its
/api → :4000 proxy.
- Run Hon
- What Hon does
- Security — the credential vault
- Recovering your credentials
- Splitwise integration
- AI engine
- Tech stack & tools
- Run it — NAS or home server
- Setup inside the app
- Where data lives
- External APIs & data sources
- Environment variables
- How Hon finds Chrome
- Troubleshooting & diagnostics
- Project layout
- Sidecar scripts
Hon logs into your financial accounts on a schedule you control, normalizes everything into one local database, and presents it as a dashboard. Each tab in the web app:
- Overview — net worth, this-cycle cash flow, projected end-of-cycle bank balance, spending pie, budget vs. actual, and "saved this cycle".
- Assets — banks, credit cards, brokerages, pension funds, plus manual assets (car by plate, property, cash) and bank-scraped loans.
- Activity — every transaction, searchable, with categorization, refund linking, Splitwise splits, and a per-transaction "savings" toggle (savings transfers drop out of spend and are tallied separately).
- Fixed bills — auto-detected recurring bills with per-merchant frequency and a "due this cycle" total.
- Subscriptions — recurring digital subscriptions, bucketed.
- Piggy banks — savings goals with progress rings.
- Loans — bank-scraped + manual, with payment history.
- Vouchers — Shufersal / BuyMe / HTZone gift-card balances with sync.
- Insights — spending breakdowns and brokerage performance charts.
- Settings — categories, billing cycle, AI engine, vault, integrations.
All bank/scraper credentials live in an AES-256-GCM vault, encrypted with a key derived (scrypt, OWASP-2024 cost for new vaults) from a passphrase you choose. The vault is locked at rest; you unlock it once per session. Lost passphrase = re-enter credentials (documented as a feature, not a bug — Hon can't read them without it).
The engine binds to 127.0.0.1 and every API route is gated by a bearer token
carried in the URL fragment (so it never lands in server logs). LLM provider
API keys, like every other secret, are stored in the vault — never plaintext
on disk.
If you forget the vault passphrase, there's no backdoor (that's the point). You re-enter each connection's credentials, which re-encrypts them under a new passphrase. Your transaction history and balances are NOT lost — only the saved login credentials need re-entering.
Hon links transactions to Splitwise expenses, tracks who owes whom, and folds "owed to you" into your cash-flow projection. Connect with your Splitwise API key in Settings.
Hon runs a local LLM (via node-llama-cpp) for transaction categorization and
free-text budget insights. Pick the model in Settings → AI engine. Nothing
goes to any cloud unless you explicitly configure an API-based provider
(OpenAI-compatible or Ollama).
- Sidecar: Node + TypeScript, Fastify (+
@fastify/staticto serve the web build), better-sqlite3, Puppeteer + israeli-bank-scrapers, node-llama-cpp, SnapTrade SDK. - Web: React 19, Vite, TypeScript (strict), Vitest.
- Storage: SQLite (WAL), AES-256-GCM vault.
- Deploy: single local engine —
web/distis built on launch and served by the sidecar at/; no separate web server, no packaging step.
Hon runs headless on a NAS (Synology, QNAP, …) or any home server, reachable over your LAN or a private VPN (Tailscale, WireGuard).
The image bundles the engine, the built UI and headless Chromium, and builds
web/dist itself — one command, nothing to pre-build. Run it from the repo
root:
cp .env.example .env # then set a long random HON_TOKEN
docker compose up -d --buildReach it at http://<server>:4000/#token=<HON_TOKEN>. The container is
restart: unless-stopped (survives reboots) and persists the database, vault
and any downloaded AI models in the hon-data volume. Generate a token with:
node -e "console.log(require('crypto').randomUUID())"Run the engine directly — its launcher builds web/dist on first start:
HON_HOST=0.0.0.0 HON_PORT=4000 HON_HEADLESS=1 npm run web --prefix sidecar(The engine binds 127.0.0.1 by default; HON_HOST=0.0.0.0 exposes it on the
LAN. HON_HEADLESS=1 stops it trying to open a browser on a headless box.)
Security note: the bearer token (HON_TOKEN) is the only thing protecting
your finances once Hon is bound to 0.0.0.0. Use a strong token and keep Hon
on your LAN or a private VPN — never the public internet.
First launch:
- Create the vault passphrase (Settings → unlock).
- Add a connection (Assets → + Add asset → pick your bank).
- Enter credentials; Hon scrapes on demand or on a schedule.
All under one directory (the "data dir"):
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Hon |
| Windows | %APPDATA%\Hon |
| Linux | $XDG_DATA_HOME/Hon (or ~/.local/share/Hon) |
Override with HON_DATA_DIR. Contents:
| File / dir | What |
|---|---|
hon.db |
the SQLite database (accounts, transactions, budgets, …) |
vault/ |
encrypted credentials + bank sessions |
dev-token |
the persisted bearer token (mode 0600) |
browser-profiles/ |
persistent Chrome profiles for pension funds |
logos/ |
cached institution logos |
debug/ |
failure screenshots + HTML/JSON dumps |
sidecar.log |
engine log (tee'd by the launcher) |
- israeli-bank-scrapers — drives Chrome to log into Israeli banks + cards.
- SnapTrade — brokerage aggregation (IBKR, etc.).
- data.gov.il — vehicle lookup by licence plate (car asset valuation).
- Frankfurter — FX rates (
api.frankfurter.dev), for multi-currency net worth. - Splitwise — shared-expense tracking (optional, API key).
- Pension portals — Migdal, Harel, Clal, Meitav, Menora (custom Puppeteer).
- Voucher portals — Shufersal, BuyMe, HTZone.
| Var | Default | What |
|---|---|---|
HON_DATA_DIR |
OS default | Override the data directory. |
HON_PORT |
0 (random) |
Engine port. The launcher uses 4000. |
HON_HOST |
127.0.0.1 |
Bind address. 0.0.0.0 to expose on LAN. |
HON_TOKEN |
auto | Bearer token. Auto-generated + persisted if unset. |
PUPPETEER_EXECUTABLE_PATH |
auto | Explicit Chrome path. |
HON_LOG_DEBUG |
unset | Verbose debug logging when set to 1. |
HON_HEADLESS |
unset | Don't open a browser on launch (server mode). |
Hon needs a real Chrome/Chromium (not the bundled Puppeteer one, which it
skips downloading). At launch it searches common install paths for Chrome,
then Edge, then Chromium. Override with PUPPETEER_EXECUTABLE_PATH.
The engine streams structured logs to stderr and tees them to
<dataDir>/sidecar.log. Each scrape attempt is greppable by its run id.
Check <dataDir>/debug/<companyId>.png (a screenshot at the point of failure)
and the matching HTML/JSON dump.
Delete the fund's profile under <dataDir>/browser-profiles/<companyId>/
(or the lock files inside it) and re-sync.
sqlite3 "$HOME/Library/Application Support/Hon/hon.db"See Recovering your credentials.
No backdoor by design. Re-enter credentials to re-encrypt under a new passphrase; history/balances are preserved.
Israeli credit cards bill once a month; Hon shows the next-bill outstanding (pending + scheduled charges), which can differ from the issuer's "current" figure mid-cycle.
The engine couldn't find web/dist. Run cd web && npm run build (the
launcher normally does this for you), then reload.
| Connector | File |
|---|---|
| Banks + cards | sidecar/src/scrapers.ts |
| Pension funds | sidecar/src/pension.ts |
| Brokerages (SnapTrade) | sidecar/src/snaptrade.ts |
| Vouchers | sidecar/src/voucherScrapers.ts |
| Loans | sidecar/src/bankLoans.ts |
| Vehicle lookup | sidecar/src/vehicle.ts |
| FX | sidecar/src/fx.ts |
| LLM | sidecar/src/llm.ts |
| Vault | sidecar/src/vault.ts |
| Categorization | sidecar/src/categorize.ts |
Hon/
├── package.json root — `npm run dev` launches engine + web
├── sidecar/ the local engine
│ ├── web.mjs launcher: token, Chrome detection, builds web/dist,
│ │ spawns the engine
│ ├── src/ engine source (see below)
│ └── tests/ vitest unit tests
└── web/ the React app
├── src/ React source (tab-by-tab views)
└── dist/ production build (built on launch, served at /)
| File | Responsibility |
|---|---|
server.ts |
Fastify app — all HTTP routes, token gate, serves web/dist |
httpRewrite.ts |
strips the /api prefix so the client reaches /<route> |
db.ts |
SQLite schema + migrations |
repo.ts |
typed data access (the only place that touches SQL) |
runner.ts |
scrape orchestration (dispatch, OTP, retries) |
scrapers.ts |
bank + card scrapers (israeli-bank-scrapers) |
pension.ts |
pension-fund scrapers (custom Puppeteer) |
snaptrade.ts |
brokerage aggregation |
voucherScrapers.ts |
gift-card balance scrapers |
bankLoans.ts |
loan scraping + amortization |
vehicle.ts |
licence-plate vehicle lookup |
vault.ts |
AES-GCM credential vault |
llm.ts |
on-device LLM (categorization + insights) |
categorize.ts |
three-tier categorization |
fx.ts |
currency conversion |
budget.ts |
budget + cash-flow projection |
loanMatcher.ts |
links transactions to loans |
splitwise.ts |
Splitwise sync |
piggy.ts |
savings-goal math |
log.ts |
structured logger |
cd sidecar
npm run web # start the engine (+ open the browser)
npm test # vitest unit tests
npm run typecheck # tsc --noEmitFor the web app:
cd web
npm run build # produce web/dist (the engine serves this)
npm run dev # Vite dev server with hot-reload (proxies /api → :4000)
npm test # vitest
npm run typecheck # tsc -b --noEmitHon is a personal project, shared in case it's useful. No warranty; use at your own risk with your own financial credentials.