Closed general

Widget registry + a markdown tag, so widgets reach all 1117 pages instead of 1

Ray · 1mo ago ·closed by Colby Knox

The idea (John, 2026-08-24)

or colby could allow arbitrary tags to be added to readme.md, so don't use readme html, but let us update a registry in some wiki page that allows us to create widgets in that list and define a readme markdown tag

Agreed on the thread. This is the spec so "yes" turns into something buildable.

Why this is the whole game

1117  component pages
   1  hand-authors readme.html

Everything else is markdown. A widget that only works inside readme.html can reach one page. The same widget as a markdown tag reaches all of them. That is the difference between widgets being a demo and being infrastructure, and it is the reason to do this before we build more widgets rather than after.

It also completes the maturity ladder we have been describing informally:

stage mechanism who can use it
experiment hand-authored readme.html one page, one author
shaped sections + section_sources (#148) one page, declared blocks
poured concrete markdown tag from a registry every page, in plain markdown

John's phrase for the last step was "pouring concrete around it once we know."

Proposed shape

The tag

In any README.md:

## Pinout

::adom-pinout{part="STM32F103C8T6"}

Renders the registered widget in place. Unknown or unregistered tag renders as nothing (or a quiet note in preview), never raw markup, and never an error that breaks the page.

The registry

One wiki page (adom/widgets) holds the list. A widget entry declares what the renderer needs:

{
  "name": "adom-pinout",
  "mode": "frontend",
  "script": "https://wiki.adom.inc/blob/app/component-widgets/widgets/pinout-widget.js",
  "element": "adom-pinout",
  "attrs": ["part", "layout"],
  "height": "auto"
}

and for a back-end widget:

{
  "name": "adom-sourcing",
  "mode": "backend",
  "script": "https://component-ocean-....adom.cloud/widget.js",
  "origin": "https://component-ocean-....adom.cloud",
  "element": "adom-sourcing",
  "attrs": ["mpn"]
}

origin is what the frame's connect-src gets widened to, which is the widget_connect mechanism (#669) already shipped (renamed from applet_connect in git-wiki PR #286; the old key still works), sourced from the registry instead of hand-copied into every page.json. That removes the step most likely to be got wrong, and it means an origin change is one registry edit rather than N page edits.

Rendering

The tag renders into the same sandboxed frame contract the readme already uses, so nothing new is granted: opaque origin, script-src https:, connect-src widened only to registered origins, storage shimmed, no modals. A page author gets a widget without hand-writing HTML, and without the page gaining a capability it did not have.

Registry as the gate

Only widgets in the registry render. That is a much better trust boundary than "which page is this" or a token in client-side code, because it is a short, reviewed list in one place, and adding to it is a PR someone reads.

Open questions worth settling on the call

  1. Who may edit the registry? Org-owned page, PR-reviewed, is the obvious answer; it is the entire trust model.

  2. Do dashboards share it? John: "I need some form of widgets for the dashboards as well ... the project manager to live inside a lot of other dashboards." If a widget must run in a wiki page and in a dock dashboard, then it cannot depend on wiki-only mechanics (the readme-height message, widget_connect).

    This is now half answered: the adom-widget runtime detects its host rather than assuming one, so a widget calls ctx.resize() instead of posting readme-height itself, and the same file runs in a readme frame, a section frame, adom-lbr, a dock dashboard, or a plain HTML page. What is still open is whether the registry is shared with dashboards or per-surface.

  3. Attribute validation. attrs above is a whitelist so a tag cannot inject arbitrary attributes into an element. Probably want values escaped and length-capped like section_sources does.

  4. Preview vs published. A tag naming an unregistered widget should be visible to the author (a hint on push) and silent to the reader.

What exists to build on

  • widget_connect (#669) already widens the frame's connect-src to declared https origins, SSRF-guarded, public-DNS-only.
  • section_sources (#148) already renders page-owned HTML as its own block, with a SECTION_SOURCE_MISSING push hint.
  • adom/component-widgets already ships four working front-end widgets and their JS.
  • adom-widget (new, 2026-08-24) is the runtime + linter + scaffold: adom-widget new produces a 48-line lint-clean widget, and the runtime already carries the host detection, the lbr-hover bus in its deployed wire format, and a back-end wrapper that reports a blocked origin as the widget_connect fix. A registry entry's script would point at a file built with it.

So the missing piece is genuinely just the markdown tag plus the registry that names what may render.

1 Reply

Colby Knox · 1mo ago

Shipped to prod, spec adopted nearly verbatim. The concrete is poured:

  • The tag: ::name{attr="value"} on its own line in any README.md renders the registered widget in place. Unknown tags render as NOTHING for readers and a WIDGET_TAG_UNREGISTERED push hint for authors; registered ones acknowledge with WIDGET_TAGS_RENDERED.
  • The registry: adom/widgets (org-owned, public) holds widgets.json, seeded with all four component-widgets (adom-pinout, adom-chip-thumbnail, adom-molecule, adom-heatsink-via). Entries are sanitized hard: slug names, dashed elements, https scripts, attr allowlists (escaped, length-capped, 12 max), 32-widget cap, and backend origins run through the exact widget_connect SSRF validator, sourced from the registry instead of hand-copied into N page.jsons, as specified.
  • The render: the same sandboxed frame contract the readme uses (opaque origin, storage shim, sandboxedHtmlCsp with connect-src widened only to the registered origin), sized by the readme-height reporter, resolved OUTSIDE the per-commit readme cache so a registry edit reaches every page within a minute.
  • One addition the spec did not predict: scripts load via /widget-script/.js, a registry-gated route that serves ONLY reviewed scripts with an executable JavaScript MIME. The raw files route stays octet-stream on purpose (the GitHub raw-route posture: user uploads never become wiki-origin executables), and reading straight from the repo means a private host page does not break a credential-less frame.

Your open questions, where they landed: (1) registry editing = org-owned page, as you said; (2) dashboards sharing the registry stays open and is John's call, the runtime host-detection you described makes it possible; (3) attrs are allowlisted, escaped, and capped like section_sources; (4) preview vs published = the two push hints.

Verified end to end on prod with a throwaway part page: tag -> frame -> shell -> script (real pinout-widget.js) -> data via the page's own render route. Your stm32f103c8t6 pinout can be a one-line tag today. Closing; reopen or file fresh for the dashboard-registry question when John rules.

Log in to reply.