Download

name: molecule-publish description: Publish a molecule OR a generic KiCad/EAGLE board to the Adom wiki - one publisher, two shapes — runs the OCCT molecule-mode conversion (anchored GLB + footprint + symbol with stats gates), assembles the component package, and publishes via adom-wiki. The EDA-agnostic middle of the pipeline; companion to adom-molecule-import (which does wiki → Hydrogen). Use when the user says "publish this molecule to the wiki", "upload molecule bundle", "convert and publish my molecule", "molecule to the wiki", "publish my board" (plain, non-molecule boards use BOARD MODE - no anchoring gates), or an EDA export skill (kicad-export-molecule, fusion-export-molecule, altium-export-molecule) hands off here after exporting. Every publish also emits the render/ assets (including APM's per-version render archive behind the board version selector) and component dependencies adom-project-manager (APM) reads. user-invocable: true argument-hint: " --step <f.step> --board <f.kicad_pcb|f.brd> --sch [--pin medium|large] [--silk-top png --silk-bottom png] [--org adom]"

molecule-publish — source bundle → wiki molecule

The EDA-agnostic middle of the molecule pipeline. Input is the bare-minimum bundle any EDA export produces; output is a published, pipeline-ready wiki component. The Hydrogen half is adom-molecule-import — this skill is its publish-side companion.

EDA export skill        THIS SKILL                     adom-molecule-import
(kicad/fusion/altium) → convert → package → publish  → wiki → Hydrogen

Two shapes: molecule vs board

Molecule (machine pins + MP markers) Board (plain KiCad/EAGLE)
Convert --molecule --board (anchor/gold/footprint, ALL stats gates) plain step2glb convert (no molecule flags, no anchor gates)
Tag molecule board
Footprint/symbol JSON required (wire attach points) not applicable
render/ + deps (APM) yes yes

Decide by the board itself: Adom machine pins + MP1-MP4 markers -> molecule; otherwise board. Both shapes get <slug>.glb from step2glb (never an EDA-native GLB), model_3d_path pointing at it, and the APM stages below.

Contract — inputs vs the published set

The user supplies sources; this skill generates and attaches the rest. The published page always carries the full set — GLB + STEP + schematic + board + metadata — and every downstream tool expects all five (import reuses the GLB, wiring reads the metadata). The GLB and footprint/symbol JSON are never user-supplied: they come out of the OCCT conversion below.

Inputs — the bare-minimum bundle

Required File Notes
yes STEP (.step) exported ON the design machine so all 3D models (machine pins, contacts, MP markers) are baked in
yes Board/layout (.kicad_pcb or .brd) what footprint+symbol generation parses
yes Schematic — .kicad_sch (EVERY sheet: root + sub-sheets) or .sch source completeness + APM's hierarchical schematic view renders from these
board shape .kicad_pro + any .kicad_sym/.pretty used APM render sources
generated GLB OCCT conversion output — never user-supplied, always published
generated Metadata OCCT footprint/symbol JSONs + the authored package.json
optional Silk PNGs (top/bottom) white artwork on transparent
optional Extras .f3d/.usdz/gerbers/BOM/CPL — carry what the EDA produced

Rule: never accept an EDA-native GLB. KiCad, Fusion, and service-kicad can all emit GLBs — those bypass anchoring, gold materials, meter normalization, optimization, and footprint emit. The ONLY GLB in a molecule package comes from the OCCT conversion below.

Stage 1 — Convert (OCCT molecule mode)

step2glb convert <name>.step --board <name>.kicad_pcb --pin medium \
  -o <slug>.glb   # --board implies --molecule; add --silk-top/--silk-bottom PNGs

Requires step2glb >= 0.11.0 (adom-wiki pkg install adom/adom-step2glb). (No adom-wiki on the container? Bootstrap it first: curl -fsSL https://wiki.adom.inc/download/adom/adom-wiki-cli/1.0.2/adom-wiki-cli-v1.0.2 -o ~/.local/bin/adom-wiki && chmod +x ~/.local/bin/adom-wiki — then keep using adom-wiki, not legacy tools.) It posts multipart to /convert?molecule=true&pin=..., polls the job, downloads the GLB and <slug>_footprint.json + <slug>_symbol.json beside it, prints the full stats block, and emits gate hints on failures. Fallback (older CLI): curl -X POST ".../convert?molecule=true&pin=..." -H "X-Client: <agent>" -H "X-Job-Name: <name>" -F "step=@..." -F "board=@...".

Board shape: use a plain convert instead — step2glb convert <name>.step -o <slug>.glb — and SKIP the molecule stats gates below (they do not apply; if the output warns molecule_markers_detected, it IS a molecule — switch).

pin = machine-pin size on the board (medium | large). Poll GET /jobs/{id} until complete, then gate on the stats — never publish a degraded conversion:

Field Must be If not
anchored true MP markers missing/undetected — fix the board, re-export
footprint_applied true board parse failed — read warnings[]
contact_z ≈2.8–8.4 mm wrong pin param or missing contact models
warnings[] empty each entry is a stop-sign, not a footnote

Artifacts: GET /jobs/{id}/result<name>.glb, /jobs/{id}/footprint<name>_footprint.json, /jobs/{id}/symbol<name>_symbol.json.

Stage 2 — Package

<slug>/
  package.json          # see REQUIRED fields below
  <slug>.glb            # OCCT artifact — MUST be named exactly <slug>.glb (see below)
  <name>.kicad_pcb|.brd # board source
  <name>.kicad_sch|.sch # schematic source
  <name>_footprint.json # OCCT artifact — per-pad wire-attach Z
  <name>_symbol.json    # OCCT artifact
  README.md
  [extras: silk PNGs, .f3d, .usdz, gerbers, bom, cpl]

package.json REQUIRED fields (publish 400s or silently under-registers without them):

{
  "slug": "<slug>", "version": "1.0.0", "type": "component",
  "description": "<≥20 chars>", "tags": ["molecule", "..."],
  "component": { "mpn": "<name>", "manufacturer": "", "category": "other" },
  "dependencies": {},
  "hero": { "headline": "...", "subhead": "...", "screenshot": "screenshots/hero.png" }
}
  • The component block is what creates the page's component_metadata row — without it metadata.model_3d_path is never set and imports fail with "no published GLB" even though the file is there.
  • The hero block + screenshots/hero.png are hard-required at publish.

Do NOT include a page.json — the server generates it, and a hand-made one can blank the page brief or override org/visibility on reindex.

Name the GLB exactly <slug>.glb. At publish the wiki auto-converts the STEP to a PLAIN <slug>.glb (no anchoring, no gold) and points model_3d_path at it — if your anchored OCCT GLB has any other name, the plain one shadows it and every import silently gets an unanchored model. (This is exactly what broke the COSMIIC boards.) Matching the name ensures your anchored GLB is the one model_3d_path resolves to.

Stage 2.5 — Component dependencies (BEFORE publish — one version per cycle)

APM lists a board/molecule's components from package.json.dependencies (one-hop expand). Map the design's BOM parts to wiki component slugs and MERGE them into the Stage 2 package.json — before Stage 3's publish, so each publish cycle produces exactly ONE registry version (a deps-only follow-up publish creates an extra version whose renders are identical: harmless under APM's dedup, but noise in the version selector).

  • Mapping helper: skills/publish-board/kicad_board_bundle.py on the adom/adom-project-manager page (adom-wiki repo clone adom/adom-project-manager). Mind its Value-fallback caveat: value-named symbols like R_4.3K_0402 are NOT component slugs — resolve the real MPN.
  • Write owner-qualified refs (adom/<slug>) into dependencies. MERGE, never overwrite — preserve component, hero, tags, model_3d_path.
  • Verify each referenced component page exists; flag missing ones.
  • The dependency graph is a REGISTRY concept — it rides Stage 3's pkg publish, not the repo push.
  • Known behavior to keep in mind: deps are real registry deps, so pkg install <board> will pull the component pages too.

Stage 3 — Publish + verify

adom-wiki pkg publish [--org adom]
adom-wiki repo push <owner>/<slug> --files <every file above> -m "<name> molecule"
adom-wiki page visibility <owner>/<slug> --preset open   # or private

Verify before declaring done:

  • adom-wiki api /api/v1/pages/<slug>metadata.model_3d_path is set
  • the GLB at model_3d_path is byte-identical to YOUR gated conversion output — this is the anchoring proof. (Do NOT inspect the GLB for a molecule_anchor node: the optimizer flattens it away by design — the anchoring survives as baked geometry, not as a node. A gate on that node false-fails every properly converted molecule.)
    curl -fsSL "https://wiki.adom.inc/blob/component/<slug>/<slug>.glb" -o /tmp/check.glb
    sha256sum /tmp/check.glb <slug>.glb   # MUST match — if not, the page is
    # serving a different GLB (e.g. the wiki's plain auto-conversion): re-push
    # your OCCT GLB as <slug>.glb and re-verify.
    
    Your conversion's stats block (molecule_anchored: true, no warnings) plus this checksum equals a verified anchored GLB on the page.
  • the page's Files tab shows the full bundle (registry and git layers are separate — publish alone does not populate Files)
  • the registry tarball is the source of record per version: Stage 2's layout means every publish carries the full board source, and adom-wiki pkg install <owner>/<slug>@<version> delivers any past version's files (APM's version selector relies on this for "give me the source of an older version" — render/ is previews only, never source).

Stage 3.5 — APM render assets + version archive (AFTER publish, every time)

APM shows PCB + hierarchical schematics + the board version selector from a pre-rendered render/ folder; without it, boards trip APM's red "missing render folder" bar and fall back to slow live rendering.

adom-wiki pkg install adom/adom-project-manager   # once per container (needs >= 0.4.1)
adom-project-manager --render-board <slug>        # push-only: writes ONLY render/

Ordering is load-bearing: run this AFTER Stage 3's pkg publish + repo push. --render-board stamps the archive with the version it reads from the PUBLISHED package.json on the page — run it before the publish and it stamps the previous version.

--render-board (APM >= 0.4.0) fully owns the version archive — never write render/<version>/ or edit render/manifest.json yourself (double-writing fights its content dedup). On each run it:

  • renders + pushes the top-level render/* = current version (including render/board.glb whenever a GLB exists);
  • content-hashes the rendered assets and, ONLY if they differ from the last archived version, writes render/<version>/... and prepends a versions[] entry to manifest.json (v2: {v:2, current, versions[]}, newest-first). A deps/metadata-only republish adds NO entry.

Verify after the run:

  • render/manifest.json is on the page, parses, and current == the version you just published;
  • a content-changing publish added a versions[] entry + render/<version>/ files; a metadata-only republish did NOT (dedup working as intended).

Re-run on every content update so it never goes stale. KiCad sources render today; EAGLE/Fusion (.brd/.sch) pages report "nothing rendered" and skip gracefully — APM shows a static version label for them (Fusion rendering is landing in APM; nothing changes on this side when it does).

Stage 4 — Handoff

Import to Hydrogen is adom-molecule-import's job (ships with adom/adom-molecule): authenticated clone + adom-molecule create --glb ... --no-optimize. Do not re-implement it here.

Attach-points caveat: adom-molecule import <slug> (the one-shot verb) currently carries ONLY the GLB — no footprint/symbol reach Hydrogen, so the molecule has no wire attach points. Until that's fixed, register with the board included so Hydrogen generates and attaches the footprint at create: adom-molecule create --owner <o> --name <n> --glb <slug>.glb --pcb <board> --no-optimize (use --brd for EAGLE/Fusion boards).

Page polish rules (field-tested — molecule-pipeline #190)

Hard-won from ~10 real imports; each one cost a debugging detour:

  • Heroes on board/component pages are static imagespage hero --image, never --screenshot/billboard (billboard composes an app-style browser frame around the render: "images within images").
  • Browse-card thumbnails bake at publish time — a repo-only hero push does NOT refresh the card. Republish with a version bump, then verify the served card PNG actually changed (sha256 the blob).
  • Keep board pages PDF-free. Any PDF in the repo becomes an unwanted auto-scanned "Datasheet" section with no manifest opt-out — ship docs on a dedicated docs page or as release assets instead.
  • Draco-compress big scene GLBs only. Multi-MB workcell/scene models: gltf-transform optimize --compress draco (35 MB → ~1.3 MB, <3 s load). Chip/molecule-sized GLBs: do NOT draco — it comes out ~40% BIGGER than quantized and the wiki readme sandbox can't decode it (adom-step2glb #3). Your published molecule GLB is already optimized by OCCT — leave it alone.
  • Plain components (no MP markers) skip axis normalization — molecule mode anchors Z-up, but a plain step2glb convert preserves the source STEP's axes; check orientation per board and bake a ±90° X root rotation only when the source needs it.
  • Wiki page animations are baked glTF animations in the viewer GLB — GIFs only work inside README sections.
  • adom-molecule-import — the wiki → Hydrogen companion
  • kicad-export-molecule / fusion-export-molecule / altium-export-molecule — the EDA → bundle front-ends that hand off here
  • adom-step2glb — the conversion CLI/service this skill drives
  • molecule-pipeline — the top-level router across the whole chain