Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

455 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Expense Buddy

Expense Buddy Logo

Get it on Google Play

Latest Release Build Status

Expense Buddy is a privacy-first expense tracker built with React Native and Expo, designed around one core idea: turn transaction SMS messages into draft expenses automatically, let you review them on-device, and keep the confirmed data synced to a GitHub repository you control.

Manual entry, analytics, multi-currency support, and GitHub sync are all there, but the product's differentiator is the import pipeline: scan recent Android SMS messages, extract likely expenses, stage them locally, and import only what you approve.

Why Expense Buddy

  • Auto-detect likely expenses from Android transaction SMS messages
  • Surface new matched transactions with local Android notifications that reopen the review flow
  • Keep raw SMS content on-device and out of GitHub sync
  • Review, edit, reject, or dismiss imported items before they become expenses
  • Sync confirmed expenses across devices using your own private GitHub repository
  • Track expenses manually too, with custom categories, payment methods, and saved instruments
  • Explore spending with charts, filters, and multi-currency analytics

Auto-Import First

Expense Buddy ships a hybrid SMS import pipeline for Android. Transaction detection and field extraction stay deterministic and explainable, while category suggestion can be upgraded by a bundled on-device LiteRT model. The flow remains intentionally review-first: the app finds likely transactions, stages them locally, and waits for your approval before anything is added to your expense history.

Today, the import system:

  • scans a recent SMS window on Android
  • can detect newly received transaction SMS messages in the background on Android
  • uses deterministic rules for transaction extraction
  • runs a bundled native LiteRT classifier for default-category suggestions
  • falls back to the regex category suggestion when model confidence is low
  • keeps raw SMS data local to the device

Planned direction:

  • keep the import flow fully on-device
  • broaden parser coverage beyond the initial regex packs
  • replace the seed LiteRT model with a model trained on more independent labels
  • keep ML limited to suggestion-quality improvements while review-first import remains the guardrail

The current ML model is a first integration milestone, not a final quality claim. It is trained on a small heuristic-shaped seed set and is intentionally gated behind conservative fallback behavior.

For the model-workspace architecture diagrams and the current Android-ready model contract, see tools/sms-ml/docs/model-architectures.md.

Features

SMS Import and Review

  • Android-only SMS import using the native expense-buddy-sms-parser parsing engine (pure Kotlin, no JS bridge)
  • Android-only background transaction alerts using the native expense-buddy-sms-module module
  • Zero-hop native sync: a single syncInboxAsync bridge call reads, parses, classifies, deduplicates, and queues items in native Room — JS only receives a count
  • Inline READ_SMS permission handling through the native module
  • Optional Settings toggle for background SMS alerts with RECEIVE_SMS and POST_NOTIFICATIONS gating
  • Review queue where each staged item can be accepted, edited, rejected, or dismissed — surfaced through a React Context provider subscribed to native events
  • Local notifications route back into the review queue instead of silently creating expenses
  • Native LiteRT category suggestion with regex fallback for low-confidence predictions
  • Conservative category suggestion resolver built around shipped default categories
  • Local-only processing with no backend parsing

Expense Tracking

  • Quick add flow with amount, category, date, notes, and payment method
  • Optional math expression entry like 120+30
  • Custom categories with icons, colors, editing, and reordering
  • Saved payment instruments for cards and UPI handles
  • Full create, edit, delete, and soft-delete sync behavior
  • Day-level detail view and searchable history

GitHub Sync

  • Private repository sync using a fetch-merge-push workflow
  • Daily CSV files in expenses-YYYY-MM-DD.csv format
  • Optional settings sync for non-sensitive app settings
  • Dirty-day tracking so only changed dates are re-uploaded
  • Differential fetch and upload using remote blob SHA caching
  • Timestamp-based auto-resolution with true conflict detection when needed
  • Manual sync controls plus optional auto-sync on launch or on change

