07a — Web UI: Local-First Shells & Backend-Driven UI (Partition A)
modifiedOct 17, 2026
DocTypesources
Intentlong-term
LastUpdatedJun 23, 2026
Owners
Statusactive
SummaryCondensed, map-ready summary of Topic 7 partition A — Local-first Go-hosted browser/desktop apps and Backend-driven / generated UI systems.
TicketPROJECT-MAPS-001
Title07a Web UI Local Shells & Backend-Driven UI (Partition A Condensed)
Topicsresearch, projects, concept-maps, web-ui, local-first, backend-driven-ui
WhatForUse as condensed evidence for concept-map node/edge synthesis of the local-shell and backend-UI arcs.
WhenToUseAfter reading the first-batch source report 07 and before refining the topic concept map.
07a — Web UI: Local-First Shells & Backend-Driven UI (Partition A)
Executive summary
- Partition scope: Cluster 1 (Local-first Go-hosted browser/desktop apps) and Cluster 2 (Backend-driven / generated UI systems) from the first-batch source report
sources/07. - Two architecture spines: (1) Go binary + embedded frontend serving derived content from local files; (2) UI-as-data transported from backend/Goja to a React renderer that interprets known node kinds.
- Strongest arcs: md-view daemon→Wails migration (process model rewrite), Go-Go Parc/Retro Obsidian vault publishers (single-binary + git-sync), Fringe Admin DSL (renderer-as-interpreter), Widget IR pipeline (Goja authors data, React renders).
- Concept-map spine for Cluster 1:
Markdown/YAML source → Go renderer (fragment) → embedded SPA or Wails WebView → browser augmentation → agent-readable mirror. - Concept-map spine for Cluster 2:
JS/Goja authoring → Widget IR (JSON) → Go validation/transport → React renderer (interpreter) → Storybook contract surface. - Start here:
Projects/2026/06/13/ARTICLE - Replacing md-view with a Wails v2 Desktop Application - Technical Deep Dive.md(process model migration) andProjects/2026/05/16/PROJECT REPORT - Fringe Admin DSL Backend Driven Admin Interfaces Deep Dive.md(renderer-as-interpreter).
Scope and search method
Corpus: Projects/2026/{04,05,06}/ Markdown files.
Partition: Cluster 1 (Local-first Go-hosted browser/desktop apps) + Cluster 2 (Backend-driven / generated UI systems) from sources/07.
Search: filename + grep for SQLide|md-view|Wails|Go-Go Parc|Retro Obsidian|Fringe Admin|Browser-Side React Widget|WidgetRenderer|Widget IR|DMETA Viewer|Fake CMS|Playbook.*Wasm.
Selection: deeply read the 8 canonical files; heading-scanned 5 adjacent files.
Evidence ledger
| Path | Evidence level | Lines / basis | Cluster | Why it matters |
|---|---|---|---|---|
Projects/2026/04/02/PROJ - SQLide Browser - Go Wasm SQL IDE.md |
read | full file | C1 | Canonical Go/Wasm + sqlite-wasm worker split architecture |
Projects/2026/04/02/ARTICLE - Playbook - Self-Contained Go Wasm and JavaScript Browser Applications.md |
heading-scanned | lines 1-80 | C1 | Extracted architectural playbook from SQLide; when-to-use rules |
Projects/2026/05/07/ARTICLE - md-view - Building a Daemon-Based Markdown Viewer in Go.md |
read | full file | C1 | Three-process daemon architecture: CLI/daemon/browser, SSE reload, inline everything |
Projects/2026/05/28/PROJ - md-view - Markdown Viewer Daemon.md |
read | full file | C1 | Productized status: Chroma, Mermaid, image path resolution, i3 titles |
Projects/2026/06/13/ARTICLE - Replacing md-view with a Wails v2 Desktop Application - Technical Deep Dive.md |
read | full file | C1 | Process model rewrite: daemon→Wails, RenderBody fragment contract, re-runnable augmentation |
Projects/2026/05/14/PROJECT REPORT - Go-Go Parc Website - Implementation Deployment and Git-Sync Runtime.md |
read | full file | C1 | Single-binary Go+SPA, git-sync sidecar, atomic reload, YAML normalization |
Projects/2026/06/06/PROJ - Retro Obsidian Publish - A Retro Monochrome Vault Browser.md |
read | full file | C1 | Vault browser with SSR sidecar, agent-readable mirrors, a14y 99/100 |
Projects/2026/05/19/ARTICLE - DMETA Viewer - A Go and React Single-Binary YAML Browser with Swiss Typography.md |
heading-scanned | lines 1-80 | C1 | Single-binary Go+React YAML browser; Swiss typography design system |
Projects/2026/06/18/PROJECT REPORT - Fake CMS 11ty Frontend - GraphQL to Static Site Deep Dive.md |
heading-scanned | lines 1-80 | C1 | GraphQL-to-Eleventy static site; project-local plugin pattern |
Projects/2026/04/30/PROJ - Browser-Side React Widget Runtime - In-Browser TSX Compilation and Reload.md |
read | full file | C2 | Source-as-data pipeline: esbuild-wasm, blob URL import, strict import policy, module registry |
Projects/2026/05/16/PROJECT REPORT - Fringe Admin DSL Backend Driven Admin Interfaces Deep Dive.md |
read | full file | C2 | Renderer-as-interpreter, Goja backend execution, opaque action IDs, page versioning, protobuf transport |
Projects/2026/06/04/ARTICLE - WidgetRenderer Standalone Site - Goja Authored React Rendered UI.md |
read | lines 1-120 | C2 | Goja authors Widget IR (JSON), Go serves, React renders; package separation |
Projects/2026/06/05/ARTICLE - Building a Goja UI DSL from Scratch - Widget IR to xgoja.md |
heading-scanned | lines 1-80 | C2 | Widget IR evolution: Goja→xgoja provider, five surfaces to sync |
Projects/2026/06/07/ARTICLE - Widget IR - Building a Data-First React Rendering Pipeline for RAG Evaluation.md |
read | lines 1-120 | C2 | Full data-first pipeline: authoring→IR→validation→HTTP→React; five surfaces, ActionSpec boundary |
Condensed per-arc summaries
Arc 1: SQLide Browser — Go/Wasm split architecture (C1)
- Split architecture invariant: Go handles text processing and state (SQL splitting, statement classification); SQLite's own Wasm build runs in a dedicated worker for DB operations and OPFS persistence. Go never talks to SQLite directly (
Projects/2026/04/02/PROJ - SQLide Browser - Go Wasm SQL IDE.md, lines 22-30). - Bridge lifecycle: Go module exports via
syscall/js, loaded throughgo-bridge.jswhich injectswasm_exec.js, instantiates Wasm, and polls for up to 3s for the Go module to register itself (lines 68-75). - OPFS requires COOP/COEP headers: Cross-origin isolation (
require-corp,same-origin) is mandatory; without it, OPFS silently degrades to in-memory (lines 112-120). - Working rule: "Keep the split architecture. Go does text processing and state; SQLite Wasm does database operations in a worker" (lines 130-133).
- Playbook generalization: The
04/02Playbook article extracts the pattern: use Go/Wasm when reusing Go logic, NOT when the module is a thinsyscall/jswrapper; binary size is ~2-4 MB overhead.
Arc 2: md-view daemon — CLI/daemon/browser three-process model (C1)
- Three protocols, one purpose each: Unix socket (CLI→daemon NDJSON), HTTP (daemon→browser pages), SSE (daemon→browser reload events). Never mix protocols (
Projects/2026/05/07/ARTICLE - md-view...md, lines 60-80). - Daemon start without fork: Go lacks
fork(). CLI re-executes its own binary withservesubcommand,SysProcAttr{Setpgid: true}, then polls for socket file (lines 160-175). - Inline everything: All CSS, JS, and Chroma stylesheets embedded via
go:embed. No external assets, no CDN, works offline (lines 135-145). - SSE over WebSockets: SSE is unidirectional, rides on HTTP infrastructure, close to zero incremental complexity. WebSockets' bidirectionality is unnecessary for file-change notification (lines 205-220).
- Failure mode: fsnotify watches inode, not path.
git checkoutrecreates file → watch lost, SSE stays open but no events arrive (lines 225-235). - Productized features (05/28): Chroma highlighting (200+ languages), Mermaid diagrams with MutationObserver theme re-render, relative image path rewriting via
/file/handler with directory allowlist, dark/light toggle, i3/Sway window titles.
Arc 3: md-view Wails migration — process model rewrite (C1)
- Core change: Browser moves inside the process. HTTP transport removed; Wails bound methods + events replace HTTP/SSE (
Projects/2026/06/13/ARTICLE - Replacing md-view with a Wails v2...md, lines 45-55). - Renderer survives as fragment producer:
Render(filePath, opts) -> full HTML pagebecomesRenderBody(filePath, opts) -> { Frontmatter, Body, Title }. The shell (toolbar, dropzone, content area) lives infrontend/dist/index.htmland persists across file opens (lines 80-100). - Re-runnable augmentation invariant: In a stable-shell WebView, all DOM augmentation (copy buttons, Mermaid) must be re-runnable after fragment swaps.
augment.jsexposeswindow.MDSAugmentPage()called after everyshowContent(html)(lines 105-130). - Build system cutover:
wails buildis mandatory, not plaingo build. Plaingo buildproduces a binary that fails with "Wails applications will not build without the correct build tags" (lines 155-165). - Known limitation: Linux
SingleInstanceLockuses D-Bus and did not deduplicate second launches on this machine. Code is correct by API but behavior is platform-specific (lines 170-185). - Working rules distilled: (1) If browser moves inside process, remove network transport. (2) Preserve renderer as pure component. (3) In stable-shell WebView, augmentation must be re-runnable. (4) Menu callbacks must emit events, not update DOM directly. (5) Relative file serving needs allowlist with separator-aware prefix check.
Arc 4: Go-Go Parc Website — single-binary + git-sync (C1)
- Content/application separation: Application code changes → new container image + Kubernetes rollout. Content changes → new Git commit in vault repo.
git-syncsidecar tracks vault, calls reload endpoint (Projects/2026/05/14/PROJECT REPORT - Go-Go Parc Website...md, lines 10-20, 290-310). - Atomic reload:
RuntimeState.Reload()builds new vault + search index together, swaps both under mutex. Failed reload leaves old state active (lines 170-185). - SnapshotProvider interface: Handlers ask provider for current
(*vault.Vault, *search.Index)pair, not owning vault directly. This indirection enables atomic swap without changing handlers (lines 55-65). - YAML normalization bug:
goldmark-metareturnsmap[interface{}]interface{}for nested YAML; Go JSON encoder can't serialize non-string keys. Fix: recursivenormalizeYAMLValue()moved invariant into parser (lines 140-165). - Wiki-link suffix resolution: Builds index mapping every path suffix to full slug.
[[tribal/app]]resolves toresearch/kb/tribal/app-auth. First registered suffix wins (lines 100-120). - Rollout failures as learning: SSH secret permissions (fsGroup + 0440), GHCR image pull secrets, memory limits, homepage heuristic, YAML encoding — each fix became part of deployed configuration (lines 370-440).
Arc 5: Retro Obsidian Publish — vault browser with SSR + a14y (C1)
- Single binary + SSR sidecar: Go binary serves API + embedded React SPA. Node.js Express sidecar pre-fetches data, renders via
renderToString(), returns HTML. Go reverse-proxies with SPA fallback on sidecar failure (Projects/2026/06/06/PROJ - Retro Obsidian Publish...md, lines 28-40). - No hydration mismatch: SSR renders simplified components; client uses
createRoot()withroot.textContent = ""to clear SSR content and mount fresh. SSR HTML still visible to crawlers (lines 42-55). - Agent-readable mirrors:
/index.md,/note/{slug}.mdendpoints with frontmatter, canonicalLinkheaders,## Sitemapsections. Content negotiation:Accept: text/markdownreturns markdown mirrors. a14y score 62→99 (lines 30-38). - Vault directory is single source of truth: Application reads, never writes. All data (HTML, search index, backlinks, file tree) derived from Markdown files (working rule).
- Three-container pod: app (Go), ssr (Node.js), git-sync (vault sync). Vault secrets via VaultOperator.
Arc 6: Browser-Side React Widget Runtime — source-as-data (C2)
- Core pipeline:
message source string → esbuild-wasm TSX transform → Blob URL → dynamic import(blobUrl) → React component → timeline render(Projects/2026/04/30/PROJ - Browser-Side React Widget Runtime...md, lines 25-35). - Source is data until browser imports it: Widget message is JSON on the wire. Server doesn't compile. Source becomes executable only after policy checks + esbuild transform + blob import (lines 55-70).
- Shared React instance: Runtime injects React from host via
window.__LIVE_WIDGET_HOST__.React. Prevents duplicate React / invalid hook calls. Widget authors writeReact.useState()without importing (lines 85-95). - Import-as-capability:
@live/baseand@live/chartsare virtual modules. Runtime rewrites specifiers to blob URLs pointing at host-provided facade modules. Imports become capabilities, not packages (lines 120-140). - Parser-backed import rewriting: Uses
@babel/parser(notes-module-lexer) because import analysis happens before TSX compilation and must understand JSX syntax (lines 160-175). - Widget-to-widget imports with cycle detection: Compiled widgets registered as
@live/widgets/<message-id>. Graph tracks imports/importers, rejects cycles (lines 180-200). - Not HMR, runtime module replacement: No Vite graph, no file path, no patch protocol. Custom source hash, blob URL, keyed remount with new
key(lines 75-85).
Arc 7: Fringe Admin DSL — renderer-as-interpreter (C2)
- Core rule: "Authoring may be fluent. Transport must be JSON/protobuf data. Rendering must be explicit interpretation. Domain writes must stay app-owned." (
Projects/2026/05/16/PROJECT REPORT - Fringe Admin DSL...md, lines 37-50). - Page/node/action model: Page contains shell metadata, top-level nodes (each with
kind,props, children), optional surfaces (modals, drawers). Actions carry semantic metadata (type,target,intent,presentation,placement). Browser-visibleidis generated by runtime, not a trusted command name (lines 55-90). - Renderer switches on
node.kind:renderAdminNode(node, ctx)is an explicit interpreter. Unknown kinds show fallback<pre>. No hidden mapping from backend strings to arbitrary React imports (lines 95-120). - Goja backend execution: Flow exports
initialStateandrender.ctx.bind(actionBuilder, callback)registers callbacks with opaque ids. Browser dispatches action id → session checks page version → calls Goja callback → returns new AdminPage (lines 125-160). - Page version scoping: Stale browser actions return informational toast effect instead of applying stale mutation.
event.PageVersion != s.Version→ return toast, not mutate (lines 165-180). - Persistence is app-owned:
pkg/intakeadmin/store is outsidepkg/admindsl/. Admin DSL knows how to render tables/forms; app knows what an intake request means. Host modules (host/intake-admin) are narrow, JSON-round-tripped (lines 190-230). - Component growth driven by real screens: New primitives added only when needed:
resourceTable,imageGallery,editableList,monthAvailabilityGrid,previewFrame,diffView. Each requires schema + validator + Go builder + Goja export + frontend renderer + tests + Storybook (lines 250-290). - Storybook as contract surface: Every node kind needs stories for normal, empty, mobile, and error states. If a primitive can't be described with a stable JSON fixture, its design is not ready (lines 295-330).
- Protobuf transport: Envelope is typed (
AdminFlowState,AdminPage,AdminNode);propsremainsgoogle.protobuf.Structfor evolution. Renderer receives plain TypeScript objects, independent of protobuf (lines 335-360).
Arc 8: Widget IR pipeline — Goja authors data, React renders (C2)
- Central invariant: Goja produces Widget IR (JSON), not HTML. React is the sole renderer and keeps ownership of CSS Modules, actions, and accessibility. If Go rendered HTML, it would create a second UI implementation (
Projects/2026/06/04/ARTICLE - WidgetRenderer...md, lines 40-55;Projects/2026/06/07/ARTICLE - Widget IR...md, lines 15-30). - Widget IR shape:
WidgetNode = TextNode | ElementNode | ComponentNode. All props must be JSON-serializable. No functions, React elements, or live references across boundaries (Projects/2026/06/07/..., lines 55-70). - ActionSpec boundary: React callbacks can't appear in JSON.
onAnnotationSelectActionis converted to a callback that fires server actions. Works uniformly for buttons, table rows, transcript annotations, document selections (Projects/2026/06/07/..., lines 75-85). - Five surfaces to sync: Adding a new component requires updating (1) TypeScript IR types, (2) React renderer, (3) Goja DSL helpers, (4) server schema, (5) stories/tests. Missing any surface produces visible failures (
Projects/2026/06/07/..., lines 90-110). - xgoja provider packaging: DSL wrapped as xgoja provider, generates a binary that serves React WidgetRenderer app backed by JavaScript verbs. Token bridge and default shell chrome needed for standalone visual quality (
Projects/2026/06/05/ARTICLE - Building a Goja UI DSL...md, lines 20-40). - Package separation:
pkg/widgetdsl(authoring),pkg/widgetrunner(execution/validation),pkg/widgetserver(HTTP),pkg/defaultspa(embedded frontend),pkg/widgetschema(schema metadata),packages/rag-evaluation-site(reusable React npm package) (Projects/2026/06/04/..., lines 60-80).
Topic architecture / spine
Cluster 1 spine: Local-first Go-hosted apps
flowchart LR
Source[Markdown/YAML source files] --> Renderer[Go renderer core\nRenderBody / goldmark / Chroma]
Renderer --> Fragment[HTML fragment]
Fragment --> Shell[Stable frontend shell\nSPA or Wails WebView]
Shell --> Augment[Re-runnable DOM augmentation\ncopy buttons / Mermaid / syntax highlight]
Augment --> User[Browser / desktop window]
Source --> Derived[Derived data\nBleve search / backlinks / tree]
Derived --> API[JSON REST API]
API --> Shell
Sync[git-sync sidecar] --> Reload[Atomic reload endpoint]
Reload --> Derived
Reload --> Renderer
Mirror[Agent-readable mirrors\n/index.md / SSR / a14y] --> Shell
Cluster 2 spine: Backend-driven / generated UI
flowchart LR
Authoring[JS/Goja authoring script\nrequire widget.dsl / admin flow] --> IR[Widget IR / AdminPage\nJSON-compatible data]
IR --> Validation[Go validation\nschema / node kinds / props]
Validation --> Transport[HTTP transport\nprotobuf JSON or REST]
Transport --> Renderer[React renderer\ninterpreter, not code execution]
Renderer --> Components[Real React components\nCSS Modules / accessibility]
Components --> User[Browser]
Action[Opaque action id + page version] --> Backend[Goja callback / host module]
Backend --> Store[App-owned store\nSQLite / domain writes]
Store --> NewPage[New AdminPage / Widget IR]
NewPage --> Transport
Storybook[Storybook contract surface] --> Renderer
Clusters and subclusters
Cluster A: Local-first Go-hosted browser/desktop apps
- Subcluster A1: Go/Wasm browser tools — SQLide Browser (split Go/Wasm + sqlite-wasm worker), Playbook generalization. Invariant: Go owns logic, worker owns engine; COOP/COEP required for OPFS.
- Subcluster A2: Daemon/browser productivity tools — md-view daemon (three-protocol model), md-view productized (Chroma/Mermaid/images). Invariant: one protocol per purpose; inline everything for offline.
- Subcluster A3: Desktop shell migration — Wails v2 replacement of md-view. Invariant: renderer survives as fragment producer; augmentation must be re-runnable in stable-shell WebView.
- Subcluster A4: Vault/knowledge-site publishers — Go-Go Parc Website (git-sync + atomic reload), Retro Obsidian Publish (SSR sidecar + agent mirrors), DMETA Viewer (single-binary YAML browser). Invariant: vault is read-only source of truth; content and application updates are separate loops.
- Subcluster A5: Static site generation — Fake CMS 11ty (GraphQL-to-Eleventy). Invariant: project-local plugin owns data fetching/normalization; templates remain visible for teaching.
Cluster B: Backend-driven / generated UI systems
- Subcluster B1: Browser-side widget runtime — Browser-Side React Widget Runtime (esbuild-wasm, blob URL, import-as-capability). Invariant: source is data until compiled + imported; shared React instance; strict import policy.
- Subcluster B2: Admin DSL with Goja backend — Fringe Admin DSL (renderer-as-interpreter, opaque action IDs, page versioning). Invariant: page is data, node kind is explicit, action id is opaque, host modules are narrow, app schemas are app-owned.
- Subcluster B3: Widget IR pipeline — WidgetRenderer Standalone, Widget IR to xgoja, Widget IR Data-First. Invariant: Goja authors data, React renders; Widget IR is JSON, not HTML; five surfaces must stay in sync.
- Subcluster B4: Storybook/fixture contract — Both Fringe Admin DSL and Widget IR use Storybook as a contract surface for every node/widget kind. Invariant: if a primitive can't be described with a stable JSON fixture, its design is not ready.
Recurring concepts, technologies, and failure modes
Concepts
renderer-as-fragment-producer— RenderBody returns chrome-free HTML fragment, not full pagere-runnable DOM augmentation— scripts must survive fragment swaps in stable-shell WebViewrenderer-as-interpreter— React switches on node.kind, not code executionsource-as-data— widget source is just a string until policy checks + compilationopaque action ID— browser dispatches ids, backend resolves callbackspage version scoping— stale browser actions return effects, not mutationsimport-as-capability— module registry rewrites specifiers to blob URLscontent/application separation— git-sync content updates vs image rebuild deploymentsatomic reload— vault + search index swapped together under mutexagent-readable mirror— markdown mirrors, SSR, a14y endpointssingle-binary Go + SPA—go:embedfrontend into Go binarySnapshotProvider— handlers ask provider for current state, enabling atomic swapStorybook contract surface— every node/widget kind needs fixtures for normal/empty/error/mobile statesnarrow host modules— Goja flows call app-owned APIs, not generic write accessone protocol, one purpose— Unix socket for CLI, HTTP for pages, SSE for reload
Technologies
Go/Wasm(GOOS=js GOARCH=wasm,syscall/js,wasm_exec.js)sqlite-wasm(@sqlite.org/sqlite-wasm, OPFS, OO1 API)Wails v2(bound methods, events, AssetServer.Handler, SingleInstanceLock)goldmark(GFM, Chroma highlighting, frontmatter)fsnotify(file watching, inotify inode limitation)Bleve(in-memory full-text search, fuzzy/prefix matching)esbuild-wasm(browser-side TSX compilation)@babel/parser(TSX-aware import analysis)Goja(JavaScript runtime for admin flows, Widget DSL)protobuf(AdminFlowState envelope, google.protobuf.Struct for props)Vite(frontend build, library vs app mode, COOP/COEP headers)git-sync(Kubernetes sidecar, symlink-based checkout, webhook reload)RTK Query(Redux Toolkit API data fetching, SSR cache preloading)Express(SSR sidecar, renderToString)Eleventy(static site generation, project-local plugin)
Failure modes
fsnotify inode loss— file deleted/recreated (git checkout) loses watch; SSE stays open but no eventsCOOP/COEP silent degradation— missing cross-origin isolation headers → OPFS falls back to in-memory silentlystale PID files— daemon crash without cleanup → CLI must detect and auto-recoverWails build tag failure— plaingo buildfails; must usewails buildor explicit tag setD-Bus single-instance failure— Linux SingleInstanceLock doesn't deduplicate via D-BusYAML map[interface{}]interface{}— goldmark-meta nested values not JSON-serializable; needs recursive normalizationduplicate React instances— widget imports React → invalid hook calls; must inject host Reactconcurrent esbuild initialize— multiple widgets compiling concurrently race intoesbuild.initialize; fix with memoized promisees-module-lexer TSX failure— lexer can't parse JSX before esbuild transform; must use@babel/parserschema/fixture growth outruns renderer— new widget types without Storybook coverage or renderer cases produce silent fallbacksGoja struct field name drift— Go struct JSON tags vs Goja export; fix with JSON round-trippage version staleness— browser dispatches action from old page; must return informational effect, not mutatehomepage heuristic ambiguity— fallback/indexselection picks nested source index; must prefer explicit home slugsone-shot DOM augmentation— scripts that run once per page load break when only#contentis replaced
Candidate concept-map material
Nodes
| Node | Type | Confidence | Notes |
|---|---|---|---|
Local-first web app shell |
concept | high | Single binary serving API + static frontend |
Single-binary Go + SPA |
concept | high | go:embed pattern across vault browsers, DMETA, SQLide |
Go/Wasm browser tool |
technology | high | GOOS=js GOARCH=wasm, syscall/js |
Split Go/Wasm + worker architecture |
concept | high | Go owns logic, worker owns engine |
sqlite-wasm worker |
technology | high | OPFS persistence, COOP/COEP required |
Wails desktop shell |
technology | high | Bound methods + events, AssetServer.Handler |
md-view daemon |
project | high | Three-protocol model, status: migrated to Wails |
RenderBody fragment contract |
concept | high | Renderer returns chrome-free HTML fragment |
Re-runnable DOM augmentation |
concept | high | Scripts survive fragment swaps in stable-shell WebView |
Go-Go Parc Website |
project | high | Single-binary + git-sync, status: current/production |
Retro Obsidian Publish |
project | high | Vault browser + SSR + a14y, status: current/production |
Atomic reload (vault+search) |
concept | high | RuntimeState.Reload swaps both under mutex |
SnapshotProvider |
concept | high | Handlers ask provider for current state pair |
Agent-readable web mirror |
concept | high | Markdown mirrors, SSR, a14y endpoints |
git-sync sidecar |
technology | high | Kubernetes content sync via symlink + webhook |
Content/application separation |
concept | high | Content updates ≠ application deployments |
Backend-driven UI DSL |
concept | high | UI as data transported from backend to renderer |
Widget IR |
concept | high | JSON-compatible UI node tree, not HTML |
Renderer-as-interpreter |
concept | high | React switches on node.kind, explicit cases |
Opaque action ID |
concept | high | Browser dispatches ids, backend resolves callbacks |
Page version scoping |
concept | high | Stale actions return effects, not mutations |
Storybook contract surface |
concept | high | Fixtures for every node/widget kind |
Narrow host modules |
concept | high | Goja flows call app-owned APIs |
Import-as-capability |
concept | high | Module registry rewrites specifiers to blob URLs |
Source-as-data (until compiled) |
concept | high | Widget source is string until policy + compilation |
Shared React instance |
concept | high | Host injects React, prevents duplicate copies |
Fringe Admin DSL |
project | high | Renderer-as-interpreter + Goja + protobuf, status: current |
Browser-Side React Widget Runtime |
project | high | esbuild-wasm + blob URL + import policy, status: active/experimental |
WidgetRenderer Standalone Site |
project | high | Goja-authored React-rendered UI, status: current |
Widget IR Data-First Pipeline |
project | high | Full pipeline for RAG evaluation, status: current |
esbuild-wasm |
technology | high | Browser-side TSX compilation |
@babel/parser for TSX imports |
technology | high | TSX-aware import analysis before compilation |
Five surfaces to sync |
concept | high | TS IR, renderer, Goja helpers, server schema, stories/tests |
Goja |
technology | high | JS runtime for admin flows and Widget DSL |
protobuf transport |
technology | high | AdminFlowState envelope with Struct props |
DMETA Viewer |
project | medium | Single-binary Go+React YAML browser, heading-scanned |
Fake CMS 11ty Frontend |
project | medium | GraphQL-to-static-site, heading-scanned |
Playbook: Go/Wasm browser apps |
artifact | high | Extracted architectural playbook from SQLide |
fsnotify inode loss |
failure-mode | high | Watch lost on file recreation |
Wails build tag failure |
failure-mode | high | Plain go build fails without Wails tags |
YAML map[interface{}]interface{} |
failure-mode | high | Nested YAML not JSON-serializable |
es-module-lexer TSX failure |
failure-mode | high | Lexer can't parse JSX before transform |
concurrent esbuild initialize |
failure-mode | high | Race condition on wasm initialization |
schema/fixture growth outruns renderer |
failure-mode | high | New types without coverage produce silent fallbacks |
one-shot DOM augmentation breaks on reload |
failure-mode | high | Scripts must be re-runnable in stable shell |
SPA-only shells weak for agents/search |
failure-mode | medium | Until SSR or Markdown mirrors added |
Should DMETA/Widget IR/Admin DSL be one umbrella or separate UI-IR traditions? |
open-question | medium | Three parallel UI-IR traditions with overlapping concepts |
Should Wails/md-view have its own app-shell lifecycle map? |
open-question | medium | daemon→Wails v2→Wails v3 evolution |
Edges
Single-binary Go + SPA --serves--> Local-first web app shell [high] (Projects/2026/05/14, 06/06)
Go/Wasm browser tool --uses--> Split Go/Wasm + worker architecture [high] (Projects/2026/04/02)
Split Go/Wasm + worker architecture --requires--> sqlite-wasm worker [high] (Projects/2026/04/02)
sqlite-wasm worker --requires COOP/COEP headers--> OPFS persistence [high] (Projects/2026/04/02)
md-view daemon --migrated to--> Wails desktop shell [high] (Projects/2026/06/13)
Wails desktop shell --preserves--> RenderBody fragment contract [high] (Projects/2026/06/13)
RenderBody fragment contract --enables--> Re-runnable DOM augmentation [high] (Projects/2026/06/13)
Re-runnable DOM augmentation --prevents--> one-shot DOM augmentation breaks on reload [high] (Projects/2026/06/13)
Wails desktop shell --must use--> wails build (not plain go build) [high] (Projects/2026/06/13)
Go-Go Parc Website --uses--> git-sync sidecar [high] (Projects/2026/05/14)
git-sync sidecar --calls--> Atomic reload (vault+search) [high] (Projects/2026/05/14)
Atomic reload (vault+search) --uses--> SnapshotProvider [high] (Projects/2026/05/14)
Content/application separation --enables--> git-sync sidecar [high] (Projects/2026/05/14)
Retro Obsidian Publish --adds--> Agent-readable web mirror [high] (Projects/2026/06/06)
Agent-readable web mirror --requires--> SSR sidecar [high] (Projects/2026/06/06)
Backend-driven UI DSL --compiles/transports--> Widget IR [high] (Projects/2026/05/16, 06/07)
Widget IR --interpreted by--> Renderer-as-interpreter [high] (Projects/2026/05/16, 06/04)
Renderer-as-interpreter --switches on--> node.kind [high] (Projects/2026/05/16)
Renderer-as-interpreter --validated by--> Storybook contract surface [high] (Projects/2026/05/16, 06/07)
Opaque action ID --dispatched by--> browser [high] (Projects/2026/05/16)
Opaque action ID --resolved by--> Goja callback [high] (Projects/2026/05/16)
Page version scoping --guards against--> stale browser actions [high] (Projects/2026/05/16)
Narrow host modules --called by--> Goja flows [high] (Projects/2026/05/16)
Narrow host modules --write to--> App-owned store [high] (Projects/2026/05/16)
Browser-Side React Widget Runtime --uses--> esbuild-wasm [high] (Projects/2026/04/30)
Browser-Side React Widget Runtime --enforces--> Source-as-data (until compiled) [high] (Projects/2026/04/30)
Source-as-data (until compiled) --requires--> Shared React instance [high] (Projects/2026/04/30)
Import-as-capability --rewrites specifiers via--> Module registry [high] (Projects/2026/04/30)
Module registry --must use--> @babel/parser for TSX imports [high] (Projects/2026/04/30)
es-module-lexer TSX failure --fixed by--> @babel/parser for TSX imports [high] (Projects/2026/04/30)
WidgetRenderer Standalone Site --separates--> Goja authoring / Go serving / React rendering [high] (Projects/2026/06/04)
Widget IR Data-First Pipeline --requires syncing--> Five surfaces to sync [high] (Projects/2026/06/07)
Five surfaces to sync --prevents--> schema/fixture growth outruns renderer [high] (Projects/2026/06/07)
YAML map[interface{}]interface{} --fixed by--> recursive normalizeYAMLValue [high] (Projects/2026/05/14)
fsnotify inode loss --causes--> lost file watch on recreation [high] (Projects/2026/05/07)
concurrent esbuild initialize --fixed by--> memoized initialization promise [high] (Projects/2026/04/30)
Cross-links to other topic slices
- Topic 02 (JS runtimes/goja/xgoja): Fringe Admin DSL uses Goja for backend admin flow execution; Widget IR pipeline wraps DSL as xgoja provider. Goja struct field name drift and JSON round-trip pattern shared. The
widget.dsl/rag.dslGoja native modules are direct instances of the Go-backed module provider pattern from Topic 02. - Topic 03 (typography/design systems): DMETA Viewer uses Swiss typography system (single font, single size, weight+color hierarchy). DMETA design-system compiler produces Widget IR that the React renderer consumes. Storybook contract surfaces overlap with design-system visual parity work. CSS governance patterns shared.
- Topic 04 (infra/auth/deployment): Go-Go Parc and Retro Obsidian Publish deploy via K3s GitOps with Argo CD, Vault Secrets Operator, Traefik ingress, cert-manager TLS. git-sync sidecar + reload endpoint pattern is infra-adjacent. Wails packaging touches release tooling (GoReleaser). GHCR image pull secrets and fsGroup permissions are infra concerns.
- Topic 05 (AI agents/transcripts/observability): Agent-readable web mirrors (markdown mirrors, SSR, a14y) directly serve agent observability use cases. Browser-Side React Widget Runtime was designed for chat timeline widget injection — overlaps with chat overlay/frontend tool execution. Widget IR pipeline originated in RAG evaluation system. Pinocchio web chat cleanup shares headless provider factoring.
- Topic 06 (data/RAG/search): Bleve search index in Go-Go Parc/Retro Obsidian. Widget IR pipeline is from the RAG Evaluation System. SQLite as canonical store (SQLide, intake admin). Derived search indexes rebuilt atomically with vault content. OPFS as browser-side SQLite persistence.
- Topic 01 (hardware/embedded): Wails desktop shell for reMarkable upload (md-view). Cardputer web serial demos share browser-to-device bridge pattern. Loupedeck dynamic UI runtime shares Goja-driven UI rendering concepts with Fringe Admin DSL.
Open questions and second-pass targets
- Should
DMETA / Widget IR / Admin DSLbe treated as one umbrella UI-IR node or three separate parallel traditions? They share renderer-as-interpreter and Storybook contracts but differ in transport (protobuf vs REST vs blob URL) and authoring (Goja vs browser-side TSX vs Goja+xgoja). - Should
Wails/md-viewget its own app-shell lifecycle map: daemon/browser → Wails v2 → Wails v3 bridge? The process model migration is a first-class architectural learning. - Is
Content/application separationa topic-07 concept or an infra concept? It straddles both. DMETA ViewerandFake CMS 11tywere only heading-scanned; deeper reading needed to confirm whether they introduce new architectural invariants or repeat the single-binary pattern.Fringe Admin DSLearlier reports (05/13, 05/15) andBottom-Up Admin DSL Widget IR(05/18) need deeper reading to trace the evolution from static Storybook fixtures to Goja backend.- Are there additional Widget IR recipe-level reports (06/06 RAG-EVAL DSL directory) that introduce new semantic recipes beyond the ones covered?
Start here
Projects/2026/06/13/ARTICLE - Replacing md-view with a Wails v2 Desktop Application - Technical Deep Dive.md— the most concentrated source for the process-model rewrite pattern: daemon→Wails, fragment contract, re-runnable augmentation, build cutover, and distilled working rules. This single file captures the Cluster 1 architectural evolution.Projects/2026/05/16/PROJECT REPORT - Fringe Admin DSL Backend Driven Admin Interfaces Deep Dive.md— the canonical source for the renderer-as-interpreter pattern: page/node/action model, Goja backend execution, opaque action IDs, page versioning, Storybook as contract surface, and app-owned persistence. This single file captures the Cluster 2 architectural invariants.
Report-format notes
- This condensed report follows the guidelines contract but is intentionally denser than the first-batch report: per-arc summaries are 2-5 bullets focused on invariants and design decisions, not trivia.
- Evidence ledger marks
readvsheading-scannedexplicitly. All 8 canonical files were fully read; 5 adjacent files were heading-scanned for architectural signal only. - Nodes are typed per the guidelines contract:
project,concept,technology,platform,workflow,artifact,failure-mode,open-question. - Cross-links name the specific shared concept, not just the topic number, to enable explicit bridge construction in the final map.
- The two architecture spines (Cluster 1 and Cluster 2) are kept separate because they genuinely have different data flows, even though they share concepts like
renderer-as-interpreterandStorybook contract surface.