No description
  • Go 77.6%
  • JavaScript 18.7%
  • Shell 2.1%
  • CSS 1.6%
Find a file
2026-08-17 16:41:33 -06:00
bin xmark: rename module to quorum.dev/wwww/xmark 2026-08-17 16:41:33 -06:00
cmd/xmarkgen xmark: rename module to quorum.dev/wwww/xmark 2026-08-17 16:41:33 -06:00
js xmark: rename module to quorum.dev/wwww/xmark 2026-08-17 16:41:33 -06:00
AGENTS.md xmark: rename module to quorum.dev/wwww/xmark 2026-08-17 16:41:33 -06:00
allowlists_test.go use go to generate js tag lists 2026-08-03 11:08:34 -06:00
buffer.go port xmark out of autonaut's internal/mkd 2026-08-02 17:32:04 -06:00
buffer_test.go port xmark out of autonaut's internal/mkd 2026-08-02 17:32:04 -06:00
generate.go use go to generate js tag lists 2026-08-03 11:08:34 -06:00
go.mod xmark: rename module to quorum.dev/wwww/xmark 2026-08-17 16:41:33 -06:00
go.sum port xmark out of autonaut's internal/mkd 2026-08-02 17:32:04 -06:00
prompt.go port xmark out of autonaut's internal/mkd 2026-08-02 17:32:04 -06:00
README.md xmark: rename module to quorum.dev/wwww/xmark 2026-08-17 16:41:33 -06:00
stream_test.go port xmark out of autonaut's internal/mkd 2026-08-02 17:32:04 -06:00
x-mark.md port xmark out of autonaut's internal/mkd 2026-08-02 17:32:04 -06:00
xmark.go use go to generate js tag lists 2026-08-03 11:08:34 -06:00
xmark_test.go port xmark out of autonaut's internal/mkd 2026-08-02 17:32:04 -06:00

xmark

quorum.dev/wwww/xmark — LLM-flavored markdown rendering for Go web UIs, ported out of autonaut (internal/mkd).

xmark renders markdown the way an agentic chat UI needs it:

  • Render(src string) string — markdown → sanitized HTML fragment. goldmark (GFM + chroma class-based syntax highlighting) followed by a bluemonday sanitizer. The x-mark custom elements (<x-note>, <x-sh>, <x-ref>, <x-tree>, …) and their semantic attributes survive sanitization so the client can hydrate them into rich components.
  • Buffer — accumulates streamed LLM deltas and flushes rendered fragments only at structurally safe boundaries (never mid-block, never inside an unclosed <x-*>/HTML element), so each fragment can be appended to the DOM as-is. Write(delta) per token batch, Close() at stream end, Open() to detect a live-streaming <svg> diagram.
  • SVG diagrams — a standalone (or fenced, or inline) <svg> is routed around goldmark/bluemonday, which would fragment or lowercase-mangle it, and delivered inert via RenderDiagram / RenderDiagramLive: HTML-escaped inside a div.svg-host for the client's DOMPurify pass to hydrate.
  • StylesheetCSS() — the chroma CSS for the class-based highlighting.
  • Prompt — the embedded x-mark.md authoring guide. Append it to a model's system prompt so it emits <x-*> markup and theme-aware SVG this package renders.
import "quorum.dev/wwww/xmark"

html := xmark.Render("# hello\n\n<x-note type=\"info\">hi</x-note>")

buf := xmark.New()
for delta := range stream {
    if frag := buf.Write(delta); frag != "" {
        send(frag) // append to the DOM
    }
}
send(buf.Close())

Client contract

js/ is the browser half, plain ESM with no dependencies (DOMPurify is injected by the host app):

  • js/xmark.js — createXmark({ purify, postRenderSelector }) returns the enhancers: installPurifyHooks() (teaches DOMPurify the x-mark / SVG tags and attrs), hydrateSvgHosts / hydrateXTrees, enhance(root), watch(root, { onAdded }) (re-enhance as server-rendered fragments land), installTreeToggles(), and the postRenderer safety net that lifts escaped <svg> source out of streamed text into live diagrams — always through DOMPurify.
  • js/allowlists.js — the tag/attr allowlists, generated from the Go vars (go generate ./..., see cmd/xmarkgen); allowlists_test.go fails when it's stale. Go is the single source of truth for both sanitizer layers.
  • js/xmark.css — structural styles only (svg-host hidden until hydrated, diagram sizing, the live-preview pulse). Component themes belong to the host app via the --x-* custom properties.
<script type="module">
  import { createXmark } from "./xmark.js";
  const xm = createXmark({ purify: window.DOMPurify });
  xm.installPurifyHooks();
  xm.enhance(document.body);
  xm.watch(document.body, { onAdded: () => scrollToBottom() });
  xm.installTreeToggles();
</script>

Scripts

  • bin/test — bin/fmt + bin/cibuild
  • bin/fmt — go mod tidy + go generate ./... + goimports + node syntax check of js/
  • bin/cibuild — staticcheck + go test + go vet