Analytics

  • Daily trend charts and category or payment-method breakdowns
  • Multi-currency grouping and filtering
  • Advanced filters for date range, amount, search text, categories, methods, and saved instruments
  • Shared filter state between History and Analytics

User Experience

  • Works on Android, iOS, and Web for core expense tracking
  • SMS import is Android-only and requires a native build
  • Play-installed Android builds support native in-app update checks and standard full-screen Play update flows
  • In-app review prompts are Play-only, lightly rate-limited locally, and still subject to Google Play eligibility decisions
  • Dynamic locale loading for English (US, UK, IN), Hindi, and Japanese
  • Dark mode, changelog gating, update notifications, and reusable Tamagui UI primitives

How the SMS Import Flow Works

  1. Open Settings and scan recent messages, or enable background SMS alerts on Android.
  2. Expense Buddy reads recent Android transaction SMS messages on-device or parses newly received SMS messages locally in the background.
  3. A single syncInboxAsync native bridge call reads, parses, classifies, deduplicates, and inserts items into a native Room queue — no JS orchestration.
  4. The parser extracts likely transaction details, generates a deterministic SHA-256 fingerprint for dedup, and produces a regex fallback category suggestion.
  5. The native module scores the same messages with a bundled LiteRT category model, replacing the regex suggestion only when confidence is high enough.
  6. If a new background match arrives while the app is not foregrounded, a local notification opens the review flow.
  7. The review UI (backed by a React Context provider subscribing to native onReviewQueueUpdated events) shows pending candidates.
  8. You review each candidate and decide whether to accept, edit, reject, or dismiss it.
  9. Only accepted items become normal expense records and participate in optional GitHub sync.

This review-first model is deliberate. The app aims to reduce manual entry without hiding how an import decision was made.

Getting Started

Prerequisites

  • Node.js 24.x or higher
  • Yarn 4.5.0
  • Expo CLI
  • For iOS: Xcode and CocoaPods
  • For Android: Android Studio and SDK
  • For SMS import development: an Android development build or release build, because Expo Go cannot load the custom native SMS module

Installation

git clone https://github.com/sudokoi/expense-buddy.git
cd expense-buddy
yarn install
yarn start

Run the app

  • iOS: yarn ios
  • Android: yarn android
  • Web: yarn web

GitHub Sync Setup

Sign in with GitHub on Android

  1. Go to Settings > GitHub Sync.
  2. Tap Sign in with GitHub.
  3. Approve the device-flow code in the browser.
  4. Pick a personal repository you own and can write to.
  5. Save the branch and test the connection.

Token-based setup for Web or fallback use

  1. Create a GitHub Personal Access Token.
  2. Grant Contents: Read and write for a fine-grained token, or use the classic repo scope for a private repository.
  3. In the app, enter the token, repository in owner/repo format, and branch.
  4. Save the config and test the connection.

Auto-sync options

  • Sync on app launch
  • Sync after every add, edit, or delete
  • Manual sync with upload and download controls

Architecture

Expense Buddy uses Expo Router for navigation, Tamagui for UI, XState stores for app state, and a service layer for sync, storage, analytics, and SMS import logic.

Key implementation details:

  • file-based routing under app/
  • XState stores for expenses, settings, filters, notifications, and UI state
  • React Context provider for SMS review queue (native-owned Room persistence, not an XState store)
  • service-layer sync engine for GitHub fetch, merge, conflict handling, and uploads
  • single native Android SMS module (expense-buddy-sms-module) handling permissions, inbox scanning, ML classification, and queue persistence — expense-buddy-sms-parser is a pure Kotlin library with no JS bridge
  • property-based and unit tests across storage, sync, parsing, and store behavior
  • tracked Expo native modules for background SMS alerts and Play Core integrations

For the deeper architecture write-up, see ARCHITECTURE.md.

Project Structure

