A Python CLI with no dependencies that maps a whole BOM to JLCPCB/LCSC part numbers, prices it at the quantity you actually order, downloads the datasheets and zips up a fab package. Each pick comes with the reasons it was chosen, and lines it is unsure about are marked ambiguous instead of guessed. The JLCPCB web UI does this one part at a time.
Requires Python 3.11+. rich is optional, for nicer tables.
git clone https://github.com/Tommycode3/jlcfind && cd jlcfind
pipx install . # or: pip install .
PYTHONPATH=src python3 -m jlcfind --help # without installingjlcfind search "100nF 0402 X7R 16V" # parametric search, ranked + reasons
jlcfind part C2128 --json # tier, stock, price breaks, datasheet
jlcfind resolve examples/sample_bom.csv # BOM -> audit CSV (status per line)
jlcfind cost examples/sample_bom.csv --qty 50 --out cost.md
jlcfind bom examples/sample_bom.csv --out jlc_bom.csv # JLCPCB assembly BOM format
jlcfind datasheets examples/sample_bom.csv # PDFs + manifest.json
jlcfind package examples/sample_bom.csv --qty 50 \
--gerbers ./gerbers --cpl ./cpl.csv --out board_fab.zipMost commands accept --json and --fresh (bypass cache). Config and cache live in ~/.jlcfind/ (override with JLCFIND_HOME):
jlcfind config --set extended_part_fee_usd=3 default_board_qty=10 prefer_basic=true
jlcfind cache --clearTests run offline: pip install pytest && python3 -m pytest.
Headers from KiCad, JLCPCB and generic exports are matched by synonym (LCSC Part #, Manufacturer Part Number, Comment/Value, Footprint/Package, ...). Designator lists are split and ranges like R1-R4 expanded; quantity defaults to the designator count.
Each line is tried by LCSC code, then MPN, then value + footprint, and the first match wins. An exact code or MPN match is resolved. A parametric hit is resolved only if it is Basic/Preferred, its package contains the requested one, and the requested value appears in its MPN or description. Everything else is ambiguous with a note on what to check, because a wrong part on an assembled board costs far more than a manual review.
Free text like 4k7 0603 1% is parsed into package, value (SI prefixes, 4k7 1R0
Search over-fetches 60 rows, drops parts below min_stock, and sorts by an additive score. For tier
Tier dominates because an Extended part carries a one-time setup fee that, on small runs, dwarfs any unit-price difference. Stock and price are logarithmic and capped so they only break ties. The weights are hand-tuned, not fitted, and every term that fires is printed as a reason by search and written to the audit CSV by resolve.
For
ambiguous lines are costed, unresolved lines are excluded, and a warning fires when stock is below
Networking is stdlib urllib against the free jlcsearch API plus the LCSC product-detail endpoint, throttled to 0.5 s spacing, retried with linear backoff, and cached in SQLite: 24 h for search/stock/price, 30 days for datasheet URLs. Gerbers and CPL are bundled, not generated, so it works with KiCad, Altium or EasyEDA exports.
Version 0.1.0. 23 offline unit tests cover spec parsing, BOM I/O, price breaks, cost and resolution status; the network code is tested by hand, not in CI.
- Upstream search quality is the main limit. On 2026-10-30 jlcsearch returned unrelated parts for several queries (an MPN search for
STM32F103C8T6returned an LDO;10k 0402returned an inductor). jlcfind marks theseambiguous, but it cannot return a part the API doesn't. Exact LCSC-code lookups were reliable in the same test. - Value matching is a substring check:
100nFwon't match0.1uF, and1kcan match11k. - Fees follow JLCPCB's Basic/Preferred/Extended policy as of the default config; check jlcpcb.com before ordering.
- The LCSC detail endpoint is undocumented. If it changes, datasheet URLs come back empty.
- The CPL check only looks at headers.
MIT. See LICENSE.