name: publish-board description: Publish or update a KiCad project to the Adom wiki so it renders in the Adom Project Manager — 3D board, hierarchical schematic, PCB — backed by a component library. Triggers include "upload my kicad project to the wiki", "publish my board", "push my kicad project so I can view it in the project manager", "update my board on the wiki". user-invocable: true

Publish a KiCad board to the wiki

Turn a local KiCad project into a wiki board page that renders in the Adom Project Manager (rotatable 3D board with real components, hierarchical schematic, KiCad-colored PCB), backed by a component library.

Data model: board → library → components

  • Board pagetype: component, category: board, tags ["board", …] (or molecule). Ships the render files: .kicad_pro, .kicad_pcb, EVERY .kicad_sch (root + sub-sheets), and a <Board>.3dshapes/ of custom 3D models. Its single dependency is the library.
  • Library pagetype: component, tag ["library"], title "<Board Name> Library", slug <board-slug>-library. dependencies = every component on the board. Ships the board's .kicad_sym + .pretty.
  • Component pages — the existing per-component pages, keyed by MPN: slug = the normalized MPN, title leads with the MPN. Never publish or depend on a component keyed by its value/properties (e.g. slug cap-2u2-0402-6v3, title "2.2uF 0402") — value names collide (many parts are "2.2uF 0402"), don't resolve MPN→slug, and break dedup + the dependency graph. If a board references a value-named component page, re-slug it to the MPN (or point the dep at the real MPN page) rather than depending on the value-named one.

The Manager reads the board's one dependency (the library), then lists the library's dependencies (the components). board_deps expands any dependency that itself has dependencies, so this resolves automatically.

Workflow

1. Pull the project (from the user's machine via adom-desktop)

Ask for / find the .kicad_pro. Pull the project folder (or at least): .kicad_pro, .kicad_pcb, every .kicad_sch, .kicad_sym, .pretty/. Use adom-desktop shell_execute (find the files) + pull_file.

2. Analyze it

Run the helper on the pulled folder:

python3 skills/publish-board/kicad_board_bundle.py <project-dir>

It reports the render files, board_name, the 3D model refs (models_std vs models_custom), and the components (ref, value, mpn, slug).

3. Bundle the custom 3D models + normalize the refs

models_std (${KICAD*_3DMODEL_DIR}/…) resolve on the render service — leave them. For each models_custom ref, pull the .step/.wrl from the user's machine into <Board>.3dshapes/<basename>. Then normalize the PCB's model refs to project-relative paths so the published source is portable:

python3 skills/publish-board/kicad_board_bundle.py <project-dir> --normalize

This rewrites every custom (model "…") ref to <Board>.3dshapes/<basename> (forward slashes; KiCad resolves them next to the .kicad_pcb, and the Manager's GLB render bundles them by basename), leaving ${KICAD*_3DMODEL_DIR} refs and every offset/scale/rotate untouched.

NEVER publish a .kicad_pcb with machine-specific ABSOLUTE model paths (/home/<user>/…, C:\Users\<user>\…). They resolve nowhere on the render service or on anyone else's machine (and not even on the author's, if they wrote them for a different OS). Run --normalize and confirm grep -E '\(model "(/|[A-Za-z]:\\\\)' <pcb> is empty before pushing.

4. Map components → wiki slugs (MPN → slug)

Slug = MPN lowercased, non-alphanumeric → -. The helper falls back to the schematic Value when no MPN property exists — verify the slugs actually match real wiki component pages (GET /api/v1/pages/<slug>), because value-named symbols (R_4.3K_0402) are NOT wiki component slugs. Resolve the real MPN per part (BOM, the symbol's MPN/LCSC field, or ask the user). Warn + list any that aren't on the wiki — they won't appear in the component list until published.

5. Ensure each component renders in the Manager — REQUIRED (adom-lbr JSON)

The Manager renders a component's symbol + footprint + per-EDA layer stackup from the canonical adom-lbr JSON on its page (<MPN>.adom-lbr.json). It falls back to a lossy on-the-fly KiCad import ONLY if that file is absent — and renders nothing for a component page that has only a footprint, only a symbol, or non-KiCad sources. So every component on the board must carry a <MPN>.adom-lbr.json on its wiki page; generate + push it wherever it's missing:

# fetch the component's KiCad files from its page, then convert:
adom-lbr import-kicad --sym <MPN>.kicad_sym --fp <MPN>.kicad_mod --mpn <MPN>   # → <MPN>.adom-lbr.json
adom-wiki repo push <owner>/<slug> --files <MPN>.adom-lbr.json -m "add adom-lbr JSON for the Project Manager"

adom-lbr is the adom/adom-lbr EDA translator; the adom-lbr JSON is its canonical hub (it can also import from Altium .SchLib/.PcbLib/.IntLib). Verify in the Manager that the component's source reads "adom-lbr json", not "kicad (generated)".

Interim step: this conversion is moving into adom/molecule-publish (see its issue #7) so the pipeline delivers the JSON automatically; do it here until then.

6. Library page — create or update, and VERIFY completeness

  • Slug <board-slug>-library, title "<Board Name> Library", type: component, tags ["library"], dependencies = the owner-qualified component slugs.
  • On every update, ensure every component on the board is present in the library's dependencies; add any missing ones.
  • Ship .kicad_sym + .pretty.
  • Publish needs a hero (generate a simple 1200×630 billboard) + a 3D file for the component type (reuse any component .step): adom-wiki pkg publish [--org <org>] --skip-lint, then repo push the package.json + .kicad_sym + .pretty.

7. Board page — create or update

  • type: component, category: board, tags ["board", …], dependencies = { "<owner>/<board-slug>-library": "^0.1.0" }.
  • Needs a hero + a 3D file (reuse a component model or a board render).
  • pkg publish (this updates the wiki dependency GRAPH — repo push alone does NOT), then repo push: .kicad_pro, .kicad_pcb, all .kicad_sch, the <Board>.3dshapes/. Set visibility open.

8. Regenerate the stored render assets — REQUIRED on every publish/update

After the board files are published, regenerate the pre-rendered assets so the Manager loads the board instantly (no live render) and the wiki 3D preview is fresh:

adom-project-manager --render-board <board-slug>

This renders the 3D GLB + PCB SVG + per-sheet schematic SVGs and pushes them to the page's render/ folder (with a manifest.json). The Manager serves render/ directly when present and only falls back to live rendering when it's absent. Stale render/ = the board shows its OLD 3D/PCB/schematic after an edit, so never skip this after changing .kicad_pcb/.kicad_sch/models.

9. Verify

Open the Manager; confirm the board appears (Personal/Organization by owner) and its 3D + schematic + PCB render, and the component list matches the board.

Gotchas (learned the hard way)

  • repo push ref: the component namespace is a single shared namespace. Use the bare slug for repo push <slug>; pkg publish needs --org <org> if the slug is owned by an org (a 409 already exists … owned by <org> tells you which).
  • Dependency graph vs file: the Manager reads the package.json FILE (so repo push is enough for it), but the wiki's dependency-graph UI comes from pkg publish — re-publish (bump the version) to update the graph.
  • Hierarchical schematics: upload the .kicad_pro + EVERY .kicad_sch. The Manager renders the whole project so the root's sheet-symbol boxes resolve; a single sheet alone renders wrong.
  • 3D models: bundle every non-${KICAD*_3DMODEL_DIR} (model …) into <Board>.3dshapes/ and normalize the refs to <Board>.3dshapes/<basename> (step 3). Machine-specific absolute paths are the #1 cause of "board renders as a bare PCB / the render service errors" — and they break even on the author's own box if written for a different OS. The Manager bundles by basename so relative, Unix-absolute, and Windows-absolute all render, but only relative paths are portable source, so always normalize before publishing.
  • Every page needs a hero; components additionally need a 3D file — even the library. Generate/reuse one to pass the (hard-enforced) publish lint.