35 KiB
| name | description |
|---|---|
| library-manager | Manage Vecmocon's component library. Extract parameters from a component datasheet PDF into the per-typeid Excel template, check Gitea for a duplicate MPN_make, classify to a typeid, update that typeid's template (versioning, changelog, backfill), fill a per-part workbook, verify with a human, read the Altium symbol/footprint refs, and push a part folder to Gitea. Can UPDATE an existing part instead of hard-stopping on a duplicate. WRITES the mandatory SOP parameters (from the verified Excel) directly into the .SchLib symbol and COMPILES an Altium integrated library (.IntLib) bundling symbol + footprint, so every part folder holds five files (workbook, datasheet, .SchLib, .PcbLib, .IntLib). Every Description follows Vecmocon's strict Altium Description Format. Use whenever the user uploads a datasheet, builds/updates a library entry, adds a parameter, fills .SchLib parameters, builds an integrated library, or pushes to Gitea. ALWAYS trigger on "\datasheet", "\library", "\library-manager", or "\schlib". |
Library Manager
Turn one component datasheet into a verified, versioned library entry in Gitea. The guiding idea is honesty and traceability: every value lands in the right column and unit, anything the datasheet doesn't state stays blank, and nothing reaches Gitea until a human has confirmed it.
Ask, don't assume
This is a deliberately interactive skill. At every decision point, ask the user and wait for an answer — do not assume a default and proceed. In particular, always confirm: the make; the typeid/classification you inferred; whether any new parameters should be added to the template; the extracted values (the verification loop); that the symbol/footprint actually match this part; and whether to apply a new parameter to existing parts (backfill). When something is ambiguous, ask a specific question rather than guessing. It is always better to ask one more question than to write the wrong thing into the library.
One more thing to confirm when a part already exists: whether to update it or stop (don't silently overwrite), and if updating, which fields change (values, symbol/footprint, datasheet). An update still goes through the same verification loop before anything is pushed.
Pushing is the exception — push automatically. Once a part is verified and assembled (or a template/version change has been made, or a verified update is ready), push to Gitea on your own, without asking for confirmation. Never add a "shall I push?" step — just push, then tell the user where it landed. (You still flag a genuine symbol/footprint mismatch, because that's a correctness issue, not a push confirmation.)
Inputs
- A datasheet PDF whose filename is the MPN (e.g.
BAT46WJ.pdf). If it's a series datasheet, search that exact MPN inside to read the correct variant. - The make (manufacturer), given by the user. The
maketag is the first word of the manufacturer, alphanumerics only (Texas Instruments →Texas, Nexperia →Nexperia). - Later in the flow, after verification: an Altium symbol (
.SchLib) and footprint (.PcbLib) file, provided by the user.
The identifier: MPN_make_typeid
Every part folder, every per-part workbook, and column A of every sheet (MPN_make_type)
use the same tag:
<MPN>_<make>_<typeid> e.g. BAT46WJ_Nexperia_SCH
typeid is the part's type-ID code from the taxonomy (references/taxonomy.md, full source
assets/template/Type_ID.xlsx) — Schottky → SCH, MOSFET → MOS, LDO → LDO. In the new
template each typeid is its own sheet (125 of them). The broader Class (Diode,
Transistor, IC …) is used only to organise the library repo into top-level folders.
Gitea layout (two repos)
skill repo/ this skill's own files (updated versions land here too)
library repo/
<Class>/ e.g. Diode, IC, Transistor, Resistor, ...
<MPN>_<make>_<typeid>/ e.g. BAT46WJ_Nexperia_SCH
<MPN>_<make>_<typeid>.xlsx this part's own one-row parameter sheet
<MPN>_data.pdf the datasheet
<symbol>.SchLib user-provided, with all parameters written in
<footprint>.PcbLib user-provided
<MPN>.IntLib integrated library (symbol + footprint, compiled by the skill)
Every part folder holds five files — the workbook, the datasheet, the .SchLib (with the
full parameter set written into it), the .PcbLib, and the compiled .IntLib. The .SchLib
parameter fill and the .IntLib build are not optional — they run on every part before the
push (see Mandatory symbol parameters and Build the integrated library below).
There is no single master workbook — each part carries its own sheet inside its folder.
Connection + repo names live in config/gitea.env (SKILL_REPO, LIBRARY_REPO), so runs
need no per-session token. If the host is unreachable, the git steps fail clearly and write
nothing.
Who's running this (operator identity)
The whole org shares one Claude account and one Gitea token, so the skill can't tell who's running it on its own. Instead it records the operator's name on everything it pushes, and asks only once per person. Establish the identity at the very start of a run:
-
Read
~/.library-manager-idon the operator's machine (via the desktop bridge):cat ~/.library-manager-id. -
If it exists (JSON like
{"name":"Priya Sharma","email":"priya@vecmocon.com"}) → use it, don't ask. -
If it does NOT exist → this person isn't onboarded yet, so ask once (do this even though the config carries a default, so a teammate is never silently logged as "admin"):
"First time using the library skill on this machine — what name should your library changes be recorded under? (If you're the admin, just enter
admin.) And your email, if you have one."Then save it so it's remembered forever:
echo '{"name":"<Name>","email":"<email>"}' > ~/.library-manager-id. Every later run finds it in step 1 and never asks again — the admin answersadminonce, each teammate answers their own name once, and from then on everyone is attributed correctly with no prompt. -
Only if you genuinely can't ask (an unattended / scheduled run, or the machine isn't reachable) fall back to the config
OPERATORdefault so the run isn't blocked — and say in your summary that attribution used the default rather than a confirmed person.
Then carry that identity through the run:
- pass
--author "<Name> <<email>>"to everypush-part/push-skill/commit-push, and - pass
--by "<Name>"toappend_parameter.
(Equivalent alternatives the scripts also read: export LM_AUTHOR_NAME=... LM_AUTHOR_EMAIL=...
for the session, or drop the same ~/.library-manager-id file in the container home.)
Identity precedence (first one that's set wins): --author flag → LM_AUTHOR_* env →
per-person ~/.library-manager-id → the per-install OPERATOR default in
config/gitea.env. So this admin install has OPERATOR=admin, meaning every run/push here
is recorded as "admin" automatically, with no file or prompt needed. A member's own
~/.library-manager-id (or an explicit --author) overrides that default with their real name.
This stamps the operator onto three things: the commit author (shown in git log, the
Gitea commit page, and git blame), the commit message (it ends with (by <Name>), so the
name shows right in Gitea's activity feed), and a By column in the changelog. Honest limit:
the top-line "X pushed to main" in Gitea's activity still shows the shared token owner —
only giving each person their own Gitea token changes that bottom layer.
Workflow
Run these in order. Each python/bash command is a helper in scripts/.
0. Sync the skill state from Gitea first — always
The skill's state (the template, the per-typeid versions, and the changelog) lives in the skill repo, and it grows over time. A fresh install/session starts from the packaged v1 state, so if you don't sync first, a second template change wouldn't build on the first — the versions would restart at v1 and the changelog would look like it only holds the latest change. So begin every run by pulling the current state:
python scripts/gitea_components.py pull-skill
This copies template.xlsx, versions.json, and CHANGELOG.xlsx from the skill repo into the
local skill, so version bumps continue correctly (v2 → v3 → …) and the changelog stays
cumulative from the very first change.
1. Duplicate check first — before any real work
The part's presence is keyed on MPN + make (typeid not known yet). If it already exists, stop; re-doing an existing part would only risk overwriting good data.
python scripts/gitea_components.py check-mpn --mpn <MPN> --make <make>
ABSENT (exit 0) → this is a new part; continue to step 2.
EXISTS … (exit 3) → the part is already in Gitea. Don't silently overwrite it, but don't
dead-end either — ask the user whether they want to update the existing part or stop. If
they want to revise it (new/corrected values, a swapped symbol/footprint, a newer datasheet),
go to Updating an existing part. If not, stop here. (If the user's request already said
"update"/"revise"/"fix" this part, take that as the answer and go straight to the update flow.)
2. Classify → typeid (and its Class)
Read the datasheet, identify the part, and match it to the closest subclass in
references/taxonomy.md; record its typeid (= the template sheet name). The Class
(for the library-repo folder) comes from the same taxonomy row —
scripts/common.py:class_folder(typeid) returns it (e.g. SCH → Diode).
3. Confirm the typeid's template (and add parameters if asked)
Check whether that typeid has a sheet in assets/template/template.xlsx.
- No sheet for this typeid → ask the user to upload the template sheet for it. Add it to
assets/template/template.xlsx, then push the updated skill files to the skill repo (see Pushing the skill repo). Then continue. - Sheet exists → print all of that sheet's parameters (its column headers) in the
chat and ask the user whether any new parameters should be added.
-
No → go to step 4.
-
Yes → collect the new parameter name(s), then:
python scripts/append_parameter.py --typeid <typeid> \ --param "New Parameter(unit)" [--param "Another(unit)"] \ --desc "why these were added" --by "<operator name>"This appends the column(s) at the end of that typeid's sheet, bumps that typeid's Template Version and Skill Version together (v1→v2 — see Per-typeid versioning), and writes one row to the global changelog
assets/CHANGELOG.xlsx. Then sync the updated skill files + changelog to the skill repo withpush-skillautomatically (see Pushing the skill repo) — that merges the new changelog row onto the one already in Gitea rather than overwriting it.Then ask: should this change apply to the parts of this typeid already in Gitea?
- No → go to step 4 (only the current part gets the new column).
- Yes → backfill (see Backfilling existing parts), then tell the user the previous sheets were updated, and go to step 4.
-
4. Extract and fill the per-part workbook
Read every parameter the datasheet actually states into that typeid's columns, converting to each header's unit. Leave blanks where the datasheet is silent — an honest blank beats a guess.
The Description column is special: it is not free prose but a strict _-joined
engineering string — a type prefix, the defining parameters in a fixed order, package near the
end, optional AEC-Q last (e.g. CHIP_RES_36kΩ_62.2mW_±0.1%_0402, CHIP_CAP_2.2uF_100v_±10%_1210_x7r,
SCH_100V_0.25A_SOD-323F). references/description_format.md defines the format for every
type in the library: the four the Altium SOP spells out (Resistor, Capacitor, Zener, TVS) are
strict; the rest are the house extension on the same basis. Look up the part's type there,
build the Description to that format, and if a real datasheet doesn't fit the format cleanly,
follow the pattern and flag the mismatch to the engineer rather than bending it silently.
Collect the values into a small part.json:
{"mpn":"BAT46WJ","manufacturer":"Nexperia","typeid":"SCH",
"values":{"Description":"SCH_100V_0.25A_SOD-323F","Forward Voltage(V)":"0.71",
"Reverse Voltage(V)":"100","Forward Current(A)":"0.25","Package":"SOD-323F"}}
(typeid SCH → prefix SCH, format SCH_Vr_Io_Package, so a 100 V / 250 mA Schottky in
SOD-323F becomes SCH_100V_0.25A_SOD-323F.)
python scripts/fill_templates.py part.json \
--template assets/template/template.xlsx --dest <stage>/<tag>/
This writes <tag>.xlsx with column A = the tag, Skill Version (col B) and Template
Version (col C) stamped from this typeid's current versions, and the four design columns
left blank for now.
The part workbook has up to two sheets:
- Sheet 1 — the typeid's parameter sheet (the one filled row).
- Sheet 2 —
Version History— added only when this typeid has had a template/skill update. It lists the cumulative change history for that typeid (Date, Skill Version, Template Version asv1 → v2, Description) — every change up to the version this file was built at. So a part built at v3 shows bothv1 → v2andv2 → v3; a still-at-v1 typeid has no second sheet. The history is read fromassets/CHANGELOG.xlsx, so make sure the local changelog is current (it's kept in sync bypush-skill) before building parts.
5. Human verification loop
Deliver the filled workbook to the user and ask them to verify it. If they report an error or say it isn't right, go back to step 4, re-read the datasheet more carefully, re-fill, and hand it back. Repeat until the user confirms it's verified. Nothing is pushed until this passes — the engineer is the ground truth for the numbers.
6. Symbol + footprint → the design columns
Once verified, ask the user to upload the symbol (.SchLib) and footprint
(.PcbLib) files. Copy them into the staging part folder under their proper names (so
the Path columns match the files that actually get stored — strip any upload-staging prefix
the environment may have added), then read all four design values in one shot:
cp <uploaded_symbol> <stage>/<tag>/<symbol_name>.SchLib
cp <uploaded_footprint> <stage>/<tag>/<footprint_name>.PcbLib
python scripts/altium_refs.py design \
--symbol <stage>/<tag>/<symbol_name>.SchLib \
--footprint <stage>/<tag>/<footprint_name>.PcbLib > design.json
This produces (verified against real Ultra-Librarian exports):
- Library Ref = the component name inside the
.SchLib(e.g.CGA3E3X7R1H474K080AE) - Library Path = the
.SchLibfile name - Footprint Ref = the base pattern inside the
.PcbLib; Altium ships IPC density variants (-L/-M/-N) alongside the base, and the base is the one used (e.g.CAP_CGA3_TDK, notCAP_CGA3_TDK-L) - Footprint Path = the
.PcbLibfile name
These Ref names come from inside the files and can differ from the MPN or filename. If a Ref
comes back null (or a footprint shows several unrelated candidates), ask the user to confirm
the name from Altium's properties and edit design.json. Then re-fill so the columns land:
python scripts/fill_templates.py part.json \
--template assets/template/template.xlsx --dest <stage>/<tag>/ --design design.json
Once you have the symbol and its Library Ref, always write the full parameter set into the
.SchLib from the verified per-part Excel — see Mandatory symbol parameters below. This is
compulsory on every run; do not ask the engineer whether to do it — just do it. It is how the
verified workbook values (and the Description) land in the Altium symbol's properties, and the
.IntLib is then built from this enriched symbol.
7. Assemble the part folder — build the .IntLib, then five files
The staging folder <tag>/ should hold the per-part <tag>.xlsx, the datasheet (name it
<MPN>_data.<ext>), the enriched symbol (.SchLib with parameters written in, step 6), and the
footprint (.PcbLib). Now compile the integrated library from the enriched symbol + footprint
so the folder carries all five files — see Build the integrated library below:
python scripts/build_intlib.py --schlib <stage>/<tag>/<sym>.SchLib \
--pcblib <stage>/<tag>/<fp>.PcbLib --out <stage>/<tag>/<MPN>.IntLib
8. Push to the library repo, under the part's Class
python scripts/gitea_components.py push-part --folder <stage>/<tag> --typeid <typeid> \
--author "<operator name> <<operator email>>"
This places the folder at components/<Class>/<tag>/ — creating the Class folder if it
doesn't exist yet, or pushing into it if it does — and commits and pushes. Confirm to the
user where it landed.
Mandatory symbol parameters (.SchLib)
The SOP (§5) requires every schematic symbol to carry a fixed parameter set in its Altium
properties — Manufacturer, Manufacturer Part, Value, Tolerance, Operating Temperature, ROHS, Datasheet, Process, Vecmocon Part Code, and the two second-source
fields — with the Comment set to the MPN. The skill stamps these onto the symbol from the
verified workbook. This step is compulsory on every part build — never ask whether to fill the
.SchLib parameters; always do it before assembling the folder and building the .IntLib.
This runs as its own task too, not only inside new-part creation: whenever the user hands
over one or more .SchLib files and wants their parameters filled/updated (e.g. "\schlib", "add
these parameters to this symbol", "update the schlib"), read the datasheet/specs for each part,
build its params.json, and run scripts/schlib_write.py per file — same steps as below.
The skill writes these directly into the .SchLib in pure Python with
scripts/schlib_write.py (it rebuilds the OLE around the enlarged Data stream, preserving
every other byte, and strips the Ultra-Librarian Manufacturer_Name / Manufacturer_Part_Number
defaults that duplicate the SOP fields). Three kinds of value:
- Read from the datasheet (don't just echo given text — open the PDF and fill the real,
verified values):
Value= the value only in shorthand (e.g.1u,12p,10k— no package), plusManufacturer,Manufacturer Part,Operating Temperature,Tolerance,ROHS,Datasheet, andProcessby inference from the package. - Leave blank for now —
Manufacturer 2/Manufacturer Part 2(the second source). Don't populate these by default; they stay hidden in Altium until filled later. (An optional cross-reference search to find a second source is documented inreferences/schlib_parameters.mdbut is currently off — only do it if the engineer asks.) - Ask the engineer — only
Vecmocon Part Code(internal, not derivable).
Leave any genuinely-unknown field blank — the SOP hides blank parameters, so a gap simply stays
empty until filled. The full method for the second-source search is in
references/schlib_parameters.md.
Write the full parameter set — the typeid template's engineering columns plus the SOP
params above (see references/schlib_parameters.md) — and source it from the verified per-part
Excel so the symbol and the workbook can never disagree. After the sheet is verified (step 5),
pass that <tag>.xlsx to the writer with --from-xlsx: every engineering column and the
Description are read straight out of it and written into the .SchLib. Then layer on the
SOP-only fields that aren't template columns (the Value shorthand, Manufacturer Part,
Operating Temperature, ROHS, Datasheet, Process, Vecmocon Part Code, and the blank
second-source pair) via a small params.json; on any name collision the params.json value
wins. Pass --typeid too, so any template column the datasheet left silent is still present
(blank):
python scripts/schlib_write.py --schlib <in>.SchLib \
--from-xlsx <stage>/<tag>/<tag>.xlsx --params params.json \
--out <stage>/<tag>/<sym>.SchLib --typeid <TYPEID>
(--params is optional if the Excel already carries everything you need; --from-xlsx is
optional if you'd rather hand-build the whole set in params.json — give at least one.) The
Description written onto the symbol (and into the component's ComponentDescription field) is
the exact one from the Excel, which was built to references/description_format.md.
Passing --typeid also fills the symbol's Type parameter with the component type for that
typeid — the taxonomy Class (e.g. Resistor, Capacitor, Diode, Transistor,
Relay / Contactor, Inductor / Magnetics, Integrated Circuit (IC)) — so the symbol
self-describes what kind of part it is. It's derived from the typeid (which came from the
datasheet), so it's set automatically; only an explicit Type in the Excel/params overrides it.
Deliver the resulting .SchLib; the engineer opens it in Altium once to confirm it loads, then
Saves to Server with a revision note. The full parameter set, each value's source, the
params.json shape (incl. the remove list), and the mini-stream size caveat are in
references/schlib_parameters.md — read it before building the parameter set. If a file doesn't
round-trip, fall back to scripts/altium_params.py (emits an Altium DXP script to apply the same
parameters from inside Altium). Always have the engineer confirm the file opens in Altium — the
skill writes Altium's own binary format, so Altium is the final validator.
Build the integrated library (.IntLib)
Every part also gets a compiled integrated library — one file that bundles the schematic
symbol (with the parameters written in) and its footprint, so the component resolves in Altium
with no separate .PcbLib to locate. scripts/build_intlib.py compiles it in pure Python, no
Altium needed, and it's the fifth file in every part folder.
python scripts/build_intlib.py --schlib <stage>/<tag>/<sym>.SchLib \
--pcblib <stage>/<tag>/<fp>.PcbLib --out <stage>/<tag>/<MPN>.IntLib
How it works and what it needs:
- Feed it the enriched
.SchLib(afterschlib_write.pyhas written the parameters in) so the integrated symbol carries the full parameter set and the correct ComponentDescription. - The symbol must contain a footprint model link (an Altium RECORD=45
ModelName/ModelType=PCBLIBin itsDatastream — Ultra-Librarian and Altium exports include this). The builder reads that link to know which footprint to bind, and errors clearly if it's absent — in that case the symbol has no footprint assigned, so fix the symbol (or re-export it) first. - It builds the
.IntLibas an OLE compound file with five streams — the embedded.schliband.pcblib(zlib-compressed at Altium's default level), plusLibCrossRef.Txt,Parameters .bin, andVersion.Txt— reusing a bundled container skeleton (assets/templates/intlib_container.IntLib) for the exact directory layout Altium expects, and a FAT-first compound-file writer (build_intlib.write_cfb). Both the outer container and the embedded symbol are written FAT-first — this matters: a FAT-last layout re-opens fine in olefile and even standalone in Altium, but Altium's IntLib extractor throws "Stream read error" on it. The two embedded libraries are compressed at zlib's default level (0x789c); Altium's decompressor rejects other levels (e.g. level-90x78da). - The builder self-validates: it re-opens the output, decompresses both embedded libraries, and
confirms they round-trip and that the cross-reference names the symbol + footprint. Even so,
Altium is the final validator — have the engineer open the
.IntLibonce (or, as a guaranteed fallback, compile a.LibPkgin Altium from the same.SchLib+.PcbLib).
Per-typeid versioning
Versioning is per typeid, not global. Each typeid carries its own template_version and
skill_version in assets/template/versions.json (both start at 1). When a parameter is
added to a typeid, that typeid gets a new template, so its template_version bumps — and on
the back of that its skill_version bumps too (v1→v2). Only that typeid moves; every
other typeid keeps its versions. Those two numbers are exactly what fill_templates stamps
into that typeid's rows (cols B and C), so a row always records the template/skill version it
was built against. append_parameter.py does the bump; common.py is the single source for
reading and writing these numbers.
The changelog
append_parameter.py maintains one global changelog as an Excel workbook at
assets/CHANGELOG.xlsx (sheet Changelog, styled green header). Every time a
typeid's template/version changes, one row is appended with columns
Date | Typeid | Skill Version | Template Version | Description — the version columns hold
the new versions, and Description is your note (or the parameter(s) added if you gave none).
The changelog lives in the skill repo in Gitea as well, and it is cumulative from the
first change onward. Two things keep it that way: at the start of a run pull-skill (step 0)
brings the current changelog down so a new change appends to the full history, and on push
push-skill merges the new local rows onto the changelog already in Gitea — appended,
never overwritten. So the Gitea copy is the growing, authoritative history across machines and
sessions; the merged file is copied back locally so the two stay in sync. If you ever see the
Gitea changelog with only the latest change, it means step 0 (pull-skill) was skipped.
Backfilling existing parts
When the user wants a newly-added parameter applied to parts of that typeid already in Gitea:
python scripts/gitea_components.py checkout --dest work/
python scripts/gitea_components.py list-type --typeid <typeid> --root work/ --json
list-type lists every existing part of that typeid with the files in its folder — including
its datasheet, which is co-located. For each one: read that datasheet, re-extract the values
(including the new parameter), and rebuild its per-part sheet in place:
python scripts/fill_templates.py <that_part>.json \
--template assets/template/template.xlsx --dest work/<Class>/<that_tag>/
Because fill_templates uses the current template and current versions, each rebuilt sheet
picks up the new column and the bumped version automatically. When all are done, push once
and tell the user the previous sheets were updated:
python scripts/gitea_components.py commit-push --root work/ --message "backfill <param> into <typeid>"
Updating an existing part
When the duplicate check finds the part (or the user asks to revise one that's already in Gitea), you're editing a part in place rather than assembling a new one. The mechanics are the same edit-in-a-checkout pattern as backfill — the difference is you're changing one part's own data, not applying a template change across a whole typeid. The guiding rule doesn't change: nothing is overwritten until the engineer has verified the new version.
-
Locate the part in a checkout you can commit. Clone the library repo, then find the part's folder and typeid (recovered from its tag):
python scripts/gitea_components.py checkout --dest work/ python scripts/gitea_components.py find-part --mpn <MPN> --make <make> --root work/ --jsonfind-partreturns the part's Class, tag, typeid, the editable folder path underwork/, and the files in it (its current<tag>.xlsx, datasheet, symbol, footprint). If it printsNOT FOUND(exit 4), the part isn't actually there — treat it as a new part and go back to the normal add flow from step 2. -
Decide with the user what's changing. A part update can revise any of: the parameter values (re-read the datasheet, or a corrected/newer one), the symbol/footprint, or the datasheet PDF itself. Ask which, so you only touch what's meant to change and leave the rest of the folder intact.
-
Apply the change in place, in
work/<Class>/<tag>/. A key thing to understand first:fill_templatesrewrites the whole data row, so it fills the four design columns (Library Ref/Path,Footprint Ref/Path) from the--designmap you give it — and leaves them blank if you don't. When you rebuild a sheet, always re-supply the design values, or you'll silently wipe the symbol/footprint refs that were already there. The symbol and footprint files live in the part folder, so re-deriving them is cheap: pointaltium_refsat whatever the folder will hold after your change.-
Values (re-read the datasheet, or a corrected/newer one) → read the current
<tag>.xlsxand the folder's datasheet so you start from what's there, re-extract into a freshpart.json(Description still built toreferences/description_format.md), re-derive the design columns from the folder's existing symbol/footprint, and rebuild the sheet in place with--design:python scripts/altium_refs.py design \ --symbol work/<Class>/<tag>/<symbol>.SchLib \ --footprint work/<Class>/<tag>/<footprint>.PcbLib > design.json python scripts/fill_templates.py part.json \ --template assets/template/template.xlsx --dest work/<Class>/<tag>/ --design design.jsonBecause
fill_templatesreads the current template and versions, the rebuilt sheet keeps this typeid's version stamp (a part-data fix isn't a template change, so nothing bumps) and picks up any columns the typeid has gained — while the--designmap carries the existing symbol/footprint refs through unchanged. (If a part somehow has no symbol/footprint yet, there's nothing to preserve — rebuild without--design.) -
Symbol/footprint → copy the new
.SchLib/.PcbLibinto the folder under their proper names (replacing the old ones), then re-derive against the new files and rebuild with--designexactly as above (this is step 6 of the add flow). Still flag a genuine symbol/footprint-vs-part mismatch — that's a correctness issue. -
Datasheet → drop the newer PDF in as
<MPN>_data.<ext>, replacing the old one. If the values should reflect it, also redo the values step above.
-
-
Verify, then push. Hand the rebuilt
<tag>.xlsxback and run the same human verification loop (step 5) — the engineer is still the ground truth. Once confirmed, commit the checkout and push (attributed to the operator, with a message that says it's an update):python scripts/gitea_components.py commit-push --root work/ \ --message "update <tag>: <what changed> (by <operator name>)" \ --author "<operator name> <<operator email>>"The authored commit and message are the record of the revision (visible in
git log, the Gitea commit view andgit blame); the changelog stays reserved for template/version changes, not per-part data fixes. Tell the user what changed and where it landed.
Pushing the skill repo
When skill files change (a new typeid template, a parameter add, a version/changelog bump),
push the skill's own files to the skill repo with push-skill automatically (no
confirmation):
python scripts/gitea_components.py push-skill --author "<operator name> <<operator email>>" \
--message "Sync skill files + changelog"
push-skill clones the skill repo, copies the skill files in with the GIT_TOKEN blanked
out (the real token never leaves the machine), and merges CHANGELOG.xlsx — appending
this run's new rows onto the changelog already in Gitea so earlier entries are preserved — then
writes the merged changelog back locally. (The older push_to_gitea.sh still exists for a
plain flat push, but it does not merge the changelog or blank the token, so prefer
push-skill for the skill repo.)
Resources
assets/template/template.xlsx— the master template: one sheet per typeid (125), source of every sheet's headers, styling and order. Columns A/B/C are alwaysMPN_make_type/Skill Version/Template Version;Library Ref/Path,Footprint Ref/PathandManufacturersit near the end.assets/template/Type_ID.xlsx+references/taxonomy.md— Class → Subclass → Type ID.references/description_format.md— Vecmocon's Altium Description Format (the_-joined engineering string for each part's Description column). Defines a format for every type: the four SOP-defined ones (RES/CAP/Zener/TVS) are strict, the rest are the house extension on the same basis. Read it before filling any Description.references/schlib_parameters.md— the SOP mandatory symbol parameters (§5) for the.SchLib: the parameter set, where each value comes from, and how the generated Altium script stamps them onto the symbol.assets/template/versions.json— per-typeidtemplate_version+skill_version.assets/CHANGELOG.xlsx— global version/parameter changelog (created on first add; merged into the skill repo's copy in Gitea bypush-skill).scripts/common.py— taxonomy loader (load_taxonomy,class_folder), version store (get_versions,version_labels,bump_versions), and the tag helper (part_tag).scripts/fill_templates.py— build one per-part<tag>.xlsx(version-stamped); reused for backfill.scripts/append_parameter.py— append parameter(s) to a typeid, bump its versions, write the changelog.scripts/altium_refs.py— read Library/Footprint Ref from.SchLib/.PcbLib.scripts/schlib_write.py— write the SOP mandatory parameters directly into a.SchLib(pure-Python OLE rebuild; removes the Ultra-LibrarianManufacturer_Name/Manufacturer_Part_Numberdefaults). Primary path; seereferences/schlib_parameters.md.scripts/altium_params.py— fallback: generate an Altium DelphiScript that stamps the same parameters onto a.SchLibfrom inside Altium (DXP → Run Script).scripts/build_intlib.py— compile a component's.SchLib+.PcbLibinto an Altium integrated library (.IntLib) in pure Python (FAT-first OLE writer + Altium-level zlib); the fifth file in every part folder. Needs the enriched.SchLib(parameters written) with a footprint model link. Usesassets/templates/intlib_container.IntLibas the container skeleton.assets/templates/intlib_container.IntLib— a known-good single-component.IntLibreused purely as the OLE container skeleton bybuild_intlib.py(all its streams are overwritten).scripts/gitea_components.py—check-mpn,find-part(locate an existing part to update),checkout,list-type,place-part,commit-push,push-part(library repo), andpush-skill(skill repo: token-blanked push + append-only changelog merge).scripts/push_to_gitea.sh— push a folder's contents to a Gitea repo (used for the skill repo).config/gitea.env— host, user, token, and theSKILL_REPO/LIBRARY_REPOnames (secret — do not push the token).