A privacy-conscious Android app that turns Bancolombia statements into actionable financial insights, powered by an AI assistant you can chat with.
Amounts in the screenshots above are masked with the in-app privacy toggle.
- Import Bancolombia XLSX statements — Savings, Credit Card (incl. multi-currency COP/USD), Investment Fund. Period coverage is tracked per file.
- Process every imported transaction with one tap: Classify (REAL_EXPENSE, REAL_INCOME, INTERNAL_TRANSFER, …) → Polish (clean merchant name, recurrence, payment method) → match internal transfers between your own accounts.
- Chat with Gemini about your money. Multi-turn function-calling lets it pull totals, list merchants, suggest aliases, or recategorize batches — every write is gated by an explicit confirmation card.
- Audit any decision: every classification override leaves a JSON trail (
reasoning,source,at) on the transaction. - Train merchants by alias: "Rappi Restaurantes is Rappi" — the alias persists, future imports follow it, and matching past transactions are backfilled immediately.
- Insights dashboard: net worth + 6-month chart, income vs expense, recurring vs one-off, top merchants, by-category breakdown, by-weekday spend.
Most personal-finance apps in Latin America either charge a subscription, ship financial data to third-party servers, or lock users into proprietary formats. Mintroot:
- No subscription, no ads, no broker. You bring your own Gemini API key (free tier is enough for monthly use).
- Encrypted on-device storage. SQLCipher-backed Room DB; the API key is stored alongside transaction data in the same encrypted file.
- Auditable. Open source, no hidden classification rules — the LLM does the work, results are cached as data, never code.
- Bancolombia-shaped. The parser understands the bank's actual XLSX layout, including Colombian-locale amount strings, US-locale savings amounts, multi-currency CC sheets, installment plans, and reversal pairs.
XLSX ─► Parser ─► Transactions ─► Classify (Gemini) ─► Polish (Gemini) ─► Insights
▲ │ │
│ ▼ ▼
└────────── Classification Cache Merchant Aliases
(user overrides win) (user-trained)
- Parser: Apache POI on Bancolombia XLSX with locale-aware amount parsing and per-account-type adapters.
- Classifier: Gemini Flash-Lite, batched 20-tx-per-request; results cached on
raw_descriptionso repeats short-circuit the model. - Polisher: Gemini Flash-Lite, Spanish-only output (Bancolombia descriptions are Spanish); user aliases pre-empt the model.
- Chat: stateless multi-turn Gemini client with seven function tools (read: query, aggregate, accounts, categories, aliases; write: add alias, recategorize batch).
- Storage: Room + SQLCipher. v1 baseline schema, destructive migration during pre-release.
- Build:
./gradlew :app:assembleDebug - Install on device (Android 12+):
adb install -r app/build/outputs/apk/debug/app-debug.apk(use-tfor MIUI). - Launch → tap the violet Connect Gemini card on Home → Settings → paste your key from aistudio.google.com/apikey.
- Tap Import → pick a Bancolombia XLSX statement → tap Process.
Toggle Auto-process new imports in Settings → Automation if you want the Classify + Polish chain to fire automatically after every import.
./gradlew :app:assembleDebugRequirements:
- JDK 17 (Zulu, Temurin, or equivalent)
- Android SDK 35, Min SDK 31 (Android 12)
- AGP 8.13.x (Hilt blocks AGP 9.x)
Kotlin · Jetpack Compose · Hilt · Room + SQLCipher · WorkManager (foreground services) · Apache POI · Vico (charts) · Gemini v1beta REST · Core SplashScreen.
- AI-first, not rule-based. The LLM classifies and polishes; results are cached as data. No hardcoded merchant lists, glosa regexes, or category catalogs.
- The raw file is the source of truth. Imported XLSX files are archived; the DB is derived from them and rebuildable.
- Privacy is non-negotiable. Encrypted at rest. The only outbound call is to your own Gemini key.
- The transaction is the atomic unit. Transfers, payments, installments, and loan payments are either a transaction or a relationship between transactions.
- Classification is metadata, not structure. The core (date, amount, description, account) is immutable; the interpretation (category, classification type, person) is mutable and auditable.
- Explicit states over booleans. Lifecycled entities use
enum status, not correlated boolean flags. - Multi-currency from day one. Every transaction declares its currency. No implicit COP assumptions.
- Auditability for life. Every classification change leaves a trail.
Design docs are intentionally kept local-only (excluded via .gitignore) because they reference real bank-statement samples. If you are a contributor and need access, contact the maintainer.
Signed APK via GitHub Releases. Sideload-only (the app needs file-system access for XLSX import; no Play Store dependency).
The release.yml workflow builds a signed APK and creates a GitHub Release every time a v*.*.* tag is pushed.
One-time setup — generate a keystore once and add four secrets to the repo (Settings → Secrets and variables → Actions):
keytool -genkey -v -keystore mintroot.keystore -alias mintroot \
-keyalg RSA -keysize 2048 -validity 10000
base64 -i mintroot.keystore | pbcopy # paste into RELEASE_KEYSTORE_BASE64| Secret | Value |
|---|---|
RELEASE_KEYSTORE_BASE64 |
base64-encoded keystore file |
RELEASE_KEYSTORE_PASSWORD |
the store password you set |
RELEASE_KEY_ALIAS |
mintroot (or whatever alias you chose) |
RELEASE_KEY_PASSWORD |
the key password |
Cut a release:
git tag v1.0.1
git push origin v1.0.1The workflow runs, builds, signs, and creates the Release. The APK is named mintroot-1.0.1.apk. versionName comes from the tag; versionCode is the GitHub Actions run number (monotonic).
On every launch the app calls GitHub's Releases API, compares the latest tag against the installed versionName, and shows a violet update banner on Home if a newer version exists. Tap Install update → the app downloads the APK to its cache and hands it to Android's Package Installer (you'll need "Install unknown apps" granted to Mintroot the first time).
Banner can be dismissed; check fires again on the next process start. Repo slug is BuildConfig.GITHUB_REPO, set in app/build.gradle.kts.
Pre-release. Daily-driven by the maintainer; schema may break between commits (the app falls back to a destructive re-import).
TBD (MIT or Apache 2.0).





