Skill/SKILL.md

19 KiB

name description
library-manager Manage Vecmocon's component library: extract parameters from a component datasheet PDF into the per-typeid Excel template (125 type-IDs across 18 classes - resistors, capacitors, diodes, transistors, ICs, connectors, sensors, etc.). The user gives a datasheet named as its MPN plus the make. The skill checks Gitea for a duplicate MPN_make and hard-stops if present, classifies the part to a typeid, confirms or updates that typeid's template (per-typeid version, changelog, backfill), fills a per-part workbook, loops on human verification, then takes the Altium symbol (.SchLib) and footprint (.PcbLib), fills the Library/Footprint columns, assembles a part folder (xlsx, datasheet, symbol, footprint) and pushes it to the library repo under its Class. Use WHENEVER the user uploads a component datasheet, builds a library entry, adds a parameter to a type template, or pushes a part to Gitea. ALWAYS trigger on "\datasheet", "\library", or "\library-manager", or any component-library / datasheet-extraction task.

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.

Pushing is the exception — push automatically. Once a part is verified and assembled (or a template/version change has been made), 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 make tag 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
        <footprint>.PcbLib          user-provided

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:

  1. Read ~/.library-manager-id on the operator's machine (via the desktop bridge): cat ~/.library-manager-id.

  2. If it exists (JSON like {"name":"Priya Sharma","email":"priya@vecmocon.com"}) → use it, don't ask.

  3. 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 answers admin once, each teammate answers their own name once, and from then on everyone is attributed correctly with no prompt.

  4. Only if you genuinely can't ask (an unattended / scheduled run, or the machine isn't reachable) fall back to the config OPERATOR default 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 every push-part / push-skill / commit-push, and
  • pass --by "<Name>" to append_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>

EXISTS … (exit 3) → stop and tell the user the part is already present in Gitea. End here. ABSENT (exit 0) → continue.

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. SCHDiode).

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 with push-skill automatically (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. Collect them into a small part.json:

{"mpn":"BAT46WJ","manufacturer":"Nexperia","typeid":"SCH",
 "values":{"Description":"100 V 250 mA Schottky, SOD323F","Forward Voltage(V)":"0.71",
           "Reverse Voltage(V)":"100","Forward Current(A)":"0.25","Package":"SOD323F"}}
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 as v1 → v2, Description) — every change up to the version this file was built at. So a part built at v3 shows both v1 → v2 and v2 → v3; a still-at-v1 typeid has no second sheet. The history is read from assets/CHANGELOG.xlsx, so make sure the local changelog is current (it's kept in sync by push-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 .SchLib file 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, not CAP_CGA3_TDK-L)
  • Footprint Path = the .PcbLib file 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

7. Assemble the part folder

The staging folder <tag>/ should now hold the four files: the per-part <tag>.xlsx, the datasheet (name it <MPN>_data.<ext>), the symbol, and the footprint.

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.

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>"

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 always MPN_make_type / Skill Version / Template Version; Library Ref/Path, Footprint Ref/Path and Manufacturer sit near the end.
  • assets/template/Type_ID.xlsx + references/taxonomy.md — Class → Subclass → Type ID.
  • assets/template/versions.json — per-typeid template_version + skill_version.
  • assets/CHANGELOG.xlsx — global version/parameter changelog (created on first add; merged into the skill repo's copy in Gitea by push-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/gitea_components.pycheck-mpn, checkout, list-type, place-part, commit-push, push-part (library repo), and push-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 the SKILL_REPO / LIBRARY_REPO names (secret — do not push the token).