Know when something you own appears in an official product recall.
RecallLedger is a local-first command-line tool that imports a household inventory, synchronizes official U.S. Consumer Product Safety Commission (CPSC) recalls, and keeps a durable review history. Exact UPC and brand-aligned model matches are highlighted; name similarity can only produce a candidate for human review.
No account, server, telemetry, or runtime dependency is required.
General home inventory tools record possessions. Recall search tools look up a product on demand. RecallLedger connects those workflows and preserves what you decided:
inventory.csv -> local SQLite ledger <- official CPSC JSON
|
v
exact/candidate evidence
|
v
confirmed / ignored / resolved
See the overlap research for comparisons with adjacent GitHub projects and the v0.1 specification for the precise contract.
Requirements: Python 3.11 or newer.
python -m pip install .
recallledger init --db demo.db
recallledger import examples/inventory.csv --db demo.db
recallledger sync --file examples/cpsc-recalls.sample.json --db demo.db
recallledger check --db demo.dbThe sample produces one EXACT UPC match and one CANDIDATE name match. Every
result links back to the official notice. Record a decision using the displayed
match ID:
recallledger review 2 --status ignored --db demo.db
recallledger check --json --db demo.dbThe actual match ID is printed by check; use that value if it is not 2.
Running check again recomputes evidence but preserves the review status.
The first network sync must be bounded explicitly:
recallledger sync --since 2026-08-01 --db recallledger.dbLater syncs can omit the date. RecallLedger reuses the newest stored CPSC
LastPublishDate, including that date again so updated records are safely
upserted:
recallledger sync --db recallledger.dbThe source is the public CPSC Recalls API. RecallLedger does not scrape recall pages and never writes to CPSC.
Required columns are item_id, brand, and name. Optional columns are
model, upc, serial, purchase_date, and notes.
item_id,brand,name,model,upc,serial,purchase_date,notes
fan-bedroom,Hampton Bay,Halwin 52-inch Ceiling Fan,,840059614922,,2024-05-01,Bedroomitem_idis your stable local identifier. Reimporting it updates that item.purchase_date, when present, must beYYYY-MM-DD.- Import is additive/upserting; items absent from a later CSV are not deleted.
- UPC punctuation and spacing are ignored for matching.
| Evidence | System type | Score | Meaning |
|---|---|---|---|
| Exact normalized UPC | exact |
1.00 | Strong identifier evidence |
| Exact model plus aligned brand | exact |
0.98 | Strong combined evidence |
| Exact model without aligned brand | candidate |
0.85 | Model collision needs review |
| Aligned brand plus name similarity >= 0.72 | candidate |
measured | Discovery hint only |
exact still does not mean “officially confirmed for this physical unit.” Check
the model, serial/date range, images, remedy, and other conditions on the linked
CPSC notice. Only a user can set confirmed.
Review states are:
unreviewed: new evidence.confirmed: the user verified the official notice applies.ignored: the evidence does not apply to this item.resolved: the applicable recall was handled.
recallledger init [--db PATH]
recallledger import FILE [--db PATH]
recallledger sync [--db PATH] [--file FILE | --since YYYY-MM-DD]
recallledger check [--db PATH] [--json]
recallledger review MATCH_ID --status confirmed|ignored|resolved [--db PATH]
Successful commands return exit code 0, including check when matches exist.
Boundary failures return 1; argument syntax errors return 2. Automation
should consume check --json, not parse the human-readable layout.
All inventory, recall snapshots, matches, and reviews live in the SQLite file
selected by --db. The application sends only a date filter and a descriptive
User-Agent to the CPSC endpoint; inventory data never leaves the machine.
The runtime is Python standard library only:
argparsefor the CLIsqlite3for transactions and durable stateurllibfor read-only CPSC requestscsvandjsonfor boundary formatsdifflibfor conservative candidate similarity
The rationale is recorded in ADR 0001.
python -m pip install -e ".[dev]"
python -m ruff check .
python -m ruff format --check .
python -m mypy src
python -m unittest discover -s tests -v
python -m buildThe automated tests include the full offline CLI flow and never depend on the live CPSC service. Before a release, also run one recent date-bounded live sync.
If a command fails, follow the exact repair paths in Troubleshooting. See Contributing for patch scope and test expectations.
RecallLedger is an aid, not a complete recall or legal-safety service. CPSC data can omit identifiers, and a product name can be ambiguous. Always use the linked official notice as the authority and follow the manufacturer's/CPSC remedy.