Parts on hand: the maker's inventory, and only the rest ordered¶
A source
This page is a source of edakit – a concept, a prompt or the rules of a session –, shown as it is in the repository. Read it as such; the guides say what edakit does.
Status 2026-11-03: decided and built – steps 1 and 2 in edakit (edakit/inventory.py, edakit order, edakit
inventory, handbook 8.4 and 10.1); left is step 3, the live run against the owner's inventory, in TODO.md. Rewritten
on the owner's word the same day – "wir beginnen KISS": one document with a table of fixed columns, in whatever format
the maker keeps it, named in edakit.local.toml, read and never written – and decided in a decision round (decisions 9
to 19). The first version of 2026-11-02 (PartsLedger as the source, a match by sibling and kit, the way back to
PartsLedger, the survey of other tools) is in this file's history; its decisions are at the end, marked where the
rewrite replaces them.
Why¶
edakit buys every part it does not have assembled. A part soldered by hand (bom: false), an item off the board
([[extra]]), every part of a bought or hand-wired board: edakit order writes a cart line for each, need plus spares,
rounded up to the supplier's minimum and pack size (handbook 8.4). What lies in the maker's drawer is not asked. On
2026-11-02 the owner's first LCSC order went out that way – 26 lines of through-hole parts, LEDs, resistors and
headers (docs/concepts/done/parts-order.md) – and nothing checked a single line against what was at home.
By the yardstick (docs/concepts/done/design-as-text.md), what the maker has lives in their head or in a file edakit
does not know. Two words to keep apart: stock is what the assembler has (edakit stock, PARTS.stock, JLCPCB's
catalogue); the maker's own parts are on hand, listed in the inventory.
The inventory: one table, any format¶
The inventory is a document with a table of named columns. edakit reads these formats, by the file's extension:
| Format | Which tables count | Read with |
|---|---|---|
.md |
every pipe table whose header row has the required columns | edakit's own parser; a cell's link text counts ([NE555N](https://github.com/tgd1975/edakit/blob/main/docs/concepts/done/parts/ne555n.md) is NE555N) |
.html, .htm |
every <table> whose first row has the required columns |
the standard library's html.parser |
.csv |
the file is the table | the standard library; ,, ; or tab, UTF-8 with or without BOM – what Excel and LibreOffice write |
.xlsx |
every sheet whose first non-empty row has the required columns | openpyxl, a dependency already (EasyEDA's pick-and-place file) |
.ods |
the same, OpenDocument Spreadsheet – LibreOffice Calc's format | zipfile and xml.etree of the standard library, no new dependency |
Every other table, sheet and column is ignored – a sheet of notes, a column "Fach" or "Bestellt am" bothers nobody. Column names are compared without case and surrounding blanks.
The columns, by their default names:
| Column | Content | Needed by edakit |
|---|---|---|
ID |
the maker's name for the row – the part number read off the part (NE555N), or anything (R-330-THT) |
required |
Quantity |
pieces on hand, a whole number ≥ 0 | required |
LCSC |
the LCSC number (C439782) |
optional – the first key of the match |
Name, Description, Link |
for the maker; edakit shows them in its report | optional |
A row is a part when it matches a parts entry of the project, in this order:
- By LCSC number – from the row's
LCSCcolumn, else from the LCSC map by the row'sID(below) – equal to the entry'slcsc. - By part number – the row's
IDequal to the entry'smpn, case and blanks ignored, the comparison PARTS.stock makes against JLCPCB's MPN.
Nothing else: no family siblings, no kits by value, no guess from the description. A resistor assortment counts only where the maker gives its rows an LCSC number or an MPN – their statement that this is the part. The same part in several rows, tables, sheets or files is summed: parts of one type may lie in more than one place.
The LCSC map. Who does not want an LCSC column in their inventory keeps a second table beside it, with the
columns ID and LCSC, in any of the formats above. The inventory stays untouched; the map translates its IDs. An ID
mapped to two LCSC numbers is an error.
Where it is named: edakit.local.toml¶
The inventory is the maker's and private – it belongs in no project's repository, and nobody else's checkout has it.
Its paths go into edakit.local.toml beside edakit.toml, a file of this checkout that git ignores – as Claude
Code's settings.local.json –, never into edakit.toml itself:
# edakit.local.toml – this checkout's, in .gitignore
[inventory]
files = [ # the parts on hand; edakit order takes from them (8.4)
"~/Dokumente/Teile/inventory.xlsx",
"~/Dokumente/Teile/inventory_*.md", # a glob: every file it matches
]
lcsc_map = "~/Dokumente/Teile/lcsc.csv" # optional: ID → LCSC, the inventory left as it is
[inventory.columns] # optional: the maker's own column names
id = "Teil"
quantity = "Anzahl"
lcsc = "LCSC-Nr."
files is one path or a list of paths and globs, formats mixed: an inventory split into inventory_ics.md and
inventory_leds.md is two entries or one glob – the hierarchy named explicitly, no link followed, so no question what
is part of it and what a link outward (decision 18). The column map lies beside the paths, since it describes the same
local files. ~ and relative paths are resolved against the project's folder.
The file is per checkout: each project names its inventory once, and a second machine has its own. edakit inventory
template adds edakit.local.toml to the project's .gitignore, as the skill new-project does for a new project;
edakit order and edakit inventory say in a note when git tracks the file after all.
What happens:
| Settings | edakit does |
|---|---|
no edakit.local.toml, or no [inventory] in it |
nothing changes anywhere – the whole concept is opt-in; CI and another maker's machine never see it |
| a path, no such file; a glob that matches nothing | error, stop: inventory: ~/Dokumente/Teile/inventory.xlsx not found (edakit.local.toml) |
| a file without a matching table, each file on its own | error, stop: the required columns, and the headers it found per table or sheet |
a quantity that is no whole number (~10, ein paar, empty) |
error, stop: file, table or sheet, row |
| an extension edakit cannot read | error, stop, naming the formats it reads |
An error stops edakit order before it writes a cart: an order computed past a broken inventory would be the wrong
one.
What edakit does with it¶
It checks, it does not book. edakit reads the inventory and compares; it never lowers a quantity when it orders. What really leaves the drawer is decided at the bench – a part lost, a value changed, a board not built after all. No reservation, no look-ahead stock keeping: two orders a week apart may count the same five pieces, and the maker sees it at the drawer.
edakit order– for every cart line that needsnpieces (need plus spares, as today) withhon hand:min(h, n)come from the inventory and the rest is ordered, rounded tomoqandstepas before; a rest of 0 writes no cart line. The line's comment says so:C1 (5 + 0, 3 on hand).hand_assembly.mdgets a column "From" per part –on hand,cartoron hand + cart– and at its end the list "Out of the drawer": each inventory row, its place and the pieces to take before soldering. A basket across projects (--with) sums the lines first and applies the inventory of the project it runs in once.edakit inventory– for the current project every hand-soldered part and extra against the inventory: needed, on hand, short; the inventory's paths and their file dates first.edakit inventory QUERYlists the rows whose ID, name or description match – for the maker and for the agent.edakit inventory template FILE– a new empty inventory: the header row with the columns as the settings name them (the defaults without a column map), as.md,.xlsxor.ods; it never overwrites a file, writes the path intoedakit.local.tomlwhen that names none yet, and adds the file to.gitignore.
The inventory does not count for an assembled position: JLCPCB places from LCSC's stock, not from the maker's drawer.
What stays as it is¶
edakit stock, PARTS.stock and the snapshot are the assembler's; the inventory never answers for an assembled part.- PARTS.supplier: a hand-soldered part without a supplier still warns – the inventory is a place to take from, not a
place to buy; a part nobody sells any more gets its entry with the skill own-part (
own.what = "bin", handbook 4.5). - No new check code:
edakit orderandedakit inventoryreport; the gate's stage P stays as it is. - The regulatory review: a part from the drawer has its compliance data from its entry like every part (
"rohs": "not known"for one of unknown origin, handbook 15 – support, not legal advice). spare_pctandspareare counted into the need before the inventory is applied.
By the yardstick¶
Before: what the drawer holds is in the maker's head. After: it is a table in a file of the maker's – text or a
spreadsheet, outside every project on purpose, since it is private and outlives any of them. The project gains nothing
that exists only in EasyEDA; what an order took from the drawer is in hand_assembly.md of its run. What stays by hand
is the maker's own: keeping the table true.
Risks¶
- The inventory lies – a part used without lowering its count: the cart is short by that part. Then one small
order more, days not weeks;
hand_assembly.mdnames what to take, so the gap shows at the drawer, not at the bench. - A wrong LCSC number in the map – the maker's 1/8 W resistor counted as the graph's 1/4 W one. The maker's
statement, as any entry they write;
edakit inventoryshows the row's name and description beside the match, so a look catches it.
Order of work¶
Each step on the owner's word; 1 and 2 built on 2026-11-03.
- Reading and the order (built):
edakit.local.toml, a readeredakit/inventory.pyfor the five formats and the LCSC map, the match, the errors,edakit orderandhand_assembly.md,edakit inventory; a fixture per format, tests for each match rule and each error; handbook 8.4, 10.1, the glossary ("Inventory", "On hand"); a fragmentpatch– no project must act. - The template (built):
edakit inventory templatefor.md,.xlsx,.ods. - A live run: the next parts order against the owner's inventory – the carts shortened,
hand_assembly.mdnaming what to take; what the run finds goes into handbook 8.4.
Later, each on its own word:
- Lowering on command –
edakit inventory take: a command of its own, never part of ordering, that lowers the quantities by what a run'shand_assembly.mdtook. The hard part is the write: a cell changed in place in.md,.html,.xlsxand.odswithout touching the rest, and which row gives when the part lies in several. - The choice – part-search, part-selector and circuit-design look into the inventory first for a hand-soldered
position, with
edakit inventory QUERY. - Other sources – PartsLedger, InvenTree, Part-DB, Binner, PartsBox (surveyed in the first version, this file's
history). PartsLedger's
INVENTORY.mdis read today as any markdown inventory with a column map (id = "Part",quantity = "Qty"); how it would write the inventory itself – a part in several places, what is a replacement and what an increase – is PartsLedger's question, open. Its name (decision 6) goes with it.
Decisions¶
Taken by the owner on 2026-11-02 in a decision round (TD-99) – 1 to 8 – and by the owner's rewrite of 2026-11-03 – 9 on.
- Scope: the order and the choice, "edakit ist Konsument". Holds: edakit reads, the way back to PartsLedger is dropped. The choice is a later step since 2026-11-03; lowering on command a later option of its own.
- ~~
[project] binwith a path; missing on a machine, a note and the full carts.~~ Replaced 2026-11-03: the path in a local settings file; set and missing is an error. - Up to need plus spares come from the inventory:
min(h, n), the rest ordered. - ~~Siblings listed, never counted; kits counted once they are data.~~ Replaced 2026-11-03: the match by LCSC number and MPN only.
- – (dropped by 1)
- The name: open – PartsLedger's, with PartsLedger out of this concept.
- – (dropped by 1)
- ~~Profiles
partsledger,csvandxlsx.~~ Replaced 2026-11-03: the formats.md,.html,.csv,.xlsx,.ods, no profile per tool. - KISS: one document, a table of fixed columns, in
.md,.html,.csv,.xlsxor.ods; in a workbook every sheet, in a page every table with the right column names; other columns ignored; the column names mappable. - The word is inventory – the internationally plainest; "bin" goes.
- Check, never book: edakit compares and lowers nothing; lowering only as a command of its own, later.
- Local settings: the inventory's path in a file in no repository. Not set, ignored; set and missing, or without a matching table, an error that stops.
- An LCSC map beside the inventory as the alternative to an
LCSCcolumn, the inventory left untouched. - A template for
.md,.xlsxand.ods. - Later: lowering on command, PartsLedger and other inventory tools.
edakit.local.tomlper project, besideedakit.tomland in.gitignore– not a file per machine.- Required:
IDandQuantity; the match by theLCSCcolumn, else the LCSC map, elseIDas the MPN. - Several files as a list of paths and globs in
edakit.local.toml, with step 1 – no link followed. edakit ordershortens the cart by what is on hand,min(h, n); the inventory itself stays as it is.
Set by Claude and confirmed the same day: the default column names in English, compared without case; the LCSC map a
table with ID and LCSC in any of the five formats; one part in several rows or files summed; a quantity that is
no whole number an error that stops; the match by LCSC number or ID as the MPN and nothing else; the template
writing edakit.local.toml and .gitignore, a note when git tracks the file; the choice a later step.