بنقرة واحدة
add-bank-sms-parser
Add a new bank SMS parser or a new SMS shape to an existing bank.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Add a new bank SMS parser or a new SMS shape to an existing bank.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | add-bank-sms-parser |
| description | Add a new bank SMS parser or a new SMS shape to an existing bank. |
Arguments: $ARGUMENTS — bank slug and one or more sample SMS bodies
(verbatim, including TRAI sender ID and ISO received_at if known).
AGENTS.mdbank_sms_parser/models.pybank_sms_parser/parsers/base.pybank_sms_parser/api.pybank_sms_parser/parsers/__init__.pyDo not write parser code before reading the real SMS body verbatim. SMS bodies are short, but bank templates vary in subtle ways (date format, mask format, ordering of clauses). Skipping this step produces parsers that match imagined structure and silently drop fields.
From each body, identify:
Rs./INR, XX1234/x1234/*XX1234, date
format, IMPS:/RRN:/UPI Ref, Bal Rs./Avl Limit:/Available limit)received_at from the forwarder is needed as a date
fallbackbank_sms_parser/parsing/ helpers before ad-hoc regex:
parse_date, parse_datetime, parse_amount, parse_money,
received_at_to_ist, normalize_whitespace, extract_card_mask,
extract_account_mask.BaseSmsParser and implements
parse(body: str, *, sender: str | None = None, received_at: datetime | None = None) -> ParsedSms.ParsedSms(email_type=..., bank=..., transaction=SmsTransactionAlert(...)).
SmsTransactionAlert.amount requires a Money. Wrap bare numerics
as Money(amount=parse_amount(match.group("amount")), currency="INR");
use parse_money(...) only when the captured text already contains
the currency prefix (parse_money itself returns Money).
raw_description is debug-only and excluded from dump/repr — do not
stash real SMS content in serialized fields.BaseSmsParser subclass per distinct SMS shape with a
stable email_type stringonecard_cc_transaction_alert) — do not split into one class
per phrasing_PARSERS ordered tuple of parser instances (first match wins,
even when there is only one parser){Bank}Parser(BankSmsParser) dispatcher with
bank = "{slug}" and parsers = _PARSERSparse(body, *, sender=None, received_at=None) that forwards
both keyword args to the dispatcherparsers/{bank}.py) and subpackage
(parsers/{bank}/) layouts are both valid: slice.py and
hdfc.py are multi-shape single files; icici/ and onecard/
are subpackages. Reach for a subpackage when the bank is large or
splits naturally by shape; otherwise a single file is fine.email_type stable and bank-prefixed (e.g.
hdfc_dc_transaction_alert). bank-email-fetcher stores these
values verbatim — never rename."{slug}": {Bank}Parser to the
PARSERS dict in bank_sms_parser/parsers/__init__.py.
api.SUPPORTED_BANKS = tuple(PARSERS) and the CLI bank list
follow automatically.tests/fixtures/sms/{bank}/{slug}.txt
plus a parametrized case in tests/test_new_parsers.pytests/fixtures/sms/{bank}/negative/{slug}.txt
and add it to test_real_negative_fixtures_raise_parse_error_PARSERS orderingFirst match wins. Order matters:
ParserStubError stubs at the very end, so they never shadow
real parsers.Indian bank SMSes share TRAI senders across many message types. A naive parser will happily extract an "amount" from an OTP and emit a fake transaction. Every parser must:
ParseError (or, if the shape is
well-known and intentionally unimplemented, ParserStubError). Do
not parse them as transaction alerts.amount and direction; transaction/spend alerts also
require account_mask or card_mask; payment-received alerts may
omit the mask if the bank's template does not include one. If any
required field is missing — including because the body looks
truncated — raise ParseError. Do not fabricate.direction from the verb (debit: debited, spent, paid,
withdrawn, purchased; credit: credited, received, refunded,
reversed; declined: declined, failed). Reject the SMS if no
canonical verb is present.sender argument as a secondary signal at most
(e.g. to disambiguate two ICICI shapes); never as the sole evidence
that an SMS is a transaction alert.If the SMS body has no usable date, parsers must accept the optional
received_at argument and use it as the fallback for
transaction_date / transaction_time. received_at is a UTC
datetime per Part 1's contract; convert to Asia/Kolkata via
received_at_to_ist (from bank_sms_parser.parsing) before
extracting .date() / .time(). An SMS that arrived at 02:30 IST
will otherwise land on the previous UTC day. Do not invent a date
from today(); either use what the body says, what the forwarder
gave us (IST-converted), or leave the field None.
ParseError (or ParserStubError for known-but-unimplemented
shapes). Never return None — the dispatcher needs the exception to
try the next parser.parse_sms, SUPPORTED_BANKS,
exceptions, and bank-level imports
(from bank_sms_parser.parsers.{bank} import {Bank}Parser).XX0000 /
x0000 / xx0000 / 0000; reference numbers 000000000000;
customer names Customer (Hi Akhil → Hi Customer); fake
merchants like SampleSubs Monthly. Anonymize VPAs, phone
numbers, and bank short-links the same way.AGENTS.md.After implementation, from the package root, run:
uv sync # only if deps are not yet installed
uv run pytest -q
uv run ruff check
uv run ty check
All must pass before commit. Match conventions in AGENTS.md.