Local-first AI finance categorizer. Your bank data never leaves your machine.
Upload any bank statement CSV and NumbyAI automatically detects the format, categorizes every transaction using a local LLM (Ollama), and surfaces patterns across months. No cloud. No subscriptions. No data sharing.
NumbyAI Demo: Watch on YouTube β
Drop a bank statement CSV and watch NumbyAI auto-detect columns and categorize every transaction using a local LLM.
Track spending by category, monitor budgets, and analyze cash flow trends β all from a single view.
The Rule Advisor analyzes your categorization patterns and suggests reusable rules, making future uploads instant.
- Drop any CSV β the heuristic parser detects metadata rows, column layout, date format, currency, and number format automatically, without you mapping anything. Falls back to the LLM when confidence is low.
- Rule engine runs first β saved patterns (regex, bank-specific, amount filters) categorize known transactions instantly, without touching the LLM.
- LLM handles the rest β remaining transactions are batched and sent to Ollama in parallel workers. Confident results are committed; ambiguous ones go to the review queue.
- Review queue β flag-and-resolve UI with bulk select, conflict detection, and one-click rule creation from any pattern.
- Rule analysis β analyzes all your transactions for inconsistencies and suggests new rules to clean up historical data.
- Dashboard β category breakdowns, month-over-month trends, cash flow, budget vs actual.
Most tools require you to manually map columns. NumbyAI's heuristic engine handles the messy reality of real-world bank exports:
| Signal | How |
|---|---|
| Metadata preamble rows | Scans from top, finds first row with both a date and a numeric value β everything above is skipped |
| Column roles | Scores each column independently (date density, numeric density, text length, emptiness) |
| Inflow/Outflow split | Detects adjacent complementary numeric columns (one empty when the other isn't) β common in UK/EU exports |
| Date format | Pattern-matches against 9 formats: YYYY-MM-DD, DD/MM/YYYY, MM/DD/YYYY, DD.MM.YYYY, DD Mon YYYY, short-year variants |
| Number format | Distinguishes EU (1.234,56) from US (1,234.56) by counting comma/dot separator signals |
| Currency | Detects from symbols ($β¬Β£Β₯βΉβ½β©) and ISO codes (USD EUR GBP PLN CHF etc.) in headers and data cells |
| Balance column | Identifies monotonically-signed numeric columns near the amount column |
| Bank / Format | Country | Notes |
|---|---|---|
| Chase | πΊπΈ US | 7-column with Post Date and Category |
| Bank of America | πΊπΈ US | 4-column, running balance |
| Wells Fargo | πΊπΈ US | No header row |
| Barclays | π¬π§ UK | Inflow/outflow split columns |
| HSBC | π¬π§ UK | Metadata preamble, separate debit/credit |
| ING | π³π± NL | Semicolon-delimited, EU number format |
| Sparkasse | π©πͺ DE | Semicolon-delimited, EU decimals, multi-row metadata |
| UBS | π¨π CH | CHF currency detection, preamble rows |
| BNP Paribas | π«π· FR | Semicolon-delimited, signed amounts |
| NAB | π¦πΊ AU | AUD, debit/credit columns |
| Santander | π¬π§ UK / πͺπΈ ES | Multiple regional formats |
| Revolut | π Multi | Multi-currency exports |
| Tab-delimited | Any | Auto-detected |
| Pipe-delimited | Any | Auto-detected |
| Generic w/ metadata | Any | Account info header rows auto-skipped |
When heuristic confidence is low, the LLM is called with a structured prompt and the first 15 rows to fill the gaps. Heuristic results always win when confident.
Upload CSV
β
βΌ
Statement Analyzer
ββ Heuristic engine ββββ high confidence βββΆ column mapping resolved
ββ LLM fallback ββββ low confidence βββΆ LLM fills gaps
β
βΌ
Rule Engine ββββ saved preferences (regex patterns, bank filters)
ββ Match found βββΆ category applied instantly
ββ No match βββΆ LLM batch queue
β
βΌ
Ollama (parallel workers, configurable batch size)
ββ Confident result βββΆ category committed
ββ Uncertain βββΆ MANUAL_REVIEW flag
β
βΌ
Review Queue
ββ Bulk select + assign category
ββ Per-transaction rule creation
ββ Conflict resolution (AI vs reviewer)
β
βΌ
Dashboard
- Zero-config format detection β works on statements with metadata headers, blank rows, split debit/credit columns, EU/US number formats, and 9 date format variants
- Multi-currency β detects and stores transaction currency; dashboard handles mixed-currency months
- Parallel LLM batching β configurable worker count and batch size; processes large statements fast
- Rule analysis β post-hoc analysis finds categorization conflicts and suggests new rules across historical data
- Bulk review UI β checkbox select-all, bulk categorize, inline conflict resolution
- Budget tracking β set monthly budgets per category, visualized against actuals
- Multi-bank β each upload is tagged to a bank; rules can be bank-specific or global
- Auth optional β runs in single-user mode with no auth required; plug in Auth0 for multi-user
- SQLite (dev) / PostgreSQL (prod) β swap via
DATABASE_URL - Privacy first β no telemetry, no external API calls, runs entirely on your machine
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser (:8000) β
β ββββββββββββββββββ βββββββββββββββββββββββββββ β
β β Upload Wizard β β Dashboard β β
β β (SimpleUpload) β β Charts Β· Budgets Β· β β
β β Auto-detection β β Review Β· Trends β β
β ββββββββββββββββββ βββββββββββββββββββββββββββ β
ββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β REST + SSE (streaming)
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β FastAPI Server (:8000) β
β βββββββββββββββ ββββββββββββ ββββββββββββββββββββββ β
β β Statement β β Rule β β Ollama LLM β β
β β Analyzer β β Engine β β (parallel batches)β β
β βββββββββββββββ ββββββββββββ ββββββββββββββββββββββ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SQLite (dev) / PostgreSQL (prod) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββ
β Ollama (:11434) β
β Local LLM β default: qwen3.5:9b β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Income Β· Housing & Utilities Β· Food & Groceries Β· Transportation Β· Insurance Β· Healthcare Β· Shopping Β· Entertainment Β· Travel Β· Debt Payments Β· Internal Transfers Β· Investments Β· Other
| Dependency | Version | Notes |
|---|---|---|
| Python | 3.11+ | Backend runtime |
| Node.js | 18+ | Frontend build |
| Ollama | Latest | Local LLM inference |
Works on Windows, macOS, and Linux. The only prerequisites are Python 3.11+, Node.js 18+, and Ollama.
# 1. Clone
git clone https://github.com/RoXsaita/NumbyAI-Public.git
cd NumbyAI-Public
# 2. Install Ollama and pull the default model
python run.py setup-ollama
# 3. Copy env file
cp server/.env.example server/.env # macOS / Linux
copy server\.env.example server\.env # Windows (cmd)
# 4. Start everything (venv, deps, migrations, frontend build, server)
python run.py startApp runs at http://localhost:8000.
Upload the included sample_bank_export.csv β it's a realistic two-month export with metadata header rows, recurring merchants, and edge cases designed to exercise the parser.
NumbyAI-Public/
βββ server/
β βββ app/
β β βββ main.py # API routes
β β βββ config.py # Pydantic settings
β β βββ database.py # SQLAlchemy models
β β βββ services/
β β β βββ statement_analyzer.py # Heuristic format detection + LLM fallback
β β β βββ categorization_rules.py
β β β βββ llm_service.py # Ollama client + batching
β β β βββ ollama_service.py
β β βββ tools/
β β βββ statement_parser.py # CSV/XLSX β transaction rows
β βββ tests/
β β βββ fixtures/ # Real-world format CSVs (Chase, Barclays, ING, ...)
β β βββ test_statement_analyzer.py
β βββ alembic/ # DB migrations
β βββ Dockerfile
βββ web/
β βββ src/
β βββ components/SimpleUpload.tsx # Upload wizard
β βββ widgets/dashboard.tsx # Main dashboard
β βββ lib/api-client.ts
βββ sample_bank_export.csv # Two-month test statement with metadata preamble
βββ run.py # Cross-platform CLI (Windows / macOS / Linux)
βββ Makefile # macOS / Linux shortcut (optional)
All config via environment variables. See server/.env.example.
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
DB connection string | sqlite:///./finance_recon.db |
SECRET_KEY |
JWT signing key | dev-only-not-for-production |
OLLAMA_URL |
Ollama server URL | http://localhost:11434 |
OLLAMA_MODEL |
Model for categorization | qwen3.5:9b |
CATEGORIZATION_BATCH_SIZE |
Transactions per LLM batch | 20 |
CATEGORIZATION_MAX_WORKERS |
Parallel batch workers | 2 |
AUTH0_DOMAIN |
Auth0 domain (optional) | Disabled |
All commands work on Windows, macOS, and Linux via run.py:
python run.py start # Stop β migrate β build β start
python run.py stop # Kill the server
python run.py logs # Tail backend logs
python run.py check # ruff + mypy + pytest
python run.py setup-ollama # Install/verify Ollama + pull model
python run.py test-e2e # End-to-end categorization (requires Ollama)
python run.py clear-db # Delete the SQLite databasemacOS / Linux shortcut (Makefile)
If you have make installed, the Makefile still works:
make restart # Stop β migrate β build β start
make stop # Kill all services
make logs # Tail backend logs
make check-python # ruff + mypy + pytest
make test-e2e # End-to-end categorization (requires Ollama)cd server
pytest tests --cov=app --cov-report=term-missingcd web && npm install && npm run build
# Dev mode with mock data (no backend needed):
npm run build:devNo separate dev server β FastAPI serves the built frontend as static files.
- Use
pythoninstead ofpython3(Windows Python installer registerspython). - Ollama: install from ollama.com/download/windows or
winget install Ollama.Ollama. - The
Makefilerequires GNU Make (e.g. via Git Bash or WSL) β userun.pyinstead.
- Ollama:
curl -fsSL https://ollama.com/install.sh | sh. - Everything else works out of the box.
- Ollama:
brew install ollama. - Both
run.pyandmakework.
# 1. Build the frontend first
cd web && npm install && npm run build && cd ..
# 2. Start the app + Ollama
docker-compose up
# 3. Pull the model inside the Ollama container (first run only)
docker-compose exec ollama ollama pull qwen3.5:9bApp runs at http://localhost:8000. Data is persisted in Docker volumes (sqlite_data, ollama_data).
A Dockerfile and railway.toml are included. For production:
- Set
DATABASE_URLto a PostgreSQL connection string - Set
SECRET_KEYto a secure random value - Set
ENVIRONMENT=production - Point
OLLAMA_URLat your Ollama instance


