Skip to content

somebox/bomi

Repository files navigation

bomi

CI

bomi logo

Bill of Materials Integration — applying DevOps-style tooling to electronics projects.

bomi is a Python CLI for researching JLCPCB/LCSC parts and keeping a per-project BOM in version control. It caches part data in a shared local SQLite database and stores project selections in .bomi/project.yaml.

AI agents (Claude Code, Cursor, GitHub Copilot, etc.) can drive it directly — searching the catalog, comparing parts, updating the BOM, and pulling datasheet analysis without touching a browser. After a lot of iteration and many PCBs made, bomi proved to be a significant time saver: easier to track decisions, catch stock issues early, and keep BOM costs under control across revisions.

somebox.github.io/bomi — demos, examples, and getting-started guide

Requirements

  • Python 3.11+
  • uv for install and development
  • Network access for live catalog search
  • An OpenRouter API key only if you want datasheet analysis or summaries

Install

git clone https://github.com/somebox/bomi.git
cd bomi

# Install the CLI globally as `bomi`
uv tool install -e .

# Or, to work on the repo
uv sync

Note for asdf users: uv tool install installs into uv's own tool environment, which may not be on PATH under all asdf-managed Python shims. If you get "No preset version installed for command bomi", run directly with:

uv run --directory /path/to/bomi bomi <command>

Set BOMI_PROJECT (see Project Resolution) to avoid needing --project on every command.

Configuration

Global config lives here:

  • macOS: ~/Library/Application Support/bomi/config.yaml
  • Linux: ~/.local/share/bomi/config.yaml

Minimal config (see config.yaml.example in the repo):

openrouter_api_key: sk-or-v1-...

Environment variables override config values:

export BOMI_OPENROUTER_API_KEY=sk-or-v1-...

The shared cache database is stored alongside the config as parts.db.

First Use

# 0. Sync the category tree (one-time, cached for 24h)
bomi sync

# 1. Search the live catalog
bomi search "10k 0402 resistor"

# 2. Cache one or more exact parts
bomi fetch C8287 C25900

# 3. Query the local cache offline
bomi query --package 0402 --basic-only --attr "Resistance >= 10k"

# 4. Inspect or compare cached parts
bomi info C8287
bomi compare C8287 C25900

# 5. Analyze a cached part's datasheet with OpenRouter (default prompt covers key specs)
bomi analyze C8287

info, compare, analyze, and datasheet all work from the local cache. If a part is missing, run bomi fetch <code> first.

Project Workflow

Projects store their BOM in .bomi/project.yaml, which is meant to be committed with the rest of the design files.

cd my-pcb-project
bomi init --name "my-board" --description "Motor driver board"

# Add parts to the BOM (fetches from catalog if not already cached)
bomi select C8287 --ref R1 --qty 2 --notes "10k pull-up"
bomi select C1525 --ref C1 --qty 1 --notes "100nF bypass"
bomi select C1525 --ref C2 --qty 1 --notes "100nF bypass"

# Review the BOM
bomi list
bomi list --format json
bomi list --format csv
bomi list --check

# Project summary
bomi status

# Edit selections
bomi relabel R1 R3
bomi deselect C2

bomi init currently:

  • creates .bomi/project.yaml
  • appends datasheet PDF ignore rules to .gitignore

Project Resolution

Project context is resolved in this order:

  1. --project <path>
  2. BOMI_PROJECT env var
  3. walking up from the current directory to find .bomi/project.yaml

If you're running bomi from outside the project directory (e.g. via uv run --directory), set BOMI_PROJECT so project commands work without --project on every call:

export BOMI_PROJECT=/path/to/my-pcb-project

Commands

Research commands

Command Notes
sync Fetch and cache JLCPCB category tree (skips if <24h old, --force to refresh)
categories [query] List cached categories, optionally filtered by name
search <keyword> Live JLCPCB search, results are cached locally. --category filters server-side
fetch <codes>... Cache exact LCSC codes
query [keyword] Search the local cache only. --category filters by category
info <designator-or-code> Show one cached part by project designator (for example R1) or LCSC code
compare <codes>... Compare cached parts
analyze <code> Analyze one cached datasheet with OpenRouter
datasheet <codes>... Download PDFs and optionally generate markdown summaries
db stats Show cache statistics
db clear Clear the local cache

