Skip to content

Engineering portal — handoff for another engineer or AI

Read this before touching https://engineering.embeddedera.com. Paths are on the shop server Plex (Ubuntu 24.04, user angel). No secret values are written here; only where they live.

What it is

A static site listing every KiCad board in the EmbeddedEra GitHub org: schematic and board viewers (KiCanvas), an interactive 3D model, an InteractiveHtmlBom, four renders, ERC/DRC counts, manufacturing specs and the fab-pack releases. Nothing is hand-edited; it is rebuilt from the repos. Design and log: engineering-portal.

The pieces and where they are

Piece Where Notes
Build script ~/.local/bin/engineering-build (python3) lists repos with gh, clones to ~/engineering/repos/, writes ~/engineering/site/docs/
Deploy script ~/.local/bin/engineering-deploy (bash) runs the build, MkDocs, wrangler pages deploy; skips deploy when the tree hash is unchanged
Schedule crontab -l → 20 * * * * under flock log ~/.local/state/engineering-deploy.log, lock ~/.local/state/engineering-deploy.lock
Site source ~/engineering/site/mkdocs.yml, docs/assets/ Material theme copied from the SOP site; vendored kicanvas.js, model-viewer.min.js, meshopt_decoder.js, mv-init.js; navigation.instant must stay OFF
Per-commit cache ~/engineering/cache/<repo>/<board>/<sha>/ renders, board.glb, ibom, _check-<sha>.json; delete a file to force a rebuild of that piece
3D models ~/engineering/3dmodels/ (KiCad packages3D subsets) and ~/kicad-lib/3dmodels/ (Git LFS) ~/.local/bin/kicad-3dmodels fetches missing .3dshapes; git lfs pull in ~/kicad-lib after cloning
GLB material fix ~/.local/share/glbfix/fix-materials.mjs gltf-transform; makes the viewer match the raytraced renders
Helpers ~/.local/bin/kicad-check, kicad-ibom, gltfpack (symlink into nvm) all run the pinned container kicad/kicad:10.0.5
Hosting Cloudflare Pages project embeddedera-engineering, custom domain engineering.embeddedera.com token in ~/.config/cloudflare/env (CLOUDFLARE_API_TOKEN, account id)
Login gate Cloudflare Access app "EmbeddedEra Engineering" (+ "(pages.dev previews)") Google login; allowed departments engineering + admin from ~/Notes/roles/departments.yml; managed by ~/.local/bin/onboard access-sync
Home tile ~/assistant/home.py TILES["engineering"], departments.yml tiles: restart systemctl --user restart assistant.service after editing

GitHub: what is configured where

Thing Where Purpose
gh CLI login ~/.config/gh/hosts.yml (account angelEmbeddedEra, org owner) the build lists repos, reads releases, triggers workflows
KICAD_LIB_TOKEN fine-grained PAT, value in ~/.config/github/env; set as a repo secret on every product repo (gh secret set KICAD_LIB_TOKEN -R EmbeddedEra/<repo>) lets CI clone the private library EmbeddedEra/KiCad (contents: read only)
CI workflow .github/workflows/kicad-checks.yml, master copy in EmbeddedEra/Project_Template; verbatim copies in Dashcam_Drive, Cow_Robot_Board, Cow_Remote job erc-drc on every push under hardware/**; job fab-outputs on tags hw/<board dir with _ for spaces>/<rev>
Fab pack release asset <board>-<rev>-fab.zip gerbers, drill, BOM, CPL, schematic PDF, assembly PDFs, renders, pnp/ YY1 files, REQUIREMENTS.md from hardware/<board>/fab.yml
Library repo EmbeddedEra/KiCad (~/kicad-lib) .gitattributes tracks *.step *.STEP *.stp *.wrl in LFS; scripting/neoden/ holds kicad_to_yy1.py + neoden_yy1_machine_setup.toml (bench feeder state) CI checks it out with lfs: true after installing git-lfs in the container
Product manifest product.yml at each repo root, schema in Project_Template/docs/product-yml.md boards[].status: shipping / prototype / retired drives the Production / In development / Archive sections
Excluded repos EXCLUDE_REPOS near the top of engineering-build KiCad, Project_Template, EmbeddedEra-products/modules, DIY-Multiprotocol-TX-Module

Other secrets an agent may need (values never in the vault)

  • ~/.config/cloudflare/env — Cloudflare API token (Pages, DNS, Access).
  • ~/.config/github/env — KICAD_LIB_TOKEN.
  • ~/.config/inventree/env — ERP URL + owner token (portal links to parts by IPN only).
  • Everything is also in the Vaultwarden vault; SOP-020 lists the credentials register.

Rules that apply

  • Never sudo apt; user-space only (nvm, uv, ~/.local/bin). See ~/CLAUDE.md.
  • Try changes with a local build (engineering-build, then mkdocs serve on 127.0.0.1) before deploying; a deploy is one command and the CDN caches by file name, so renders and models carry the commit hash in their names.
  • Procedures: SOP-021 New PCB Design (tags, fab.yml, fab pack), SOP-008 KiCad Library (IPNs, LFS), SOP-019 Cloudflare Changes, all at https://sop.embeddedera.com.

Verified deployment and recovery — 2026-09-18

  • Versioned source is now ~/assistant/scripts/{engineering-build,engineering-deploy,kicad-check} and ~/assistant/static/engineering/{mkdocs.yml,portal.v1.css}. Installed tools must match the reviewed main branch. Use the sandbox first; tests/test_engineering_portal.py and tests/test_kicad_check_reports.py are the offline regressions. Run provider fixtures under systemd-run --user --wait --pipe --collect -p RestrictAddressFamilies=AF_UNIX.
  • engineering-deploy [main|preview] builds in a private temporary copy, regenerating docs/boards. Failed discovery, pull, build or upload does not replace the previous successful docs or hash. Use this entrypoint; a standalone build into live docs is not atomic.
  • Cron's outer lock remains engineering-deploy.lock; the script's shared main/preview lock is engineering-deploy-internal.lock. Never make these the same file. Branch hashes are ~/.local/state/engineering-deploy.<branch>.hash, written only after successful upload and (main only) local docs promotion. The old unqualified hash is not used.
  • Main success promotes generated docs to ~/engineering/site/docs and retains the previous successful tree as docs.prev. Preview never promotes into main docs. A post-upload local promotion failure exits nonzero, states that the upload already happened, and leaves the hash unwritten so recovery retries honestly. Pre-change tools, config and superseded check caches are retained at ~/.local/state/engineering-backups/task148/.
  • Test overrides: ENGINEERING_SITE_DIR, ENGINEERING_DOCS_DIR (builder), ENGINEERING_REPOS_DIR, ENGINEERING_CACHE_DIR, ENGINEERING_KICAD_CHECK, and deploy ENGINEERING_STATE_DIR, ENGINEERING_BUILD, ENGINEERING_MKDOCS, ENGINEERING_WRANGLER, ENGINEERING_CF_ENV, ENGINEERING_TMPDIR. Keep isolated roots and empty fixture credentials for failure tests; never rely on an environment flag alone to prevent live mutations.
  • Check caches actually live at ~/engineering/cache/<repo>/_check-<sha>.json. Schema 2 records SHA, checker/library fingerprint, exit code and validated report. Old reports cannot prove tool execution and are regenerated. Existing environment-noise/fragment filtering in kicad-check remains; these counts are not unfiltered manufacturing sign-off. CI status is separately matched to the same commit and is unknown when no matching run exists.
  • Board identity uses exact normalized boards[].path. Canonical project filenames win over old sibling project files; missing metadata is not borrowed. Unclassified does not mean Archive. Source layouts with no outline/components have a visible BOM failure, not a fabricated output. Angel explicitly excluded the three empty drafts from #148 on 2026-09-18; #148 is closed and their hardware follow-up remains under #149 (see engineering-portal).
  • Browser smoke check: serve a sandbox MkDocs output on loopback, then run ~/.local/share/shots-venv/bin/python ~/assistant/scripts/engineering-browser-check.py http://127.0.0.1:<port>/ --artifacts <evidence-dir>. It checks phone/desktop overflow, Home links, both KiCanvas canvases, source-commit text and BOM highlighting. Keep assets/portal.v1.css in extra_css to prevent the Home/Feedback controls overflowing a phone.

Log

  • 2026-09-16: written for handing the portal to another engineer or AI.

  • 2026-09-16: Production correction confirmed by Angel: Robot-Cow-004B is shipping; Robot Cow 4.0.1 is retired (Cow_Robot_Board commit 6a43367). The existing 4.0.1 fab pack is historical, not a pack for the production 004B board. See engineering-portal Open items for 004B fab.yml, release, and unverified IPN/firmware mappings.

  • 2026-09-16: User prioritized a usage collector/dashboard and revenue-oriented operating plan during workflow implementation. Collector shipped at EmbeddedEra/ai-capacity and Home; see ai-capacity. Hardware workflow changes are preserved, not rolled out: resume implementation/STATUS.md in /home/angel/Documents/Codex/2026-09-16/home-angel-notes-projects-engineering-portal. The old phase2 process ended without a report; restart its bounded brief after reviewing partial diffs.

September 17: business operations automation direction

Current plan and task assignments: business-operations-automation. Tasks240–243 cover inventory valuation/build capacity, deterministic employee-scoped ERP actions, actual receivables/payables reporting, and private Chase/supplier imports. Reuse existing assistant actions and department agents. Prefer tested functions with schemas and receipts over repeated model reasoning; preserve existing Claude memory/routing and per-user permissions.