kharcha-core 0.1.0

Deterministic core of the Kharcha UPI expense tracker: SMS parsing, spam rejection, categorization, money math, dedupe. Rule-based, no AI.
Documentation
  • Coverage
  • 47.78%
    43 out of 90 items documented0 out of 33 items with examples
  • Size
  • Source code size: 532.69 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.52 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 13s Average build duration of successful builds.
  • all releases: 13s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • AkashPriyadarshii/kharcha-core
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • AkashPriyadarshii


Why

Every UPI payment in India arrives as text first — an SMS, a push notification, an email receipt. Three parsers (Dart generic, Kotlin generic, a 190-bank fleet) disagreed on the same message, money floated on doubles, and duplicates slipped through reworded carrier footers.

  • One engine. engine::parse() is the only door in. SMS, notification, email body — all one string.
  • Triple-signal dedupe. UPI ref → content hash (footer-proof, unlike body hashing) → 300s cross-channel window.
  • Exact money. i64 paise end to end. Both parents float at the edge.
  • Proven, not promised. 56 tests incl. a 34-row SMS parity corpus. Zero clippy warnings.

Quickstart

cargo add kharcha-core
git clone https://github.com/AkashPriyadarshii/kharcha-core
cargo test
cargo run --bin demo -- "INR 340.00 debited from A/C **1234 to ZOMATO UPI:623829102812. Bal: INR 12,400.00"
ParsedTransaction { payment: ParsedPayment { amount_paise: 34000, merchant: "ZOMATO", is_income: false, upi_ref: Some("623829102812"), balance_paise: Some(1240000), account_mask: Some("1234"), bank_name: None, needs_review: false }, sender: "HDFCBK", timestamp_ms: 0, content_hash: 8485077374821435771 }
cargo clippy --all-targets -- -D warnings
Command What
cargo test Full gate: 22 unit + 34 parity rows
cargo run --bin demo -- "<sms>" [sender] Parse one message, print the struct
cargo clippy --all-targets -- -D warnings Lint gate: zero warnings
cargo build --release cdylib (.so/.dll) for FFI consumers

API

Call Replaces
parse_capture / parse_captures Dart parseUpiNotification, Kotlin GenericUpiParser.parse
check_capture insertCaptured dedupe (ref → hash → 300s window)
categorize_merchant + normalize_merchant_text Categorizer
apply_filter TransactionFilter.apply
split_bill, parse_amount, is_spam, encode_inbox_line Same-named helpers

Contracts: money is i64 paise, timestamps are epoch millis, parse returns null for spam/casual text by design. Full consumer guide: docs/INTEGRATION.md. Agent rules: docs/AGENT-INTEGRATION.md.

Architecture

src/
  lib.rs             — public API + uniffi scaffolding
  engine.rs          — parse(sms, sender, ts): single entry, batch API, content hash
  parser.rs          — UPI/bank SMS parser (Dart port, fancy-regex lookahead)
  non_transaction.rs — spam rejection (recharge/OTP/loan/request/failure)
  categorize.rs      — merchant normalize + learned-beats-builtin rule match
  dedupe.rs          — ref gate + hash gate + 300s window with ref backfill
  filter.rs          — in-memory transaction filter
  money.rs           — parse_amount → i64 paise
  split.rs           — exact-paise bill split
  ffi.rs             — uniffi surface (Kotlin first); core stays FFI-agnostic
  bin/demo.rs        — smoke CLI
tests/parity.rs      — 34-row Dart-vs-Rust SMS corpus
bindings/kotlin/     — generated uniffi Kotlin bindings (committed, never hand-edited)
docs/                — INTEGRATION.md (humans), AGENT-INTEGRATION.md (agents)

Non-goals

  • No bank fleet (v1.x). 190 per-bank parsers stay out until live captures demand them; the generic path covers common formats.
  • No storage, clock, or network. The core decides; callers own rows, timestamps, and sync.
  • No AI. Rule maps and regex only. A PR containing "LLM" is rejected.
  • No fraud detection. Parsing text is this crate's whole job; safety-switch logic lives in the app.
  • No multi-currency amounts yet. Parser reads ₹/Rs/INR; AED/SGD SMS return null (v1.x).

Ecosystem

Author

Akash Priyadarshi (Patna, Bihar, India) · GitHub · Portfolio · LinkedIn · Resume

Social

X / Twitter · Threads · Instagram · Reddit

Deterministic UPI parsing in Rust — sms parser, upi expense tracker core, offline-first fintech.