A free, offline desktop app for organizing your DIY electronics parts. Track what you have, where it lives, and whether you have enough to build your next project — all without an internet connection or cloud account.
Simple DIY Electronics Inventory runs on your Mac as a standalone app (or from source on Mac/Linux). Your data stays in a single local file on your machine, so there is nothing to sign up for, no subscription, and no server to maintain.
- Synth builders and electronics hobbyists who accumulate resistors, capacitors, ICs, and other components across multiple storage containers
- Workshop organizers who want to know at a glance what they have, where it is, and what they need to buy
- BOM checkers who want to import a bill of materials and instantly see which parts are in stock and which need ordering
- Download the latest
.dmgfrom GitHub Releases. - Drag Simple DIY Electronics Inventory into your Applications folder.
- Launch it from Applications.
Signed releases should open normally. If macOS blocks an older build, right-click the app and choose Open, or go to System Settings > Privacy & Security > Open Anyway.
Requires Python 3.11 or newer.
Using uv (recommended):
git clone https://github.com/danielmiller/simple-diy-electronics-inventory.git
cd simple-diy-electronics-inventory
uv sync --dev
uv run python -m eurorack_inventoryUsing pip:
git clone https://github.com/danielmiller/simple-diy-electronics-inventory.git cd simple-diy-electronics-inventory python -m venv .venv source .venv/bin/activate pip install -e ".[dev]" python -m eurorack_inventory
- Browse all your parts in a searchable, sortable table
- Edit part details inline: name, category, quantity, package, location, and supplier SKU
- Add richer metadata: manufacturer, MPN, supplier name, purchase URL, notes
- Adjust quantities quickly with
+1,-1,+10, and-10buttons - Add search aliases so you can find parts by alternate names
- Jump from a part directly to its storage location
- Find and merge duplicate parts with a side-by-side comparison dialog that highlights conflicts and lets you pick which fields to keep
- Bulk-normalize part names from the Tools menu to clean up inconsistent naming
- Create storage containers: grid boxes with rows and columns, binders with numbered card slots, or custom bins
- See your storage laid out visually — each container shows which parts are in which slots
- Drag and drop parts between compartments
- Merge multiple empty grid cells into larger regions for bigger components, and split them back apart later
- Resize containers with validation so you never accidentally lose occupied slots
- See utilization counts per container at a glance
Instead of manually sorting every component into a slot, let the app do it:
- Preview before applying — see exactly what would go where before committing
- Choose a mode: incremental (only place currently unassigned parts) or full rebuild (clear and recompute)
- Choose a scope: all parts, a hand-picked selection, or a single category
- Optionally target a specific container (e.g. "fill this binder box") with an optional quantity filter to prioritize parts above a threshold
- Parts are classified by size and matched to compatible slots, with a flexible compatibility system that prefers ideal fits but allows alternatives
- If a part's storage class changes, the app automatically unassigns it from any incompatible slot
- Every assignment run is saved so you can undo it later
- Import BOMs from Excel spreadsheets or PDF documents (PDF requires optional Java + tabula-py)
- Normalize and edit BOM line items: component type, value, quantity, package
- Match BOM items to your existing inventory with fuzzy search — see match scores and reasons
- Create new inventory parts directly from unmatched BOM items, pre-filled with BOM data
- Filter by match status: all, matched, or unmatched
- Bulk-delete BOM sources you no longer need
- Normalize BOM names automatically from the Tools menu (cleans up prefixes, suffixes, and formatting)
- Promote a fully verified BOM to a project for build tracking
- Generate a shopping list from one or more BOMs showing what you need, what you have, and what to buy — then copy it to clipboard or export as CSV
- Browse your projects in a dedicated tab with maker, revision, and notes
- See part availability at a glance: the app compares your BOM requirements with current stock
- Create build instances with optional nicknames and track their status
- Rename projects via right-click context menu
- Type a few characters and the app searches across part names, aliases, categories, supplier SKUs, and package types
- Fuzzy matching means you don't need exact spelling — close matches surface automatically
- Results are ranked by relevance with bonuses for exact and substring matches
Your inventory lives in a single SQLite database file. The app provides two ways to protect it:
Database backup (exact snapshot — best for disaster recovery):
- From the app: File > Export Backup... / File > Restore Backup...
- From the command line:
python -m eurorack_inventory --export-backup ~/Desktop/backup.db
CSV export (human-readable — great for sharing or spreadsheet editing):
- From the app: File > Export as CSV... / File > Import from CSV...
- From the command line:
python -m eurorack_inventory --export-csv ~/Desktop/data.zip
Restore always creates a safety copy of your current database first. CSV import replaces all data atomically and rolls back if any integrity check fails.
If you already track parts in Excel, you can import them directly:
python -m eurorack_inventory --import ./parts_inventory.xlsx
The importer reads columns for Category, Component, Total Qty, Tayda SKU, and Merged From. It automatically creates search aliases and places imported parts in the default Unassigned location.
Your database is created automatically the first time you launch the app:
| Platform | Path |
|---|---|
| macOS | ~/Library/Application Support/Simple DIY Electronics Inventory/eurorack_inventory.db |
| Linux | ~/.local/share/simple-diy-electronics-inventory/eurorack_inventory.db |
Use --db PATH to open a different database file. Runtime logs are stored in a logs/ folder next to the database.
python -m eurorack_inventory --help
| Flag | Description |
|---|---|
--db PATH |
Path to the SQLite database file |
--import PATH |
Import an Excel workbook before launching the GUI |
--import-mode {replace_snapshot,merge_quantities} |
Import strategy (both currently produce the same result) |
--headless-import |
Run the import and exit without opening the GUI |
--bootstrap-demo-storage |
Create demo containers and the default Unassigned location |
--export-backup PATH |
Export a full database backup and exit |
--restore-backup PATH |
Restore the database from a backup file and exit |
--export-csv PATH |
Export all data as CSV files in a zip archive and exit |
--import-csv PATH |
Import data from a CSV zip archive (replaces all current data) and exit |
- The spreadsheet importer does not use source location columns to auto-place parts.
- BOM PDF import requires Java and the optional
tabula-pydependency (pip install -e ".[bom-pdf]"). - The app supports importing and matching BOMs but does not yet support authoring a BOM from scratch.
The rest of this README covers architecture, build processes, and development setup for contributors.
The app is built in Python with a PySide6 (Qt) GUI and a single SQLite database. There is no server or network component.
src/eurorack_inventory/
__main__.py # module entry point
main.py # CLI parsing and app startup
app.py # AppContext construction and wiring
config.py # database/log/resource paths
db/ # SQLite wrapper and SQL migrations
domain/ # dataclasses, enums, storage geometry helpers
repositories/ # SQL-backed data access
services/ # business logic
ui/ # PySide6 screens, dialogs, and models
resources/ # icons and app resources
tests/ # pytest suite
scripts/ # build helpers
The codebase is split into explicit layers:
- db/ — SQLite connection management and migration runner
- domain/ — dataclasses, enums, and pure storage/grid geometry helpers
- repositories/ — direct SQL access for parts, storage, projects, and audit events
- services/ — business logic (inventory, import, search, storage, auto-assignment, BOM extraction, classifier, settings)
- ui/ — PySide6 screens, dialogs, Qt models, and styling
This separation keeps business rules outside the UI and makes the service layer testable without launching the desktop app.
The app uses a single SQLite file with WAL journal mode and foreign keys enabled. Schema changes are tracked by numbered SQL migrations applied via PRAGMA user_version.
For the full schema walkthrough and ER diagram, see docs/DATABASE_DESIGN.md.
| Table | Purpose |
|---|---|
parts |
Canonical component record with metadata, total qty, denormalized primary slot shortcut, and storage class override |
part_aliases |
Extra searchable names tied to a part |
part_locations |
Authoritative multi-location placement rows with per-slot qty |
storage_containers |
Named physical container with type and JSON metadata |
storage_slots |
Individual compartment or merged region inside a container |
modules |
Build target (called "projects" in the UI) |
bom_lines |
Required quantity of a part for a project |
builds |
Concrete build instance of a project |
build_updates |
Status or note entries for a build |
settings |
Stored JSON/text configuration such as classifier thresholds |
audit_events |
Append-only record of user-visible changes |
assignment_runs |
Stored plan and pre-run snapshot for undo |
The search index is built in memory from repository data. Each part contributes candidates for its name, category, supplier SKU, package, and aliases. Scoring uses rapidfuzz.fuzz.WRatio with bonuses for exact matches, substring matches, and full-token coverage. Source weights ensure names and aliases rank higher than category or package matches.
Auto-assignment is a two-step plan-then-apply system:
- Plan — classifies parts into storage classes (
small_short_cell,large_cell,long_cell,binder_card), gathers available slots, and packs parts using a category-affinity first-fit strategy with a flexible compatibility matrix - Apply — writes slot assignments and stores the run for undo
Classification uses regex matching against part names/categories plus quantity thresholds. Users can override the storage class per part. The compatibility matrix allows cross-class placement with penalties, preferring ideal fits but reducing unassigned counts.
| Dependency | Purpose |
|---|---|
| Python 3.11+ | Runtime |
| PySide6 | Desktop GUI |
| RapidFuzz | Fuzzy text search |
| pandas | Spreadsheet import |
| openpyxl | Excel file reading |
| tabula-py | PDF BOM import (optional, requires Java) |
| pytest | Testing (dev) |
| PyInstaller | macOS app bundling (dev) |
pip install -e ".[dev]"
bash scripts/build_macos.shOr using Make:
make dmg
The build script removes build/ and dist/, runs PyInstaller, applies code signing (ad-hoc for local builds, Developer ID when configured), and optionally creates a DMG if create-dmg is installed (brew install create-dmg).
To publish releases that open without Gatekeeper warnings, configure these GitHub Actions secrets:
| Secret | Purpose |
|---|---|
MACOS_CERTIFICATE_P12_BASE64 |
Base64-encoded Developer ID Application certificate |
MACOS_CERTIFICATE_PASSWORD |
Password for the .p12 file |
APPLE_SIGNING_IDENTITY |
Full signing identity string |
APPLE_ID |
Apple ID email for notarization |
APPLE_TEAM_ID |
Apple Developer team ID |
APPLE_APP_PASSWORD |
App-specific password for notarization |
| Target | Description |
|---|---|
make install |
Install with BOM-PDF support |
make install-dev |
Install with dev and BOM-PDF extras |
make run |
Launch the app |
make test |
Run the test suite |
make clean |
Remove build and dist directories |
make dmg |
Build the macOS app bundle |
make release VERSION=x.y.z |
Bump version, commit, tag, and push |
pytest
The test suite covers search, inventory CRUD, spreadsheet import, storage geometry, auto-assignment planning and undo, classifier rules, BOM operations, and selected UI behavior.