PennyWise is a minimalist, AI-powered expense tracker for Android that automatically extracts transaction data from SMS messages using on-device processing.
Please reference these documents when working on this project:
- Architecture:
/docs/architecture.md- MVVM + Clean Architecture patterns, layer responsibilities - Design System:
/docs/design.md- Material 3 theming, colors, typography, components - PRD:
/prd.md- Product requirements, features, timeline - Backup & Restore:
/docs/backup-format.md- Backup JSON format + the forward/backward compatibility contract. Read this before changing anything a backup serializes (entities,data/backup/).
- UI Framework: Jetpack Compose with Material 3
- Architecture: MVVM with Clean Architecture (UI, Domain, Data layers)
- State Management: Unidirectional Data Flow with StateFlow
- DI: Hilt for dependency injection
- Database: Room for local storage
- AI/ML: MediaPipe LLM (Qwen 2.5) for on-device processing
- Background: WorkManager for SMS scanning
- Material You: Dynamic color from wallpaper (Android 12+)
- Light/Dark Theme: Full support with semantic color roles
- Spacing: 8dp grid system
- Typography: Material 3 type scale
- Navigation: NavigationBar for phones, NavigationRail for tablets
- Edge-to-Edge: All screens use PennyWiseScaffold with default TopAppBar for consistent system bar handling
- Consistent UI: PennyWiseScaffold provides default TopAppBar with options for title, navigation, actions, and transparency
- Follow Kotlin coding conventions
- Use meaningful variable names
- Implement proper error handling with sealed classes
- Ensure UI components are reusable and testable
- Always test on both light and dark themes
Working on Phase 1: Core Foundation (Project setup, Material 3 theming, Room database, Navigation)
- Build:
./gradlew build - Test:
./gradlew test - Lint:
./gradlew lint
We follow Semantic Versioning (SemVer) - MAJOR.MINOR.PATCH:
- MAJOR: Breaking changes, major UI overhauls, architecture changes
- MINOR: New features, significant improvements
- PATCH: Bug fixes, minor improvements, performance optimizations
Current version: 2.1.3 (versionCode: 13)
Recent version history:
- 2.1.3: Federal Bank support, Discord community, GitHub issue templates
- 2.1.2: Spotlight tutorial, SBI/Indian Bank support, auto-scan on launch
- 2.0.1: Previous release
The project now uses a multi-module architecture:
- app: Main Android application module
- parser-core: Standalone bank parser module (no Android dependencies)
Bank parsers are now in the parser-core module for reusability across platforms.
- Location: Add to
parser-core/src/main/kotlin/com/pennywiseai/parser/core/bank/ - Base Class: All bank parsers extend
BankParserabstract class- Indian Banks: MUST extend
BaseIndianBankParserto inherit centralized mandate, subscription, and balance update logic. - UAE Banks: MUST extend
UAEBankParserfor currency and transaction type handling.
- Indian Banks: MUST extend
- Key Methods:
getBankName(): Returns the bank's display namecanHandle(sender: String): Checks if parser can handle SMS from senderparse(smsBody, sender, timestamp): ReturnsParsedTransactionor null
- Override Patterns: Banks typically override:
extractAmount(): Bank-specific amount patternsextractMerchant(): Bank-specific merchant extractionextractTransactionType(): If needed for special cases
- Registration: Add new parser to
BankParserFactory.parserslist in parser-core - Return Type: Use
ParsedTransactionfrom parser-core - Imports for parser-core:
com.pennywiseai.parser.core.TransactionTypecom.pennywiseai.parser.core.ParsedTransactionjava.math.BigDecimalfor amounts
- Use
com.pennywiseai.tracker.data.mapper.toEntity()to convert ParsedTransaction to TransactionEntity - The mapper handles type conversions between modules
- Airtel Payments Bank
- Al Rajhi Bank (Saudi Arabia) - Arabic SMS support
- Alinma Bank (Saudi Arabia) - Arabic SMS support
- Altana Federal Credit Union (USA)
- American Express (AMEX)
- Axis Bank
- Bank of Baroda
- Bank of India
- Canara Bank
- Central Bank of India
- Chase Bank (USA)
- City Union Bank
- DBS Bank
- Federal Bank
- HDFC Bank
- HSBC Bank
- Huntington Bank (USA)
- ICICI Bank
- IDBI Bank
- IDFC First Bank
- Indian Bank
- Indian Overseas Bank
- India Post Payments Bank (IPPB)
- Jio Payments Bank
- JioPay
- Jammu & Kashmir Bank
- Jupiter Bank
- Juspay
- Karnataka Bank
- Kerala Gramin Bank
- Kotak Bank
- LazyPay
- Liv Bank (UAE) - Digital bank
- Mashreq Bank
- mBank CZ (Czech Republic) - Czech SMS support
- M-PESA (Kenya) - Mobile money service
- Navy Federal Credit Union (USA) - NFCU
- NMB Bank / Nabil Bank (Nepal)
- OneCard
- Priorbank (Belarus) - Russian/Belarusian SMS support
- Punjab National Bank (PNB)
- Punjab & Sind Bank (PSB)
- Saraswat Co-operative Bank
- Saudi National Bank / Al Ahli (SNB-AlAhli, Saudi Arabia) - Arabic SMS support
- Siddhartha Bank Limited (Nepal)
- State Bank of India (SBI)
- Slice
- South Indian Bank
- Standard Chartered Bank
- STC Bank (Saudi Arabia)
- T-Bank / Tinkoff (Russia) - Russian SMS support
- Union Bank
- Utkarsh Bank
When implementing any feature, please ensure it aligns with the architecture patterns and design system defined in the documentation.
Backups serialize Room entities directly to JSON via kotlinx.serialization
(data/backup/). The format is forward- and backward-compatible by design.
The one rule: every backup-serialized field (entity columns + the wrapper
models in BackupModels.kt) must have a Kotlin default value. Missing keys
in an older backup fall back to defaults; unknown keys from a newer backup are
ignored. Dropping a default re-introduces the "can't restore old backup" bug
(#414). BackupSchemaGuardTest enforces this in CI.
- When adding an entity column: give it a Kotlin default;
@Contextualif it'sBigDecimal/LocalDate/LocalDateTime;@Serializableif it's an enum. - When in doubt, use the backup-maintainer subagent / backup-format
skill, and read
/docs/backup-format.md.
Never use pii in comments, code anywhere
- Parser tests must use the shared JUnit helpers under
ParserTestUtils. For full guidance (examples, migration checklist), readdocs/parser-test-standards.md.