expense-buddy/
├── app/
│   ├── (tabs)/
│   │   ├── index.tsx           # analytics (default tab, charts and breakdowns)
│   │   ├── add.tsx             # manual expense entry
│   │   ├── history.tsx         # history and filters
│   │   ├── settings.tsx        # sync, import, and app settings
│   │   └── _layout.tsx
│   ├── +html.tsx
│   ├── +not-found.tsx
│   ├── github/repo-picker.tsx  # GitHub repository selection flow
│   ├── modal.tsx
│   └── _layout.tsx
├── components/
│   ├── analytics/              # charts, filters, and analytics UI
│   ├── history/                # history list and related UI
│   ├── ui/                     # shared styled components
│   ├── NotificationStack.tsx
│   ├── Provider.tsx
│   └── SyncIndicator.tsx
├── hooks/                      # analytics, auth, sync, changelog, update, and SMS import action hooks
├── services/
│   ├── sms-import/
│   │   └── suggestion-resolver.ts
│   ├── background-sms/
│   │   ├── android-background-sms-module.ts
│   │   └── background-sms-permissions.ts
│   ├── github-sync.ts          # GitHub API client
│   ├── sync-machine.ts         # sync state machine
│   ├── sync-manager.ts         # sync orchestration
│   ├── merge-engine.ts         # conflict resolution and merge logic
│   ├── expense-storage.ts      # local expense persistence
│   ├── settings-manager.ts     # settings persistence and sync support
│   ├── secure-storage.ts       # encrypted secure storage
│   ├── storage.ts              # MMKV adapter with AsyncStorage fallback
│   ├── update-checker.ts
│   └── auto-sync-service.ts
├── providers/                  # React Context providers
│   └── sms-import-review-provider.tsx
├── stores/
│   ├── expense-store.ts
│   ├── settings-store.ts
│   ├── filter-store.ts
│   ├── notification-store.ts
│   ├── ui-state-store.ts
│   └── store-provider.tsx
├── modules/
│   ├── expense-buddy-sms-module/ # Single SMS bridge module (permissions, scan, ML, queue)
│   ├── expense-buddy-sms-parser/     # Pure Kotlin parsing library (no JS bridge)
│   ├── expense-buddy-play-core/      # Play Store update and review native module
│   └── expense-buddy-logger/         # On-device structured logging
├── locales/                    # en-US, en-GB, en-IN, hi, ja
├── decisions/                  # ADRs and technical decisions
├── assets/
├── constants/
├── types/
├── utils/
└── scripts/

Testing

yarn test
yarn test:watch

The test suite includes unit tests and property-based tests for sync, storage, parsing, and state-management behavior.

Configuration

The app does not require user-provided environment variables.

The GitHub OAuth Client ID is configured in app.config.js and can be overridden for local Expo development with EXPO_PUBLIC_GITHUB_OAUTH_CLIENT_ID.

Build profiles are defined in eas.json:

  • development for dev client builds
  • preview for internal testing
  • production for store-ready builds
  • internal for direct APK distribution

Building

Development

yarn start

Production

# iOS
eas build --platform ios --profile production

# Android
eas build --platform android --profile production

# APK for testing
eas build --platform android --profile internal

Release automation is documented in .github/RELEASE.md.

Privacy

Expense Buddy does not collect user data. Expense data lives on-device by default, and optional sync writes only to the GitHub repository you configure. Raw SMS import data is processed locally and is not uploaded as part of sync.

See PRIVACY.md for the full privacy policy.

Reporting Issues

  • In the app: Settings > App Information > Report an Issue
  • On GitHub: Issue templates

Contributing

Read CONTRIBUTING.md before opening a pull request. Please follow our Code of Conduct. For security vulnerabilities, see our Security Policy.

This project uses a strict issue-first contribution process. If you want to propose a fix, feature, refactor, or documentation change, open an issue first and discuss the problem and proposed solution before sending code.

License

Expense Buddy is available under the AGPL-3.0 License.

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages