---
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 page** — `type: 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 page** — `type: 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:

```bash
# 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.