Project commands

Command Notes
init Create .bomi/project.yaml in the current directory
select <code> --ref REF Add a BOM entry, fetching the part if needed
deselect <ref> Remove a BOM entry by reference
relabel <old> <new> Rename a BOM entry reference
list Show the BOM with cached part data (bom is an alias)
status Show project summary, cost estimate, and warnings

Output Formats

Most research commands support --format table|json|csv|markdown.

Commands that currently support --format:

  • search
  • fetch
  • query
  • info
  • compare
  • analyze
  • list
  • db stats

Most JSON output uses this envelope:

{
  "status": "ok",
  "command": "search",
  "count": 5,
  "results": []
}

list --format json and bom --format json both return { "status": "ok", "command": "...", "data": [...] }.

status is text-only today.

Attribute Filters

Filter syntax:

--attr "AttributeName operator value"

Supported operators: >=, <=, >, <, =, and != (mainly for non-numeric attribute values).

Values support SI prefixes such as 10k, 100n, and 4.7u. Non-numeric values use string matching with = or !=.

Examples:

bomi search "0402 resistor" --attr "Resistance >= 10k"
bomi query --category "Chip Resistor" --attr "Resistance = 36k"
bomi query --attr "Capacitance <= 100n"
bomi search "RGB LED" --attr "Forward Current >= 100mA"
bomi query --category "Slide Switches" --attr "Circuit = SP3T"

search vs query filters

For package, minimum stock, maximum price (qty-1 tier), and --attr filters, the same rules are applied after a live search (in-memory, on normalized parts) and inside the local query path (SQL). The --basic-only and --preferred-only flags apply on the JLCPCB API for search only; they are enforced in SQL for query but are not re-applied locally after a search. --category for search resolves to an exact synced subcategory name for the API; for query it is a substring match on cached parts.category.

Data Locations

What Location
Global config ~/Library/Application Support/bomi/config.yaml on macOS, ~/.local/share/bomi/config.yaml on Linux
Shared cache database parts.db in the same global data directory
Project BOM .bomi/project.yaml inside a PCB project
Optional project docs docs/ inside your project

Project Structure

src/bomi/
  api.py         HTTP client for JLCPCB search and detail endpoints
  analysis.py    datasheet download and OpenRouter analysis
  categories.py  category validation (query) and API name resolution (search)
  cli.py         Click command definitions and output orchestration
  config.py      config and path handling
  db.py          SQLite schema and persistence (Database supports `with ... as db`)
  filters.py     shared package/stock/price/--attr rules for search vs query
  normalize.py   API response normalization
  output.py      table/json/csv/markdown formatters and BOM views for list/bom
  project.py     project file and BOM handling
  scrape.py      category tree scraper for JLCPCB
  search.py      local cache query helpers

Website and demo assets

The static site under site/ includes terminal demos in site/presentation/. To regenerate casts and copy the Reveal deck after editing demo/generator/scenes.yaml or demo/presentation/index.html:

python build_site.py

Then commit the updated site/presentation/ files. GitHub Pages only publishes what is in the repo; it does not run this script. Details: demo/README.md.

Documentation

  • docs/bomi-guide.md: short agent-oriented usage guide (also at somebox.github.io/bomi/guide.html)
  • docs/features.md: backlog / future-feature ideas (not a roadmap)
  • docs/examples.md: command examples
  • docs/bomi-api-internals.md: current API notes and implementation boundaries
  • docs/sqlite-database-guide.md: local cache schema and query examples

Development

uv sync
uv run pytest -v

Contributing

PRs are welcome. A good starting point is:

  1. run uv sync
  2. read README.md and the docs linked above
  3. run uv run pytest -v
  4. keep behavior changes reflected in the docs

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors