342 lines
19 KiB
Markdown
342 lines
19 KiB
Markdown
# A workshop/office assistant: what's worth building
|
||
|
||
Feasibility note. The ask: identify laptops and computers by camera, identify
|
||
components (mainboards especially), pull up disassembly guides, research part specs
|
||
automatically, and hold a conversation about planning a project — all scoped per room.
|
||
|
||
**The one finding that reorganises the whole thing: stop trying to recognise the
|
||
object, and read the label on it.** Everything below follows from that.
|
||
|
||
## Why "identify it by shape" is the wrong problem
|
||
|
||
Ask a local 7–13B vision model what laptop it is looking at and you will get a
|
||
confident, wrong answer, because:
|
||
|
||
- **Laptops are visually identical by design.** A closed ThinkPad T480 and a T490 are
|
||
the same black rectangle. So are half of Dell's Latitude line. There is no visual
|
||
feature to learn, and a model that claims otherwise is pattern-matching on the
|
||
wallpaper.
|
||
- **Mainboards are worse, not better.** Board layout varies more than a laptop shell
|
||
does, but the discriminating detail — where the fourth M.2 slot is, which VRM
|
||
configuration — is exactly what a photo at workbench distance and a general-purpose
|
||
VLM cannot resolve.
|
||
- **Getting it wrong is expensive here**, unlike in the pantry. A wrong yoghurt costs a
|
||
tap. A disassembly guide for the wrong laptop revision costs a broken clip or a
|
||
ribbon cable, and a wrong pinout costs the board.
|
||
|
||
Meanwhile, every one of these objects **carries its own identity in printed text**:
|
||
|
||
| Object | Where its identity actually is |
|
||
|---|---|
|
||
| Laptop | Service tag / serial sticker on the base — and on Dell/Lenovo/HP that tag resolves to the *exact factory configuration* |
|
||
| Mainboard | Model silkscreened on the PCB (`PRIME B450M-A`), usually near the RAM slots or the PCIe bracket |
|
||
| GPU / PSU / drives | Model and part number on the label |
|
||
| ICs | Top-marking, when it hasn't been sanded |
|
||
|
||
So the pipeline is **OCR-first**: photo → detect text regions → read them → match
|
||
against a parts database. The VLM's job is the small, tractable one it is good at —
|
||
"what kind of thing is this, and where on it is the label" — and the identification
|
||
comes from characters, not from vibes. This also degrades honestly: an unreadable
|
||
label produces "I can't read it, hold it closer" rather than a plausible wrong model.
|
||
|
||
**What stays hard, permanently:** an unmarked part. A capacitor, a sanded IC, an
|
||
anonymous barrel connector. Nothing here will identify those, and the assistant should
|
||
say so rather than guess.
|
||
|
||
## The four capabilities, ranked by whether they're worth it
|
||
|
||
### 1. Conversational project planning — build this first
|
||
|
||
The cheapest and the most useful, and the only one with no perception problem in it.
|
||
It is a text LLM with a notebook: what am I building, what have I got, what's the next
|
||
step, what did I decide last Tuesday and why. The value is entirely in the *notebook*
|
||
being persistent and per-project, not in the model being clever.
|
||
|
||
This is also the piece that makes the others worth having: an identified mainboard is
|
||
only useful if there is somewhere to put it ("this is for the NAS build").
|
||
|
||
Shape: a small service in the pattern this repo already uses four times over
|
||
(`identity`, `chores`, `pantry-vision`) — SQLite, an HTTP API, bearer token, a static
|
||
frontend on a display. Projects, notes, parts, photos, decisions.
|
||
|
||
### 2. Part-spec research — build it, with one hard rule
|
||
|
||
**Every spec must be quoted from a fetched document, with its URL, and never generated
|
||
from the model's memory.** This is the same rule `digest-engine`'s political prompt
|
||
enforces on claims about the world and `pantry-vision` enforces on stock writes, and
|
||
here it is a safety property rather than a quality one: a hallucinated TDP wastes an
|
||
afternoon, a hallucinated pinout destroys hardware.
|
||
|
||
Practically: fetch the vendor page or datasheet PDF, cache it locally, extract, and
|
||
show the extract next to its source. If nothing was fetched, the answer is "I couldn't
|
||
find a datasheet", not a paragraph of plausible numbers.
|
||
|
||
**This is the first component in this project that deliberately reaches the open
|
||
internet for content**, which is worth stating plainly given the local-first doctrine
|
||
everything else follows. It is outbound-only, it does not require anything to be
|
||
exposed, and it should run against an explicit allowlist of sources (vendor domains,
|
||
iFixit, datasheet archives) with everything it fetches cached on disk — so the same
|
||
board is looked up once, not once per question.
|
||
|
||
### 3. Disassembly guides — mostly a link, and that's fine
|
||
|
||
iFixit is the corpus, and it has a public API. The honest scope is: resolve the
|
||
identified model to a guide, show the steps and images on the workshop display, cache
|
||
what you fetch. Do not rewrite the guide through an LLM — the steps are the thing, and
|
||
an LLM paraphrase of "disconnect the battery before removing the board" is strictly
|
||
worse than the sentence itself.
|
||
|
||
Vendor service manuals (Lenovo's HMM PDFs, Dell's service manuals) cover what iFixit
|
||
doesn't, and are the reason the cache is worth having: they are large PDFs you want
|
||
locally, once.
|
||
|
||
### 4. Camera identification — build it last, and OCR-first
|
||
|
||
By the time the three above exist, this is a convenience: it saves typing a model
|
||
number. Useful convenience — hands are usually dirty or full — but it is the piece
|
||
with the perception risk, and it should not be the first thing attempted.
|
||
|
||
The interaction that actually works: hold the label to the camera, get the text back
|
||
with a confidence, **confirm before anything acts on it** — the identical
|
||
propose-never-auto-commit rule `pantry-vision` runs on. Scanning a barcode or QR code
|
||
where one exists (most service tags have one) is strictly better than OCR and should
|
||
be tried first.
|
||
|
||
## Per-room scoping, which the plumbing now supports
|
||
|
||
"Make this a per-room system" splits into two questions, and the boring one is now
|
||
answered:
|
||
|
||
**Which devices are in which room** — done. Every kiosk and audio endpoint declares a
|
||
`room` (an HA area_id) in `CoreSystemConfig.json`; it is baked into the agent and
|
||
published as `suggested_area`, so HA files each device in the right area by itself. See
|
||
`docs/rooms-and-endpoints.md`. The workshop is a room like any other: give it a display
|
||
and it declares `room: workshop`.
|
||
|
||
**Which assistant is active in which room** — the design question, and the answer that
|
||
fits this project is: *the room selects the toolset, not the personality.* A voice
|
||
request in the workshop can reach the parts database and the project notebook; the same
|
||
words in the kitchen reach `pantry-vision` and the recipes. That is a routing table
|
||
from area_id to capability set, sitting in front of HA Assist, and it is small.
|
||
|
||
Two reasons to do it that way rather than one assistant with everything:
|
||
|
||
- **Ambiguity collapses.** "What have I got?" means stock in the kitchen and parts in
|
||
the workshop, and no amount of prompt engineering makes one agent reliably guess
|
||
which room the words came from — but `identity`'s `/speaker` already answers "who
|
||
spoke in this area", and the area is right there in the request.
|
||
- **The dangerous tools stay where they belong.** Nothing in the kitchen should be able
|
||
to open a disassembly guide, and nothing in the workshop needs to book out groceries.
|
||
|
||
## The workspace, and why it is an SMB share
|
||
|
||
The assistant needs somewhere to put things: fetched datasheets, extracted specs,
|
||
generated diagrams, photos of the board, project notes, a scratch directory per
|
||
project. Making that a **plain directory on the container host, exported over SMB**, is
|
||
right for a reason worth stating: it means every artefact is a file you can open from a
|
||
laptop with no API, no export step, and no dependence on this project still existing in
|
||
two years. The assistant's output should outlive the assistant.
|
||
|
||
```
|
||
/opt/smart-home/workshop/
|
||
projects/<slug>/
|
||
notes/ markdown the assistant and you both write
|
||
datasheets/ everything fetched, cached, named by part
|
||
diagrams/ generated SVGs (see the next section)
|
||
photos/ what the camera captured
|
||
scratch/ the assistant's working directory
|
||
```
|
||
|
||
**This project already runs Samba** — `gallery-smb`, from `setup-container-host.sh`.
|
||
Two things follow, and the second is a real trap:
|
||
|
||
- **Reuse the container, add a share.** Samba serves many shares on one port; a second
|
||
Samba container would fight the first for **445, which is already claimed**
|
||
(`ports.gallery_smb`). That is the same class of collision already recorded as open
|
||
decision #31 for Music Assistant, and it is avoidable here by construction: one
|
||
`smb` container, a `gallery` share and a `workshop` share, separate accounts.
|
||
- **The gallery share is `read only = yes`. This one cannot be**, and that is the
|
||
entire security difference between them. A writable share is fine; a writable share
|
||
that an LLM writes into deserves three limits, none of which are exotic:
|
||
- **Its own volume**, not a subdirectory of anything else. The blast radius of a bad
|
||
path is then "the workshop workspace", which is recoverable.
|
||
- **Its own account**, not the gallery's. Guest access off, same as the gallery.
|
||
- **No execution.** Nothing in the workspace is ever run by anything on the host —
|
||
it is a place for documents, and the moment it becomes a place for scripts it is a
|
||
different security question than this note answers.
|
||
|
||
Keep the assistant's *state* — projects, parts, decisions — in SQLite as with every
|
||
other service here, and the *artefacts* on the share. The database is the index; the
|
||
share is the filing cabinet. Mixing them (blobs in SQLite, or state in files) gets you
|
||
the worst of both: a database you cannot browse and files nothing can query.
|
||
|
||
## Technical display widgets, and the one decision that makes them cheap
|
||
|
||
The thin-client canvas SDK today has `stat`, `chart`, `image`, `video`, and plain
|
||
markdown-ish text. The wanted additions — schematics, board plans, code-flow and
|
||
data-structure diagrams, breadboard layouts, 3D — look like six new widgets. They are
|
||
mostly one:
|
||
|
||
> **Render to SVG on the container host; show it in the canvas.** One new `svg` window
|
||
> kind, plus renderers server-side.
|
||
|
||
That keeps the SDK's dependency-free, no-build-step property (the thing that makes it
|
||
maintainable), puts heavy tooling on the machine that already has heavy tooling, and
|
||
means a diagram is a *file in the workspace share* as well as something on a screen.
|
||
Client-side rendering libraries would put a megabyte of JavaScript on a kiosk to
|
||
produce a picture the server could have produced once and cached.
|
||
|
||
| Widget | How | Honest difficulty |
|
||
|---|---|---|
|
||
| **Circuit diagrams** | `netlistsvg` (or KiCad's own SVG export) from a netlist the assistant produces | Medium — see the notation note below, which is the whole job |
|
||
| **Board plans** | KiCad `.kicad_pcb`/Gerber → SVG, server-side, pre-rendered | Medium, and only for boards you have files for. There is no path from a *photo* of a board to a layout drawing |
|
||
| **Code-flow diagrams** | Graphviz `dot` → SVG | **Easy.** Graphviz is small, deterministic, and an LLM writes `dot` reliably |
|
||
| **Data-structure diagrams** | Graphviz (records/HTML-like labels) → SVG | Easy, same pipeline |
|
||
| **Assembly guides** | The guide's own step images in sequence — see the iFixit section | Easy in 2D |
|
||
| **Breadboard diagrams** | Fritzing-style, and Fritzing's value *is* its part library, which is not callable | **Hard, and least worth it** — a photo of the actual breadboard is usually better and always more honest |
|
||
| **3D models** | glTF + a vendored three.js on the kiosk | The only one that genuinely needs client-side code — see below |
|
||
|
||
### EU/IEC notation is a symbol-library decision, not a rendering one
|
||
|
||
Rectangular resistors, not zigzags. This matters more than it sounds: **most schematic
|
||
tooling defaults to ANSI/US symbols**, and a renderer that cannot be given a symbol set
|
||
will quietly produce American schematics forever.
|
||
|
||
So the selection criterion for the schematic renderer is *"can I supply my own symbol
|
||
library?"* before anything about output quality. `netlistsvg` takes custom skins, which
|
||
is the concrete lever — an IEC skin, written once, vendored in the repo like every
|
||
other asset here. KiCad can be configured the same way. Anything that hardcodes its
|
||
symbols is disqualified regardless of how good its output looks, because the first
|
||
zigzag resistor is the last time anyone trusts the diagram.
|
||
|
||
The same applies downstream: state the convention in the prompt that generates the
|
||
netlist, and check it on the way out. A diagram in the wrong notation is not a style
|
||
complaint — it is a diagram that reads wrong to the person holding the soldering iron.
|
||
|
||
### The holographic look is a variable override, not a new stylesheet
|
||
|
||
The canvas SDK is already a holo aesthetic — glow text, glowing panel edges, a pulse
|
||
animation, a dark blue base — and, importantly, it is already parameterised. Every
|
||
colour in `glow.css` comes from custom properties on `:root`
|
||
(`--admin-accent`, `--admin-glow-color`, `--admin-edge`, `--admin-panel`, `--admin-bg`).
|
||
|
||
So "make the workshop look holographic in purple/magenta" is **one small override file
|
||
loaded after the SDK**, not a fork of it:
|
||
|
||
```css
|
||
/* workshop-theme.css — loaded after glow.css. Overrides only. */
|
||
:root {
|
||
--admin-bg: #0a0510; /* near-black, violet-biased */
|
||
--admin-panel: rgba(28, 12, 44, 0.82);
|
||
--admin-edge: rgba(200, 120, 255, 0.32);
|
||
--admin-accent: #c084fc; /* the purple everything glows in */
|
||
--admin-text: #eadcff;
|
||
--admin-muted: #a98fc4;
|
||
--admin-glow-color: #ff3ec8; /* magenta glow against a purple accent */
|
||
}
|
||
```
|
||
|
||
Two magenta-on-purple choices worth making deliberately: the **accent** (borders,
|
||
labels, chrome) reads better as the lighter purple, and the **glow** as the magenta —
|
||
glow bleeds and saturates, so the more aggressive colour belongs to the effect rather
|
||
than to the thing being read. Keep `--admin-good`/`--admin-warn` as they are; green
|
||
and amber mean something, and recolouring them into the theme would cost that meaning.
|
||
|
||
**Do not tint the technical drawings.** This is the one rule that keeps the look from
|
||
becoming a liability: a schematic, a board plan or a pinout table needs contrast and
|
||
neutral colour far more than it needs to match the frame — trace colours mean things,
|
||
and a magenta glow over a resistor value is how you misread it. So:
|
||
|
||
- Holo treatment on the **chrome**: window frames, titles, edges, the pulse, the
|
||
background.
|
||
- The **drawing surface stays neutral** — a light panel for schematics (they are drawn
|
||
for paper and read best that way), or high-contrast line art on near-black. The
|
||
frame around it can glow all it likes.
|
||
- Anything conveying state by colour — a red LED in a diagram, an error, a
|
||
live measurement — keeps its own colour. The theme owns the furniture, not the data.
|
||
|
||
The same override trick works if a future room wants its own palette; the SDK never
|
||
needed to know about themes for this to be possible, which is why it costs one file.
|
||
|
||
### 3D: worth doing, but not first, and not with a live viewer at first
|
||
|
||
3D is the one item that cannot be an SVG. Two paths:
|
||
|
||
- **Pre-rendered orbit frames** — render N views server-side, ship them as an image
|
||
sequence, scrub with a drag. Cheap, works on every surface including the ones with
|
||
no GPU, and covers "let me see what this connector looks like from behind", which is
|
||
most of the actual need.
|
||
- **A real viewer** — vendored three.js plus glTF. It is roughly a megabyte of
|
||
JavaScript on a kiosk that currently ships none, which is a real break with the
|
||
SDK's "vendored, dependency-free" rule and should be a deliberate decision rather
|
||
than a drift into one.
|
||
|
||
Start with the frames. Move to a viewer if and only if manipulating the model turns
|
||
out to be what people do, rather than glancing at it.
|
||
|
||
**3D assembly guides** — exploded views with per-step visibility — are the most
|
||
speculative item in this entire note. They need a model *with assembly structure*,
|
||
which almost nothing you download has, and authoring one per project is more work than
|
||
the repair. Park it.
|
||
|
||
## Hardware
|
||
|
||
The workshop needs what the kitchen already has: a screen you can touch with one
|
||
knuckle, a camera, a microphone. `hosts/kitchen-display/` is exactly this shape
|
||
already — a Sway kiosk, a webcam, an agent, one workspace — so a workshop display is
|
||
that image with a different frontend, not a new class of device.
|
||
|
||
The camera wants to be better than the kitchen's, though, and differently: reading a
|
||
service tag or a PCB silkscreen is a **macro** problem. Autofocus at 10–20 cm and
|
||
enough resolution to resolve 2 mm text matter far more than field of view. A cheap
|
||
USB microscope/inspection camera is a better fit than a webcam, and is worth pricing
|
||
before assuming the C920 answer carries over.
|
||
|
||
## The compute problem, again
|
||
|
||
One RTX 3060, already carrying Assist, four digests a day, `pantry-vision` and
|
||
`chores`. Adding OCR is fine (it is small, and CPU OCR is viable). Adding a second
|
||
large model that has to be resident is not — and "the workshop assistant felt slow
|
||
because someone asked for a digest" is exactly the contention already flagged as open
|
||
decision #4. Design for one model swapped predictably, not two resident.
|
||
|
||
## Recommended order
|
||
|
||
1. **The project notebook + conversational planning, and the workspace share.** No
|
||
camera, no internet, no new hardware. Useful on day one, and it is where everything
|
||
else lands — including every artefact the later steps produce.
|
||
2. **Spec research with mandatory citation**, against an allowlist, cached on disk.
|
||
3. **The `svg` window kind + a Graphviz renderer.** One kind and one small tool buys
|
||
code-flow and data-structure diagrams immediately, and is the pipeline the schematic
|
||
and board-plan renderers then plug into.
|
||
4. **Guide lookup**, by typed model number.
|
||
5. **Schematics with an IEC symbol skin** — the notation work is the work.
|
||
6. **Camera identification**, barcode first and OCR second, proposing rather than
|
||
acting.
|
||
7. **3D**, as pre-rendered orbit frames. A live viewer only if manipulation turns out
|
||
to be what people actually do.
|
||
|
||
The purple/magenta holo theme is not in that order because it is not a step: it is one
|
||
override file and can land whenever.
|
||
|
||
Steps 1–3 need no new hardware at all — a browser on any existing thin client reaches
|
||
them. That matters: it means the whole idea can be proved before buying a workshop
|
||
display, and if the conversation-and-notebook half turns out to be the only part
|
||
anyone uses, that is a complete and useful outcome rather than a failure.
|
||
|
||
## What is unverified here
|
||
|
||
Everything past step 1. Specifically: whether iFixit's API terms permit caching what
|
||
this would cache; whether a local VLM can read a PCB silkscreen at all under workshop
|
||
lighting (testable today with any webcam and a spare board — do this before buying an
|
||
inspection camera); whether service-tag lookups work without a vendor account; and
|
||
whether the OCR-first pipeline holds up on the labels that are scratched, curved, or
|
||
under a warranty sticker, which in a workshop is most of them.
|
||
|
||
On the display side specifically: whether `netlistsvg`'s skin mechanism really can
|
||
express a full IEC symbol set (the notation requirement rests entirely on that, and it
|
||
is worth a two-hour spike before committing to the tool); whether an LLM produces
|
||
netlists that are *correct* rather than merely well-formed, which is a different and
|
||
much harder property; and how big a vendored three.js actually is against the kiosk's
|
||
budget before deciding 3D is affordable.
|