Add all-type Description Format reference (RES/CAP/diode/transistor/... per Altium SOP); add update-existing-part flow + find-part command

main
admin 2026-07-14 05:59:48 +00:00
parent aa76bdc573
commit 1e3c22f34f
No known key found for this signature in database
6 changed files with 526 additions and 21 deletions

135
SKILL.md
View File

@ -9,10 +9,13 @@ description: >-
(per-typeid version, changelog, backfill), fills a per-part workbook, loops on human (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 verification, then takes the Altium symbol (.SchLib) and footprint (.PcbLib), fills the
Library/Footprint columns, assembles a part folder (xlsx, datasheet, symbol, footprint) and 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 pushes it to the library repo under its Class. Can also UPDATE a part already in the library
datasheet, builds a library entry, adds a parameter to a type template, or pushes a part to (revise its values, symbol, footprint, or datasheet) instead of hard-stopping on a duplicate.
Gitea. ALWAYS trigger on "\datasheet", "\library", or "\library-manager", or any Every Description it writes follows Vecmocon's strict Altium Description Format. Use WHENEVER
component-library / datasheet-extraction task. the user uploads a component datasheet, builds a library entry, adds a parameter to a type
template, updates/revises/corrects an existing part, or pushes a part to Gitea. ALWAYS trigger
on "\datasheet", "\library", or "\library-manager", or any component-library /
datasheet-extraction / library-update task.
--- ---
# Library Manager # Library Manager
@ -33,11 +36,15 @@ existing parts** (backfill). When something is ambiguous, ask a specific questio
guessing. It is always better to ask one more question than to write the wrong thing into the guessing. It is always better to ask one more question than to write the wrong thing into the
library. 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 **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 template/version change has been made, or a verified update is ready), push to Gitea **on your
confirmation**. Never add a "shall I push?" step — just push, then tell the user where it own, without asking for confirmation**. Never add a "shall I push?" step — just push, then tell
landed. (You still flag a genuine symbol/footprint mismatch, because that's a correctness the user where it landed. (You still flag a genuine symbol/footprint mismatch, because that's a
issue, not a push confirmation.) correctness issue, not a push confirmation.)
## Inputs ## Inputs
@ -154,8 +161,13 @@ stop; re-doing an existing part would only risk overwriting good data.
python scripts/gitea_components.py check-mpn --mpn <MPN> --make <make> 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 `ABSENT` (exit 0) → this is a **new part**; continue to step 2.
here.** `ABSENT` (exit 0) → continue.
`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) ### 2. Classify → typeid (and its Class)
@ -198,14 +210,27 @@ Check whether that typeid has a sheet in `assets/template/template.xlsx`.
Read every parameter the datasheet actually states into that typeid's columns, converting to 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 each header's unit. **Leave blanks where the datasheet is silent — an honest blank beats a
guess.** Collect them into a small `part.json`: 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`:
```json ```json
{"mpn":"BAT46WJ","manufacturer":"Nexperia","typeid":"SCH", {"mpn":"BAT46WJ","manufacturer":"Nexperia","typeid":"SCH",
"values":{"Description":"100 V 250 mA Schottky, SOD323F","Forward Voltage(V)":"0.71", "values":{"Description":"SCH_100V_0.25A_SOD-323F","Forward Voltage(V)":"0.71",
"Reverse Voltage(V)":"100","Forward Current(A)":"0.25","Package":"SOD323F"}} "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`.)
```bash ```bash
python scripts/fill_templates.py part.json \ python scripts/fill_templates.py part.json \
--template assets/template/template.xlsx --dest <stage>/<tag>/ --template assets/template/template.xlsx --dest <stage>/<tag>/
@ -334,6 +359,80 @@ and tell the user the previous sheets were updated:
python scripts/gitea_components.py commit-push --root work/ --message "backfill <param> into <typeid>" 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.
1. **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):
```bash
python scripts/gitea_components.py checkout --dest work/
python scripts/gitea_components.py find-part --mpn <MPN> --make <make> --root work/ --json
```
`find-part` returns the part's Class, tag, typeid, the editable folder path under `work/`,
and the files in it (its current `<tag>.xlsx`, datasheet, symbol, footprint). If it prints
`NOT 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.
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.
3. **Apply the change in place, in `work/<Class>/<tag>/`.** A key thing to understand first:
`fill_templates` **rewrites the whole data row**, so it fills the four design columns
(`Library Ref/Path`, `Footprint Ref/Path`) from the `--design` map 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: point `altium_refs`
at whatever the folder will hold **after** your change.
- **Values** (re-read the datasheet, or a corrected/newer one) → read the current
`<tag>.xlsx` and the folder's datasheet so you start from what's there, re-extract into a
fresh `part.json` (Description still built to `references/description_format.md`),
re-derive the design columns from the folder's existing symbol/footprint, and rebuild the
sheet in place **with `--design`**:
```bash
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.json
```
Because `fill_templates` reads 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 `--design` map 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`/`.PcbLib` into the folder under their proper
names (replacing the old ones), then re-derive against the **new** files and rebuild with
`--design` exactly 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.
4. **Verify, then push.** Hand the rebuilt `<tag>.xlsx` back 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):
```bash
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 and `git 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 ## Pushing the skill repo
When skill files change (a new typeid template, a parameter add, a version/changelog bump), When skill files change (a new typeid template, a parameter add, a version/changelog bump),
@ -359,6 +458,10 @@ plain flat push, but it does not merge the changelog or blank the token, so pref
`MPN_make_type` / `Skill Version` / `Template Version`; `Library Ref/Path`, `MPN_make_type` / `Skill Version` / `Template Version`; `Library Ref/Path`,
`Footprint Ref/Path` and `Manufacturer` sit near the end. `Footprint Ref/Path` and `Manufacturer` sit near the end.
- `assets/template/Type_ID.xlsx` + `references/taxonomy.md` — Class → Subclass → Type ID. - `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.
- `assets/template/versions.json` — per-typeid `template_version` + `skill_version`. - `assets/template/versions.json` — per-typeid `template_version` + `skill_version`.
- `assets/CHANGELOG.xlsx` — global version/parameter changelog (created on first add; - `assets/CHANGELOG.xlsx` — global version/parameter changelog (created on first add;
merged into the skill repo's copy in Gitea by `push-skill`). merged into the skill repo's copy in Gitea by `push-skill`).
@ -369,9 +472,9 @@ plain flat push, but it does not merge the changelog or blank the token, so pref
- `scripts/append_parameter.py` — append parameter(s) to a typeid, bump its versions, write - `scripts/append_parameter.py` — append parameter(s) to a typeid, bump its versions, write
the changelog. the changelog.
- `scripts/altium_refs.py` — read Library/Footprint Ref from `.SchLib`/`.PcbLib`. - `scripts/altium_refs.py` — read Library/Footprint Ref from `.SchLib`/`.PcbLib`.
- `scripts/gitea_components.py``check-mpn`, `checkout`, `list-type`, `place-part`, - `scripts/gitea_components.py``check-mpn`, `find-part` (locate an existing part to
`commit-push`, `push-part` (library repo), and `push-skill` (skill repo: token-blanked update), `checkout`, `list-type`, `place-part`, `commit-push`, `push-part` (library repo),
push + append-only changelog merge). 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 - `scripts/push_to_gitea.sh` — push a folder's contents to a Gitea repo (used for the skill
repo). repo).
- `config/gitea.env` — host, user, token, and the `SKILL_REPO` / `LIBRARY_REPO` names - `config/gitea.env` — host, user, token, and the `SKILL_REPO` / `LIBRARY_REPO` names

Binary file not shown.

View File

@ -3,7 +3,7 @@
# Use a token scoped to these repos (repository: write) and rotate periodically. # Use a token scoped to these repos (repository: write) and rotate periodically.
GIT_HOST=gitea.vecmocon.com GIT_HOST=gitea.vecmocon.com
GIT_USER=nitishKumar GIT_USER=nitishKumar
GIT_TOKEN=451bff1dc32202cbc0a371f8e5645079466d2120 GIT_TOKEN=
# Target repos — TWO now (set these to the exact repo names on your Gitea): # Target repos — TWO now (set these to the exact repo names on your Gitea):
# SKILL_REPO : holds this skill's own files (SKILL.md, scripts, assets, ...). # SKILL_REPO : holds this skill's own files (SKILL.md, scripts, assets, ...).
# LIBRARY_REPO : holds components, one folder per Class (Diode, IC, ...); inside each, # LIBRARY_REPO : holds components, one folder per Class (Diode, IC, ...); inside each,

26
evals/evals.json Normal file
View File

@ -0,0 +1,26 @@
{
"skill_name": "library-manager",
"evals": [
{
"id": 0,
"name": "resistor-description-format",
"prompt": "We're adding the Yageo RC0402FR-0736KL to our component library. From its datasheet: resistance 36 kohm, tolerance 1%, package 0402, rated power 63 mW (1/16 W), thick-film chip resistor, not AEC-Q qualified. Following our library process, what exactly should go in this part's Description field in its library sheet? Give me the final Description string.",
"expected_output": "A strict SOP Description string (e.g. CHIP_RES_36kOhm_63mW_+-1%_0402): type prefix, value, wattage, tolerance, package; no AEC-Q token since not qualified. NOT free prose.",
"files": []
},
{
"id": 1,
"name": "capacitor-description-format",
"prompt": "Adding a TDK CGA5L1X7R2A225K MLCC to the library. Datasheet: 2.2 uF, 100 V, tolerance 10%, 1210 case size, X7R dielectric, AEC-Q200 qualified. Per our library workflow, what is the exact Description field value for this part?",
"expected_output": "A strict SOP Description string (e.g. CHIP_CAP_2.2uF_100v_+-10%_1210_x7r_AECQ-200): type, value, voltage, tolerance, package, temp-coefficient, AEC-Q last. NOT free prose.",
"files": []
},
{
"id": 2,
"name": "existing-part-update-flow",
"prompt": "The part BAT46WJ from Nexperia is already in our library, but its forward-voltage value was entered wrong. I want to correct it. Walk me through exactly how you'd handle this with our library tooling, including the commands you'd run.",
"expected_output": "Recognizes this is an UPDATE of an existing part (not a hard-stop): offers update-or-stop, uses checkout + find-part to locate it, rebuilds the sheet in place with fill_templates (no version bump), keeps human verification, then commit-push with operator attribution. Does not invent a delete/re-add.",
"files": []
}
]
}

View File

@ -0,0 +1,334 @@
# Description format (Vecmocon Altium Library SOP)
This is the authoritative rule for the **Description** field the skill writes into a part's
workbook. It has two layers:
1. The **four formats the SOP defines outright** — Resistor, Capacitor, Zener, TVS — from
*Engineering Data Management — SOP: Component Naming, Mandatory Parameters, and Design Item
ID Format* (§6). Follow these parameter orders **strictly** (with one house tweak: the
Zener/TVS prefix uses the generic diode code `ZEN`/`TVS`, not the SOP's `DIO-Z`/`DIO-T` — see
the note under those two below).
2. A **house extension** that carries the *same basis* to every other type in the library
(all 125 type-IDs / 18 classes), so no component is left without a Description convention.
These are built on the SOP pattern and are the working standard; when a specific part
doesn't fit cleanly, follow the pattern and confirm the token order with the engineer rather
than inventing something off-pattern.
## The basis (applies to every component)
The Description is **not** a free-form sentence. It is a single string of `_`-joined tokens in
this shape:
```
PREFIX_param1_param2_..._Package_[AECQ-XXX]
```
- **PREFIX** — a short token (or two) naming the sub-family / technology, e.g. `CHIP_RES`,
`ELE_CAP`, `SCH`, `NMOS`. The per-type prefix is listed for every type below.
- **params** — the part's defining ratings, in the **fixed order** given for that class. Read
them off the datasheet. If the datasheet is silent on a required token, leave it out and flag
it — an honest gap beats a guessed value.
- **Package** — the IPC/industry package or case code, near the end (`0402`, `SOD-323`,
`SOIC-8`, `LQFP-48`, `SMD,D6.3xL5.8mm`, …).
- **AECQ-XXX** — only when the datasheet states automotive qualification (`AECQ-200`,
`AECQ-101`, `AECQ-100`); it is always the **last** token. Omit entirely if not stated —
never assume qualification.
Description ≠ Design Item ID ≠ Comment — three different fields that share notation but not
content: **Description** is the strict string here (SOP §6); **Design Item ID** (SOP §2) is a
shorter procurement id (`RES_36kΩ_±0.1%_0402`) — use it only as a guide to token vocabulary,
never put it in the Description column; **Comment** (SOP §4) is always the exact MPN.
## Notation conventions (from the SOP examples)
- **Value / unit** with SOP casing: `36kΩ`, `2.2uF`, `600Ω`, `48MHz`, `10uH`. Use `Ω` for ohms;
`uF`/`nF`/`pF`, `uH`/`nH`/`mH`, `Hz`/`kHz`/`MHz`, `F` for farads (supercaps). A **range** uses
`~` (`3.5V~28V`, `5.2V~5.6V`).
- **Power** `62.2mW`, `500mW`, `344W`; **voltage** `100v`, `25V`; **current** `0.25A`, `250mA`.
- **Tolerance** signed percent `±0.1%`, `±10%`.
- **Temperature coefficient** (ceramics) lower-case dielectric class: `x7r`, `c0g`, `x5r`.
- Keep tokens in the same style throughout so descriptions sort and read consistently.
---
# Layer 1 — the four SOP-defined formats (strict)
**Resistor**
```
Type_RES_Value_Wattage_Tolerance_Package_AECQ-XXX(optional)
```
Example: `CHIP_RES_36kΩ_62.2mW_±0.1%_0402`
**Capacitor**
```
Type_CAP_Value_Voltage_Tolerance_Package_TemperatureCoefficient_AECQ-XXX(optional)
```
Example: `CHIP_CAP_2.2uF_100v_±10%_1210_x7r`
**Zener diode**
```
ZEN_VoltageZener(Vz)_Power_Package_AECQ-XXX(optional)
```
**TVS diode**
```
TVS_VoltageBreakdown(Vbr)_VoltageClamping(Vc)_Current(Ip)_Package_AECQ-XXX(optional)
```
**House prefix note:** the SOP §6 wrote these two as `DIO-Z` / `DIO-T`, but Vecmocon
standardised on the **generic diode type code** (`ZEN`, `TVS`, and likewise `SCH`, `ESD`, …) as
the prefix for *all* diodes. So use `ZEN` / `TVS` here — the parameter order (Vz+Power for
Zener; Vbr+Vc+Ip for TVS) is still exactly the SOP's; only the prefix token differs.
---
# Layer 2 — house extension, every other type (same basis)
Each class below gives its **parameter order** (the tokens between prefix and package) and the
**per-type prefix**. Package is always the second-to-last token; optional `AECQ-XXX` is last.
## Resistor (RES family) — `PREFIX_Value_Power_Tolerance_Package_[AECQ]`
| Type | Prefix | Notes |
|------|--------|-------|
| FIX Thick-film chip | `CHIP_RES` | SOP example; the strict format above |
| TFR Thin-film chip | `TFILM_RES` | precision/low-tempco; may append tempco (ppm) |
| MFR Metal-film | `MFILM_RES` | |
| CFR Carbon-film | `CFILM_RES` | |
| MOR Metal-oxide | `MOX_RES` | high-power leaded |
| WWR Wirewound | `WW_RES` | low-ohm/high-power |
| SHT Current-sense/shunt | `SHUNT_RES` | value in mΩ (e.g. `2mΩ`), power token is the sense power |
| ARR Array/network | `ARR_RES` | add element count/config, e.g. `4x`, before value |
| POT Potentiometer/trimmer | `POT` | `POT_Value_Taper_Power_Package` (taper `LIN`/`LOG`) |
| FSR Fusible/safety | `FUSE_RES` | |
| NTC thermistor | `NTC` | `NTC_R25_Beta_Tolerance_Package` (R25 e.g. `10kΩ`, Beta e.g. `B3950`) |
| PTC thermistor | `PTC` | `PTC_R25_Package` (or trip current/temp if that's the rated spec) |
Example: `SHUNT_RES_2mΩ_1W_±1%_2512` · `NTC_10kΩ_B3950_±1%_0402`
## Capacitor (CAP family) — `PREFIX_Value_Voltage_Tolerance_Package_[Dielectric]_[AECQ]`
| Type | Prefix | Notes |
|------|--------|-------|
| CER Ceramic MLCC | `CHIP_CAP` | SOP; dielectric token (`x7r`/`c0g`…) required |
| ELE Aluminium electrolytic | `ELE_CAP` | tolerance often omitted; case like `SMD,D6.3xL5.8mm` |
| TAN Tantalum | `TANT_CAP` | |
| PLY Aluminium-polymer | `POLY_CAP` | low-ESR; ESR may follow voltage |
| FLM Film (MKT/MKP) | `FILM_CAP` | |
| SFY Safety Class-X/Y | `SAFETY_CAP` | add safety class token (`X2`/`Y1`) after value |
| SUP Supercapacitor/EDLC | `SUPERCAP` | value in farads, e.g. `1F`; add ESR if rated |
Example: `ELE_CAP_33uF_25V_SMD,D6.3xL5.8mm` · `SUPERCAP_1F_5.5V_RADIAL`
## Inductor / Magnetics — `PREFIX_Value_Current_[DCR]_Package_[AECQ]`
| Type | Prefix | Format detail |
|------|--------|---------------|
| PWR Power inductor | `PWR_IND` | `PWR_IND_L_Isat_DCR_Package` (L e.g. `10uH`, Isat `3A`) |
| FBD Ferrite bead | `FB` | `FB_Impedance@freq_Current_Package` (e.g. `FB_600Ω@100MHz_2A_0603`) |
| CMC Common-mode choke | `CMC` | `CMC_Impedance@freq_Current_Package` |
| RFI RFI choke | `RFI_CHK` | `RFI_CHK_L_Current_Package` |
| XFM Transformer | `XFMR` | `XFMR_Ratio_Power_Package` (ratio e.g. `1:1`) |
| CTX Current transformer | `CT` | `CT_Ratio_Package` (e.g. `1000:1`) |
| CPL Coupled inductor | `CPL_IND` | `CPL_IND_L_Current_Package` |
## Diode — reverse-voltage / current ratings, then package
The prefix is the **generic diode type code (the typeid itself)**`REC`, `FRD`, `SCH`, `SIC`,
`ZEN`, `TVS`, `ESD`, `SWI`, `BRG`, `LED` — not a `DIO-x` form.
| Type | Prefix | Format |
|------|--------|--------|
| REC Rectifier | `REC` | `REC_Vrrm_Io_Package` |
| FRD Fast-recovery | `FRD` | `FRD_Vrrm_Io_trr_Package` |
| SCH Schottky | `SCH` | `SCH_Vr_Io_Package` |
| SIC SiC Schottky | `SIC` | `SIC_Vr_Io_Package` |
| ZEN Zener | `ZEN` | `ZEN_Vz_Power_Package` |
| TVS TVS | `TVS` | `TVS_Vbr_Vc_Ip_Package` |
| ESD ESD protection | `ESD` | `ESD_Vrwm_Vc_Channels_Package` |
| SWI Switching/small-signal | `SWI` | `SWI_Vr_Io_trr_Package` |
| BRG Bridge rectifier | `BRG` | `BRG_Vrrm_Io_Package` |
| LED Indicator LED | `LED` | `LED_Color_Vf_If_Package` (color e.g. `RED`) |
Example (Schottky BAT46WJ, 100 V / 250 mA): `SCH_100V_0.25A_SOD-323F`
## Transistor — `PREFIX_Voltage_Current_[Rds(on)]_Package_[AECQ]`
The polarity/channel is **folded into the prefix** as a single token (matching the SOP's own
Design Item ID form, e.g. `NMOS_20V_SOT-23`), not carried as a separate `_NCH`/`_PCH` token.
| Type | Prefix | Format |
|------|--------|--------|
| BJT BJT | `BJT_NPN` / `BJT_PNP` | `BJT_NPN_Vceo_Ic_Package` |
| MOS MOSFET (Si) | `NMOS` / `PMOS` | `NMOS_Vds_Id_Rdson_Package` |
| SCM SiC MOSFET | `NSICFET` / `PSICFET` | `NSICFET_Vds_Id_Rdson_Package` |
| GAN GaN FET | `GANFET` | `GANFET_Vds_Id_Rdson_Package` |
| IGBT IGBT | `IGBT` | `IGBT_Vces_Ic_Package` |
| JFET JFET | `NJFET` / `PJFET` | `NJFET_Vds_Idss_Package` |
| DIG Digital/bias-R transistor | `DTR_NPN` / `DTR_PNP` | `DTR_NPN_Vceo_R1/R2_Package` |
Example: `NMOS_20V_6A_15mΩ_SOT-23` · `BJT_NPN_50V_0.1A_SOT-416FL`
## Integrated Circuit (IC) — one line per subtype; package always last (before AECQ)
| Type | Prefix | Format |
|------|--------|--------|
| MCU Microcontroller | `MCU` | `MCU_Core_Flash_Package` (e.g. `MCU_M0+_128Kb_LQFP-48`) |
| LDO LDO regulator | `LDO` | `LDO_Vout_Iout_Package` (`ADJ` if adjustable) |
| DCD DC-DC IC | `DCD` | `DCD_Topology_Vin_Iout_Package` (topology `BUCK`/`BOOST`/`BUCKBOOST`) |
| PMU PMIC | `PMIC` | `PMIC_Rails_Package` |
| BMS BMS AFE | `BMS` | `BMS_Cells_Package` (e.g. `16S`) |
| DRV Gate/motor driver | `DRV` | `DRV_Type_Voltage_Current_Package` (type `GATE`/`MOTOR`/`HB`) |
| AMP Amplifier/op-amp | `AMP` | `AMP_GBW_Channels_Package` |
| CMP Comparator | `CMP` | `CMP_Channels_Package` |
| VRF Voltage reference | `VREF` | `VREF_Voltage_Tolerance_Package` |
| ADC ADC | `ADC` | `ADC_Bits_Rate_Package` |
| DAC DAC | `DAC` | `DAC_Bits_Channels_Package` |
| ISO Isolator/optocoupler | `ISO` | `ISO_Channels_IsolationV_Package` |
| XCV Transceiver | `XCVR` | `XCVR_Bus_Speed_Package` (bus `CAN`/`RS485`; e.g. `XCVR_CAN_5Mbps_SOIC-8`) |
| AFE Analog front end | `AFE` | `AFE_Function_Package` |
| MEM Memory | `MEM` | `MEM_Type_Size_Interface_Package` (e.g. `MEM_FLASH_128Mb_SPI_SOIC-8`) |
| LOG Logic gate | `LOG` | `LOG_Function_Package` (e.g. `AND2`, `BUF`) |
| SEN Sensor IC | `SEN_IC` | `SEN_IC_Type_Package` |
| IFC Interface/expander | `IFC` | `IFC_Function_Package` |
| CLK Clock/RTC | `CLK` | `CLK_Freq_Package` (or `RTC_Package`) |
| SVR Supervisor/reset | `SVR` | `SVR_Threshold_Package` |
| MTR Energy metering | `METER` | `METER_Phases_Package` |
## Protection Device — `PREFIX_ratings_Package`
| Type | Prefix | Format |
|------|--------|--------|
| FUS Fuse | `FUSE` | `FUSE_Current_Voltage_Package` (speed `F`/`T` may precede current) |
| RSF Resettable/PPTC | `PPTC` | `PPTC_Ihold_Voltage_Package` |
| VAR Varistor/MOV | `MOV` | `MOV_Vrms_Energy_Package` |
| GDT Gas-discharge tube | `GDT` | `GDT_Vspark_Package` |
| CBK Circuit breaker | `BREAKER` | `BREAKER_Current_Poles_Package` |
## Power Conversion Module — `PREFIX_Vin_Vout_Power_Package`
| Type | Prefix | Notes |
|------|--------|-------|
| DCM DC-DC module | `DCM` | non-isolated PoL |
| IDC Isolated DC-DC | `IDCM` | isolated brick |
| INV Inverter (DC-AC) | `INV` | `INV_Power_Voltage_Package` |
| OBC On-board charger | `OBC` | `OBC_Power_Voltage_Package` |
| CHG Charger module | `CHG` | `CHG_Power_Voltage_Package` |
| PSU AC-DC SMPS | `PSU` | `PSU_Power_Vout_Package` |
| RCM Rectifier module | `RECT` | `RECT_Current_Voltage_Package` |
## Relay / Contactor — `PREFIX_CoilVoltage_ContactRating_Package`
| Type | Prefix | Notes |
|------|--------|-------|
| RLS Signal relay | `RLY_S` | contact rating e.g. `2A/30V` |
| RLP Power relay | `RLY_P` | |
| SSR Solid-state relay | `SSR` | `SSR_ControlV_LoadRating_Package` |
| RLR Reed relay | `RLY_REED` | |
| CTC Contactor | `CTC` | HV/HC contact rating |
## Switch / Button — `PREFIX_[Positions]_Rating_Package`
| Type | Prefix | Notes |
|------|--------|-------|
| SWT Tactile | `SW_TACT` | rating e.g. `50mA/12V` |
| PBT Push button | `SW_PB` | |
| DSW DIP/slide | `SW_DIP` | positions e.g. `4P` |
| RSW Rocker/toggle | `SW_ROCK` | |
| RSY Rotary | `SW_ROT` | positions e.g. `12POS` |
## Connector — `CON_TYPE_Positions_Pitch_Package`
| Type | Prefix | Notes |
|------|--------|-------|
| CWB Wire-to-board | `CON_W2B` | e.g. `CON_W2B_2x2_P2.0` |
| CBB Board-to-board | `CON_B2B` | |
| HDR Header/socket | `CON_HDR` | pitch e.g. `2.54mm` |
| FFC FFC/FPC | `CON_FFC` | |
| USB USB/data | `CON_USB` | add USB type (`C`, `MICRO`) |
| PWC Power/high-current | `CON_PWR` | add current rating |
| TBK Terminal block | `CON_TB` | |
## Antenna / RF — `PREFIX_Band_Package`
| Type | Prefix | Notes |
|------|--------|-------|
| ANC Chip antenna | `ANT_CHIP` | band e.g. `2.4GHz` |
| ANP PCB/trace antenna | `ANT_PCB` | |
| ANE External/whip | `ANT_EXT` | add connector token |
| SAW SAW filter | `SAW` | `SAW_Freq_Package` |
| RFM RF/wireless module | `RFMOD` | protocol e.g. `BLE`, `WIFI`, `LTE` |
## Crystal / Oscillator / Timing — `PREFIX_Freq_[Load]_Package`
| Type | Prefix | Notes |
|------|--------|-------|
| XTL Crystal | `XTAL` | `XTAL_Freq_LoadCap_Package` (e.g. `XTAL_48MHz_18pF_SMD2016-4P`) |
| OSC Crystal oscillator | `OSC` | `OSC_Freq_Package` |
| MMO MEMS oscillator | `MEMS_OSC` | |
| RSN Ceramic resonator | `RESON` | `RESON_Freq_Package` |
## Battery / Cell — `PREFIX_Capacity_Voltage_Format`
| Type | Prefix | Notes |
|------|--------|-------|
| CLI Li-ion cell | `CELL_LI` | format e.g. `18650`; capacity `2600mAh` |
| CLF LiFePO4 cell | `CELL_LFP` | |
| CCO Coin/button | `CELL_COIN` | add chemistry (`CR`/`LIR`) + size (`2032`) |
| CNI NiMH | `CELL_NIMH` | |
| BPK Battery pack | `PACK` | `PACK_Voltage_Capacity` (e.g. `48V_20Ah`) |
| CHL Cell holder | `HOLDER` | `HOLDER_CellType_Package` |
## Audible / Indicator
| Type | Prefix | Format |
|------|--------|--------|
| BUZ Magnetic buzzer | `BUZ_MAG` | `BUZ_MAG_Voltage_Freq_Package` |
| PBZ Piezo buzzer | `BUZ_PIEZO` | `BUZ_PIEZO_Voltage_Freq_Package` |
| SPK Speaker | `SPK` | `SPK_Power_Impedance_Package` |
| IND Indicator lamp | `IND` | `IND_Color_Voltage_Package` |
## Display / HMI — `PREFIX_Resolution/Digits_Size_Interface`
| Type | Prefix | Notes |
|------|--------|-------|
| DSG 7-segment | `DISP_7SEG` | `DISP_7SEG_Digits_Color_Package` |
| OLE OLED | `DISP_OLED` | resolution e.g. `128x64`, size `0.96in` |
| LCD LCD | `DISP_LCD` | char (`16x2`) or graphic resolution |
| TFT TFT | `DISP_TFT` | resolution + size + interface (`SPI`/`RGB`) |
## Sensor (discrete / module) — `SEN_TYPE_Range_[Interface]_Package`
| Type | Prefix | Notes |
|------|--------|-------|
| STE Temperature | `SEN_TEMP` | range + interface (`I2C`/`ANALOG`) |
| SCU Current (Hall) | `SEN_CURR` | range e.g. `±50A` |
| SVO Voltage/isolated | `SEN_VOLT` | |
| SHA Hall/position | `SEN_HALL` | type (`LATCH`/`LINEAR`) |
| SIM IMU/accel | `SEN_IMU` | axes (`6AXIS`) + interface |
| SPR Pressure | `SEN_PRES` | range + interface |
## Thermal / Cooling
| Type | Prefix | Format |
|------|--------|--------|
| FAN Fan | `FAN` | `FAN_Size_Voltage_Airflow` (size e.g. `40x40mm`) |
| HSK Heatsink | `HSK` | `HSK_Dimensions_ThermalResistance` |
| TPD Thermal pad/TIM | `TIM` | `TIM_Conductivity_Thickness` |
---
## When a part doesn't fit
The Layer-2 formats are the working house standard, but real datasheets vary. If a part is
missing a token the format asks for, leave it out and flag it. If it has a defining rating the
format doesn't capture, add it in the sensible position and **tell the engineer** what you
added so the convention can be updated deliberately. Never silently bend a format — an
inconsistent Description is worse than one confirmed question. The Layer-1 (SOP) formats are
fixed and are not up for reinterpretation.

View File

@ -15,6 +15,13 @@ testing or offline work):
early duplicate gate, run BEFORE classifying.) Prints EXISTS/<tag> or ABSENT; exit 0 early duplicate gate, run BEFORE classifying.) Prints EXISTS/<tag> or ABSENT; exit 0
if absent, 3 if it already exists (so a shell can hard-stop). if absent, 3 if it already exists (so a shell can hard-stop).
find-part --mpn BAT46WJ --make Nexperia [--root work/] [--json]
Locate an existing part so it can be REVISED (the update path the mirror of
check-mpn, which gates *new* parts). Reports the part's Class, tag, typeid and the
files in its folder. Point --root at a `checkout` clone and the folder it returns is
the real, editable one to change in place before `commit-push`. Exit 0 if found, 4 if
not (so a shell can branch: found -> update, not found -> fall through to add).
checkout --dest work/ checkout --dest work/
Clone the library repo to a working dir you can browse and edit in place. Clone the library repo to a working dir you can browse and edit in place.
@ -142,6 +149,12 @@ def find_part_dirs(root, prefix="", typeid=None):
yield cls, name, pdir yield cls, name, pdir
def _typeid_of(tag):
"""Recover the typeid from a part tag <MPN>_<make>_<typeid>. The typeid is the last
underscore-delimited token, so this is robust even if the MPN itself contains underscores."""
return tag.rsplit("_", 1)[1] if "_" in tag else ""
def cmd_check_mpn(env, args): def cmd_check_mpn(env, args):
root, _ = _root(env, args) root, _ = _root(env, args)
prefix = mpn_make_prefix(args.mpn, args.make) prefix = mpn_make_prefix(args.mpn, args.make)
@ -153,6 +166,31 @@ def cmd_check_mpn(env, args):
print("ABSENT") print("ABSENT")
def cmd_find_part(env, args):
"""Locate an existing part by MPN+make so it can be REVISED — the mirror image of
check-mpn (which gates *new* parts). Reports the folder, its typeid and its files.
Point --root at a checkout (from `checkout`) and the folder it returns is the real,
editable, committable one that's the update path: checkout -> find-part -> edit in
place -> commit-push. Without --root/--local it clones a throwaway copy for a read-only
look. Exit 0 if found, 4 if not (so a shell can branch)."""
root, _ = _root(env, args)
prefix = mpn_make_prefix(args.mpn, args.make)
matches = list(find_part_dirs(root, prefix=prefix))
if not matches:
print("[]" if args.json else "NOT FOUND")
sys.exit(4)
out = [{"class": cls, "tag": name, "typeid": _typeid_of(name),
"folder": pdir, "files": sorted(os.listdir(pdir))}
for cls, name, pdir in matches]
if args.json:
import json
print(json.dumps(out, indent=2))
else:
for o in out:
print(f'{o["class"]}/{o["tag"]} (typeid {o["typeid"]}) -> {", ".join(o["files"])}')
def cmd_checkout(env, args): def cmd_checkout(env, args):
dest = clone(env, args.dest) dest = clone(env, args.dest)
print(f"library repo checked out at {dest}") print(f"library repo checked out at {dest}")
@ -370,6 +408,10 @@ def main():
p = sub.add_parser("check-mpn"); p.add_argument("--mpn", required=True) p = sub.add_parser("check-mpn"); p.add_argument("--mpn", required=True)
p.add_argument("--make", required=True); p.add_argument("--local"); p.add_argument("--root") p.add_argument("--make", required=True); p.add_argument("--local"); p.add_argument("--root")
p = sub.add_parser("find-part"); p.add_argument("--mpn", required=True)
p.add_argument("--make", required=True); p.add_argument("--local"); p.add_argument("--root")
p.add_argument("--json", action="store_true")
p = sub.add_parser("checkout"); p.add_argument("--dest", required=True) p = sub.add_parser("checkout"); p.add_argument("--dest", required=True)
p = sub.add_parser("list-type"); p.add_argument("--typeid", required=True) p = sub.add_parser("list-type"); p.add_argument("--typeid", required=True)
@ -401,14 +443,14 @@ def main():
if args.cmd in ("push-skill", "pull-skill"): if args.cmd in ("push-skill", "pull-skill"):
needs.add("SKILL_REPO") needs.add("SKILL_REPO")
elif args.cmd in ("check-mpn", "checkout", "commit-push", "push-part") or \ elif args.cmd in ("check-mpn", "checkout", "commit-push", "push-part") or \
(args.cmd in ("list-type", "place-part") and not getattr(args, "local", None) and not getattr(args, "root", None)): (args.cmd in ("list-type", "place-part", "find-part") and not getattr(args, "local", None) and not getattr(args, "root", None)):
needs.add("LIBRARY_REPO") needs.add("LIBRARY_REPO")
for k in sorted(needs): for k in sorted(needs):
if not env.get(k): if not env.get(k):
sys.exit(f"missing {k} in env/config") sys.exit(f"missing {k} in env/config")
{"check-mpn": cmd_check_mpn, "checkout": cmd_checkout, "list-type": cmd_list_type, {"check-mpn": cmd_check_mpn, "find-part": cmd_find_part, "checkout": cmd_checkout,
"place-part": cmd_place_part, "commit-push": cmd_commit_push, "push-part": cmd_push_part, "list-type": cmd_list_type, "place-part": cmd_place_part, "commit-push": cmd_commit_push,
"push-skill": cmd_push_skill, "pull-skill": cmd_pull_skill}[args.cmd](env, args) "push-part": cmd_push_part, "push-skill": cmd_push_skill, "pull-skill": cmd_pull_skill}[args.cmd](env, args)
if __name__ == "__main__": if __name__ == "__main__":