← Commit history
Cargo.lock+10−10
@@ -4,7 +4,7 @@ version = 4  [[package]] name = "adom-aiflow"-version = "0.1.33"+version = "0.1.34" dependencies = [  "aiflow-analyze",  "aiflow-board",@@ -23,7 +23,7 @@ dependencies = [  [[package]] name = "aiflow-analyze"-version = "0.1.33"+version = "0.1.34" dependencies = [  "serde",  "serde_json",@@ -32,7 +32,7 @@ dependencies = [  [[package]] name = "aiflow-board"-version = "0.1.33"+version = "0.1.34" dependencies = [  "serde",  "serde_json",@@ -40,7 +40,7 @@ dependencies = [  [[package]] name = "aiflow-bridge"-version = "0.1.33"+version = "0.1.34" dependencies = [  "serde",  "serde_json",@@ -48,7 +48,7 @@ dependencies = [  [[package]] name = "aiflow-copper"-version = "0.1.33"+version = "0.1.34" dependencies = [  "aiflow-board",  "aiflow-grid",@@ -58,7 +58,7 @@ dependencies = [  [[package]] name = "aiflow-grid"-version = "0.1.33"+version = "0.1.34" dependencies = [  "aiflow-board",  "serde",@@ -67,7 +67,7 @@ dependencies = [  [[package]] name = "aiflow-place"-version = "0.1.33"+version = "0.1.34" dependencies = [  "aiflow-board",  "serde",@@ -76,7 +76,7 @@ dependencies = [  [[package]] name = "aiflow-pours"-version = "0.1.33"+version = "0.1.34" dependencies = [  "aiflow-board",  "aiflow-copper",@@ -86,7 +86,7 @@ dependencies = [  [[package]] name = "aiflow-router"-version = "0.1.33"+version = "0.1.34" dependencies = [  "aiflow-board",  "aiflow-grid",@@ -96,7 +96,7 @@ dependencies = [  [[package]] name = "aiflow-run"-version = "0.1.33"+version = "0.1.34" dependencies = [  "serde",  "serde_json",
Cargo.toml+1−1
@@ -14,7 +14,7 @@ members = [ ]  [workspace.package]-version = "0.1.33"+version = "0.1.34" edition = "2021" license = "MIT" repository = "https://wiki.adom.inc/adom/adom-aiflow"
SKILL.md+19
@@ -57,6 +57,25 @@ No recording may outlive an hour (a hard cap on every recording), `finish` and `  The judgement is in these skills, which this tool executes: kicad-place-route-loop (place for routability, the levers when routing cannot close, go back to placement), kicad-copper-pours (which nets get a pour and which never do, priorities, the Kelvin pair, the preflight lessons), and the tool-neutral eda-engineering skillpack (eda-end-to-end-layout, eda-kelvin-current-sense, eda-copper-ablation, eda-pour-planning-measurement, eda-thermal-bottlenecks, eda-multilayer-current-review). +## Companion skills (load the one for the step you are on)++AI Flow's binary is the instrument, the gates and the hands; the judgement for each step lives in a skill. Load it when the step begins:++| step | skill |+|---|---|+| a brief or a video to reproduce, before any board exists | `aiflow-intake` |+| choosing parts, the fab profile (in-house by default, JLCPCB on request), symbols, footprints and 3D models | `aiflow-sourcing` |+| datasheet equations, stocked values, margins | `aiflow-circuit-design` |+| loop and transient simulation, vendor PSpice models | `aiflow-simulate` |+| schematic and board from a netlist, KiCad 10 traps | `aiflow-schematic-to-board` |+| an Adom molecule: pins, contacts, grid, export and publish | `aiflow-molecule` |+| a vendor login, account or verification code | `aiflow-credentials` |+| two-layer power layout: hot loop, SW node, Kelvin taps, thermal vias | `aiflow-power-layout` |+| silkscreen | `aiflow-silkscreen` |+| after every step: the clip goes on the project page | `aiflow-live-clips` |+| after `finish`: the molecule on a scaffold wired to the control panel | `aiflow-scaffold-probe` |+| metrics and comparisons | `aiflow-measurement`, `aiflow-comparison-video` |+ ## What is measured (read aiflow-measurement)  The number is the human's prompt to your "done, here is your video" (`deliver`), and the cost per step is your thinking, not the binary's seconds. Every command you run is a turn in the append-only run.jsonl with the gap before it as thinking time (`adom-aiflow ledger` reads it back); declare `step <name>` as you move, and `step <name> --back --why "..."` when a later step sends you back. `finish` is the qualified board; `deliver --video --message` ends the clock.
bin/adom-aiflow
⋯ 1 unchanged line ⋯
docs/release-0.1.34.mdadded+18
@@ -0,0 +1,18 @@+# AI Flow 0.1.34++Ten new skills from the second board built with AI Flow (a 12 V to 5 V, 1 A buck molecule), covering what the run had to work out on its own. The binary is unchanged from 0.1.33 apart from the version.++| skill | what it guides |+|---|---|+| `aiflow-intake` | a brief (or a video to reproduce) to requirements, with the clock started at the prompt |+| `aiflow-sourcing` | parts and CAD: the in-house fab profile by default (Mouser plus Adom stocked parts), JLCPCB on request; manufacturer CAD first, then distributor CAD, then the wiki, then your own labelled model |+| `aiflow-circuit-design` | datasheet equations in a script, stocked-value searches, margins and the part-reading checklist |+| `aiflow-simulate` | ngspice loop and switching models, vendor PSpice models, and a written design conclusion |+| `aiflow-schematic-to-board` | schematic and board generated from one netlist, and the KiCad 10 traps |+| `aiflow-molecule` | Adom molecule rules, conformance, STEP export and molecule publishing |+| `aiflow-power-layout` | two-layer power layout: the hot loop, the SW node, Kelvin taps, thermal vias, the current-density loop |+| `aiflow-credentials` | vendor logins without asking the human; bot checks go to the human as one click |+| `aiflow-live-clips` | every step's clip appended to the project page as the run goes |+| `aiflow-scaffold-probe` | the finished molecule on a scaffold wired to the Control Panel, the layout JSON and the probe plan |++The main skill now has a "Companion skills" table saying which one to load at each step.
package.json+1−1
@@ -1,7 +1,7 @@ {   "slug": "adom-aiflow",   "type": "app",-  "version": "0.1.33",+  "version": "0.1.34",   "title": "AI Flow",   "description": "Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board. One Rust binary with a crate per step (placement helpers, a grid router with Kelvin taps, pours with keepouts, KiCad's DRC gate, live landing through the KiCad Bridge, copper measurement, current and thermal analysis) and a finish line that refuses an unfinished board. Every command answers with hints for the AI; every turn, its thinking time and every rework loop go into run.jsonl, so Claude, Codex and any other engine are compared on the same flow. KiCad today; Altium, Fusion and Adom's own web apps next.",   "summary": "Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board. The AI thinks its way from placement through routing, pours, current and thermal analysis to a delivered video; the binary does the fast, deterministic parts of every step, hands back hints, and keeps a ledger of every turn, every return to an earlier step, and the clock from the prompt to done.",
page.json+1−1
@@ -1,7 +1,7 @@ {   "slug": "adom-aiflow",   "type": "app",-  "version": "0.1.33",+  "version": "0.1.34",   "title": "AI Flow",   "description": "Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board. One Rust binary with a crate per step (placement helpers, a grid router with Kelvin taps, pours with keepouts, KiCad's DRC gate, live landing through the KiCad Bridge, copper measurement, current and thermal analysis) and a finish line that refuses an unfinished board. Every command answers with hints for the AI; every turn, its thinking time and every rework loop go into run.jsonl, so Claude, Codex and any other engine are compared on the same flow. KiCad today; Altium, Fusion and Adom's own web apps next.",   "summary": "Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board. The AI thinks its way from placement through routing, pours, current and thermal analysis to a delivered video; the binary does the fast, deterministic parts of every step, hands back hints, and keeps a ledger of every turn, every return to an earlier step, and the clock from the prompt to done.",
skills/adom-aiflow/SKILL.md+19
@@ -57,6 +57,25 @@ No recording may outlive an hour (a hard cap on every recording), `finish` and `  The judgement is in these skills, which this tool executes: kicad-place-route-loop (place for routability, the levers when routing cannot close, go back to placement), kicad-copper-pours (which nets get a pour and which never do, priorities, the Kelvin pair, the preflight lessons), and the tool-neutral eda-engineering skillpack (eda-end-to-end-layout, eda-kelvin-current-sense, eda-copper-ablation, eda-pour-planning-measurement, eda-thermal-bottlenecks, eda-multilayer-current-review). +## Companion skills (load the one for the step you are on)++AI Flow's binary is the instrument, the gates and the hands; the judgement for each step lives in a skill. Load it when the step begins:++| step | skill |+|---|---|+| a brief or a video to reproduce, before any board exists | `aiflow-intake` |+| choosing parts, the fab profile (in-house by default, JLCPCB on request), symbols, footprints and 3D models | `aiflow-sourcing` |+| datasheet equations, stocked values, margins | `aiflow-circuit-design` |+| loop and transient simulation, vendor PSpice models | `aiflow-simulate` |+| schematic and board from a netlist, KiCad 10 traps | `aiflow-schematic-to-board` |+| an Adom molecule: pins, contacts, grid, export and publish | `aiflow-molecule` |+| a vendor login, account or verification code | `aiflow-credentials` |+| two-layer power layout: hot loop, SW node, Kelvin taps, thermal vias | `aiflow-power-layout` |+| silkscreen | `aiflow-silkscreen` |+| after every step: the clip goes on the project page | `aiflow-live-clips` |+| after `finish`: the molecule on a scaffold wired to the control panel | `aiflow-scaffold-probe` |+| metrics and comparisons | `aiflow-measurement`, `aiflow-comparison-video` |+ ## What is measured (read aiflow-measurement)  The number is the human's prompt to your "done, here is your video" (`deliver`), and the cost per step is your thinking, not the binary's seconds. Every command you run is a turn in the append-only run.jsonl with the gap before it as thinking time (`adom-aiflow ledger` reads it back); declare `step <name>` as you move, and `step <name> --back --why "..."` when a later step sends you back. `finish` is the qualified board; `deliver --video --message` ends the clock.
skills/aiflow-circuit-design/SKILL.mdadded+93
@@ -0,0 +1,93 @@+---+name: aiflow-circuit-design+description: >-+  The engineering step of an adom-aiflow run between sourcing and simulation: derive every component value from the datasheet's own equations in a script that sits beside the values (design/calcs.py writes design/calcs.json), search the stocked values instead of assuming ideal ones, check margins at both ends of every tolerance, derate what derates, write the reasoning next to each choice, and catch the classic part-reading mistakes (Isat typical vs minimum, Isat vs Irms, the wrong row of a series table, nominal vs maximum body size, a dimension written from memory). Trigger words: aiflow circuit design, design equations, calcs.py, calcs.json, component values, datasheet equations, feedback divider, inductor selection, Isat, output capacitance, DC bias derating, feed-forward capacitor, UVLO divider, losses, efficiency, margins.+---++# aiflow-circuit-design: values from equations, in a script++Every value on the schematic must trace back to an equation, a stocked part and a limit. Nothing typed by hand, nothing remembered. The script is the design record; simulation (aiflow-simulate) checks it, it does not replace it.++## 1. calcs.py writes calcs.json++`design/calcs.py` reads the brief's numbers, applies the datasheet equations in order, and writes `design/calcs.json`. Simulation scripts, the BOM notes, the schematic note and the aiflow spec read the JSON; nobody retypes a number.++Structure that worked (see `buck-12v5v-molecule/design/calcs.py`):++```python+"""<part> <topology>: every value from the datasheet equations (<doc id + revision>)."""+# ---- brief --------------------------------------------------------------+VIN_NOM, VIN_MAX, VIN_MIN = 12.0, 16.0, 9.0      # from requirements.json, range marked assumed+VREF = 0.596                                      # datasheet 5.5, 0.581..0.611+# ---- feedback divider from stocked values -------------------------------+# ---- inductor (eq 8/9/10) -----------------------------------------------+# ---- output capacitance (eq 11..14) -------------------------------------+# ... one block per function, each citing its equation or section+json.dump(out, open("calcs.json", "w"), indent=1)+```++Rules:++- Cite the equation or section on every block, with the datasheet revision in the header.+- The part's limits are constants in the script (reference with tolerance, on-resistance, minimum current limit, EN thresholds, frequency range, absolute maximums).+- Print results at both ends of each tolerance, not only nominal (`vout_range_vref_tol`).+- When you choose a value different from the equation's result, keep both in the JSON (`calc_pF`, `chosen_pF`) and a `note` with the reason.+- Mark a target you set yourself as self-set, separate from a brief requirement. A self-set budget missed by a little is a judgement; a requirement missed is a failure.++```bash+cd design && python3 calcs.py     # prints the table, writes calcs.json+```++## 2. Search the stock, not the E-series++On the in-house profile the resistor set is 41 values (aiflow-sourcing). Enumerate singles and series pairs, keep the constraints the datasheet puts on the network (divider current, top resistor range for the feed-forward cap), and sort by error, then part count:++```python+for rtop_parts in singles + pairs:+    for rbot_parts in singles + pairs:+        if not (5e3 <= rbot <= 30e3) or not (50e3 <= rtop <= 250e3):+            continue+        cands.append((abs(v - VOUT), n_parts, rtop_parts, rbot_parts, v))+```++The same search applies to UVLO dividers, LED resistors and anything else with a stocked alternative.++## 3. Margins and derating++- **MLCC capacitance at DC bias.** A 22 uF 0805 X5R 10 V at 5 V keeps roughly half. Use the manufacturer's bias curve when it exists and write the factor (`DERATE = 0.55`) with its source.+- **On-resistance hot.** x1.4 over the 25 C value unless the datasheet gives a curve.+- **Voltage.** Ceramics at least 1.5 to 2x the working voltage; electrolytics above the maximum input including hot-plug ringing.+- **Absolute maximums.** Compute the worst-case voltage at every limited pin (EN at the maximum input was 2.09 V against 5.5 V here; the script also printed it at 28 V).+- **Dissipation, physically.** I squared R at the hot on-resistance over the conduction duty, plus a switching estimate, plus gate drive. The same watts go into the aiflow spec's `hot` entries for `analyze thermal`, with the arithmetic in `hotNote`.++## 4. Reading a part correctly (the mistakes this catches)++Before a part's number enters calcs.py, check each of these against the datasheet page, and cite the page in the note:++| Check | The trap |+|---|---|+| Right row | Series tables list many values; the 15 uH row (DCR 118 max, Isat 3.7, Irms 3.5) sits next to rows with double the current. Quote the MPN on the row you read. |+| Isat vs Irms | Isat is a saturation point (here: inductance down 30 %); Irms is a heating limit (here: about 40 C rise). They answer different questions; check both. |+| Typical vs minimum | Isat was a typical figure. Compare it with the converter's current limit, and say which limit (the minimum high-side limit, 2.5 A here; the maximum limit for surviving a short) and how much margin is left. |+| Max vs typical DCR | Use the maximum DCR for losses and thermal (118, not 98 mOhm). |+| Nominal vs maximum size | The same inductor was "5.7 x 5.3 x 2.8" in the header (maximum) and 5.6 x 5.2 in the drawing (nominal). Footprints and courtyards use the drawing with its tolerances; say which one you wrote. |+| From memory | A case size or height typed from memory is wrong until a page says otherwise (the electrolytic's case was). |+| Vendor tuning | Internally compensated regulators are tuned for their table values; the TI table's 15 uH for 5 V beat the equation's Lmin of 22.9 uH. Say why you left the equation. |++## 5. Write the reasoning where the value lives++Each `note` in calcs.json says what the value does, why this one, and what would change it. The BOM `note` column repeats the one line a buyer or reviewer needs ("Isat 3.7 A / Irms 3.5 A >= 2.5 A HS limit min"). The schematic's design note quotes the headline numbers from the JSON.++## 6. Hand off++`design/calcs.json`, `design/bom.csv` with notes, and a list of values the simulation must confirm (feed-forward cap, output capacitance, anything chosen against the equation). Next: aiflow-simulate.++## Worked example: TPS54202, 12 V to 5 V / 1 A (datasheet SLVSD26C)++- Feedback: 68k + 5.6k over 10k, 4.98 V nominal (-0.35 %), 4.86 to 5.11 V across the reference tolerance.+- Inductor: 15 uH Abracon AMPLH5030S-150MT; ripple 0.39 A at 12 V, 0.46 A at 16 V, peak 1.23 A; Isat 3.7 A typical against the 2.5 A minimum high-side limit.+- Output: 3 x 22 uF 0805 X5R stocked, 36.3 uF effective at 5 V; eq 14 gives fo 21.8 kHz, under the 40 kHz limit.+- Feed-forward: eq 16 gives 99.4 pF; 68 pF chosen after the loop sweep (aiflow-simulate explains why the model's favourite was rejected).+- EN UVLO: 1M over 150k, start 8.58 V, stop 6.87 V.+- Losses: 0.25 W in U1 (0.15 W conduction hot, about 0.09 W switching, gate drive), 0.12 W in L1 at the maximum DCR, about 93 % efficiency estimated. These became the spec's `hot` watts.+- The 3 % load-step budget in calcs.py was self-set; the vendor model later showed 3.6 %, inside the usual 5 % for a 5 V rail, so COUT stayed. Labelling it self-set is what made that an easy call.
skills/aiflow-credentials/SKILL.mdadded+71
@@ -0,0 +1,71 @@+---+name: aiflow-credentials+description: >-+  How an adom-aiflow run gets into vendor sites (TI, Mouser, DigiKey, manufacturer CAD portals, PSpice downloads) without ever asking the human for a login: the ladder pup vault, then import the user's own browser logins, then vault sync from another desktop, then create or reset an account with the user's work email and read the verification code from Gmail with adom-google. Human-verification (bot) checks go to the human as ONE click, never solved or bypassed; another account's saved password is never submitted; secrets are never printed or passed through tools that crash on them. nb (the user's real Chrome) when pup is blocked. Trigger words: vendor login, sign in to TI, myTI account, Mouser login, DigiKey login, need a password, credentials, sign up on a vendor site, verification code, captcha, press and hold, bot check, pup vault, import browser logins, vault sync, nb login.+---++# aiflow-credentials: get in without asking++Datasheets, CAD, vendor models and simulator downloads often sit behind a login. Asking the human "can you sign in for me?" stops the run and is the wrong move: on the first buck molecule the human's answer was "go get my login on your own, you have tons of tools". Walk this ladder silently; the only thing that ever reaches the human is a single consent or a single click.++## 1. The ladder++Try each rung once, in order, and stop at the first that works.++1. **The pup vault.** `pup_credentials {}`: is the site there? Then `pup_login {"submit": true, "submitReason": "..."}` in a pup window on that site.+2. **The user's own browser logins.** `pup_import_browser_logins {"hostFilter": ["ti.com"]}` on the machine where their browser lives. It imports their saved Chrome/Edge logins for that host into the pup vault; the one consent it raises on their desktop is theirs to click.+3. **Another of their desktops.** Saved on a different box: `pup_vault_sync {"peer": "<box>", "reason": "..."}`.+4. **Stale password.** The browser-password-manager recovery in the pup-credentials skill.+5. **No account yet, or the password is lost.** Create the account, or reset it, with the user's work email (the Adom account they use for vendor work), in nb (section 3). Read the verification code or reset link from Gmail (section 4). Choose a strong password and get it saved right away (section 2).++Check first whether an SSO button ("Continue with Google") works in the pup profile; it needs no password at all (pup-vendor-login).++## 2. Hard lines++- **Never ask the human for a password or to sign in.** Surface only the consent a tool raises, or the one verification click.+- **Bot checks go to the human.** A captcha, a press-and-hold, "verify you are human": bring the window up, toast them with `focus` on it, say what to click, wait and read their reply. One click, ready to go. Never solve, automate or bypass a human-verification check, and never spoof a browser fingerprint to avoid one.+- **Never submit another account's saved password.** A vault entry for a colleague, a shared test user or an old address is not this user's credential. Match the account to the user before `pup_login`.+- **Secrets are never printed.** Not in the terminal, not in a log, not in a commit, a wiki page, a toast or a chat message.+- **Keep secrets away from tools that crash on them.** `credential_set` and `pup_type` carrying a password dropped the pup bridge on two machines. Keep a new password in a 0600 scratch file, feed it to the field with a trusted keystroke lane (below), let the user's browser save it when it offers to (then `pup_import_browser_logins` brings it into the vault), and delete the file.++```bash+umask 077; f=$(mktemp -p "$SCRATCH" cred.XXXX); python3 -c "import secrets;print(secrets.token_urlsafe(18))" > "$f"+# use it, save it, then:+shred -u "$f"+```++## 3. nb when pup is blocked++pup runs its own browser; some vendor sites refuse it (press-and-hold checks that even a human click cannot clear there, bot walls). nb drives the user's real signed-in Chrome (`nbrowser_*`) and passes where pup does not.++- Sign-up and sign-in on vendor portals: nb first when pup has failed once.+- Fill the forms yourself.+- Shadow-DOM form components (TI's `ti-input`, `ti-password`) ignore programmatic value sets. Focus the field and type real keystrokes with `nbrowser_type`.+- Leave the user's tabs as you found them; close only what you opened.++## 4. Verification codes from Gmail++Search the user's mailbox with adom-google's `api` passthrough; `newer_than` keeps it to this attempt:++```bash+adom-google api gmail.googleapis.com/gmail/v1/users/me/messages -q 'q=from:ti.com newer_than:1h' -q 'maxResults=3'+adom-google api gmail.googleapis.com/gmail/v1/users/me/messages/<id> -q 'format=full'+```++Decode the base64url body, take the code or the link, and use it. Do not print the message body; print only that a code was found.++## 5. Approvals that take time++Some downloads need an export or licence approval after sign-in (PSpice for TI: minutes to 48 hours). Request it at intake, record the request time in the run (`capture mark` or a note), and carry on with what does not need it (aiflow-simulate uses ngspice meanwhile). When the approval email lands, the Gmail search above finds it.++## 6. Record it++Add one line to the run's notes: which site, which rung worked, what the human had to click (if anything). If a rung was missing or broken, file it (`adom-wiki issue create adom/adom-aiflow ...`, then `adom-aiflow giveback <url>`); a bug in pup or nb goes on that bridge's page.++## Worked example: myTI for the TPS54202 PSpice model (2026-09-29)++- The AI asked the human for his TI login: wrong. The ladder above is the right answer.+- pup's browser hit a press-and-hold check a human click could not clear. In the user's own Chrome through nb, sign-up and sign-in worked; the human-verification step went to the human as one click.+- The verification code came from Gmail through adom-google; the `ti-password` field took the password only through `nbrowser_type`.+- `credential_set` and `pup_type` with a password crashed pup; read verbs kept working. Hence the scratch-file rule.+- PSpice for TI then waited on export approval, and the design carried on with ngspice results.
skills/aiflow-intake/SKILL.mdadded+103
@@ -0,0 +1,103 @@+---+name: aiflow-intake+description: >-+  The first step of an adom-aiflow run, before any board exists: turn the human's brief (a video, a spec, a chat message, "reproduce this") into requirements.json (rails, interfaces, form factor, fab target and sourcing profile, deliverables), start the clock at the prompt rather than at the first board, and ask the human only what is truly their decision. Read this the moment someone asks for a new board or molecule. Trigger words: aiflow intake, new board from a brief, requirements.json, design from a video, design from a datasheet, make a molecule, reproduce this design, what are the requirements, start the clock, prompt time, before the board exists, what should I ask the user.+---++# aiflow-intake: the brief becomes requirements.json++Everything before a board used to be unguided and untimed: on the first buck molecule the requirements, part choice, calculations, simulation and schematic took about 91 minutes and landed in the ledger as one lump of "thinking" on the first turn. Intake fixes both halves. It writes one file, `requirements.json`, that every later skill reads (aiflow-sourcing, aiflow-circuit-design, aiflow-simulate, aiflow-schematic-to-board, aiflow-molecule, aiflow-scaffold-probe), and it pins the clock to the prompt.++## 1. The clock starts at the prompt++Write the UTC of the human's message down before anything else. Use the message's own timestamp, not "now" if you are late.++```bash+date -u +%Y-%m-%dT%H:%M:%SZ   # only when the prompt is this instant+```++Today `adom-aiflow start` needs `--board` and `--spec`, so there is no run until a `.kicad_pcb` exists. Until the binary accepts a board-less start:++- Keep the time in `requirements.json` as `prompt.utc`.+- Keep a `preBoard` list (phase, start UTC, end UTC, what it produced) as you go: intake, sourcing, circuit, simulate, schematic. The run page uses it to show where the pre-board hour went.+- When the board exists, start with that time, never the current one:+  `adom-aiflow --ai-thread "<thread>" start --board <b>.kicad_pcb --spec aiflow/spec.json --engine <you> --prompt-time <prompt.utc> --target <box> --remote-board <path on the box>`+- Never subtract pre-board time and never start late to look faster (aiflow-measurement).+- Follow-up prompts on the same run are `prompt --text "..." [--at <paste time>]`; close each answer with `done --message "..."`.++Once the run exists, set up the run page and the clips page early (`report --page <owner/slug> ... --push --refresh`, then aiflow-live-clips) so the human can watch.++## 2. Read the whole brief++Get all of it, not the first impression.++- **A video.** Download it; read both the words and the frames.+  ```bash+  yt-dlp -f "bv*[height<=720]+ba/b" -o brief.mp4 "<url>"+  yt-dlp --write-auto-subs --sub-langs en --skip-download -o brief "<url>"+  mkdir -p frames && ffmpeg -i brief.mp4 -vf fps=1/10 frames/%04d.png+  ```+  Look at the frames where a schematic, a board or a spec table is on screen and write the numbers down with their timestamp.+- **A spec or datasheet.** Quote the number with page and table.+- **A message.** Copy the human's exact words into `brief.quotes`. They settle arguments later.++Anything the brief does not say is an assumption: mark it `"assumed": true` with a one-line why. Never pick a value silently.++## 3. "Reproduce X" means your own design++"Reproduce this", "do what they did", "same thing as the video" means: the same brief (inputs, outputs, function, form factor, deliverables), designed independently from scratch. Never copy their part choices, values, schematic or layout. Record it:++```json+"brief": {"reproduce": {"of": "<url>", "rule": "same brief, independent design; no values or layout copied"}}+```++Compare with theirs only at the end, and say where and why you differ.++## 4. Ask only what is truly the human's decision++Every question stops the clock's value for nothing. Decide what you can, state the default in the readback, and let the human override.++| Decide yourself (state it) | Ask (once, all together) |+|---|---|+| Form factor: an Adom molecule for Adom work (aiflow-molecule) | A number the brief contradicts or leaves ambiguous and that changes the design (5 V or 3.3 V out?) |+| Fab target: our own in-house PCB fab by default | A mating connector, enclosure or mechanical constraint you cannot see |+| Sourcing profile: follows the fab target (aiflow-sourcing) | Cost or quantity ceilings when they would change part choice |+| Input range margin, derating, test points, a power-good LED | Anything that spends money or touches another person's work |+| Deliverables the flow always makes (calcs, sim, schematic, board, 3D, video, clips page) | Deliverables beyond the flow (a scaffold layout for a specific workcell, a vendor-model run, a PR to someone's page) when the brief does not name them |++Never ask for logins or passwords (aiflow-credentials). Never ask "should I continue?".++## 5. Write requirements.json++One file beside the design. Minimum shape:++```json+{+  "prompt": {"utc": "2026-09-29T00:39:00Z", "text": "<the human's message>"},+  "brief": {"source": "<url or file>", "kind": "video", "quotes": ["..."], "reproduce": null},+  "inputs":  [{"name": "VIN", "nominal_V": 12, "range_V": [9, 16], "assumed": true, "why": "bench / control-panel rail, margin to 16 V"}],+  "outputs": [{"name": "VOUT", "V": 5.0, "tol_pct": 3, "I_A": 1.0}],+  "interfaces": {"power": ["VIN", "GND", "VOUT"], "control": ["EN"], "monitor": ["VMON"], "probe": ["SW", "FB", "VOUT", "GND"]},+  "formFactor": {"kind": "molecule", "pin": "MachinePinMediumShort", "grid_mm": 2},+  "fab": {"target": "inhouse", "layers": 2, "thickness_mm": 1.6, "design_copper_oz": 0.5},+  "sourcing": {"profile": "inhouse"},+  "deliverables": ["calcs", "ngspice loop + transient", "vendor-model check", "schematic", "board", "3D models", "molecule publish", "scaffold + probe plan", "video", "clips page"],+  "assumptions": [],+  "preBoard": []+}+```++- **inputs / outputs**: every rail with nominal, range and current. A design range wider than the brief is fine; say why.+- **fab.target**: `inhouse` (default) or `jlcpcb`. It picks `sourcing.profile` and the DRC rules profile (aiflow-molecule).+- **deliverables**: everything the human asked for, including the steps after `finish` (molecule publish, scaffold placement, probe plan, vendor simulation). A deliverable not listed here gets forgotten.++## 6. Hand off++Read the file back to the human in five lines or fewer (rails, form factor, fab and sourcing profile, deliverables, any open question) and go straight on. Next: aiflow-sourcing, then aiflow-circuit-design.++## Worked example: the TPS54202 12 V to 5 V / 1 A molecule (2026-09-29)++- The brief was a YouTube video; it was pulled apart by hand with yt-dlp and ffmpeg frame sampling and never written down as a file. This skill is that file.+- Prompt at 00:39:00Z; `start` could not run until the board existed at 02:09:55Z, so the first turn carries about 91 minutes of thinking. `preBoard` is how to show that hour honestly.+- Four requirements arrived mid-run that intake should have settled: "make sure you make a molecule so it fits into our scaffold", build on our own in-house PCB fab (so Mouser sourcing), a PSpice run matching the brief's workflow, and a scaffold placement for a live probing workcell. The first two are defaults now; the last two belong in the deliverables readback.+- The human asked "reproduce" and meant independent design: own parts, own calcs, own layout.
skills/aiflow-live-clips/SKILL.mdadded+63
@@ -0,0 +1,63 @@+---+name: aiflow-live-clips+description: >-+  Keep a live clips page for an adom-aiflow run: after every step's clip stops, append it (the 10x cut, the nine-frame contact sheet, which step, what it shows, whether it is suspect) to docs/clips.md on the project's wiki page and push it at once, so the human can follow the build in a pup or webview tab, and an overnight run leaves a morning's worth of clips. Covers the wiki sub-readme mechanics (adom-wiki repo push --files, repo-root-relative media paths, verify by looking), the clip-notes file, and the pre-push scrub. Trigger words: live clips, clips page, clips.md, follow along, watch the build, overnight run, wake up to clips, step clips, append clip, contact sheet, 10x cut, sub-readme for clips, publish clips as they land.+---++# aiflow-live-clips: the human watches the board being built++Every `step` in a run stops the previous step's clip and starts a new one. The run page (`report --push`) shows them at step changes, but a human who wants to glance at the build, or who wakes up after an overnight run, wants one page: every clip, newest last, each with a line saying what it shows. The human's words: "when the ai runs all night, the user expects to wake up to a whole bunch of new video clips".++This is your job after every step, not at the end. Never batch it.++## 1. Once, at the start++- Pick the page: the project's own wiki page (`<owner>/<project-slug>`), the same one `report --page` pushes to.+- Clone it to a staging folder in your scratchpad (`adom-wiki repo clone <owner>/<slug>`).+- Make the first push (an empty `docs/clips.md` with the header and a link from the README's feature-guides table; wiki-sub-readme).+- Open the rendered page for the human ONCE, in the surface they use (a pup window on their machine, or a Hydrogen webview tab), and tell them the URL in one line: `https://wiki.adom.inc/<owner>/<slug>/files/docs/clips.md`. Do not reopen it at every push; the page reloads.++## 2. After every step++When a clip stops (`step <next>`, `capture stop`, `finish`, `deliver`, or the clip guard), aiflow prints the clip's files: the raw `.mp4`, the `-10x.mp4` cut, the `-action.mp4` motion-only cut, and the `-sheet.png` contact sheet.++1. **Look at the contact sheet.** Nine frames from the take. Is the board in frame? Did the thing the step is about happen on camera? A blank or covered take is `suspect`.+2. **Write the note** in `<run>/clip-notes.json`, keyed by the clip's file stem:+   ```json+   "window-593052-20260929-121139": {+     "step": "Pours rework (back from the Fields solve)",+     "shows": "SW patch from U1 to the inductor, solid ground at U1's GND pin with thermal vias, every zone refilled.",+     "state": "ok"+   }+   ```+   `state` is `ok` or a sentence: a false blank flag and why it is false, a guard stop and what was lost, a missing cut.+3. **Rebuild and push** the page:+   ```bash+   python3 tools/clips_subreadme.py <run dir> <owner/slug> <staging dir>+   ```+   The script (in `buck-12v5v-molecule/tools/clips_subreadme.py`) rebuilds `docs/clips.md` from the run folder and the notes: a table (number, step, time, link, state), then one block per clip with its note, the 10x cut as a `<video>`, the action cut, the contact sheet and the raw file's size (raw recordings stay with the run, not uploaded). It copies the media into `docs/clips/`, adds the README link once, scrubs the payload and pushes with `adom-wiki repo push --files`.+4. **Verify by looking**: reload the rendered page and check the new clip plays and the sheet shows. A successful push is not a working page.++Wrap the push in `adom-aiflow exec -- python3 tools/clips_subreadme.py ...` so its time is measured.++## 3. Mechanics that bite++- **Publish with `adom-wiki repo push --files`**, not the files blob API (it does not update the git repo the Files tab reads).+- **Media paths are repo-root-relative**, even inside `docs/clips.md`: `docs/clips/<stem>-10x.mp4`, `docs/clips/<stem>-sheet.png`. The files viewer prepends `files/` to the ref as written; a path relative to the doc's own folder (`clips/x.mp4`) points at the wrong place. Use the same form for plain links to the action cuts.+- **Doc links are relative** (`docs/clips.md` from the README), never absolute URLs.+- **Push only what changed** plus `docs/clips.md`; pushing the whole run folder is slow and bloats the page.+- **Scrub before every push**: the script refuses a payload that names the in-house fab's product or carries an em-dash. Say "our own in-house PCB fab".+- **Rate limits**: one push per step is fine; do not push in a loop.++## 4. Overnight runs++- More steps, more clips: keep the per-step rhythm; the guard stops any clip past twice its budget, and a guard stop still gets a note and a push.+- If a push fails, the next step's push carries both clips (the script rebuilds from the whole run folder). Say so in the note.+- At `deliver`, add the composed video's link at the top of `docs/clips.md` and push once more.+- In the morning the page should read as a story: step, what happened, why it went back, and the fix, one clip at a time.++## Worked example: TPS54202 molecule++- Nine clips over about twelve hours: placement, routing and first pours, routing rework (back from the current analysis), pours rework (back from the Fields solve), thermal with the SW throat widened (215 to 50 A/mm2), the Fields walkthrough, the net walkthrough, silkscreen, and the 3D walkthrough.+- Two notes were not `ok`: a blank flag that was false (the board sat left of the sampled middle at that zoom; the sheet showed real footage), and a silkscreen take stopped by the guard after 43 minutes with no 10x cut made.+- The clips page was added late in the run, after the human asked. Start it at step one.
skills/aiflow-molecule/SKILL.mdadded+87
@@ -0,0 +1,87 @@+---+name: aiflow-molecule+description: >-+  Make an adom-aiflow board an Adom molecule that fits the scaffold: the 2 mm grid, the origin at the MP1 (front-left) machine pin, MachinePinMediumShort (1.6 mm pad, 1.2 mm drill) at the corners as MP1 to MP4, MachineContactMedium (1.3 mm pad, 0.78 mm drill) for the signal contacts, footprints from the Adom KiCad Library 1.2.3, the fab-rules profile (in-house default, jlcpcb optional), then STEP export, `step2glb convert --molecule` with its stats gates, and molecule-publish. Medium-pin molecules mount on a LrgMed user scaffold (4 mm medium contact grid, large pins on a 32 mm base grid). Trigger words: aiflow molecule, make it a molecule, fits our scaffold, machine pins, MachinePinMediumShort, MachineContactMedium, MP1, molecule grid, molecule outline, fab rules profile, kicad_dru, molecule conformance, molecule export, step2glb molecule, publish molecule, LrgMed scaffold.+---++# aiflow-molecule: a board that drops into the scaffold++A molecule is a small board whose machine pins seat it on a scaffold and whose contacts take wires to the Control Panel. The pin geometry is the mechanical interface: get it wrong and the board does not fit, however good the circuit is. Decide the molecule at intake (it is the default for Adom work), lay it out before placement, and lock it.++## 1. The rules++| Rule | Value |+|---|---|+| Grid | 2 mm for every pin and contact, measured from MP1 |+| Origin | the centre of MP1, the front-left (FL) corner pin; aux and grid origin on it; y up in the design frame, y down in KiCad |+| Corner pins | MP1 (FL), MP2 (FR), MP3 (BL), MP4 (BR), footprint `MachinePinMediumShort`: 1.6 mm pad, 1.2 mm drill, net GND |+| Contacts | footprint `MachineContactMedium`: 1.3 mm pad, 0.78 mm drill, one per signal the Control Panel wires to |+| Library | the Adom KiCad Library 1.2.3 (KiCad plugin manager); copy the footprints and their STEP models into the project (`lib/Molecule.pretty`, `3d/`) so the project travels |+| Markers | MP1 to MP4 are the anchoring markers the step2glb molecule conversion reads; keep those exact references and the library's 3D models on them |+| Outline | pin span plus an edge margin all round (24 x 16 mm span + 2 mm = 28 x 20 mm here) |+| Scaffold fit | medium-pin molecules mount on a LrgMed user scaffold: a 4 mm medium contact grid, with its large pins on a 32 mm base grid. Keep the pin span on 4 mm multiples so every corner pin lands on a scaffold hole |++Put the interface in netlist.json as `fixed` positions (aiflow-schematic-to-board) and in the aiflow spec as `fixedRefs` with a `fixedRefsNote`, so placement never moves them.++## 2. Designing the interface++- Size the pin span to the circuit, then round up to 4 mm multiples. Place contacts on the two short edges or wherever wiring is cleanest, on the grid, in an order that reads left to right on the silkscreen.+- Group power contacts together (input and its return side by side, output and its return side by side). Give each rail its own ground contact near it; corner pins are GND too, but they are mechanical first.+- A monitor contact that feeds a Control Panel ADC must be scaled to the ADC's range (VMON = VOUT/2 through 10k/10k here for a 3.3 V ADC).+- Test pads for probing sit on the top face, clear of the pins, with room for a probe tip (aiflow-scaffold-probe plans them).+- Label every contact's function on both faces (aiflow-silkscreen).++## 3. Fab-rules profile++The DRC gate uses the board's own `.kicad_dru`, so the fab's limits must be in it. The profile comes from `fab.target` in requirements.json:++| Profile | Rules file |+|---|---|+| `inhouse` (default) | the in-house 2-layer rules file shipped for our own in-house PCB fab (`rules/inhouse-2L.kicad_dru` in the project); design with margin above its minimums. Do not restate its process limits on public pages |+| `jlcpcb` | JLCPCB's published 2-layer capabilities as a `.kicad_dru` |++`build_board.py` copies the file beside the board; `start` carries `.kicad_pro` and `.kicad_dru` into the run; the gate needs a native kicad-cli for project rules (`ADOM_AIFLOW_KICAD_CLI=adom-aiflow-kicad-cli-remote`). Put the copper weight you designed for in the spec (`copperUm`, with a note).++## 4. Conformance check before placement++Run it yourself until the binary has a gate for it:++- MP1 to MP4 present, references exact, `MachinePinMediumShort`, at the four corners of the span, all on GND.+- Every contact is `MachineContactMedium`, on the 2 mm grid from MP1.+- Pin span on 4 mm multiples; outline = span + margin; board origin on MP1.+- All interface parts locked and in `fixedRefs`.+- Every pin and contact has its STEP model bound (`adom-aiflow models`).++## 5. Export, convert, publish++After `finish` (and silkscreen):++```bash+# on the desktop, where every model resolves:+kicad-cli pcb export step --output <design>.step <design>.kicad_pcb+# back in the container:+step2glb health+step2glb convert <design>.step --board <design>.kicad_pcb --pin medium -o <slug>.glb+```++Gate on the printed stats before publishing:++| Stat | Expect |+|---|---|+| `molecule_anchored` | `true` (false = MP markers missing from the STEP) |+| `pin_size` / `pin_size_source` | medium / `markers` |+| `footprint_applied`, `footprint_pins` | `true`, 4 |+| `warnings` | none |++Then hand the bundle (STEP, board, every schematic sheet, `.kicad_pro`, custom 3D models, the GLB and the footprint and symbol JSON) to the molecule-publish skill. Publishing is its own reviewed step: check the payload for anything confidential first, and say "our own in-house PCB fab" wherever the fab is named.++## 6. Hand off++A locked interface, a rules profile in the board, and after the build a converted GLB whose stats passed. Next: aiflow-scaffold-probe.++## Worked example: TPS54202 molecule++- 28 x 20 mm, MP1 to MP4 at (0,0), (24,0), (0,16), (24,16), all GND.+- Contacts on the short edges: J1 VIN (0,12), J2 GND (0,8), J3 EN (0,4); J4 VOUT (24,12), J5 GND (24,8), J6 VMON (24,4). Input on the left, output on the right, each with its own ground.+- Rules: in-house 2-layer profile, 1.6 mm FR4, designed for 0.5 oz outer copper.+- The Adom library footprints reference their STEP through the plugin manager's path; the project carries copies in `kicad/3d/` so the board renders on any machine.
skills/aiflow-power-layout/SKILL.mdadded+81
@@ -0,0 +1,81 @@+---+name: aiflow-power-layout+description: >-+  Layout judgement for small 2-layer power boards in an adom-aiflow run (bucks, LDOs, load switches on molecules): write the spec as the electrical judgement, keep B.Cu an unbroken ground under the hot loop (the router has no layer policy yet, so check and hand-rework FB and VOUT), give series chains one rotation, route Kelvin taps on their own layer, make SW a small solid patch, put thermal vias beside small pins not in the pad, iterate the current-density necks with Fields (215 to 50 A/mm2 here), reason about a still-air thermal budget on a small board, use the silkscreen text verb correctly, and resume `land route` by revision after a dropped reply. Trigger words: power layout, buck layout, hot loop, ground plane under the hot loop, layer policy, FB routing, Kelvin sense, SW node, switch node copper, thermal vias SOT-23, current density neck, Fields, still air, thermal budget, silkscreen text batch, kicad_silk_text_batch, land route resume, dropped reply, route_live.+---++# aiflow-power-layout: small power boards, two layers++A 2-layer power molecule has one real ground plane (B.Cu) and very little area. The binary's router and pour planner are generic; the judgement below is what made the buck molecule pass current, thermal and review. Read kicad-place-route-loop and kicad-copper-pours for the general rules; this is what is specific to power on two layers.++## 1. The spec carries the judgement++Write `aiflow/spec.json` from the schematic before `start`, with a note on every block (`*Note` fields) saying why:++- `wideNets` for VIN, VOUT, SW, GND (widths in preference order); `midNets` for BOOT.+- `kelvin`: the divider's bottom returns to the IC GND pin (`"R3.2": "U1.1"`), the divider's top senses VOUT at the output cap (`"R1.1": "C6.1"`), per the datasheet's layout section.+- `loads`: amps and `maxRiseC` per loaded net; VIN at the low end of the input range.+- `hot`: watts per part from calcs.json (aiflow-circuit-design) with the arithmetic in `hotNote`, and `tabNet` (the pin the heat leaves through; a SOT-23 has no pad, so GND and VIN pins are the heatsink).+- `pours`: GND on both layers from the outline; VIN and VOUT as `around` pours on F.Cu; SW as an explicit small `polygon`; `notPoured` for BOOT, FB and dividers.+- `solidAt` for the IC GND pin and the inductor pads; thermal and stitch vias.++## 2. Placement: the hot loop first, chains in one rotation++- Input caps, IC VIN and IC GND form the hot loop: smallest possible loop on F.Cu, the high-frequency cap closest to the pins.+- Inductor right after SW; output caps right after the inductor; the feedback network on the quiet side, away from SW.+- **Series chains get ONE rotation.** `place pack` picks 90/270 per part independently and can knot a chain: R1/R2/C9 came out VOUT-bottom, FBM-top, forcing FBM to loop round and a via into an 0402 pad. Turned 180 together, the column read VOUT, R1, FBM, R2, FB top to bottom and FBM became a 1 mm straight link. Give chains a rotation in the wish, then `place check --moves` and `place land --moves`.++## 3. Routing: keep B.Cu a ground plane under the hot loop++The grid router treats B.Cu as free space. On the buck it put 17.5 mm of VOUT and 2.8 mm of FB under the hot loop, and the VOUT Kelvin sense sliced the bottom plane under the input caps. There is no spec field yet to forbid it, so after `route`:++1. Look at B.Cu under the hot loop and under SW. Any non-GND copper there is a defect.+2. Take those nets yourself (`take route=ai`, `step routing --back --why "..."`): FB on F.Cu inside the quiet side; the VOUT sense along an edge, not across the plane.+3. Land hand routes one at a time with a dry run first: `tools/route_live.py routes.json` calls `kicad_route_net` with `dryRun`, commits only on 0 DRC errors, and chains `expectedRevision` from each reply.++Kelvin keepouts follow the tap's own layer (both layers only at its vias) and stop short of the power pin, so the IC GND pin keeps its pour (fixed in adom-aiflow 0.1.33; check older runs).++## 4. Pours: small SW, solid heat paths++- **SW is a small solid patch** from the IC's SW pin to the inductor, widening toward the inductor, never a large pour: small area, small radiated field, no neck. Open the polygon right after the pad; the first patch had a 0.95 mm throat at 60 A/mm2.+- **Solid, not thermal-relief, at heat paths**: the IC GND pin and the inductor pads (`solidAt`).+- **Thermal vias beside small pins.** A SOT-23 or 0603 pad is too small for a via; an open via in it wicks solder. Put 0.6/0.3 mm vias in the solid pour just outside the pad, clear of other nets (`pour` now does this and says how many of `count` fit).+- **Check every landed via's net.** A planned GND via whose pad touched the SW trace landed as SW and DRC passed. After `land vias`, read each via's net on the live board against the plan.++## 5. Current density: iterate with Fields++`analyze current` is a screen; the neck is found by a solve:++```bash+adom-fields analyze --board <current saved board> --spec aiflow/spec.json --out <run>/fields+adom-aiflow --ai-thread "<t>" analyze current --fields <run>/fields/fields.json+```++The first solve showed 215 A/mm2 at the SW pin and U1 at +51 C (Kelvin keepouts had fenced its GND pin off the pour, no thermal vias). Back to pours (`step pours --back --why "..."`): SW patch, solid GND and vias at U1.1, keepouts on the sense layer: 60 A/mm2 at the patch throat. Opened the throat: 50 A/mm2. Each pass: change the spec, `pour`, `land pours`, `measure`, solve, analyze. Draw the final map and register it (`artifact --kind analysis-image`).++## 6. Thermal: know when the board is area-limited++On a small board, still air sets a floor no copper can beat. Estimate it before chasing degrees: average rise is about P / (h x A), with h about 10 W/m2K per face in still air. 0.37 W on 28 x 20 mm (two faces, 0.00112 m2) is about +33 C with perfect copper, so a 30 C still-air budget is impossible by layout. Then:++- State the budget on the junction: pin rise plus psi_JB x P (U1: +44 C at the GND pin, plus about 8 C, so about 92 C at a 40 C ambient against a 125 C rating). Put it in `hotMaxRiseC` with a `hotMaxRiseNote`, and get the human's yes, since it is their product risk.+- Report moving air too (+24 C for U1 at 25 W/m2K).+- Test a fix before adding it: 8 more GND vias near U1 changed its rise by 0 C in the solve, so they were not added.++## 7. Silkscreen text through the bridge++`kicad_silk_text_batch` takes `width`, `height` and `stroke` (not size or thickness), mirrors B.SilkS by itself and refuses a `mirror` field. Its dry run refuses NEW text below the board's minimum text height (`text_height`), so small value sizes are unreachable until that minimum is lowered in the board setup (only as far as the fab profile allows). Footprint reference and value edits are refused over IPC in KiCad 10.0.5; do them offline (close the clean editor, edit the saved board, reopen, refresh 2D and 3D). `tools/silk_place.py` tries candidate spots and sizes with a dry run each and commits the first legal one. The rest is aiflow-silkscreen.++## 8. Resume `land route` by revision++`land route` has no `--from` and no dedupe (vias and pours do). When the bridge drops a reply mid-landing (trace 35 of 48 here):++1. Do not rerun: it would duplicate traces 1 to 34.+2. Read the live board's revision and check whether the trace in flight landed.+3. Write a resume plan with only the traces not on the board (`plan-route-resume.json`) and land that.+4. Record the resume in the run (`capture mark`, a note) and file it if it is new.++Adopted boards: `route` re-plans every trace of an adopted, already-routed board; land an explicit empty plan that documents nothing remains, rather than duplicate copper.++## Worked example: TPS54202 molecule++Returns in the ledger tell the story: routing (VOUT sense slicing the plane), pours twice (SW neck and U1 heat path, then the patch throat). State at the time of writing (before `finish`): gate at 0 new DRC errors and 0 unconnected, current pass at 50 A/mm2 peak, thermal pass at U1 +44 C and L1 +41 C still air against a human-approved 55 C junction-based budget.
skills/aiflow-scaffold-probe/SKILL.mdadded+100
@@ -0,0 +1,100 @@+---+name: aiflow-scaffold-probe+description: >-+  After an adom-aiflow molecule is finished: place it on a scaffold wired to the Adom Control Panel (adom/control-panel-scaffold V2.1.0 contacts: +PS1 MC1-MC4, -PS1 MC20-MC22, GND MC15/MC16/MC55-MC63, USER_IO MC29-MC54 with MC29-MC32 ADC-capable), write the Hydrogen 3D Editor v2 layout JSON (molecules with sku, name, FL-pin position, rotation, pinType, pins; 24 AWG wires from molecule contacts to control-panel contacts), and write a probe plan with test points in the molecule frame and the expected values from simulation. Trigger words: aiflow scaffold, place on scaffold, control panel wiring, workcell layout, probing workcell, Hydrogen 3D editor layout, editorVersion v2, layout json, wire to control panel, controlPanelContactName, probe plan, test points, bench check, live probing.+---++# aiflow-scaffold-probe: the molecule in its workcell++The board is not done for the human until it can be powered, driven and probed. This step places the molecule on a scaffold, wires every contact to the Control Panel, and writes down what to probe and what the numbers should be. It is a deliverable in requirements.json, not an afterthought.++## 1. Map each contact to the Control Panel++The Control Panel Scaffold (adom/control-panel-scaffold, V2.1.0) contacts that matter:++| Group | Contacts | Use |+|---|---|---|+| +PS1 | MC1 to MC4 | programmable supply output: the molecule's input rail (the PCB names the net `+PS1_SENS`: it is the rail after the current sense, not a sense-only line) |+| -PS1 | MC20 to MC22 | that supply's return |+| GND | MC15, MC16, MC55 to MC63 | panel ground: the reference for GPIO and ADC |+| USER_IO | MC29 to MC54 | GPIO; MC29 to MC32 are ADC-capable |++Rules:++- Power input to +PS1, its return to -PS1. On V2.1.0, jumper JP1 bonds -PS1 to GND once (bridged by default), so a molecule whose input return and signal ground are the same net is fine; if the user has opened JP1 to float PS1, the molecule becomes the tie point, so ask before wiring both.+- Every molecule that talks to GPIO or ADC gets its own wire to panel GND.+- Monitor outputs go to MC29 to MC32 and must be inside the ADC range (scale on the molecule, aiflow-molecule).+- Enable and control pins go to plain USER_IO; say the drive mode (open-drain low to disable, never above the pin's maximum).+- Current per wire: 24 AWG is fine at the 1 A level; parallel a second contact when the rail's current is higher or the drop matters.+- **Map by position, not by label.** Older layouts carry older panel labels; one audit found wires two contacts away from where their labels said. Check each MC name against the V2.1.0 PCB's contact positions before writing it.++Write the mapping as a table in the layout's README: molecule contact, net, panel contact, panel group, why.++## 2. The Hydrogen 3D Editor v2 layout JSON++Start from a known-good layout of the same editor version (a published workcell layout on the wiki) and change only what you must. Shape:++```json+{+  "editorVersion": "v2",+  "molecules": {+    "Buck 12V-5V Molecule": {+      "sku": "<owner>/Buck 12V-5V Molecule/v1",+      "name": "Buck 12V-5V Molecule",+      "position": {"x": 48, "y": 304, "z": 0},+      "rotation": {"z": 0},+      "scale": {"x": 1000, "y": 1000, "z": 1000},+      "pins": {"FL": {}, "FR": {}, "BL": {}, "BR": {}},+      "pinType": 5.6+    }+  },+  "wires": [+    {"name": "VIN", "gauge": "24 AWG",+     "startReference": {"moleculeName": "Buck 12V-5V Molecule", "contactName": "J1",+                        "contactPosition": {"x": 0, "y": 12, "z": 2.8}},+     "endReference": {"controlPanelContactName": "MC2"}}+  ]+}+```++- `sku` is the published molecule's wiki identity (molecule-publish comes first).+- `position` is the layout coordinate of the molecule's FL pin (MP1), in mm; `rotation.z` in degrees. Large-pin molecules and scaffolds sit on the base scaffold's grid (16 + 32 n). A medium-pin molecule needs a LrgMed user scaffold (adom/scaffold-lrgmed-<W>x<H>: large pins at the corners on the 32 mm base grid, medium contacts on a 4 mm grid): put the scaffold's FL large pin on the base grid and the molecule's FL pin on the scaffold's 4 mm grid, so the molecule's pin span must be a multiple of 4 mm. Each stacked level adds about 8.4 mm of z in the reference layouts; the editor snaps it when the layout opens.+- `pins` and `pinType`: copy what the molecule's import gives for its pin size; do not invent values.+- `contactPosition` is molecule-local (mm from MP1; z is the footprint JSON's `contact_z`, 2.8 mm for medium contacts). `contactName` matches the board's reference.+- Check the layout against the geometry before handing it over: a three.js page that loads the base grid, the scaffold GLB, the molecule GLB and the control panel GLB (Draco, so load it with DRACOLoader) at the layout's positions, with the wires drawn to each panel contact's position from the panel's `.kicad_pcb`. Land the wire ends on the panel board's top face (find the flat mesh about 160 x 45 mm; the panel's own bounding box includes the dock connector and parts below the board, so neither its centre nor its minimum z is the board). Render it headless (puppeteer-core with Chromium) and look at a close view of the contact row.+- Routing fields (`routingType`, `manualBendPoints`, `segments`, `color`, `diameter`) are what the editor writes when it routes; let it, then read the file back.++Validate before handing over: every `moleculeName` exists in `molecules`, every `contactName` exists on that molecule's footprint JSON, every `controlPanelContactName` is a real V2.1.0 contact in the right group, and no panel contact is used twice by different nets. Open it in the Hydrogen 3D editor and look.++## 3. The probe plan++Write `probe/plan.json` and a readable table in the README. Each test point in the molecule frame (mm from MP1, y up) and, once placed, in scaffold coordinates (add the FL-pin position and apply the rotation):++```json+{"frame": "molecule, mm from MP1 centre, y up",+ "points": [+  {"ref": "TP1", "net": "SW",   "x": 15.6, "y": 4.9, "measure": "switch node, 500 kHz, 0 to VIN", "ground": "TP4"},+  {"ref": "TP3", "net": "VOUT", "x": 21.6, "y": 4.9, "measure": "ripple, short ground spring to TP4", "expect": "about 3 mV pp at 12 V"}+ ]}+```++Each test gets: the setup (PS1 voltage and current limit, load, what GPIO does), the probe points, the expected value with its source (calcs.json, the ngspice result, the vendor model) and the pass band. Include the checks the design left open for the bench (the load step the model disagreed on, the UVLO thresholds). Probe ripple with the shortest ground you can; a long ground lead measures itself.++## 4. Hand off++The layout JSON, the contact mapping table, the probe plan, and a line in the run page's deliverables. If the human wants it live, the layout opens in Hydrogen and the probe plan drives the workcell.++## Worked example: TPS54202 molecule++| Contact | Net | Panel | Why |+|---|---|---|---|+| J1 (0,12) | VIN | MC2 (+PS1) | 12 V input, about 0.6 A worst case at 9 V |+| J2 (0,8) | GND | MC20 (-PS1) | input return beside the input |+| J3 (0,4) | EN | MC33 (USER_IO25) | open-drain low disables; released = the UVLO divider decides |+| J4 (24,12) | VOUT | load | bench electronic load for the 0 to 1 A step |+| J5 (24,8) | GND | MC15 (GND) | reference for ADC and GPIO |+| J6 (24,4) | VMON | MC29 (USER_IO29, ADC3) | VOUT/2, about 2.5 V |++J2 and J5 are the same net on the molecule, so this plan also joins -PS1 and panel GND through the board; with JP1 bridged (the default) they are already common, so nothing changes. The molecule sits on a LrgMed 64 x 64 scaffold (FL large pin at 240, 464; molecule FL pin at 260, 488, centred on the scaffold's 4 mm grid). Layout, preview and probe plan: the john/buck-12v5v-molecule page, `scaffold/`.++Probe points: TP1 SW (15.6, 4.9), TP2 FB (9.4, 5.6), TP3 VOUT (21.6, 4.9), TP4 GND (15.6, 2.8). Expected: VOUT 4.98 V (4.86 to 5.11 V over the reference tolerance), about 3 mV ripple at 12 V, UVLO start 8.6 V and stop 6.9 V, and a 0 to 1 A step of about 180 mV (the vendor model's figure; the fitted model said less), settling in about 0.2 ms.
skills/aiflow-schematic-to-board/SKILL.mdadded+116
@@ -0,0 +1,116 @@+---+name: aiflow-schematic-to-board+description: >-+  The bridge from a finished design to an adom-aiflow board: one netlist.json as the single source, generate the KiCad schematic (.kicad_sch with embedded, flattened library symbols, pin stubs, net labels, PWR_FLAG) and the board (.kicad_pcb built with KiCad's own pcbnew Python, molecule interface fixed, parts staged beside the outline), prove them equal with ERC and a pin-by-pin netlist comparison, then `adom-aiflow start`. Covers the KiCad 10 traps (GetFieldByName removed, 3D model paths that do not persist, the single IPC socket owned by the first KiCad process, footprint field edits refused over IPC), project library tables, and running KiCad 10's kicad-cli from a container. Trigger words: aiflow schematic, schematic to board, netlist to pcb, generate kicad_sch, generate kicad_pcb, update pcb from schematic, pcbnew python, KiCad 10 python, ERC, netlist equivalence, sym-lib-table, fp-lib-table, kicad-cli remote, ADOM_AIFLOW_KICAD_CLI, board_mismatch.+---++# aiflow-schematic-to-board: one netlist, two files, proven equal++The KiCad Bridge has no "update PCB from schematic" verb. So do not draw a schematic and hope the board matches: write the connectivity once, generate both files from it, and prove they agree before the run starts.++## 1. netlist.json is the single source++```json+{+  "design": "buck-12v5v-molecule",+  "components": [+    {"ref": "U1", "sym": "Regulator_Switching:TPS54202DDC", "value": "TPS54202DDCR",+     "fp": "Package_TO_SOT_SMD:TSOT-23-6", "mpn": "TPS54202DDCR", "mfr": "Texas Instruments",+     "src": "Mouser 595-TPS54202DDCR", "block": "core"},+    {"ref": "MP1", "sym": "Molecule:MachinePin", "fp": "Molecule:MachinePinMediumShort",+     "block": "molecule", "fixed": {"x": 0, "y": 0}}+  ],+  "nets": {"VIN": ["U1.3", "C1.1", "C2.1", "J1.1"], "GND": ["U1.1", "MP1.1"]},+  "molecule": {"pin": "MachinePinMediumShort", "grid_mm": 2, "pin_span_mm": [24, 16],+               "board_mm": [28, 20], "edge_margin_mm": 2, "origin": "centre of MP1 (FL) pin",+               "corner_pins_net": "GND"}+}+```++- `mpn`, `mfr`, `src` come from the BOM (aiflow-sourcing) and become fields.+- `block` groups the schematic sheet (input, core, output, feedback, enable, indicator, monitor, molecule, probe).+- `fixed` is the molecule interface in mm from the MP1 centre, y up (aiflow-molecule). Those parts are placed and locked; everything else is staged.+- Pins are `REF.pad`. Before generating, check that every key exists as a symbol pin number AND a footprint pad number.++## 2. The schematic: gen_schematic.py++Write the `.kicad_sch` directly as s-expressions (a small reader/writer, `sexp.py`, is enough).++- **Embed the symbols** in `lib_symbols`. A symbol that `extends` another must be flattened (copy the base body, merge the child's properties, rename the unit sub-symbols); KiCad will not resolve `extends` inside a schematic.+- **Pin stubs and labels.** Every connected pin gets a short wire stub and a net label at its end; no hand-drawn wires between parts. The schematic's netlist then equals netlist.json by construction.+- **PWR_FLAG** on each rail that arrives from off-board (VIN, GND), or ERC reports "power input not driven".+- Deterministic UUIDs (`uuid5` of design + ref + pin), 1.27 mm grid snapping, and a design note read from calcs.json.++## 3. The board: build_board.py with KiCad's own Python++Run with the Python that ships with KiCad on the desktop, not the container's:++```+"C:\Users\<user>\AppData\Local\Programs\KiCad\10.0\bin\python.exe" build_board.py+```++It creates the nets, loads each footprint (`pcbnew.FootprintLoad(dir, name)`, project `lib/<lib>.pretty` before KiCad's), sets reference, value and fields, assigns every pad's net, places and locks the `fixed` parts (KiCad is y down: `KiCad = (X0 + x, Y0 - y)`), stages the rest in a row beside the outline, draws the outline, sets the aux and grid origin on MP1, copies the fab-profile `.kicad_dru`, saves, and writes `build_board.json` (placed parts, net count, warnings). A pad with no net is a warning: read them all.++### KiCad 10 traps++- `GetFieldByName` is gone. `fp.SetField(name, value)` to set; iterate `fp.GetFields()` and match `f.GetName()` to hide or restyle.+- Model paths changed through `fp.Models()` (`m.m_Filename = ...`) did not persist in the saved board. Rewrite the `(model ...)` entries in the saved file instead (`kicad/tools/set_models.py`: path, offset, and the -90 degree X rotation for Y-up models).+- The netclass API moves between versions: wrap it in try/except and let the `.kicad_dru` carry the limits.+- **One IPC socket.** KiCad's IPC API server belongs to the first KiCad process that opened it. A second editor (another board, another user's session) answers IPC for the wrong board or not at all; `capture open` reports `board_mismatch`. Save and close only your own conflicting editors, reopen the intended board first, and never close someone else's work.+- **Footprint fields are refused over IPC** in 10.0.5 (`native_field_update_unsupported`): references, values and their text size or position cannot be edited live. Do them in build_board.py, or offline: close the clean editor, edit the saved board, reopen, then refresh both 2D and 3D views.++## 4. Project library tables++Local libraries (the Adom molecule footprints, project footprints and symbols) need `sym-lib-table` and `fp-lib-table` beside the `.kicad_pro`, with `${KIPRJMOD}` paths:++```+(fp_lib_table+  (version 7)+  (lib (name "Molecule")(type "KiCad")(uri "${KIPRJMOD}/lib/Molecule.pretty")(options "")(descr "Adom machine pins and contacts"))+)+```++Write them BEFORE ERC, or every molecule part is a library warning. 3D models go in `${KIPRJMOD}/3d/` so the project travels (molecule-publish needs them bundled).++## 5. kicad-cli from the container++The container's `/usr/bin/kicad-cli` may be distro KiCad 7 (no `pcb drc`, cannot read a KiCad 10 file), and another session can install it under you. Check the board's file version against the CLI:++```bash+kicad-cli --version; head -2 kicad/<design>.kicad_pcb+export ADOM_AIFLOW_KICAD_CLI=adom-aiflow-kicad-cli-remote   # ships with adom-aiflow 0.1.33++export KICAD_REMOTE_TARGET=<desktop>+```++The remote wrapper ships the board with its `.kicad_pro` and `.kicad_dru` to the desktop's KiCad 10 through Adom Bridge, runs `kicad-cli pcb drc`, and pulls the JSON back. For ERC and netlist export, `send_files` the schematic, its lib tables and `lib/` to the desktop and run the same kicad-cli there with `shell_execute` (reason inside the JSON args; after a timeout check the process list before re-sending).++Pushing a footprint library: `send_files` to a destination ending in `.pretty` wrote a FILE named `x.pretty`. Send to a plain folder, then `move` it into place.++## 6. Verify: ERC and netlist equivalence++```bash+kicad-cli sch erc --format json --severity-all --output erc.json <design>.kicad_sch+kicad-cli sch export netlist --output sch.net <design>.kicad_sch+```++- **ERC: 0 violations**, warnings included. Library warnings mean the tables were missing when ERC ran; save the clean report, not the first one.+- **Netlist equivalence**: every `REF.pad` in the same net on both sides (`sch.net` vs the board's pad nets), same net names, nothing extra or missing. Report it as a count (58/58 pins) and list any mismatch. This is a gate: no `start` until it passes.++## 7. Hand off++Write `aiflow/spec.json` from the schematic (wide nets, Kelvin pairs, loads, hot parts, pours; aiflow-power-layout), then start with the prompt time from requirements.json:++```bash+adom-aiflow --ai-thread "<thread>" start --board kicad/<design>.kicad_pcb --spec aiflow/spec.json \+  --engine <you> --prompt-time <prompt.utc> --target <desktop> --remote-board <path on the desktop>+adom-aiflow --ai-thread "<thread>" plan+```++Then `step components` / `components`, `models`, and placement.++## Worked example: TPS54202 molecule, KiCad 10.0.5++- netlist.json: 34 components, 10 nets, 58 connected pins; schematic and board matched 58/58.+- The first saved ERC report held 21 library-configuration warnings because the lib tables were written 22 seconds after it. Tables first, then ERC.+- `set_models.py` rewrote the model entries in the saved board, including -90 X for the three Y-up models.+- A distro KiCad 7 kicad-cli, installed mid-run by another session, broke the gate with a usage error; the remote kicad-cli fixed it.
skills/aiflow-simulate/SKILL.mdadded+80
@@ -0,0 +1,80 @@+---+name: aiflow-simulate+description: >-+  The simulation step of an adom-aiflow run, after the calcs and before the schematic is frozen: ngspice in the container with two models (an averaged loop-gain model and a cycle-by-cycle XSPICE switching transient), honest labelling of any fitted model, the ngspice syntax traps, then the vendor model (TI PSpice packages are often Cadence-encrypted even when called "unencrypted", so they run only in PSpice for TI on a Windows desktop through Adom Bridge), a vendor-vs-own comparison table and a written design conclusion. Publish results freely; never publish LTspice or PSpice speed benchmarks. Trigger words: aiflow simulate, simulate the buck, ngspice, loop gain, phase margin, crossover, Middlebrook, switching transient, load step, ripple, startup, XSPICE, d_srlatch, PSpice, PSpice for TI, vendor model, encrypted model, CDNENCSTART, validate my model.+---++# aiflow-simulate: two models of your own, then the vendor's++The calcs say what the values should do; simulation checks it where the equations are thin (loop dynamics, startup, load steps). Run your own models first, because they are fast and always available; run the vendor model to find what yours cannot see. The companion skillpack for engines and licensing is adom-spice-skillpack (ngspice, LTspice, PSpice for TI, vendor models).++## 1. ngspice: two models, one job each++Install it when missing (`apt-get install -y ngspice`). Each model is a script under `sim/` that reads `design/calcs.json` and writes a results JSON plus a PNG.++| Model | Script | Answers | Why this model |+|---|---|---|---|+| Averaged small-signal | `sim/loop.py` | crossover, phase margin, per candidate value, across input and load | AC analysis needs a linear model; a switching model gives no Bode plot |+| Cycle-by-cycle switching | `sim/transient.py` | startup, overshoot, output ripple, inductor ripple, load-step deviation and settling | ripple and current limit exist only when the switch switches |++**Loop gain.** Break the loop with a Middlebrook injection between the output and the divider (`Vx vout vfbtop DC 0 AC 1`) and compute T from the two sides. Sweep every candidate you are choosing between (feed-forward 0, 47, 68, 100 pF) at minimum, nominal and maximum input and at full and half load; write every row to `loop.json`.++**Switching.** A clock sets an SR latch; the latch resets when sensed current plus slope ramp reaches the error-amplifier output, or when the inductor current hits the current limit. FETs are switches with the datasheet on-resistance. Run it at minimum, nominal and maximum input (`VIN=9 python3 sim/transient.py`).++**Cross-check against the calcs.** Inductor ripple and output ripple must agree with calcs.json within a few percent (0.40 A simulated vs 0.389 A calculated here). If they disagree, one is wrong; find it before going on.++## 2. ngspice traps (each cost time here)++- B-source logic is `||` and `&&`, not `or` / `and`: `Brst rst 0 V = ((i(Vsense)*{RI} + v(ramp) >= v(vc)) || (i(Vsense) >= 2.5)) ? 1 : 0`.+- XSPICE `d_srlatch` has enable plus asynchronous set and reset inputs: pass `NULL` for the async pair and drive enable from a `d_pullup`: `alatch dset drst den NULL NULL dq dqb latch`.+- `wrdata` writes phase in radians. Convert before you compute a margin.+- System matplotlib breaks when a user-site numpy 2 is present: run the scripts with `PYTHONNOUSERSITE=1`.+- What converged for the switching run: `.option method=gear reltol=1e-3` and `.tran 10n <tstop> 0 10n uic`.++## 3. Label a fitted model honestly++When the vendor does not publish an internal block (internal compensation, current-sense gain), you build an equivalent. Say so in the script header, in the results JSON (`"calibration": "eq 14, no Cff"`), and in the plot title: what was fitted, to which datasheet equation, under which conditions, and what the equivalent cannot see. A fitted model compares candidates and shows trends; it does not prove a margin the datasheet does not promise.++## 4. When the model and a datasheet limit disagree, obey the limit++The model may favour a value the datasheet rules out for a reason the model cannot see. Choose the value inside the limit, write why, and plan a bench check (for example a load step on the probing workcell, aiflow-scaffold-probe).++## 5. The vendor model++If the brief asks for it, or the vendor publishes a transient model, plan it at intake: access takes time.++- **Check for encryption before you plan.** `grep -l '\$CDNENCSTART' *.lib`. TI's "Unencrypted PSpice Transient Model Package" for the TPS54202 was Cadence-encrypted: it runs only in PSpice (not ngspice, not LTspice). Never try to decrypt a model.+- **Access.** PSpice for TI needs a myTI account and export approval (minutes to 48 hours). Get the account through aiflow-credentials; never ask for a password. Carry the design on the ngspice results meanwhile.+- **Where it runs.** On a Windows desktop through Adom Bridge (send the netlist, run, pull the output back). The adom-spice-skillpack's PSpice-for-TI sub-skill covers the install, the missing batch runner, the trace limit with third-party models and reading CSDF output.+- **Same test, same metrics.** Use the same external parts, load steps and measurement windows as your transient script; copy the metric code, do not rewrite it.+- **Plan for long runs.** Vendor transient models are far slower than a behavioural model; start them early and keep working.++## 6. Compare, then conclude++One table, same metrics, both models, in `sim/<vendor>-validation.md`:++| metric | own ngspice | vendor model |+|---|---|---|+| inductor ripple pp (A) | 0.400 | 0.405 |+| startup peak inductor current (A) | 1.723 | 1.722 |+| time to 95 % (ms) | 4.76 | 4.84 |+| 0.5 A step, deviation (mV) | 77 to 78 | 89 to 91 |++Then write the design conclusion in engineering terms: what matched, what the vendor model saw that yours did not, whether any value changes, and what the bench check must confirm. A conclusion that changes nothing still says why.++## 7. What may be published++- Simulation results (waveforms, margins, ripple, the comparison of your model against the vendor's) are public.+- Never publish LTspice or PSpice solve times or tool-vs-tool speed numbers (their licences restrict benchmarks). Say it generically ("the encrypted vendor model is much slower than the behavioural one"). ngspice timings are fine.+- Public pages use ngspice-generated plots.++## 8. Hand off++`sim/loop.json`, `sim/transient_*.json`, the PNGs, the validation note with the conclusion, and any value changes pushed back into calcs.py. Next: aiflow-schematic-to-board.++## Worked example: TPS54202 (2026-09-29)++- The loop model's gm stage was calibrated so that with no feed-forward cap the crossover equals the datasheet's eq 14 (21.8 kHz); the model gave 21.4 kHz.+- Eq 16 gave 99.4 pF, and 100 pF had the best phase margin in the model, but it pushed crossover to about 57 kHz, past the datasheet's 40 kHz limit that the equivalent cannot see. 68 pF was chosen: about 29 kHz, about 110 degrees at 12 V, 1 A.+- The switching model: output ripple 3.2 mV at 12 V, 4.0 mV at 16 V; 95 % of VOUT at 4.76 ms (5 ms soft start).+- TI's model confirmed startup, ripple and inductor current and showed about 15 % more load-step deviation. Conclusion: with internal compensation fo x COUT is constant, so the step deviation (about 180 mV, 3.6 %, for a full 1 A step) does not shrink with more COUT; only a larger Cff would help, and the 40 kHz limit rules that out. COUT unchanged; confirm with a 0 to 1 A step on the workcell.
skills/aiflow-sourcing/SKILL.mdadded+99
@@ -0,0 +1,99 @@+---+name: aiflow-sourcing+description: >-+  Parts and CAD sourcing for an adom-aiflow board, before the schematic is frozen: the fab profile picks where parts come from (default "in-house" = our own in-house PCB fab, Mouser plus Adom stocked basic parts, no JLCPCB parts; user-selectable "jlcpcb" = JLCPCB/LCSC basic parts), search by spec and in stock before naming an MPN, constrain passives to the stocked set, record stock and lead time with a date, then get each part's symbol, footprint and STEP in a fixed order (manufacturer site, distributor CAD links, Adom wiki component page, draw your own labelled AI-generated) and check every model on the step2glb service. Never adom-chipsmith. Trigger words: aiflow sourcing, source the BOM, pick parts, in stock, lead time, sourcing profile, fab profile, Mouser or JLCPCB, Adom basic parts, stocked values, find the STEP, 3D model for this part, manufacturer CAD, SamacSys, Ultra Librarian, footprint source, symbol source.+---++# aiflow-sourcing: parts that exist, CAD that is true++A part that is not in stock is not a design choice, and a model with the wrong size or axis is not evidence. This skill covers which parts, and where their CAD comes from.++## 1. The fab profile picks the parts++Read `fab.target` from requirements.json (aiflow-intake) and set `sourcing.profile`. Do not wait for the human to say it.++| Profile | When | Parts come from | Never |+|---|---|---|---|+| `inhouse` (default) | Our own in-house PCB fab | Adom stocked basic parts (the pick-and-place reels) first, then Mouser | JLCPCB/LCSC-only parts |+| `jlcpcb` (user choice) | The human picks a JLCPCB build | JLCPCB/LCSC basic parts first, extended only with a reason | parts JLCPCB cannot place |++Switching profile redoes this whole pass; never mix profiles in one BOM. A thin-stock IC on the in-house profile is a note and an early order, not a reason to switch to JLCPCB parts.++## 2. Passives: the stocked set first++On `inhouse`, every R, C, LED and small magnetic that Adom stocks comes from the reels. The math bends to the stock, not the other way round (aiflow-circuit-design searches the combinations).++```bash+pnp-inventory lookup "10k 0402"                          # match to a stocked MPN+pnp-inventory parts get CR0402-FX-1002GLF --pretty       # one part, qty on hand+pnp-inventory bulk-check --bom design/bom.csv --field summary+```++The adom-basic-parts skill lists the set (41 resistor values in 0402, MLCCs by dielectric and package). When a value is not stocked, prefer a series or parallel pair of stocked parts over a non-stocked one. On `jlcpcb`, the same rule applies to JLCPCB basic parts.++## 3. Everything else: search by spec, in stock, before naming an MPN++Remembered part numbers go out of stock. Search by the spec words first; write an MPN only after.++```bash+adom-parts-search search "15uH shielded power inductor 3A" --in-stock-only | tee design/ps_15uH_shielded.txt+adom-parts-search search "10uF 25V 1206 X7R" --in-stock-only+adom-parts-search show "TPS54202DDCR"      # the human sees photos and columns+```++- One search per question. Vendor quota is shared: never loop, poll or retry.+- A `substitution` in the answer is a different part. Relay it; never design it in silently.+- Keep each search's output in `design/ps_<query>.txt`; it is the evidence for the stock column.++Record stock and lead time with the date in the BOM:++```csv+ref,value,function,mpn,manufacturer,package,source,vendor_pn,stock_checked_2026-09-29,note+U1,TPS54202DDCR,sync buck,TPS54202DDCR,Texas Instruments,SOT-23-6 (DDC),Mouser,595-TPS54202DDCR,160 (lead 140 d),thin stock; order early+```++Every reference in the netlist must have a BOM row, including contacts, machine pins and test pads (as "no part" rows). Diff the two before the schematic is frozen.++## 4. Never write a package dimension without its source++Case sizes, heights and pad spans come from the manufacturer's page or drawing, quoted with where you read them, and nominal separated from maximum. Not from memory, not from a similar part.++## 5. CAD: symbol, footprint and STEP, in this order++Every footprint needs its model (`adom-aiflow models` refuses otherwise). Take the first source that exists, and keep going down the list per file (a part may have a manufacturer STEP but no footprint).++1. **The manufacturer's own site.** Symbol, footprint and STEP. Search by the **series** as well as the full MPN: ordering codes often do not match CAD file names, and many families publish one STEP per case size, not per value.+2. **Distributor CAD links.** Mouser and DigiKey part pages link SamacSys (Component Search Engine) and Ultra Librarian downloads. Treat them as reference CAD: check them like any other, and do not republish them on a global wiki page without permission.+3. **The Adom wiki component page.** `adom-wiki page get component/<mpn-lowercase>`. Read its provenance: a file recorded as manufacturer-supplied is the manufacturer's file and can be reused as such.+4. **Only then, draw your own.** Label it AI-generated in the file name and a provenance JSON beside it: datasheet URL, revision, page, figure, retrieval date, PDF sha256, every dimension with its tolerance, simplifications, the generator script, and which OCCT path made it. Create and check the geometry on the shared step2glb OCCT service; install OCCT locally only when `step2glb health` says the service is unreachable, and record that in the provenance.++**Never use adom-chipsmith**, including the step2glb service's `/create-chip` and `/bake` endpoints, which are chipsmith underneath (their solids come out named `chipsmith_body`, `chipsmith_pin1`). If no permitted service verb can build a body, say so in the provenance and file it as a gap on adom/adom-aiflow rather than reaching for chipsmith.++Vendor sites answer curl with 403 or time out. That is a routing signal: after ONE failure switch to pup (`pup_open_window`, drive the page, download), and to nb (the user's real Chrome, `nbrowser_*`) when pup is blocked or a login is needed (aiflow-credentials). Never report "the site is timing out" while those lanes sit idle. The electronics-sites skillpack has a skill per vendor.++## 6. Check every model++Run the service checks on every model, including manufacturer and wiki ones:++```bash+step2glb health+step2glb features part.step        # bbox, floor_z, longest axis, pin1+step2glb thumbnail part.step       # look at it+```++- The bbox must match the drawing's body and the footprint.+- Height on Z. When the height sits on Y (Y-up), the footprint's model binding needs a -90 degree X rotation.+- Then look in KiCad's native 3D viewer. A rotation is not done until the part sits on its pads there.++## 7. Hand off++`design/bom.csv` with the stock column, `design/ps_*.txt`, the CAD files with their provenance, and a short note to the human listing thin-stock parts. Next: aiflow-circuit-design.++## Worked example: TPS54202 molecule (stock checked 2026-09-29)++- Remembered first picks had zero Mouser stock: Coilcraft XAL5050-153MEC (280-day lead) and Murata GRM31CR71E106KA12L (182-day lead). The spec search found Abracon AMPLH5030S-150MT (1577 in stock) and Yageo CC1206KKX7R8BB106 (18168) at once.+- TPS54202DDCR: Mouser 160, 140-day lead; DigiKey 0; JLCPCB about 180k. On the in-house profile that is a thin-stock note, not a profile switch.+- The 41-value resistor set had no single feedback-top value; calcs.py chose 68k + 5.6k in series.+- The inductor was first drawn from the datasheet with a local OCCT install before looking properly; Abracon's official STEP turned up only when searching the series `AMPLH5030S`. Panasonic publishes electrolytic STEPs by case (`DS_Alumi_D_5.zip`), and that search caught a case size written into the BOM from memory (the page says 6.3 x 5.8 mm, case D). Search first, draw last.+- Three models were Y-up and needed -90 X: Abracon AMPLH5030S, Panasonic case D, and the wiki's Samsung CL21A226MPQNNNE 0805. `step2glb features` showed it.+- `design/bom.csv` ended the run without rows for R7/R8 (the VMON divider), the contacts and the test pads: exactly what the netlist diff in section 3 catches.