<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/atom.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Markata Feed</title>
  <id>https://markata.dev/feed/atom.xml</id>
  <updated>2026-11-01T00:00:00Z</updated>
  <subtitle>Documentation for Markata, the Markdown static site generator.</subtitle>
  <link href="https://markata.dev/feed/" rel="alternate" type="text/html"></link>
  <link href="https://markata.dev/feed/atom.xml" rel="self" type="application/atom+xml"></link>
  <author>
    <name>Markata</name>
  </author>
  <generator uri="https://github.com/WaylonWalker/markata">markata-go</generator>
  <entry>
    <title>Shared Markdown content starters</title>
    <id>https://markata.dev/docs/guides/content-starters/</id>
    <updated>2026-11-01T00:00:00Z</updated>
    <published>2026-11-01T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/content-starters/" rel="alternate" type="text/html"></link>
    <summary type="text">Create reusable Markdown starters for the CLI, TUI, and web workbench.</summary>
    <content type="html">&lt;p&gt;Use a Markdown starter to define how a new page begins. The same starter is&#xA;available to &lt;code&gt;markata-go new&lt;/code&gt;, its interactive TUI, and the web workbench.&lt;/p&gt;&#xA;&lt;p&gt;Create &lt;code&gt;content-templates/guide.md&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;starter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;guide&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;A structured guide with an introduction, steps, and summary.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;aliases&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;tutorial&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;_directory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;guides&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;templateKey&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;guide&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{{title}}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;{{date}}&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;published&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;tags&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Introduction&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Steps&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Summary&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The file name supplies the starter name when &lt;code&gt;name&lt;/code&gt; is omitted. &lt;code&gt;_directory&lt;/code&gt;&#xA;sets its default output directory. &lt;code&gt;description&lt;/code&gt; and &lt;code&gt;aliases&lt;/code&gt; help users find&#xA;it in the editor. These metadata keys are not copied to the new page.&lt;/p&gt;&#xA;&lt;p&gt;The shared variables are &lt;code&gt;{{title}}&lt;/code&gt;, &lt;code&gt;{{slug}}&lt;/code&gt;, &lt;code&gt;{{date}}&lt;/code&gt;, and&#xA;&lt;code&gt;{{datetime}}&lt;/code&gt;. They work in frontmatter and body text. Unknown variables stay&#xA;as written, which lets another renderer use its own syntax.&lt;/p&gt;&#xA;&lt;p&gt;Run &lt;code&gt;markata-go new --list&lt;/code&gt; to see starters, then create content with:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;markata-go new &lt;span class=&#34;s2&#34;&gt;&amp;#34;My Guide&amp;#34;&lt;/span&gt; --template guide&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The web workbench discovers starters from the same configured&#xA;&lt;code&gt;content_templates.directory&lt;/code&gt; (default: &lt;code&gt;content-templates&lt;/code&gt;). The CLI and&#xA;interactive TUI use that same directory. Existing TOML-defined templates and&#xA;built-ins remain available.&lt;/p&gt;&#xA;&lt;p&gt;See the &lt;a href=&#34;../reference/cli.md#template-system&#34;&gt;CLI reference&lt;/a&gt; and&#xA;&lt;a href=&#34;../../spec/spec/CONTENT_TEMPLATES.md&#34;&gt;starter specification&lt;/a&gt; for the full&#xA;format and precedence rules.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Static SVG visualization foundation</title>
    <id>https://markata.dev/docs/guides/static-visualizations/</id>
    <updated>2026-10-31T00:00:00Z</updated>
    <published>2026-10-31T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/static-visualizations/" rel="alternate" type="text/html"></link>
    <summary type="text">Developing backend-rendered SVG adapters with deterministic assets, dimensions, caching, and explicit limits.</summary>
    <content type="html">&lt;p&gt;Markata is developing a shared backend rendering pipeline so diagrams and charts&#xA;can arrive as &lt;strong&gt;finished SVG assets&lt;/strong&gt;, with no visualization engine running in the&#xA;reader&amp;rsquo;s browser.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Availability:&lt;/strong&gt; This is a &lt;strong&gt;developer-only foundation&lt;/strong&gt; in&#xA;&lt;code&gt;pkg/visualizations&lt;/code&gt;. There is &lt;strong&gt;no supported &lt;code&gt;d2&lt;/code&gt; or &lt;code&gt;vega-lite&lt;/code&gt; Markdown&#xA;fence&lt;/strong&gt;, site configuration section, or new &lt;code&gt;markata render&lt;/code&gt; capability yet.&#xA;The existing &lt;code&gt;mermaid&lt;/code&gt; and &lt;code&gt;chartjs&lt;/code&gt; syntax and output are unchanged.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;what-the-foundation-provides&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;What the foundation provides&lt;/span&gt; &lt;a href=&#34;#what-the-foundation-provides&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A backend renderer produces SVG bytes from a request. The common package then&#xA;checks bounded SVG output, derives intrinsic dimensions, assigns a SHA-256-based&#xA;filename, publishes the asset and emits normal HTML for a &lt;code&gt;figure&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;source + palette + font + renderer/version + options&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       |&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       v&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;backend Renderer.RenderSVG(ctx, request)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       |&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       v&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pipeline (in-process cache and concurrent coalescing)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       |&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       v&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NewSVGAsset -&amp;gt; Publish(outputDir, asset)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       |&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       v&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;figure&amp;gt;&amp;lt;img src=&amp;#34;/assets/visualizations/&amp;lt;sha256&amp;gt;.svg&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             width=&amp;#34;960&amp;#34; height=&amp;#34;540&amp;#34; alt=&amp;#34;...&amp;#34;&amp;gt;&amp;lt;/figure&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The filename depends on the exact SVG bytes; renderer cache identity also&#xA;includes the renderer version, theme content hash, and effective options.&#xA;Repeated assets can be reused by the browser or a CDN.&lt;/p&gt;&#xA;&lt;h2 id=&#34;integrate-a-backend-in-go&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Integrate a backend in Go&lt;/span&gt; &lt;a href=&#34;#integrate-a-backend-in-go&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;An adapter implements this interface (shown here for reference, not as a&#xA;working D2 integration):&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Renderer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;RenderSVG&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;visualizations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Use &lt;code&gt;visualizations.Pipeline.Compile(ctx, backend, request)&lt;/code&gt; for a rendered&#xA;&lt;code&gt;Asset&lt;/code&gt;. &lt;code&gt;visualizations.Publish(outputDir, asset)&lt;/code&gt; writes a final static&#xA;asset; &lt;code&gt;visualizations.FigureHTML(asset, alt, caption, aboveFold)&lt;/code&gt; returns&#xA;escaped markup with an explicit image width and height.&lt;/p&gt;&#xA;&lt;p&gt;The request must include all layout-affecting inputs, especially theme and&#xA;font contents. Renderers must obey context cancellation and return actionable&#xA;errors for unsupported syntax, oversized SVG output, or unavailable layout&#xA;dependencies.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; ./pkg/visualizations/...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; -race ./pkg/visualizations/...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go vet ./pkg/visualizations/...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;why-the-constraints-matter&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Why the constraints matter&lt;/span&gt; &lt;a href=&#34;#why-the-constraints-matter&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;No layout shift from unknown image dimensions:&lt;/strong&gt; the figure includes&#xA;intrinsic &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;. Responsive site CSS still has to preserve&#xA;the intended image aspect ratio.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;No visualization JavaScript on the published page:&lt;/strong&gt; the output is a&#xA;normal external SVG image, not a browser chart/canvas library.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Smaller repeat views:&lt;/strong&gt; a fingerprinted path enables stable cache&#xA;identities, but Brotli/gzip and appropriate response headers remain&#xA;hosting responsibilities.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Bounded processing:&lt;/strong&gt; one SVG has a 4 MiB uncompressed size limit, and&#xA;the in-process cache holds up to 128 assets or 32 MiB.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Clear trust boundary:&lt;/strong&gt; the XML checks reject many active/remote&#xA;constructs but are not a complete SVG sanitizer, and do &lt;strong&gt;not&lt;/strong&gt; guarantee&#xA;a fully offline page. Author-supplied images and linked resources still&#xA;need a separate output audit.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The current restrictions also reject some legitimate SVG features such&#xA;as hyperlinks, embedded images, animation, and &lt;code&gt;foreignObject&lt;/code&gt;. Test&#xA;representative outputs before using a new engine. Large embedded fonts and&#xA;complex SVG paths can still increase network and browser-paint cost.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-comes-next&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;What comes next&lt;/span&gt; &lt;a href=&#34;#what-comes-next&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;D2 is the intended first backend adapter, followed by Vega-Lite through&#xA;&lt;code&gt;vl-convert&lt;/code&gt;, once each meets compatibility and performance checks.&#xA;Site-builder integration will need base-path-aware asset links and a&#xA;version-compatible addition to the existing render asset manifest.&lt;/p&gt;&#xA;&lt;p&gt;Mermaid and Chart.js remain the supported authoring tools until those&#xA;follow-ups land. See the &lt;a href=&#34;/docs/guides/markdown/&#34;&gt;Markdown guide&lt;/a&gt;,&#xA;&lt;a href=&#34;/docs/guides/markdown-chart-fallback/&#34;&gt;accessible Chart.js figures&lt;/a&gt;,&#xA;and &lt;a href=&#34;/docs/guides/python-renderer/&#34;&gt;renderer interoperability contract&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For exact technical invariants, see&#xA;&lt;a href=&#34;https://github.com/WaylonWalker/markata/blob/main/spec/spec/STATIC_VISUALIZATIONS.md&#34;&gt;&lt;code&gt;spec/spec/STATIC_VISUALIZATIONS.md&lt;/code&gt;&lt;/a&gt;&#xA;(after this PR merges).&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Warm renderer pool for FastAPI</title>
    <id>https://markata.dev/docs/guides/python-render-pool/</id>
    <updated>2026-10-31T00:00:00Z</updated>
    <published>2026-10-31T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/python-render-pool/" rel="alternate" type="text/html"></link>
    <summary type="text">Keep Markata renderer workers warm for concurrent FastAPI requests</summary>
    <content type="html">&lt;p&gt;The Python standalone render API normally starts the bundled Go executable for&#xA;each call. Applications that render repeatedly can instead own a fixed pool of&#xA;persistent renderer processes using &lt;code&gt;RendererPool&lt;/code&gt;. The pool is started and&#xA;stopped by the application&amp;rsquo;s lifespan; &lt;strong&gt;no separate daemon or CLI setup is&#xA;required&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;fastapi-lifespan-integration&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;FastAPI lifespan integration&lt;/span&gt; &lt;a href=&#34;#fastapi-lifespan-integration&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;contextlib&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asynccontextmanager&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;fastapi&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FastAPI&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;pydantic&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;BaseModel&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;markata&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RendererPool&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Preview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BaseModel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;markdown&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@asynccontextmanager&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;lifespan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FastAPI&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RendererPool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;workers&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;max_pending&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;workspace&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;renderer_pool&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FastAPI&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lifespan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lifespan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@app.post&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/preview&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;preview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Preview&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;renderer_pool&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;markdown&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;html&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;features&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;features&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;s2&#34;&gt;&amp;#34;assets&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The pool starts all workers at startup, verifies the persistent protocol via&#xA;a capability request, and maintains a queue of idle renderers. Each worker is&#xA;one bundled Go process that handles sequential JSON-lines requests. Requests&#xA;can run concurrently across workers. The Go protocol caches configured parser&#xA;instances so subsequent requests avoid parser reinitialization too.&lt;/p&gt;&#xA;&lt;p&gt;Set &lt;code&gt;inline_assets=True&lt;/code&gt; to embed styles and scripts in the returned result&#xA;or serve &lt;code&gt;result.assets&lt;/code&gt; separately, as with &lt;code&gt;markata.render_async&lt;/code&gt;. Rendering&#xA;options &lt;code&gt;unsafe&lt;/code&gt;, &lt;code&gt;asset_base&lt;/code&gt;, and &lt;code&gt;inline_assets&lt;/code&gt; can be supplied on individual&#xA;pool requests.&lt;/p&gt;&#xA;&lt;h2 id=&#34;lifecycle-and-limits&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Lifecycle and limits&lt;/span&gt; &lt;a href=&#34;#lifecycle-and-limits&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;workers=2&lt;/code&gt; starts two subprocesses per running application process. With&#xA;&lt;code&gt;uvicorn --workers 4&lt;/code&gt;, that is &lt;strong&gt;eight&lt;/strong&gt; Go subprocesses. Size the pool&#xA;accordingly; it does not share processes across Uvicorn workers.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;max_pending=64&lt;/code&gt; limits the number of waiting requests in addition to the&#xA;currently active worker slots. When saturated, callers receive &lt;code&gt;RenderError&lt;/code&gt;&#xA;rather than growing an unbounded backlog.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;render(..., timeout=30)&lt;/code&gt; covers queue wait and rendering. A timed-out or&#xA;cancelled in-flight request kills and replaces that worker so a late result&#xA;cannot contaminate a later request.&lt;/li&gt;&#xA;&lt;li&gt;Unexpected child exit or broken protocol also replaces the affected process.&#xA;A failed replacement makes the pool report an error rather than hang forever.&lt;/li&gt;&#xA;&lt;li&gt;Exiting the lifespan terminates and reaps its child processes. Do not share&#xA;the pool across Python event loops or fork a process after starting it.&lt;/li&gt;&#xA;&lt;li&gt;Requests retain the standalone renderer&amp;rsquo;s 200,000-byte source limit. The&#xA;wire protocol has a 1 MiB request frame limit.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The pool requires a bundled Go executable supporting &lt;code&gt;markata render --stdio&lt;/code&gt;.&#xA;The original &lt;code&gt;render()&lt;/code&gt; and &lt;code&gt;render_async()&lt;/code&gt; remain backward-compatible one-shot&#xA;APIs and do &lt;strong&gt;not&lt;/strong&gt; implicitly start a pool.&lt;/p&gt;&#xA;&lt;p&gt;An optional &lt;code&gt;workspace=&#39;.&#39;&lt;/code&gt; loads Markata&amp;rsquo;s site configuration once at startup,&#xA;matching the standalone Python renderer&amp;rsquo;s workspace behavior. Restart the pool&#xA;after changing configuration. This is not an HTML sanitizer; keep &lt;code&gt;unsafe=False&lt;/code&gt; for&#xA;untrusted authored HTML and apply your application&amp;rsquo;s own safety policy.&lt;/p&gt;&#xA;&lt;h2 id=&#34;performance-verification&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Performance verification&lt;/span&gt; &lt;a href=&#34;#performance-verification&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Measure median and p95 of warm pool calls versus &lt;code&gt;render_async()&lt;/code&gt; on the same&#xA;machine, with at least 100 requests for each fixture. Also measure throughput&#xA;at concurrency 1, 2, and 4, resident memory per pool worker, initial startup&#xA;latency, and large Chart.js response transfer. The existing standalone Go&#xA;benchmarks are not end-to-end pool timings. Do not assume the same latency&#xA;until the Python-to-Go pipe and JSON costs are measured.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>PyPI installation of Go Markata using Simon Willison’s go-to-wheel</title>
    <id>https://markata.dev/docs/guides/pypi-binary-wheels/</id>
    <updated>2026-10-31T00:00:00Z</updated>
    <published>2026-10-31T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/pypi-binary-wheels/" rel="alternate" type="text/html"></link>
    <summary type="text">Decision (October 18, 2026): pip install markata should install the Go</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;Decision (October 18, 2026): &lt;code&gt;pip install markata&lt;/code&gt; should install the Go&#xA;implementation.&lt;/strong&gt; This is an intentional handoff of the existing PyPI&#xA;distribution name, not a rename of the Python import-compatible library.&#xA;Markata remains on the &lt;strong&gt;0.x&lt;/strong&gt; release line. Existing Python releases remain&#xA;immutable on PyPI and in &lt;a href=&#34;https://github.com/WaylonWalker/markata-py&#34;&gt;WaylonWalker/markata-py&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;packaging-tool&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Packaging tool&lt;/span&gt; &lt;a href=&#34;#packaging-tool&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;We use Simon Willison&amp;rsquo;s &lt;a href=&#34;https://github.com/simonw/go-to-wheel&#34;&gt;go-to-wheel&lt;/a&gt;&#xA;(version &lt;code&gt;0.2&lt;/code&gt;) to compile our &lt;code&gt;./cmd/markata&lt;/code&gt; Go CLI into eight native wheels:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Linux amd64/arm64, both glibc and musl (four wheels).&lt;/li&gt;&#xA;&lt;li&gt;macOS Intel and Apple Silicon (two wheels).&lt;/li&gt;&#xA;&lt;li&gt;Windows amd64 and arm64 (two wheels).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;code&gt;go-to-wheel&lt;/code&gt; requires the &lt;code&gt;go.mod&lt;/code&gt; directory to also be the CLI package.&#xA;Markata&amp;rsquo;s CLI is under &lt;code&gt;cmd/markata&lt;/code&gt;. Our&#xA;&lt;a href=&#34;../../scripts/build-pypi-wheels.sh&#34;&gt;&lt;code&gt;scripts/build-pypi-wheels.sh&lt;/code&gt;&lt;/a&gt;&#xA;temporarily copies its existing &lt;code&gt;main.go&lt;/code&gt; into the module root solely for&#xA;compilation, then removes it, preserving the canonical CLI implementation and&#xA;normal Go module. It sets version and commit metadata in the built binary.&lt;/p&gt;&#xA;&lt;p&gt;When installed, &lt;code&gt;markata&lt;/code&gt; is a minimal Python entry point which executes the&#xA;bundled Go binary, &lt;strong&gt;not&lt;/strong&gt; the historical Python Markata CLI or library. There&#xA;is no network download at first run and no Go compiler required on end-user&#xA;machines.&lt;/p&gt;&#xA;&lt;h2 id=&#34;build-and-test-without-publishing&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Build and test, without publishing&lt;/span&gt; &lt;a href=&#34;#build-and-test-without-publishing&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Run from the Go repository root with Go 1.27 and Python 3.10+:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m pip install &lt;span class=&#34;s1&#34;&gt;&amp;#39;go-to-wheel==0.2&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bash scripts/build-pypi-wheels.sh 0.14.0.dev0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MARKATA_WHEEL_VERSION&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;0.14.0.dev0 python scripts/check-pypi-wheels.py dist/pypi-wheels&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m venv .venv-markata&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;. .venv-markata/bin/activate&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m pip install ./dist/pypi-wheels/markata-0.14.0.dev0-py3-none-manylinux_2_17_x86_64.whl&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;markata --help&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;markata version&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;a href=&#34;../../.github/workflows/pypi-go-wheels.yml&#34;&gt;wheel CI workflow&lt;/a&gt;&#xA;automatically repeats the build and verifies tags, embedded OS executables,&#xA;metadata, installation in a clean venv, and &lt;code&gt;python -m markata&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;publishing-the-name-handoff&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Publishing the name handoff&lt;/span&gt; &lt;a href=&#34;#publishing-the-name-handoff&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;As of this documentation change, &lt;strong&gt;the public PyPI project is still Python&#xA;Markata until a Go wheel upload succeeds and is confirmed on PyPI&lt;/strong&gt;.&#xA;The existing Python release &lt;code&gt;markata==0.10.0&lt;/code&gt; remains available as a pin.&#xA;The newest prior Python prerelease is &lt;code&gt;0.11.0.dev11&lt;/code&gt;. PyPI does not permit&#xA;replacing those immutable files with Go binaries.&lt;/p&gt;&#xA;&lt;p&gt;To publish Go Markata (first proposed PyPI Go version: &lt;strong&gt;&lt;code&gt;0.14.0&lt;/code&gt;&lt;/strong&gt;), the&#xA;owner must do the following once:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Sign into the existing &lt;a href=&#34;https://pypi.org/manage/project/markata/&#34;&gt;PyPI &lt;code&gt;markata&lt;/code&gt; project&lt;/a&gt;,&#xA;open &lt;strong&gt;Publishing&lt;/strong&gt;, and add a &lt;strong&gt;GitHub Actions Trusted Publisher&lt;/strong&gt;:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;owner: &lt;code&gt;WaylonWalker&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;repository: &lt;code&gt;markata&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;workflow filename: &lt;code&gt;pypi-go-wheels.yml&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;environment: &lt;code&gt;pypi&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;In GitHub &lt;code&gt;WaylonWalker/markata&lt;/code&gt;, create or verify a &lt;strong&gt;pypi&lt;/strong&gt; environment&#xA;with protection (reviewers and restrictions to &lt;code&gt;main&lt;/code&gt;) so an unreviewed&#xA;workflow cannot publish packages.&lt;/li&gt;&#xA;&lt;li&gt;Once CI passes and the trusted publisher is configured, open &lt;strong&gt;Actions →&#xA;Go Markata PyPI wheels → Run workflow&lt;/strong&gt;, on branch &lt;code&gt;main&lt;/code&gt;, set:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;version&lt;/code&gt;: &lt;code&gt;0.14.0&lt;/code&gt; (or another approved, &lt;em&gt;unpublished&lt;/em&gt; 0.x version)&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;publish&lt;/code&gt;: true&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;confirm&lt;/code&gt;: &lt;code&gt;REPLACE_PYTHON_MARKATA_WITH_GO&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Approve the &lt;code&gt;pypi&lt;/code&gt; environment gate.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Check the resulting PyPI release and &lt;strong&gt;test a new&lt;/strong&gt; &lt;code&gt;python -m venv&lt;/code&gt; with&#xA;&lt;code&gt;python -m pip install markata&lt;/code&gt; and &lt;code&gt;markata version&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;The publish job is a separate, minimal-permission job using PyPA&#xA;&lt;code&gt;pypa/gh-action-pypi-publish&lt;/code&gt; and short-lived OIDC tokens. Pull requests,&#xA;manual dry-runs, and non-main branches never publish. An explicit confirmation&#xA;string and GitHub environment gate prevent accidental uploads.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Freeze the Python repo&amp;rsquo;s old manual PyPI release workflow&lt;/strong&gt; as part of the&#xA;handoff so a future Python release does not retake the latest PyPI version.&#xA;It currently needs owner attention because GitHub rejects branch creation in&#xA;&lt;code&gt;WaylonWalker/markata-py&lt;/code&gt;. Do not reuse its existing &lt;code&gt;pypi_password&lt;/code&gt; secret.&lt;/p&gt;&#xA;&lt;h2 id=&#34;compatibility-consequences&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Compatibility consequences&lt;/span&gt; &lt;a href=&#34;#compatibility-consequences&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Users needing the historical Python library should pin the last Python&#xA;release in a separate environment: &lt;code&gt;python -m pip install markata==0.10.0&lt;/code&gt;.&#xA;This is &lt;strong&gt;not&lt;/strong&gt; the Go executable and is not a maintained 0.x Go release.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;import markata&lt;/code&gt; from a new Go wheel is only a tiny binary-launching&#xA;wrapper; it is not API compatible with old Python Markata plugins.&lt;/li&gt;&#xA;&lt;li&gt;Existing Go binaries, &lt;code&gt;markata-go&lt;/code&gt; entry points, Kubernetes Helm settings,&#xA;and Go GitHub releases are unchanged by this PyPI handoff.&lt;/li&gt;&#xA;&lt;li&gt;On unsupported Python/platform/architecture combinations, pip may select an&#xA;&lt;em&gt;older Python release&lt;/em&gt; rather than the Go wheel. The eight-wheel matrix must&#xA;be checked before making blanket cross-platform promises.&lt;/li&gt;&#xA;&lt;li&gt;No stable Go &lt;strong&gt;1.0&lt;/strong&gt; release or repository version tag is required.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This release is an explicitly authorized new PyPI packaging path, distinct from&#xA;the earlier GitHub repository rename. The version is chosen on dispatch.&lt;/p&gt;&#xA;&lt;h2 id=&#34;current-installation-status&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Current installation status&lt;/span&gt; &lt;a href=&#34;#current-installation-status&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The PyPI handoff has occurred: current &lt;code&gt;markata&lt;/code&gt; releases install the Go CLI after a version break from the Python implementation. Historical Python wheels remain immutable and can be pinned. This handoff does not imply Python API compatibility. The release preparation steps above document the transition process, not the present installer identity.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Fast PR gate rollout</title>
    <id>https://markata.dev/docs/guides/fast-pr-gate-rollout/</id>
    <updated>2026-10-31T00:00:00Z</updated>
    <published>2026-10-31T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/fast-pr-gate-rollout/" rel="alternate" type="text/html"></link>
    <summary type="text">Staged rollout of faster Markata pull-request checks and release-safe validation.</summary>
    <content type="html">&lt;p&gt;Tracking issue: &lt;a href=&#34;https://github.com/WaylonWalker/markata/issues/1747&#34;&gt;#1747&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;current-stage-shadow-validation&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Current stage: shadow validation&lt;/span&gt; &lt;a href=&#34;#current-stage-shadow-validation&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The new &lt;a href=&#34;../../.github/workflows/pr-fast.yml&#34;&gt;Fast PR validation&lt;/a&gt; workflow provides&#xA;an always-present &lt;code&gt;PR Gate&lt;/code&gt; job on pull requests, pushes to main, merge groups,&#xA;and manual dispatch. It runs alongside existing &lt;code&gt;CI&lt;/code&gt;; &lt;strong&gt;do not replace any&#xA;required check or weaken release gates until the new check has been observed&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;PR classification is intentionally conservative:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Only changes confined to &lt;code&gt;docs/**&lt;/code&gt;, &lt;code&gt;docs-site/**&lt;/code&gt;, &lt;code&gt;README.md&lt;/code&gt;, or&#xA;&lt;code&gt;CONTRIBUTING.md&lt;/code&gt; qualify for the docs-only Go-test exemption. The existing&#xA;documentation-site workflow still validates relevant documentation changes.&lt;/li&gt;&#xA;&lt;li&gt;All other changes check gofmt on changed Go files, run a CLI build and smoke check, and &lt;code&gt;go test -short ./...&lt;/code&gt;&#xA;with the explicitly observational Build Lab characterization excluded.&lt;/li&gt;&#xA;&lt;li&gt;Python-related source/packaging changes also run &lt;code&gt;python/tests&lt;/code&gt; unit tests.&lt;/li&gt;&#xA;&lt;li&gt;Main pushes, merge-group checks, and manual runs receive the broad path.&lt;/li&gt;&#xA;&lt;li&gt;Failure to classify changed files is an error; unknown paths are &lt;strong&gt;not&lt;/strong&gt;&#xA;considered documentation-only. Patch whitespace is always verified.&lt;/li&gt;&#xA;&lt;li&gt;Use the stable job name &lt;code&gt;PR Gate&lt;/code&gt; (not the workflow name) for rulesets.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The full Linux race/coverage shards, macOS/Windows matrix, and specialized&#xA;browser/packaging checks continue to run under existing workflows.&#xA;The Docker PR job no longer repeats a separate &lt;code&gt;go test ./...&lt;/code&gt;; Docker image&#xA;build and smoke tests remain in place, and publishing still tests source before&#xA;advancing images.&lt;/p&gt;&#xA;&lt;h2 id=&#34;observed-baseline-2026-10-29-through-2026-10-31&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Observed baseline: 2026-10-29 through 2026-10-31&lt;/span&gt; &lt;a href=&#34;#observed-baseline-2026-10-29-through-2026-10-31&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Queried the repository&amp;rsquo;s completed Actions runs through October 31, identified&#xA;91 completed pull-request runs of the &lt;code&gt;CI&lt;/code&gt; workflow (47 cancelled, 32&#xA;successful, 11 failed, and 1 other conclusion), then selected the latest &lt;strong&gt;25 non-cancelled runs&lt;/strong&gt; for latency&#xA;statistics. The sample is 19 successes and 6 failures; cancelled runs are&#xA;excluded from latency percentiles, &lt;strong&gt;not&lt;/strong&gt; silently treated as successes.&lt;/p&gt;&#xA;&lt;p&gt;Wall time uses workflow &lt;code&gt;updated_at - created_at&lt;/code&gt; (an approximation which can&#xA;include rerun elapsed time); job runtime uses &lt;code&gt;completed_at - started_at&lt;/code&gt;.&#xA;Nearest-rank percentiles are reported in seconds, rounded to the nearest&#xA;second.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Measure (25 sampled PR CI runs)&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;p50&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;p90&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;CI workflow wall time&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;323s (5m23s)&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;445s (7m25s)&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Windows short tests&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;257s&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;409s&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;macOS short tests&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;118s&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;140s&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Linux core race/coverage&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;264s&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;270s&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Linux CLI/search race/coverage&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;273s&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;287s&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Linux site integration race/coverage&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;280s&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;312s&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Lint&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;186s&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;195s&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Windows has the largest p90; Linux site/CLI also contribute substantially to&#xA;the critical path. &lt;strong&gt;Do not assume Windows is always the bottleneck.&lt;/strong&gt; The&#xA;sample&amp;rsquo;s longest observed CI wall time was 1307s, associated with a rerun.&#xA;One rerun exposed inconsistent job scheduling timestamps; do not subtract&#xA;job creation times to claim accurate runner queue time without verifying the&#xA;run attempt and dependency waits.&lt;/p&gt;&#xA;&lt;p&gt;Representative runs:&#xA;&lt;a href=&#34;https://github.com/WaylonWalker/markata/actions/runs/41243717555&#34;&gt;recent success&lt;/a&gt;,&#xA;&lt;a href=&#34;https://github.com/WaylonWalker/markata/actions/runs/41220799184&#34;&gt;Linux + Windows comparison&lt;/a&gt;,&#xA;&lt;a href=&#34;https://github.com/WaylonWalker/markata/actions/runs/41133499891&#34;&gt;slow rerun&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This baseline measures the &lt;strong&gt;existing&lt;/strong&gt; CI workflow, not the newly introduced&#xA;&lt;code&gt;PR Gate&lt;/code&gt;. Repeat the same sample method after its deployment; add separate&#xA;runner queue and dependency-wait metrics from attempt-specific timestamps.&lt;/p&gt;&#xA;&lt;h2 id=&#34;baseline-and-progression&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Baseline and progression&lt;/span&gt; &lt;a href=&#34;#baseline-and-progression&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Before switching branch protection, record at least 20 completed, non-cancelled&#xA;PR runs with each workflow&amp;rsquo;s wall time (created to completion), queue delay,&#xA;job-level duration, pass/fail and critical path. Report p50/p90, not only the&#xA;fastest run. Report cancelled runs separately because frequent commits can bias&#xA;the successful sample. Include a mix of docs, Go, frontend and packaging PRs.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;Shadow:&lt;/strong&gt; Compare &lt;code&gt;PR Gate&lt;/code&gt; against the existing &lt;code&gt;CI&lt;/code&gt; check. Investigate&#xA;any disagreement (especially tests skipped by &lt;code&gt;-short&lt;/code&gt;).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Gate migration:&lt;/strong&gt; After evidence is accepted, make only &lt;code&gt;PR Gate&lt;/code&gt; and&#xA;relevant focused checks required. Keep the broad matrix on main and nightly.&#xA;Coordinate the change with the existing &lt;a href=&#34;../../spec/spec/CI.md&#34;&gt;CI specification&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Release hardening:&lt;/strong&gt; Validate immutable SHAs and artifacts before any&#xA;stable publishing or promotion. Preserve the existing release/test/sign/SBOM&#xA;checks throughout the transition.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;github-configuration-maintainer-action&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;GitHub configuration (maintainer action)&lt;/span&gt; &lt;a href=&#34;#github-configuration-maintainer-action&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The workflow itself cannot configure repository branch protection. When ready:&#xA;protect &lt;code&gt;main&lt;/code&gt; with &lt;code&gt;PR Gate&lt;/code&gt; as a required check, require a current branch or&#xA;merge-queue validation, and forbid bypasses. Do &lt;strong&gt;not&lt;/strong&gt; drop old required checks&#xA;until both are green on real PRs and the policy change has been reviewed.&#xA;For merge queue, &lt;code&gt;merge_group&lt;/code&gt; is already subscribed.&lt;/p&gt;&#xA;&lt;h3 id=&#34;rollback&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Rollback&lt;/span&gt; &lt;a href=&#34;#rollback&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Restore the existing required check set and disable/remove &lt;code&gt;pr-fast.yml&lt;/code&gt; in a&#xA;small revert PR. Docker source tests on actual publication are unchanged.&#xA;Never roll back by bypassing a failed release test or forcing a publication.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Editor workspace file tree</title>
    <id>https://markata.dev/docs/guides/renderer-site-tree/</id>
    <updated>2026-10-30T00:00:00Z</updated>
    <published>2026-10-30T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/renderer-site-tree/" rel="alternate" type="text/html"></link>
    <summary type="text">Browse a cloned Markata workspace in the Go and Python editors</summary>
    <content type="html">&lt;p&gt;Start the Go editor for a cloned site:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;markata editor --workspace ~/git/my-site --port &lt;span class=&#34;m&#34;&gt;8002&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For the Python example, set &lt;code&gt;MARKATA_LSP_WORKSPACE&lt;/code&gt; to the same site directory&#xA;before starting &lt;code&gt;examples/fastapi_editor.py&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The Files tree lists content discovered by Markata&amp;rsquo;s glob plugin. The editor&#xA;reads &lt;code&gt;markata-go.toml&lt;/code&gt;, YAML, or JSON configuration from the selected workspace.&#xA;It uses the configured glob patterns and gitignore behavior. Without a config,&#xA;it discovers Markdown under &lt;code&gt;pages/&lt;/code&gt; and &lt;code&gt;posts/&lt;/code&gt; with Markata&amp;rsquo;s defaults. The&#xA;Feeds view groups posts selected by configured feed filters. The Tags view groups&#xA;loaded documents by their frontmatter tags. The selector shows each view&amp;rsquo;s count.&lt;/p&gt;&#xA;&lt;p&gt;Select a file to load its original source, including frontmatter. Edit it and&#xA;view the Go-rendered preview. The Go workbench saves selected Markdown files to&#xA;the site after a short pause and keeps a browser recovery copy. Scratch drafts&#xA;and imported files stay in browser storage. Use the command palette to export&#xA;the active file or import a Markdown file. The scratch &lt;code&gt;draft.md&lt;/code&gt; buffer remains&#xA;available for imported documents.&lt;/p&gt;&#xA;&lt;p&gt;Only discovered files inside the selected workspace can be read or written.&#xA;Files reached through symlinks outside the workspace are excluded. Reads and&#xA;writes are limited to 200,000 bytes; a failed read or save leaves the current&#xA;editor buffer intact.&lt;/p&gt;&#xA;&lt;h2 id=&#34;api-usage&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;API usage&lt;/span&gt; &lt;a href=&#34;#api-usage&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Go applications can use &lt;code&gt;editorworkspace.New(root)&lt;/code&gt;, &lt;code&gt;Files()&lt;/code&gt;, &lt;code&gt;Read(path)&lt;/code&gt;, and &lt;code&gt;Write(path, source)&lt;/code&gt;&#xA;from &lt;code&gt;github.com/WaylonWalker/markata/pkg/editorworkspace&lt;/code&gt;. Discovery uses the&#xA;existing glob and load plugins without running a site build.&lt;/p&gt;&#xA;&lt;p&gt;Python applications can use the same implementation through the bundled binary:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;markata&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;workspace_files&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;listing&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;workspace_files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/path/to/site&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;workspace_files&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/path/to/site&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;posts/hello.md&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;source&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The CLI exposes the JSON interface as &lt;code&gt;markata workspace --workspace /path/to/site&lt;/code&gt;&#xA;and &lt;code&gt;markata workspace --workspace /path/to/site --file posts/hello.md&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The Go and FastAPI servers provide &lt;code&gt;GET /workspace&lt;/code&gt; and&#xA;&lt;code&gt;GET /workspace/file?path=posts/hello.md&lt;/code&gt;. The Go server also accepts&#xA;&lt;code&gt;PUT /workspace/file?path=posts/hello.md&lt;/code&gt; for autosave. The browser loads source&#xA;on demand.&#xA;See the &lt;a href=&#34;./go-workbench/&#34;&gt;Go editor guide&lt;/a&gt; and &lt;a href=&#34;./fastapi-editor/&#34;&gt;Python editor guide&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;site-defaults&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Site defaults&lt;/span&gt; &lt;a href=&#34;#site-defaults&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;When the selected workspace has a config, the editor applies its palette,&#xA;light/dark fallback, aesthetic, fontpack, text size, palette variables, custom CSS,&#xA;and Markdown highlighting settings. Local &lt;code&gt;palettes/&lt;/code&gt; and &lt;code&gt;aesthetics/&lt;/code&gt; catalogs&#xA;resolve from that workspace, as does an explicit &lt;code&gt;fontpacks_file&lt;/code&gt;.&#xA;Saved browser appearance preferences take priority over site defaults.&#xA;The preview remains an article preview; it does not run page templates or a site build.&lt;/p&gt;&#xA;&lt;p&gt;Python hosts can pass &lt;code&gt;workspace=&amp;quot;/path/to/site&amp;quot;&lt;/code&gt; to &lt;code&gt;appearance()&lt;/code&gt;, &lt;code&gt;render()&lt;/code&gt;,&#xA;and &lt;code&gt;render_async()&lt;/code&gt;. The JSON command equivalent is&#xA;&lt;code&gt;markata render --workspace /path/to/site --json&lt;/code&gt; (Markdown on stdin), or&#xA;&lt;code&gt;markata render --workspace /path/to/site --appearance&lt;/code&gt; for controls and assets.&lt;/p&gt;&#xA;&lt;p&gt;The editor first discovers paths and opens the selected source. Titles, tags, and&#xA;feed membership&#xA;load afterward in the background. The Tags view becomes available when metadata&#xA;is ready and builds its tree when opened. Metadata errors do not block editing.&#xA;Use &lt;code&gt;markata workspace --paths --workspace PATH&lt;/code&gt; or&#xA;&lt;code&gt;workspace_files(PATH, metadata=False)&lt;/code&gt; for discovery without parsing documents.&#xA;Server clients can request &lt;code&gt;GET /workspace?metadata=true&lt;/code&gt; when they need metadata.&lt;/p&gt;&#xA;&lt;p&gt;If the workspace contains a real &lt;code&gt;draft.md&lt;/code&gt;, the scratch buffer appears as&#xA;&lt;strong&gt;Unsaved draft.md&lt;/strong&gt; (or a numbered variant if that name also exists). Imports&#xA;open the scratch buffer, and real workspace files retain their own browser drafts.&lt;/p&gt;&#xA;&lt;h2 id=&#34;reuse-server-state&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Reuse server state&lt;/span&gt; &lt;a href=&#34;#reuse-server-state&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The Go editor retains discovered paths and parsed document metadata for its workspace.&#xA;Repeated file requests check cached membership and read only the selected source.&#xA;The server reuses its Markdown renderer until the site configuration changes.&#xA;Browser LSP sessions share parsed workspace data and keep unsaved documents private.&lt;/p&gt;&#xA;&lt;p&gt;A filesystem watcher refreshes changed documents after a short delay.&#xA;Configuration and appearance changes refresh the renderer on its next request.&#xA;A periodic scan recovers missed filesystem events.&#xA;The Files, Feeds, and Tags trees refresh when you reload the browser page.&lt;/p&gt;&#xA;&lt;p&gt;Reopening a file or reloading the page loads its latest disk content if its browser draft has no edits.&#xA;If the draft has edits, the editor preserves them.&#xA;A warning identifies disk changes when the saved draft has a source version.&#xA;Older saved drafts remain intact during migration.&#xA;The Go workbench automatically saves edits to selected workspace Markdown files.&#xA;Scratch drafts and imports stay in browser storage until you export them. The&#xA;browser retains a recovery copy if a site save fails.&lt;/p&gt;&#xA;&lt;p&gt;Go hosts can open retained state with &lt;code&gt;editorworkspace.Open(ctx, root)&lt;/code&gt;.&#xA;Use &lt;code&gt;Paths()&lt;/code&gt;, &lt;code&gt;Files()&lt;/code&gt;, &lt;code&gt;Read(path)&lt;/code&gt;, and &lt;code&gt;Snapshot()&lt;/code&gt; for cached access.&#xA;Call &lt;code&gt;Close()&lt;/code&gt; when the host stops, or cancel the parent context.&#xA;The existing &lt;code&gt;editorworkspace.New(root)&lt;/code&gt; and Python helpers keep their one-shot behavior.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Renderer integration benchmarks</title>
    <id>https://markata.dev/docs/guides/renderer-integration-benchmarks/</id>
    <updated>2026-10-29T00:00:00Z</updated>
    <published>2026-10-29T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/renderer-integration-benchmarks/" rel="alternate" type="text/html"></link>
    <summary type="text">Measured rendering, process, HTTP, and response costs for existing Markata fixtures</summary>
    <content type="html">&lt;p&gt;These measurements use existing repository fixtures with the &lt;a href=&#34;/docs/guides/fastapi-editor/&#34;&gt;FastAPI editor&lt;/a&gt;.&#xA;The benchmark includes the exact post that &lt;code&gt;BenchmarkBuild_Incremental&lt;/code&gt; edits: &lt;code&gt;benchmarks/site/posts/blog/2024/01/post-001.md&lt;/code&gt;.&#xA;The other cases come from &lt;code&gt;rendering-fixtures/&lt;/code&gt;; they are visual regression fixtures, rather than existing performance benchmarks.&lt;/p&gt;&#xA;&lt;h2 id=&#34;fixture-coverage&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Fixture coverage&lt;/span&gt; &lt;a href=&#34;#fixture-coverage&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;File&lt;/th&gt;&#xA;&lt;th&gt;Coverage&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;post-001.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Deterministic site benchmark post, including code&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;home.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Small page with minimal assets&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;markdown-chart-fallback.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Chart.js output and accessible data fallbacks&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-card-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Cards and expressive headings&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;roads.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Roads, layout styles, and initialization script&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;story-layout.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Longer structured page&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;test-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Heading syntax and typography&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Inputs retain their complete file contents, including frontmatter.&#xA;These calls measure the standalone renderer; they do not run the site build pipeline or its frontmatter loading stage.&lt;/p&gt;&#xA;&lt;h2 id=&#34;measured-timings&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Measured timings&lt;/span&gt; &lt;a href=&#34;#measured-timings&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;All values are milliseconds. The Go column shows the median of three benchmark runs.&#xA;The other columns show medians across 15 calls, except the final column.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Fixture&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Input bytes&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Go renderer&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Python render call&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;FastAPI render timer, edit&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;HTTP edit&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;HTTP edit p95&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;post-001.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1,518&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;3.05&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;137.51&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;135.02&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;136.25&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;148.45&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;home.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;426&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.40&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;128.50&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;128.24&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;129.15&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;136.19&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;markdown-chart-fallback.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1,550&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;33.04&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;476.93&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;260.01&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;264.50&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;470.84&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-card-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1,104&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.89&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;151.58&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;152.03&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;153.45&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;167.69&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;roads.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1,598&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.08&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;139.34&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;174.50&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;177.22&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;224.00&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;story-layout.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;3,900&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.46&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;156.73&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;153.57&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;154.97&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;174.24&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;test-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1,245&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.82&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;168.01&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;151.57&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;152.70&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;170.24&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;For the existing site benchmark post, Go rendering takes about 3 ms, while a Python render call takes about 138 ms.&#xA;The Python API starts a Go process for each call and decodes its JSON output.&#xA;The gap includes process initialization, serialization, pipe transfer, and Python decoding; these measurements do not isolate each part.&lt;/p&gt;&#xA;&lt;p&gt;Chart.js has higher rendering and transfer costs because its response includes vendored JavaScript and generated initialization code.&#xA;The current fragment response still sends those feature assets with each chart edit.&#xA;Keeping shared CSS loaded does not remove all repeated feature-asset bytes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;initial-document-versus-later-edits&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Initial document versus later edits&lt;/span&gt; &lt;a href=&#34;#initial-document-versus-later-edits&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Response sizes below are uncompressed JSON body bytes, rounded to KiB (1,024 bytes).&#xA;They exclude HTTP headers and separately requested appearance assets.&#xA;Initial requests include a full document; edit requests set &lt;code&gt;include_document&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Fixture&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Initial HTTP median, ms&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Edit HTTP median, ms&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Initial response, KiB&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Edit response, KiB&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Fewer response bytes&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;post-001.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;135.39&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;136.25&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;46.44&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;20.01&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;56.9%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;home.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;130.10&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;129.15&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;8.13&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.86&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;89.4%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;markdown-chart-fallback.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;432.89&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;264.50&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;460.25&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;226.92&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;50.7%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-card-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;136.74&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;153.45&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;45.55&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;19.57&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;57.0%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;roads.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;167.05&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;177.22&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;93.22&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;43.40&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;53.4%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;story-layout.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;152.85&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;154.97&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;25.48&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;9.54&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;62.6%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;test-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;154.95&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;152.70&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;13.25&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;3.42&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;74.2%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Omitting the document shell reduces response bytes in every fixture.&#xA;It does not establish a latency improvement: each mode runs separately, and host load varies between modes.&#xA;Some fragment requests therefore take longer despite their smaller responses.&lt;/p&gt;&#xA;&lt;h2 id=&#34;timing-boundaries-and-limits&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Timing boundaries and limits&lt;/span&gt; &lt;a href=&#34;#timing-boundaries-and-limits&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Go renderer:&lt;/strong&gt; &lt;code&gt;RenderStandalone&lt;/code&gt; setup, Markdown processing, asset generation, and inline tag generation. Fixture reads occur before timing starts.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Python render call:&lt;/strong&gt; synchronous &lt;code&gt;render(..., inline_assets=True, unsafe=True)&lt;/code&gt;, including process startup, output transfer, and JSON decoding.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;FastAPI render timer:&lt;/strong&gt; asynchronous &lt;code&gt;render_async(...)&lt;/code&gt;, including process startup and JSON decoding. Document construction and HTTP response encoding occur afterward.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;HTTP time:&lt;/strong&gt; request object construction, a new localhost connection, FastAPI processing, response transfer, and body reading. Request JSON encoding and response JSON decoding are excluded.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Each Python and HTTP mode has two excluded warm-up calls and 15 measured calls per file.&#xA;Every render still starts a fresh Go process; these are warm filesystem measurements, rather than a persistent renderer process.&#xA;The nearest-rank p95 equals the maximum with only 15 samples. Use more samples for stable tail-latency decisions.&lt;/p&gt;&#xA;&lt;p&gt;The measurements ran sequentially on a shared workstation with normal background activity.&#xA;They are observations from this host, rather than service limits or a controlled before-and-after experiment.&#xA;They exclude the editor&amp;rsquo;s 350 ms debounce, browser layout, chart drawing, Mermaid execution, and user-perceived paint time.&#xA;No site build cache, encryption key, or site configuration participates in these standalone calls.&lt;/p&gt;&#xA;&lt;h2 id=&#34;environment-and-raw-results&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Environment and raw results&lt;/span&gt; &lt;a href=&#34;#environment-and-raw-results&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Date: 2026-10-29 UTC.&lt;/li&gt;&#xA;&lt;li&gt;Source revision: &lt;code&gt;f226485ead9f91081e2eb3c848b3290bf1df040a&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;CPU: AMD Ryzen 5 3600, 6 cores and 12 logical CPUs.&lt;/li&gt;&#xA;&lt;li&gt;OS: &lt;code&gt;Linux-7.2.8-9-omarchy-x86_64-with-glibc2.44&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Go: &lt;code&gt;go1.26.3 linux/amd64&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Python: &lt;code&gt;3.13.13&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;FastAPI: &lt;code&gt;0.162.0&lt;/code&gt;; Uvicorn: &lt;code&gt;0.54.0&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://github.com/WaylonWalker/markata/blob/main/benchmarks/renderer-integration-2026-10-29.json&#34;&gt;JSON report&lt;/a&gt;&#xA;contains every measured sample, fixture SHA-256 hashes, and the installed binary and wrapper hashes.&#xA;The &lt;a href=&#34;https://github.com/WaylonWalker/markata/blob/main/benchmarks/renderer-go-2026-10-29.txt&#34;&gt;Go benchmark output&lt;/a&gt;&#xA;contains iteration counts, allocation counts, and all three runs.&lt;/p&gt;&#xA;&lt;h2 id=&#34;reproduce&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Reproduce&lt;/span&gt; &lt;a href=&#34;#reproduce&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Use a virtual environment with the current Markata wheel, FastAPI, and Uvicorn.&#xA;Run these commands from the repository root, sequentially:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python python/benchmark_editor.py&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; ./pkg/plugins -run &lt;span class=&#34;s1&#34;&gt;&amp;#39;^$&amp;#39;&lt;/span&gt; -bench &lt;span class=&#34;s1&#34;&gt;&amp;#39;^BenchmarkRenderStandaloneFixtures$&amp;#39;&lt;/span&gt; -benchtime&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;200ms -count&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Python script starts a temporary localhost server and stops it when the run ends.&#xA;It writes &lt;code&gt;benchmarks/renderer-integration-YYYY-MM-DD.json&lt;/code&gt; using the UTC date.&#xA;It does not replace the live editor server.&lt;/p&gt;&#xA;&lt;p&gt;Before comparing changes, keep the fixture bytes, dependency versions, machine, and renderer options the same.&#xA;Compare medians and raw samples as well as response sizes.&#xA;Useful next measurements include process initialization, JSON encoding, asset transfer, browser paint, and memory retained after repeated diagram edits.&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-server-workbench&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Go server workbench&lt;/span&gt; &lt;a href=&#34;#go-server-workbench&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;/docs/guides/go-workbench/&#34;&gt;Go workbench&lt;/a&gt; uses the same seven fixture files and the same HTTP timing boundaries.&#xA;All fixture hashes match the Python report above. The server renders directly in process and keeps one previous result in memory.&lt;/p&gt;&#xA;&lt;p&gt;Each mode uses two excluded warm-up calls and 15 measured calls.&#xA;Before every cache-miss call, a separate unmeasured request renders a small invalidator document.&#xA;This keeps the measured fixture bytes unchanged while preventing an accidental cache hit.&#xA;Every measured response checks its &lt;code&gt;cached&lt;/code&gt; field. Cached edits use the same source repeatedly without invalidation.&#xA;The invalidator request is excluded from the HTTP time and response size.&lt;/p&gt;&#xA;&lt;h3 id=&#34;http-results&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;HTTP results&lt;/span&gt; &lt;a href=&#34;#http-results&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Values are milliseconds. Each median and p95 comes from 15 calls.&#xA;The Python column comes from the earlier report; the Go columns come from a separate run on the same workstation.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Fixture&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Python HTTP edit median&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Go initial miss median&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Go edit miss median&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Go edit miss p95&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Go cached edit median&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;post-001.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;136.245&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;2.247&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;2.143&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;3.599&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.365&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;home.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;129.152&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.645&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.466&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.867&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.324&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;markdown-chart-fallback.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;264.495&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;36.032&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;28.571&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;53.724&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.295&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-card-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;153.448&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.799&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.504&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.790&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.366&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;roads.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;177.217&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.957&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.973&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.547&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.325&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;story-layout.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;154.968&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.368&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.326&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.827&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.300&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;test-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;152.701&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.838&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.805&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.721&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.293&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;For the site benchmark post, an uncached Go edit takes 2.143 ms over loopback HTTP.&#xA;A repeated cached edit takes 0.365 ms.&#xA;The earlier Python HTTP measurement for that exact file is 136.25 ms.&lt;/p&gt;&#xA;&lt;p&gt;The Go server avoids a renderer subprocess per request. It also links feature assets instead of embedding their contents in each response.&#xA;Both differences contribute to the observed gap. These runs do not isolate language or process-startup costs.&#xA;The native Go renderer benchmark uses inline assets, so it can take longer than the Go HTTP path with linked assets.&lt;/p&gt;&#xA;&lt;h3 id=&#34;response-sizes&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Response sizes&lt;/span&gt; &lt;a href=&#34;#response-sizes&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Values are uncompressed JSON body KiB. Separately requested stylesheets, libraries, and fonts are excluded.&#xA;Initial responses contain a complete document and fragment fields. Edit responses omit the document.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Fixture&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Python edit response&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Go initial response&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Go edit response&lt;/th&gt;&#xA;&lt;th style=&#34;text-align:right&#34;&gt;Go initial-to-edit reduction&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;post-001.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;20.01&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;24.62&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;8.82&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;64.2%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;home.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;0.86&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;8.99&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;1.02&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;88.6%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;markdown-chart-fallback.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;226.92&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;24.15&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;8.54&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;64.6%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-card-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;19.57&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;12.99&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;2.99&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;77.0%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;roads.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;43.40&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;19.58&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;6.30&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;67.8%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;story-layout.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;9.54&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;30.59&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;11.82&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;61.4%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;test-headings.md&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;3.42&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;16.24&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;4.65&lt;/td&gt;&#xA;&lt;td style=&#34;text-align:right&#34;&gt;71.4%&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;The Go editor retains loaded libraries and shared styles in the preview frame.&#xA;The linked-asset policy makes its chart response smaller, but the browser must fetch each dependency when it is first needed.&#xA;Response-size reductions do not include those initial asset transfers and do not establish a browser paint-time improvement.&lt;/p&gt;&#xA;&lt;h3 id=&#34;go-measurements-and-reproduction&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Go measurements and reproduction&lt;/span&gt; &lt;a href=&#34;#go-measurements-and-reproduction&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The Go run uses runtime source revision &lt;code&gt;059bb011f3314c43ca9e0c6e51d7ed735cf68790&lt;/code&gt;.&#xA;The merged parent adds benchmark tooling and documentation without changing that runtime.&#xA;The host is the same AMD Ryzen 5 3600 workstation, with 12 logical CPUs and Go 1.26.3.&#xA;The Go HTTP client uses Python 3.14.8; the earlier Python-reference client uses 3.13.13.&#xA;The comparison includes that client-version difference. The JSON report records its timestamp, OS, binary hash, and harness hash.&lt;/p&gt;&#xA;&lt;p&gt;The Go server timer includes rendering, asset registration, and optional document construction.&#xA;It excludes HTTP JSON encoding and network transfer. The Python server timer above excludes document construction.&#xA;Use HTTP measurements to compare the complete request paths.&lt;/p&gt;&#xA;&lt;p&gt;These are sequential measurements on a shared workstation, rather than a controlled before-and-after experiment.&#xA;They exclude server startup, appearance generation, cache invalidation calls, separately fetched assets, editor debounce, browser layout, and drawing.&#xA;The Go editor debounce is 250 ms. The p95 equals the maximum with 15 samples; larger runs are needed for stable tail estimates.&#xA;No site configuration, site build cache, encryption keys, or site lifecycle stages participate.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://github.com/WaylonWalker/markata/blob/feat/go-render-workbench/benchmarks/go-workbench-2026-10-29.json&#34;&gt;Go HTTP report&lt;/a&gt;&#xA;contains every sample and fixture/binary/harness hashes.&#xA;The &lt;a href=&#34;https://github.com/WaylonWalker/markata/blob/feat/go-render-workbench/benchmarks/go-workbench-native-2026-10-29.txt&#34;&gt;native Go output&lt;/a&gt;&#xA;contains three fresh runs of the parent&amp;rsquo;s renderer benchmark on the same fixtures.&lt;/p&gt;&#xA;&lt;p&gt;Run these commands sequentially from the repository root:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go build -o /tmp/markata-workbench-benchmark ./cmd/markata-workbench&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python python/benchmark_go_editor.py --binary /tmp/markata-workbench-benchmark&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; ./pkg/plugins -run &lt;span class=&#34;s1&#34;&gt;&amp;#39;^$&amp;#39;&lt;/span&gt; -bench &lt;span class=&#34;s1&#34;&gt;&amp;#39;^BenchmarkRenderStandaloneFixtures$&amp;#39;&lt;/span&gt; -benchtime&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;200ms -count&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The standard-library Python client starts a temporary Go server on an OS-assigned loopback port and stops it after the run.&#xA;It does not restart the live editor or change its cache.&#xA;Use &lt;code&gt;--samples&lt;/code&gt;, &lt;code&gt;--warmups&lt;/code&gt;, and &lt;code&gt;--output&lt;/code&gt; to control the run. The default output uses the UTC date.&lt;/p&gt;&#xA;&lt;h2 id=&#34;browser-wasm-worker&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Browser WASM worker&lt;/span&gt; &lt;a href=&#34;#browser-wasm-worker&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Start the WASM demo before the benchmark:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 scripts/wasm-workbench.py --serve&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In another terminal, run:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run --with playwright python scripts/benchmark-wasm.py --output /tmp/wasm-benchmark.json&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Use &lt;code&gt;--url&lt;/code&gt; for a different demo address. Install Playwright Chromium if the browser is unavailable.&#xA;The benchmark uses the same seven fixtures as the HTTP clients.&#xA;Each fixture uses a fresh worker, two excluded warmups, and fifteen measured renders.&#xA;The report includes raw samples, fixture hashes, browser version, median, and p95.&lt;/p&gt;&#xA;&lt;p&gt;These timings measure worker rendering. They exclude worker startup, message transfer, layout, and paint.&#xA;Do not compare them directly with HTTP request timings.&lt;/p&gt;&#xA;&lt;p&gt;Local demos use these addresses when all three run together:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Python/FastAPI: &lt;code&gt;http://127.0.0.1:8765/&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Go server: &lt;code&gt;http://127.0.0.1:8767/&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Browser WASM: &lt;code&gt;http://127.0.0.1:8766/&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;integration-verification-on-2026-10-29&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Integration verification on 2026-10-29&lt;/span&gt; &lt;a href=&#34;#integration-verification-on-2026-10-29&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Fresh reports use the &lt;code&gt;*-suite-2026-10-29.json&lt;/code&gt; names for Python and Go.&#xA;The WASM report is &lt;code&gt;benchmarks/wasm-workbench-2026-10-29.json&lt;/code&gt;.&#xA;For &lt;code&gt;post-001.md&lt;/code&gt;, the Python HTTP edit median was 149.282 ms.&#xA;The Go HTTP edit median was 2.389 ms; the cached median was 0.301 ms.&#xA;The WASM worker median was 10.9 ms.&#xA;These measurements use different timing boundaries and asset policies, as described above.&lt;/p&gt;&#xA;&lt;h2 id=&#34;shared-editor-features-and-runtime-differences&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Shared editor features and runtime differences&lt;/span&gt; &lt;a href=&#34;#shared-editor-features-and-runtime-differences&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;All three demos provide the same editor features:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;System typography, appearance controls, and Default/Vim/Emacs/Sublime keymaps.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Open .md&lt;/strong&gt; import and &lt;strong&gt;Download .md&lt;/strong&gt; export.&lt;/li&gt;&#xA;&lt;li&gt;Automatic draft recovery and visible save status.&lt;/li&gt;&#xA;&lt;li&gt;Live previews with a 250 ms edit debounce and protection against stale results.&lt;/li&gt;&#xA;&lt;li&gt;A 200,000 UTF-8 byte limit, with errors that preserve the current draft.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;An oversized import leaves the current draft intact. Download the draft before clearing browser storage.&#xA;If storage is unavailable or full, editing and downloads remain available, but drafts cannot survive closing the page.&#xA;Each origin stores its own draft and appearance settings. Different ports do not share these settings.&#xA;For a font comparison, select the same font pack and text size in each demo.&#xA;The default uses system fonts; operating systems can display different system typefaces.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Runtime behavior&lt;/th&gt;&#xA;&lt;th&gt;Python / FastAPI&lt;/th&gt;&#xA;&lt;th&gt;Go server&lt;/th&gt;&#xA;&lt;th&gt;Browser WASM&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Rendering location&lt;/td&gt;&#xA;&lt;td&gt;Server subprocess per request&lt;/td&gt;&#xA;&lt;td&gt;Directly in Go server&lt;/td&gt;&#xA;&lt;td&gt;Persistent browser worker&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Markdown transfer&lt;/td&gt;&#xA;&lt;td&gt;HTTP to local server&lt;/td&gt;&#xA;&lt;td&gt;HTTP to local server&lt;/td&gt;&#xA;&lt;td&gt;No render request&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Rich feature assets&lt;/td&gt;&#xA;&lt;td&gt;Inline response assets&lt;/td&gt;&#xA;&lt;td&gt;Linked assets reused by browser&lt;/td&gt;&#xA;&lt;td&gt;Bundled assets cached locally&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Offline reload&lt;/td&gt;&#xA;&lt;td&gt;Requires running server&lt;/td&gt;&#xA;&lt;td&gt;Requires running server&lt;/td&gt;&#xA;&lt;td&gt;Available after &lt;strong&gt;Ready offline&lt;/strong&gt;&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Authored raw HTML&lt;/td&gt;&#xA;&lt;td&gt;Enabled inside sandbox&lt;/td&gt;&#xA;&lt;td&gt;Enabled inside sandbox&lt;/td&gt;&#xA;&lt;td&gt;Disabled&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Repeated source&lt;/td&gt;&#xA;&lt;td&gt;New renderer process&lt;/td&gt;&#xA;&lt;td&gt;Last result cache&lt;/td&gt;&#xA;&lt;td&gt;Persistent renderer runtime&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Runtime differences do not require different fonts, import controls, or draft feedback.&#xA;Raw HTML and cache policies are demo choices, rather than requirements of Python, Go, or WASM.&#xA;All previews use a sandbox. Authored external images and links can still access the network.&#xA;These demos render standalone Markdown; they do not load a site&amp;rsquo;s configuration or run its complete build lifecycle.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Editor Command Palette</title>
    <id>https://markata.dev/docs/guides/editor-command-palette/</id>
    <updated>2026-10-29T00:00:00Z</updated>
    <published>2026-10-29T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/editor-command-palette/" rel="alternate" type="text/html"></link>
    <summary type="text">Insert special Markdown syntax in the Python, Go, and WASM workbenches.</summary>
    <content type="html">&lt;p&gt;Select &lt;strong&gt;Commands&lt;/strong&gt; above the Markdown editor, or press &lt;strong&gt;Ctrl+Shift+P&lt;/strong&gt;.&#xA;On macOS, press &lt;strong&gt;Cmd+Shift+P&lt;/strong&gt;. &lt;strong&gt;Ctrl/Cmd+K&lt;/strong&gt; also works.&#xA;The dialog is titled &lt;strong&gt;Command Palette&lt;/strong&gt; and works with the Default, Vim,&#xA;Emacs, and Sublime keymaps. In the Go workbench, &lt;strong&gt;Ctrl/Cmd+P&lt;/strong&gt; opens the&#xA;fuzzy file finder.&lt;/p&gt;&#xA;&lt;p&gt;Search for a command, such as &lt;code&gt;callout&lt;/code&gt;, &lt;code&gt;diagram&lt;/code&gt;, or &lt;code&gt;highlight&lt;/code&gt;.&#xA;Use the arrow keys to choose a result, then press &lt;strong&gt;Enter&lt;/strong&gt;.&#xA;You can also select a result with a mouse or touch.&#xA;Each result shows the syntax that it inserts.&lt;/p&gt;&#xA;&lt;p&gt;For example, the &lt;strong&gt;Note box&lt;/strong&gt; command inserts:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;!!! note &amp;#34;Note&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Write your note here.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The editor selects the placeholder so you can replace it immediately.&lt;/p&gt;&#xA;&lt;p&gt;In the Python and Go browser editors, the connected language service also completes&#xA;container classes and modifiers from these commands. For example, type &lt;code&gt;::::: md-i&lt;/code&gt;&#xA;to suggest &lt;code&gt;md-icon&lt;/code&gt;. Inside its attribute block, type &lt;code&gt;{data-s&lt;/code&gt; to suggest&#xA;&lt;code&gt;data-size&lt;/code&gt;, then type &lt;code&gt;data-size=&amp;quot;&lt;/code&gt; to choose &lt;code&gt;sm&lt;/code&gt; or &lt;code&gt;lg&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Inside a Mermaid fence, the language service suggests diagram types such as&#xA;&lt;code&gt;flowchart&lt;/code&gt;, &lt;code&gt;sequenceDiagram&lt;/code&gt;, and &lt;code&gt;classDiagram&lt;/code&gt;; flowchart directions; a&#xA;flowchart starter; and Mermaid class style properties. Press &lt;strong&gt;Ctrl+Space&lt;/strong&gt; to&#xA;show completions at the cursor. The WASM editor keeps the full command palette&#xA;and does not currently connect to the LSP.&#xA;If you select text before opening Commands, the command uses that text instead.&#xA;For example, &lt;strong&gt;Highlighted text&lt;/strong&gt; changes selected &lt;code&gt;important&lt;/code&gt; to &lt;code&gt;==important==&lt;/code&gt;.&#xA;Named Lucide icon commands replace selected text with the chosen icon.&#xA;Block commands add blank lines around their output to keep surrounding paragraphs separate.&#xA;Multiline selections receive the indentation required by admonitions.&#xA;Commands use the primary selection when the editor has multiple selections.&lt;/p&gt;&#xA;&lt;p&gt;Use the editor&amp;rsquo;s normal undo command to remove an insertion in one step.&#xA;The existing draft saving and preview update run after insertion.&#xA;Press &lt;strong&gt;Escape&lt;/strong&gt;, select &lt;strong&gt;Close&lt;/strong&gt;, or click outside the dialog to cancel.&#xA;The editor keeps your text and selection and receives focus again.&lt;/p&gt;&#xA;&lt;p&gt;The catalog includes 110 authoring snippets and all 2,118 icons in the bundled Lucide pack.&#xA;Search matches command names, syntax hints, and aliases.&#xA;The palette shows up to 60 results at once. Refine the search to find more specific commands.&#xA;For example, search &lt;code&gt;Lucide: zodiac-aries&lt;/code&gt; to find that icon directly.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Family&lt;/th&gt;&#xA;&lt;th&gt;Commands&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Admonitions&lt;/td&gt;&#xA;&lt;td&gt;All documented types, closed and expanded disclosures, and split columns&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Roads&lt;/td&gt;&#xA;&lt;td&gt;Winding, timeline, steps, snake, cycle, constellation, git, and editorial; story and reveal variants&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Cards and layouts&lt;/td&gt;&#xA;&lt;td&gt;Card, box, layout, columns, grid, rail, pending cards, stack, divider, connector, and story section&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Icons and feature rows&lt;/td&gt;&#xA;&lt;td&gt;Icon tile, icon feature row, generic Lucide shortcode, every bundled Lucide icon, and custom icon-pack shortcode&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Metrics&lt;/td&gt;&#xA;&lt;td&gt;Status, statistic, delta, native meter, and progress gauge&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Interactive content&lt;/td&gt;&#xA;&lt;td&gt;Checklist and Markdown source disclosure&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Mermaid&lt;/td&gt;&#xA;&lt;td&gt;Flow, sequence, class, state, entity relationship, Gantt, pie, mind map, timeline, and git diagrams&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Chart.js&lt;/td&gt;&#xA;&lt;td&gt;Bar, line, area, stacked bar, pie, doughnut, scatter, bubble, radar, and polar area&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Web Awesome&lt;/td&gt;&#xA;&lt;td&gt;Comparison, details, tabs, copy button, QR code, badge, tag, tooltip, carousel, animated image, and raw component template&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Inline extensions&lt;/td&gt;&#xA;&lt;td&gt;Highlight, keyboard keys, emoji, superscript, subscript, attributes, footnote, and definition list&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Images and citations&lt;/td&gt;&#xA;&lt;td&gt;Captioned figure, image URL, and attributed quotation&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Site features&lt;/td&gt;&#xA;&lt;td&gt;Wikilink, post embed, external embed card, YouTube embed, hover cards, table of contents, glossary frontmatter, and contribution calendar&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;Standard Markdown&lt;/td&gt;&#xA;&lt;td&gt;Table, task list, code fence, inline code, bold, italic, strikethrough, and link&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;preview-and-site-requirements&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Preview and site requirements&lt;/span&gt; &lt;a href=&#34;#preview-and-site-requirements&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The palette uses local assets in all three workbenches.&#xA;It remains available offline after the WASM workbench caches its assets.&#xA;Bundled Lucide icons, roads, article containers, metrics, Mermaid, and Chart.js render in the standalone preview.&lt;/p&gt;&#xA;&lt;p&gt;Commands for site features state their requirements in the result description.&#xA;The standalone renderers do not load a site content index or the Web Awesome plugin and custom-element runtime.&#xA;Web Awesome commands insert the documented Markdown shortcuts for a configured site build.&#xA;They do not load third-party scripts in the standalone preview.&#xA;The raw component template supports components that have no Markdown shorthand.&#xA;Replace its tag with the required Web Awesome tag.&lt;/p&gt;&#xA;&lt;p&gt;Wikilinks and post embeds need site content. External embeds need the site embed pipeline.&#xA;Hover cards and contribution calendars need their site plugins or runtime assets.&#xA;Custom icon packs need site configuration and local SVGs.&#xA;The TOC command inserts &lt;code&gt;[[toc]]&lt;/code&gt; for the site table-of-contents plugin.&#xA;Use glossary frontmatter at the start of a new glossary post.&#xA;Replace sample image paths and IDs before publishing.&lt;/p&gt;&#xA;&lt;h2 id=&#34;try-a-complete-example&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Try a complete example&lt;/span&gt; &lt;a href=&#34;#try-a-complete-example&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Open the workbench with &lt;code&gt;?example&lt;/code&gt; to load the sample in the editor and open the command palette.&#xA;For example, visit &lt;code&gt;http://localhost:8766/?example&lt;/code&gt; for the Go workbench.&#xA;In the Go workbench, use the &lt;strong&gt;Open Markdown file&lt;/strong&gt; command to import&#xA;&lt;code&gt;examples/command-palette-showcase.md&lt;/code&gt; as a scratch draft.&#xA;The example combines icon cards, a steps road, a feature row, metrics, Mermaid, and a Chart.js chart.&#xA;It also shows Web Awesome source with its site requirement clearly identified.&#xA;The chart data is illustrative.&lt;/p&gt;&#xA;&lt;p&gt;See the &lt;a href=&#34;markdown.md&#34;&gt;Markdown guide&lt;/a&gt;, &lt;a href=&#34;markdown-containers.md&#34;&gt;container guide&lt;/a&gt;,&#xA;&lt;a href=&#34;roads.md&#34;&gt;roads guide&lt;/a&gt;, &lt;a href=&#34;icons.md&#34;&gt;icon guide&lt;/a&gt;, and &lt;a href=&#34;webawesome.md&#34;&gt;Web Awesome guide&lt;/a&gt;&#xA;for syntax details. The &lt;a href=&#34;renderer-integration-benchmarks.md#shared-editor-features-and-runtime-differences&#34;&gt;editor comparison&lt;/a&gt;&#xA;explains runtime differences.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Browser WASM renderer and local workbench</title>
    <id>https://markata.dev/docs/guides/wasm-workbench/</id>
    <updated>2026-10-28T00:00:00Z</updated>
    <published>2026-10-28T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/wasm-workbench/" rel="alternate" type="text/html"></link>
    <summary type="text">Render Markata Markdown in a browser worker, with saved drafts and offline editing.</summary>
    <content type="html">&lt;p&gt;Build and serve the workbench from the repository root:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 scripts/wasm-workbench.py --serve&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Open &lt;a href=&#34;http://127.0.0.1:8766/&#34;&gt;http://127.0.0.1:8766/&lt;/a&gt;. Go and Python 3 are build requirements.&#xA;The browser downloads the Go runtime once. No Python package, Node build,&#xA;CDN, or rendering API is required. Port 8765 remains available for the&#xA;&lt;a href=&#34;fastapi-editor&#34;&gt;FastAPI editor&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Write Markdown on the left and read its preview on the right. The editor&#xA;supports Vim, Emacs, Sublime, and default keymaps. Use the appearance picker&#xA;to change the palette, aesthetic, fonts, and text size.&lt;/p&gt;&#xA;&lt;p&gt;Use &lt;strong&gt;Open .md&lt;/strong&gt; to import a document. Use &lt;strong&gt;Download .md&lt;/strong&gt; to export it.&#xA;The document limit is 200,000 UTF-8 bytes. The footer reports render time&#xA;and draft storage status. A storage error does not stop editing or export.&lt;/p&gt;&#xA;&lt;h2 id=&#34;drafts-and-offline-use&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Drafts and offline use&lt;/span&gt; &lt;a href=&#34;#drafts-and-offline-use&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Drafts and keymap preferences stay in browser storage. Drafts use a separate&#xA;key from the FastAPI editor. On first use, the workbench can copy that editor&amp;rsquo;s&#xA;draft when both apps share an origin. Different ports have separate storage.&lt;/p&gt;&#xA;&lt;p&gt;Wait for &lt;strong&gt;Ready offline&lt;/strong&gt; before disconnecting. The service worker saves the&#xA;app, WASM renderer, editor, theme assets, and fonts. You can then reload the&#xA;page and continue editing without a network connection.&lt;/p&gt;&#xA;&lt;p&gt;Browser storage can be cleared or evicted. Private browsing can restrict it.&#xA;Export files to keep durable copies. The demo edits one document at a time;&#xA;it does not sync drafts between devices or resolve edits from multiple tabs.&lt;/p&gt;&#xA;&lt;p&gt;Markdown stays on the device. External images and links in authored content&#xA;can still contact their destinations. Raw HTML is disabled. The preview runs&#xA;in a sandbox with a separate origin and cannot read the editor&amp;rsquo;s storage.&lt;/p&gt;&#xA;&lt;h2 id=&#34;use-the-worker-in-another-app&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Use the worker in another app&lt;/span&gt; &lt;a href=&#34;#use-the-worker-in-another-app&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Build the static files, then copy the generated directory to your host:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 scripts/wasm-workbench.py --output /tmp/markata-browser&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The generated &lt;code&gt;worker.js&lt;/code&gt;, &lt;code&gt;wasm_exec.js&lt;/code&gt;, and &lt;code&gt;markata.wasm&lt;/code&gt; form the rendering&#xA;entrypoint. Keep these files together. The build copies &lt;code&gt;wasm_exec.js&lt;/code&gt; from&#xA;the Go installation that builds the module.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;worker&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Worker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;./worker.js&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;worker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onmessage&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;ready&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;worker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;postMessage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;# Hello from Markata&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;revision&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;result&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;render_ms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;fatal&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The result follows the standalone renderer&amp;rsquo;s schema version 1. It includes&#xA;HTML, feature flags, ordered assets, and head/body tags. Bundled assets contain&#xA;IDs rather than their file contents. Serve those files from &lt;code&gt;appearance/&lt;/code&gt;.&#xA;Generated initializer scripts retain their contents. The sample parent app loads each dependency once. It sends cached asset contents&#xA;to the sandboxed &lt;code&gt;preview.js&lt;/code&gt;, which disposes old Chart.js instances.&lt;/p&gt;&#xA;&lt;p&gt;Inside the initialized runtime, &lt;code&gt;markataRender(source)&lt;/code&gt; returns a JSON string.&#xA;Invalid argument types, oversized documents, and render errors return an&#xA;&lt;code&gt;error&lt;/code&gt; field. The worker preserves the request&amp;rsquo;s &lt;code&gt;revision&lt;/code&gt;. Hosts must discard&#xA;stale results. Keep one render in flight and replace pending edits with the&#xA;latest source. The sample editor uses a 250 ms debounce.&lt;/p&gt;&#xA;&lt;p&gt;The renderer uses the same Go Markdown implementation as the Python API.&#xA;It supports syntax highlighting, admonitions, containers, bundled Lucide icons,&#xA;Mermaid, and Chart.js. Site discovery, frontmatter processing, feeds, and&#xA;site-dependent plugins require a full Markata build. Mermaid runs in client mode.&lt;/p&gt;&#xA;&lt;h2 id=&#34;static-hosting&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Static hosting&lt;/span&gt; &lt;a href=&#34;#static-hosting&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Serve the output over HTTPS or loopback HTTP. Service workers do not work&#xA;from &lt;code&gt;file://&lt;/code&gt; URLs. Subdirectory hosting is supported; keep relative paths intact.&lt;/p&gt;&#xA;&lt;p&gt;Serve &lt;code&gt;.wasm&lt;/code&gt; as &lt;code&gt;application/wasm&lt;/code&gt;. The loader also supports hosts with an&#xA;incorrect MIME type. Enable gzip or Brotli compression. The generated &lt;code&gt;.gz&lt;/code&gt;&#xA;files require &lt;code&gt;Content-Encoding: gzip&lt;/code&gt; and the original file&amp;rsquo;s content type.&#xA;The Python server handles these headers automatically.&lt;/p&gt;&#xA;&lt;p&gt;The parent app reads assets from its service-worker cache. It embeds preview&#xA;fonts and styles so the isolated preview can render offline. The included server&#xA;also sets CORS headers for hosts that reuse these assets. Keep &lt;code&gt;sw.js&lt;/code&gt; available&#xA;for revalidation. Each build gives its offline cache a content-derived version.&#xA;A new version activates after its complete asset bundle is cached. Reload the&#xA;tab to use a newly installed version.&lt;/p&gt;&#xA;&lt;p&gt;The initial module is larger than a JavaScript-only Markdown parser because&#xA;it includes Go, Chroma syntax highlighting, and Markata&amp;rsquo;s extensions. On the&#xA;local benchmark build, gzip reduced the module to about 6.5 MiB. Subsequent&#xA;renders reuse the runtime and parser. The worker keeps editing responsive.&lt;/p&gt;&#xA;&lt;p&gt;To serve an existing build:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 scripts/wasm-workbench.py --output /tmp/markata-browser --no-build --serve --port &lt;span class=&#34;m&#34;&gt;8766&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Stop the server with Ctrl+C. To remove an offline copy, unregister its service&#xA;worker and clear its site data in browser settings. Export the draft first.&lt;/p&gt;&#xA;&lt;h2 id=&#34;browser-checks&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Browser checks&lt;/span&gt; &lt;a href=&#34;#browser-checks&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python3 scripts/wasm-workbench.py&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run --with playwright python -m playwright install chromium&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run --with playwright python tests/wasm/test_workbench.py&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The checks cover offline reload, import/export, draft recovery, rapid edits,&#xA;repeated diagrams and charts, keymaps, mobile width, storage failures, input&#xA;limits, worker errors, and local-only network requests. Warm-render measurements&#xA;are reported without machine-specific timing assertions.&lt;/p&gt;&#xA;&lt;h2 id=&#34;shared-editor-behavior&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Shared editor behavior&lt;/span&gt; &lt;a href=&#34;#shared-editor-behavior&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Use &lt;strong&gt;Open .md&lt;/strong&gt; to import a Markdown file. An oversized file leaves the current draft intact.&#xA;Use &lt;strong&gt;Download .md&lt;/strong&gt; to keep a copy outside browser storage.&#xA;The footer reports whether the draft was saved. Storage failures leave editing and downloads available.&#xA;See &lt;a href=&#34;/docs/guides/renderer-integration-benchmarks/#shared-editor-features-and-runtime-differences&#34;&gt;shared editor features and runtime differences&lt;/a&gt; for the comparison.&lt;/p&gt;&#xA;&lt;h2 id=&#34;insert-markdown-commands&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Insert Markdown commands&lt;/span&gt; &lt;a href=&#34;#insert-markdown-commands&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Select &lt;strong&gt;Commands&lt;/strong&gt; or press &lt;strong&gt;Ctrl+Shift+P&lt;/strong&gt; (&lt;strong&gt;Cmd+Shift+P&lt;/strong&gt; on macOS).&#xA;Search for special syntax, then press &lt;strong&gt;Enter&lt;/strong&gt; to insert it at your selection.&#xA;See the &lt;a href=&#34;editor-command-palette.md&#34;&gt;command palette guide&lt;/a&gt; for the catalog and keyboard controls.&lt;/p&gt;&#xA;&lt;p&gt;Open the workbench with &lt;code&gt;?example&lt;/code&gt; to load a Markdown example and open the command palette.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Live Markdown editor with Go</title>
    <id>https://markata.dev/docs/guides/go-workbench/</id>
    <updated>2026-10-28T00:00:00Z</updated>
    <published>2026-10-28T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/go-workbench/" rel="alternate" type="text/html"></link>
    <summary type="text">Run or embed a Go server with a live Markata Markdown editor</summary>
    <content type="html">&lt;p&gt;Run the shipped Go editor command:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;markata editor --workspace ./docs&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Open the local URL printed by the command. Edit Markdown on the left and view the preview on the right.&#xA;Press Ctrl+C to stop the server. The default address is &lt;code&gt;127.0.0.1:8766&lt;/code&gt;.&#xA;For a checkout build, run &lt;code&gt;go run ./cmd/markata-go editor --workspace ./docs&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The Go server calls Markata&amp;rsquo;s standalone renderer directly. It starts no Python process and needs no WASM runtime.&#xA;It uses the same Markdown renderer as the &lt;a href=&#34;./python-renderer/&#34;&gt;Python API&lt;/a&gt; and &lt;a href=&#34;./fastapi-editor/&#34;&gt;FastAPI editor&lt;/a&gt;.&#xA;The preview does not build a site. The language service indexes Markdown and reads workspace configuration for existing mention support.&lt;/p&gt;&#xA;&lt;p&gt;Use the appearance picker to select a palette, color mode, style, font, or text size.&#xA;Open &lt;strong&gt;Editor settings&lt;/strong&gt; to choose line wrapping, keymap, and layout. Drag the&#xA;divider between the source and preview panes to resize them. Choose &lt;strong&gt;Editor&#xA;only&lt;/strong&gt; or &lt;strong&gt;Preview only&lt;/strong&gt; to focus on one pane; &lt;strong&gt;Editor and preview&lt;/strong&gt; restores&#xA;the split.&#xA;Scrolling either pane keeps the corresponding Markdown visible in the other.&#xA;When you write or move the cursor, the preview follows the editor. Scroll sync&#xA;is on by default; turn off &lt;strong&gt;Sync editor and preview scrolling&lt;/strong&gt; in &lt;strong&gt;Editor&#xA;settings&lt;/strong&gt; to scroll each pane independently. The choice is saved in this browser.&#xA;At the end of a document, both panes keep extra scroll space so the last lines&#xA;can move above the bottom edge while you write.&#xA;In split view, a subtle marker shows the corresponding preview block, with a&#xA;thin caret and &lt;strong&gt;You&lt;/strong&gt; flag at the active location. When rendered text matches&#xA;the source line, the preview caret follows the character cursor. For content&#xA;that a renderer transforms or replaces, it falls back to the nearest mapped&#xA;source position. Click rendered text to move the source caret to the matching&#xA;text when possible; links keep their normal navigation behavior. The source&#xA;pane keeps its normal caret on the actual text&#xA;cursor. With the Vim keymap, the preview caret changes shape for normal,&#xA;insert, replace, and visual modes. Preview updates preserve&#xA;unchanged blocks, and layout changes refresh the source-to-preview mapping,&#xA;including after images and fonts load. While you edit, the preview follows the&#xA;caret after the matching content update completes, including when you keep&#xA;typing on the same line. Scroll changes caused by a render or a delayed&#xA;image/font layout are not mistaken for manual scrolling. The preview marker is&#xA;subtle and marks the rendered block for the current caret line. Nested Markdown&#xA;container boundaries add source anchors to improve scroll alignment in long&#xA;sections; these markers exist only in the preview render and do not change your&#xA;source. Within nested content, the marker follows the narrowest container that&#xA;contains the caret line.&#xA;Choose Default, Vim, Emacs, or Sublime keymaps in &lt;strong&gt;Editor settings&lt;/strong&gt;.&#xA;In Vim mode, press &lt;code&gt;/&lt;/code&gt; to search forward, &lt;code&gt;?&lt;/code&gt; to search backward, then &lt;code&gt;n&lt;/code&gt; or&#xA;&lt;code&gt;N&lt;/code&gt; to move between matches.&#xA;Code highlighting, icons, admonitions, tables, checklists, Mermaid, and Chart.js use local assets.&lt;/p&gt;&#xA;&lt;p&gt;Press &lt;strong&gt;Ctrl+P&lt;/strong&gt; (&lt;strong&gt;Cmd+P&lt;/strong&gt; on macOS) to find a site file by its path, title,&#xA;slug, or tag. The finder shows the current and recently opened files when its&#xA;search is empty.&#xA;Select a result or press &lt;strong&gt;Enter&lt;/strong&gt; to open it in the editor.&#xA;Choose &lt;strong&gt;Feeds&lt;/strong&gt; or &lt;strong&gt;Tags&lt;/strong&gt; in the workspace selector to browse posts by feed&#xA;or tag. Feed names are shown as roots with folders relative to the workspace.&lt;/p&gt;&#xA;&lt;p&gt;Edits to selected site files save back to the workspace after a short pause.&#xA;Unsaved scratch documents stay in browser storage. The browser also keeps a&#xA;recovery copy of workspace edits. Use &lt;strong&gt;Ctrl+Shift+P&lt;/strong&gt; and search for &lt;strong&gt;Download&#xA;current file&lt;/strong&gt; to export a copy, or &lt;strong&gt;Open Markdown file&lt;/strong&gt; to import a file as&#xA;an unsaved draft.&#xA;A storage error appears beside the render metrics. Editing and downloads remain available.&#xA;The server writes only selected workspace files. Scratch drafts remain local to&#xA;the browser origin, so drafts on one port remain separate from drafts on another.&#xA;Workspace saves and new-post creation require a same-origin browser request.&#xA;The server rejects missing or foreign origins before it changes a site file.&lt;/p&gt;&#xA;&lt;p&gt;The preview updates after a 100 ms pause. One request runs at a time, and newer edits replace pending edits.&#xA;Old responses cannot replace a newer draft. Errors preserve the last successful preview.&#xA;The footer shows Go render time, total edit-to-preview time, source size, and preview size.&#xA;Repeated source uses a one-entry memory cache. Appearance changes update the preview without a render request.&#xA;Workspace post embeds in &lt;code&gt;&amp;lt;!-- embed not found: post-slug --&amp;gt; ![[post-slug]]&lt;/code&gt; or &lt;code&gt;![embed](path/to/post.md)&lt;/code&gt; format&#xA;render as cards linked to the matching site post. Fenced code examples remain&#xA;literal source.&lt;/p&gt;&#xA;&lt;h2 id=&#34;language-assistance&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Language assistance&lt;/span&gt; &lt;a href=&#34;#language-assistance&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The editor connects to the existing Markata LSP through &lt;code&gt;/lsp&lt;/code&gt; over WebSocket.&#xA;The server indexes the directory from &lt;code&gt;--workspace&lt;/code&gt;. The default directory is the current directory.&#xA;The browser LSP accepts same-origin connections on &lt;code&gt;localhost&lt;/code&gt; or a loopback IP only.&lt;/p&gt;&#xA;&lt;p&gt;Type &lt;code&gt;[[&lt;/code&gt; for wiki-link suggestions, including aliases. Type &lt;code&gt;[label](&lt;/code&gt; for Markdown document paths.&#xA;Automatic suggestions wait for a short typing pause. Press &lt;strong&gt;Ctrl+Space&lt;/strong&gt; to request suggestions immediately at the cursor. Use the arrow keys and Enter to select a suggestion.&#xA;Existing frontmatter, admonition, and mention completion also use the LSP.&#xA;Broken wiki links receive an underline. The underline tooltip shows the diagnostic message.&#xA;The workbench preview resolves valid &lt;code&gt;[[wikilinks]]&lt;/code&gt; against the site&amp;rsquo;s workspace index.&#xA;Click a resolved wikilink in the preview to open that post in the editor.&#xA;Select the error and warning counts in the bottom status bar to inspect diagnostics and&#xA;jump to their source locations.&lt;/p&gt;&#xA;&lt;p&gt;The editor sends unsaved text as a synthetic &lt;code&gt;.markata/browser-draft.md&lt;/code&gt; document.&#xA;This document stays in memory. Markdown path suggestions start at the workspace root because the draft has no source file.&#xA;The Files tree opens source files from the selected workspace using Markata glob rules. The Feeds view groups files by configured feed filters, and the Tags view groups them by loaded frontmatter. The selector shows file, feed, and tag counts. See &lt;a href=&#34;./renderer-site-tree/&#34;&gt;workspace navigation&lt;/a&gt;.&#xA;Each WebSocket connection owns its own draft and index. Reload the page to index external file changes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;edit-page-properties&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Edit page properties&lt;/span&gt; &lt;a href=&#34;#edit-page-properties&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Select a site file, then choose &lt;strong&gt;Properties&lt;/strong&gt; to edit its frontmatter in the&#xA;full-height page-details view. The live preview stays visible beside it. Choose&#xA;&lt;strong&gt;Back to Markdown&lt;/strong&gt; to return to the source, or &lt;strong&gt;Edit YAML&lt;/strong&gt; to work directly&#xA;with the frontmatter block. Press &lt;strong&gt;Escape&lt;/strong&gt; to return to the article. The&#xA;command palette also has actions to open page details, add a property, and&#xA;return to Markdown.&lt;/p&gt;&#xA;&lt;p&gt;The page summary shows the title, URL slug or source path, and publication&#xA;state. Common fields appear first. Choose &lt;strong&gt;Add property&lt;/strong&gt;, search for a known&#xA;field, and select it.&#xA;Open &lt;strong&gt;Custom property&lt;/strong&gt; to add a site-specific YAML field. Edit tags as chips:&#xA;remove one tag at a time or enter a tag and choose &lt;strong&gt;Add&lt;/strong&gt;. Advanced fields&#xA;remain available under &lt;strong&gt;Show advanced properties&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Property edits update the Markdown source and use the normal workspace save&#xA;and preview behavior. Press &lt;strong&gt;Ctrl+Z&lt;/strong&gt; or &lt;strong&gt;Cmd+Z&lt;/strong&gt; to undo an edit. Use&#xA;&lt;strong&gt;Remove&lt;/strong&gt; to delete a property from the page.&lt;/p&gt;&#xA;&lt;p&gt;The footer reports the language connection state. Editing and preview continue if the connection fails.&#xA;Reload the page to reconnect. The browser adapter is shared with the &lt;a href=&#34;./fastapi-editor/&#34;&gt;FastAPI example&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For an embedded application, use &lt;code&gt;workbench.NewWithWorkspace(ctx, root)&lt;/code&gt;.&#xA;Cancel &lt;code&gt;ctx&lt;/code&gt; during shutdown to close active language connections.&#xA;&lt;code&gt;workbench.New()&lt;/code&gt; uses the current directory and the lifetime of the application.&lt;/p&gt;&#xA;&lt;h3 id=&#34;websocket-protocol&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;WebSocket protocol&lt;/span&gt; &lt;a href=&#34;#websocket-protocol&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;GET /lsp/config&lt;/code&gt; returns &lt;code&gt;rootUri&lt;/code&gt; and &lt;code&gt;documentUri&lt;/code&gt; for the selected workspace.&#xA;Connect to &lt;code&gt;/lsp&lt;/code&gt; with the page origin. Each WebSocket text message contains one JSON-RPC object.&#xA;WebSocket messages omit the stdio &lt;code&gt;Content-Length&lt;/code&gt; headers.&#xA;Send &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;initialized&lt;/code&gt;, and &lt;code&gt;textDocument/didOpen&lt;/code&gt; before language requests.&#xA;The session accepts the synthetic draft URI from the configuration response.&#xA;The server ignores browser workspace-change notifications and overrides the client workspace during initialization.&lt;/p&gt;&#xA;&lt;p&gt;Browser completion responses contain at most 200 suggestions. More specific text requests a new list.&#xA;Messages have a 2 MiB limit. A disconnect releases the session.&#xA;The endpoint rejects missing or foreign origins. It provides no authentication or shared workspace management.&#xA;Keep this example on a trusted local address.&lt;/p&gt;&#xA;&lt;h2 id=&#34;embed-the-handler&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Embed the handler&lt;/span&gt; &lt;a href=&#34;#embed-the-handler&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Mount the handler at the root of a dedicated origin:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;github.com/WaylonWalker/markata/pkg/workbench&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workbench&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;New&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fatal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Addr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;127.0.0.1:8767&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;handler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ReadHeaderTimeout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Second&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Fatal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;server&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ListenAndServe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Create one handler at startup. It prepares the shared appearance bundle once.&#xA;The handler owns no listeners, signal handlers, or application configuration.&#xA;A future builder can embed it without the demo command.&lt;/p&gt;&#xA;&lt;h2 id=&#34;render-api&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Render API&lt;/span&gt; &lt;a href=&#34;#render-api&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl http://127.0.0.1:8767/render &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -H &lt;span class=&#34;s1&#34;&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -d &lt;span class=&#34;s1&#34;&gt;&amp;#39;{&amp;#34;markdown&amp;#34;:&amp;#34;# Hello Go&amp;#34;,&amp;#34;appearance&amp;#34;:{&amp;#34;data-theme&amp;#34;:&amp;#34;light&amp;#34;}}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first editor request receives a complete preview document. Later requests use &lt;code&gt;&amp;quot;include_document&amp;quot;: false&lt;/code&gt; and receive fragments.&#xA;The iframe keeps its document, shared styles, and loaded libraries between edits.&#xA;New features add their styles once; removed features remove their conditional styles.&#xA;Chart instances are destroyed before replacement, and feature scripts initialize the new content.&lt;/p&gt;&#xA;&lt;p&gt;The JSON response contains &lt;code&gt;document&lt;/code&gt;, &lt;code&gt;html&lt;/code&gt;, &lt;code&gt;feature_head_html&lt;/code&gt;, &lt;code&gt;body_end_html&lt;/code&gt;, and &lt;code&gt;cached&lt;/code&gt;.&#xA;Metrics include &lt;code&gt;render_ms&lt;/code&gt;, &lt;code&gt;input_bytes&lt;/code&gt;, &lt;code&gt;html_bytes&lt;/code&gt;, and &lt;code&gt;document_bytes&lt;/code&gt;.&#xA;With &lt;code&gt;include_document&lt;/code&gt; set to false, &lt;code&gt;document&lt;/code&gt; is null and &lt;code&gt;document_bytes&lt;/code&gt; is zero.&#xA;Omit this option to retain the original full-document response.&#xA;The &lt;code&gt;Server-Timing&lt;/code&gt; response header also reports render time.&#xA;&lt;code&gt;document&lt;/code&gt; contains a complete HTML preview with links to this server&amp;rsquo;s assets.&#xA;Keep the server available while you view the document.&lt;/p&gt;&#xA;&lt;p&gt;Optional appearance keys are &lt;code&gt;data-theme&lt;/code&gt;, &lt;code&gt;data-palette&lt;/code&gt;, &lt;code&gt;data-aesthetic&lt;/code&gt;, &lt;code&gt;data-fontpack&lt;/code&gt;, and &lt;code&gt;data-text-size&lt;/code&gt;.&#xA;Values must occur in the bundled appearance catalogs.&#xA;The API rejects unknown fields, malformed JSON, and invalid appearance choices with HTTP 400.&#xA;It returns HTTP 413 for source above 200,000 UTF-8 bytes or a request above 1 MiB.&#xA;Requests need &lt;code&gt;application/json&lt;/code&gt;. Cross-origin render requests receive HTTP 403.&lt;/p&gt;&#xA;&lt;p&gt;The handler runs one render at a time. Canceled requests leave the queue before rendering.&#xA;An active render completes before the next render starts.&#xA;The browser stops waiting after 30 seconds. The demo server has read and write timeouts.&lt;/p&gt;&#xA;&lt;p&gt;This editor supports trusted local authoring. Authored HTML and styles remain available inside an opaque-origin iframe sandbox.&#xA;Only renderer-generated scripts run during fragment updates. Reload the page to apply changes to authored scripts.&#xA;Preview scripts cannot read the editor&amp;rsquo;s DOM or storage. Authored links and images can access external networks.&#xA;Keep the default loopback binding for local use. Add authentication and suitable resource controls before remote deployment.&lt;/p&gt;&#xA;&lt;p&gt;All built-in assets come from the server. Offline reload is not supported.&#xA;For site builds and site-specific plugins, use the normal &lt;a href=&#34;../reference/cli/&#34;&gt;CLI&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;check-persistent-preview-updates&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Check persistent preview updates&lt;/span&gt; &lt;a href=&#34;#check-persistent-preview-updates&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Start the Go workbench, then run its browser regression tests:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MARKATA_GO_WORKBENCH_URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;http://127.0.0.1:8767 &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MARKATA_TEST_CHROMIUM&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/bin/chromium &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run --with playwright python python/test_go_editor_browser.py -v&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Set &lt;code&gt;MARKATA_TEST_CHROMIUM&lt;/code&gt; to your Chromium executable.&#xA;The tests check retained stylesheets, fragment responses, conditional styles, charts, and diagrams.&lt;/p&gt;&#xA;&lt;h2 id=&#34;benchmark-the-server&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Benchmark the server&lt;/span&gt; &lt;a href=&#34;#benchmark-the-server&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;/docs/guides/renderer-integration-benchmarks/#go-server-workbench&#34;&gt;integration benchmark guide&lt;/a&gt; compares seven existing fixtures with the Python reference.&#xA;It separates initial renders, uncached edits, and cached edits. Raw samples and reproduction commands are included.&lt;/p&gt;&#xA;&lt;h2 id=&#34;shared-editor-behavior&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Shared editor behavior&lt;/span&gt; &lt;a href=&#34;#shared-editor-behavior&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Use the command palette to import or export a Markdown file. An oversized import leaves the current document intact.&#xA;Search for &lt;strong&gt;New Post&lt;/strong&gt; in the command palette to open a fuzzy picker for&#xA;built-in starters and &lt;code&gt;.md&lt;/code&gt; files in the site&amp;rsquo;s &lt;code&gt;templates/&lt;/code&gt; directory. Choose&#xA;a starter to open its details form. The title and destination folder start with&#xA;template defaults. The slug field stays empty when using the suggestion; its&#xA;ghost text and the destination path update as the title changes. Enter a custom&#xA;slug only when you want to override the title-derived filename. Creating the&#xA;post opens the new file in the editor, where later edits autosave to the site.&#xA;The footer reports whether the draft was saved. Storage failures leave editing and downloads available.&#xA;See &lt;a href=&#34;/docs/guides/renderer-integration-benchmarks/#shared-editor-features-and-runtime-differences&#34;&gt;shared editor features and runtime differences&lt;/a&gt; for the comparison.&lt;/p&gt;&#xA;&lt;h2 id=&#34;command-palette-and-markdown-commands&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Command palette and Markdown commands&lt;/span&gt; &lt;a href=&#34;#command-palette-and-markdown-commands&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Select &lt;strong&gt;Commands&lt;/strong&gt; or press &lt;strong&gt;Ctrl+Shift+P&lt;/strong&gt; (&lt;strong&gt;Cmd+Shift+P&lt;/strong&gt; on macOS).&#xA;Search for special syntax, then press &lt;strong&gt;Enter&lt;/strong&gt; to insert it at your selection.&#xA;See the &lt;a href=&#34;editor-command-palette.md&#34;&gt;command palette guide&lt;/a&gt; for the catalog and keyboard controls.&lt;/p&gt;&#xA;&lt;p&gt;To open the command palette with a complete example loaded, visit &lt;code&gt;/?example&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;review-changes-before-publishing-experimental&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Review changes before publishing (experimental)&lt;/span&gt; &lt;a href=&#34;#review-changes-before-publishing-experimental&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;When editing a Markdown file inside a Git-backed workspace, select &lt;strong&gt;Publish&lt;/strong&gt;&#xA;in the upper-right header, search for &lt;strong&gt;Publishing: Review &amp;amp; Publish&lt;/strong&gt; in the&#xA;command palette, or press &lt;strong&gt;Ctrl/Cmd+S&lt;/strong&gt; or &lt;strong&gt;Ctrl/Cmd+Shift+Enter&lt;/strong&gt;. Vim mode&#xA;also accepts &lt;code&gt;:w&lt;/code&gt;; Emacs mode accepts &lt;strong&gt;Ctrl-X Ctrl-S&lt;/strong&gt;. Each opens the same&#xA;review dialog; none of them publishes immediately.&lt;/p&gt;&#xA;&lt;p&gt;The dialog first waits until the exact text in the editor has been saved to&#xA;the workspace. It then compares that saved source with the file from the last&#xA;Git commit. &lt;strong&gt;Rendered diff&lt;/strong&gt; opens first. &lt;strong&gt;Side by side&lt;/strong&gt; shows both rendered&#xA;versions and keeps matching sections in view while you scroll; mobile can switch&#xA;between versions by tapping or swiping. &lt;strong&gt;Source diff&lt;/strong&gt; shows unified Markdown,&#xA;and &lt;strong&gt;Full diff&lt;/strong&gt; opens the detailed source viewer. The &lt;strong&gt;Commit message&lt;/strong&gt; tab&#xA;shows the message for the local commit and lets you edit it. Metadata chips&#xA;identify draft/published flag changes, slug changes, and conflicting publication&#xA;flags.&lt;/p&gt;&#xA;&lt;p&gt;The review can create a local Git commit for the selected page, using the&#xA;message shown in the &lt;strong&gt;Commit message&lt;/strong&gt; tab. After that commit, &lt;strong&gt;Push to&#xA;origin&lt;/strong&gt; is a separate action. Pushing does not prove that a deployment&#xA;succeeded; when Builder Admin verification is configured, &lt;strong&gt;Check live status&lt;/strong&gt;&#xA;can confirm the deployed source revision. “Last committed” is not necessarily&#xA;the live site revision. A scratch file must first be created or opened as a&#xA;workspace Markdown post. If the workspace has no Git history, the review&#xA;reports this rather than assuming a baseline.&lt;/p&gt;&#xA;&lt;p&gt;The publish contract and planned deployment safety gates are defined in&#xA;&lt;a href=&#34;../../spec/spec/EDITOR_PUBLISHING.md&#34;&gt;Editor publishing&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;verify-a-remote-publication-with-builder-admin-opt-in&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Verify a remote publication with Builder Admin (opt-in)&lt;/span&gt; &lt;a href=&#34;#verify-a-remote-publication-with-builder-admin-opt-in&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Publishing has deliberately separate steps: review the exact Markdown and&#xA;frontmatter, commit only that selected page, then explicitly push to &lt;code&gt;origin&lt;/code&gt;.&#xA;A successful push &lt;strong&gt;does not&lt;/strong&gt; prove the site is live.&lt;/p&gt;&#xA;&lt;p&gt;For a site deployed through Markata Builder Admin, the local editor can&#xA;optionally verify the current release&amp;rsquo;s recorded source Git commit:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;MARKATA_PUBLISH_BUILDER_URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;https://builder.example.com&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;MARKATA_PUBLISH_BUILDER_TOKEN&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;your authorized bearer token&amp;gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;markata editor --workspace ./site&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Use an API token authorized for Builder Admin&amp;rsquo;s &lt;code&gt;/api/v1/state&lt;/code&gt;. The editor&#xA;stores neither the token nor builder URL in the browser; the local backend&#xA;makes a short, authenticated, server-side GET request. Remote builder URLs&#xA;must use HTTPS (loopback HTTP is permitted for development). Redirects are&#xA;not followed, so bearer tokens cannot be forwarded to a different host.&lt;/p&gt;&#xA;&lt;p&gt;After pushing, select &lt;strong&gt;Check live status&lt;/strong&gt;. This checks&#xA;&lt;code&gt;revision.live_source_commit&lt;/code&gt;, with a fallback to the current release&amp;rsquo;s&#xA;source revision when available. It reports &lt;strong&gt;Live · Verified&lt;/strong&gt; only if that&#xA;revision matches the exact pushed SHA. Unknown revision, unavailable API,&#xA;unconfigured auth, failed build, and different live SHA never count as success.&lt;/p&gt;&#xA;&lt;p&gt;This verification identifies the release&amp;rsquo;s &lt;strong&gt;source Git revision&lt;/strong&gt;, not&#xA;its byte-for-byte rendered output, CDN cache rollout, or availability at&#xA;every public edge. Site URL health checks and other deployment providers&#xA;need dedicated follow-up adapters.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Live Markdown editor with FastAPI</title>
    <id>https://markata.dev/docs/guides/fastapi-editor/</id>
    <updated>2026-10-28T00:00:00Z</updated>
    <published>2026-10-28T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/fastapi-editor/" rel="alternate" type="text/html"></link>
    <summary type="text">Run a single-file editor with a live Markata preview</summary>
    <content type="html">&lt;p&gt;Run the single-file example:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run examples/fastapi_editor.py&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Open &lt;a href=&#34;http://127.0.0.1:8765&#34;&gt;http://127.0.0.1:8765&lt;/a&gt;. Edit Markdown on the left. The preview updates after&#xA;250 milliseconds without edits. Narrow screens stack the editor and preview.&#xA;The browser stores your draft locally. Use &lt;strong&gt;Download .md&lt;/strong&gt; to save a file.&lt;/p&gt;&#xA;&lt;p&gt;The example requires a Markata wheel containing the Python API from PR #1835.&#xA;Until that API is released, install a wheel built from that PR:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv run --with /absolute/path/to/markata-VERSION-PLATFORM.whl examples/fastapi_editor.py&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Replace the wheel path with your local wheel. With Python and dependencies already&#xA;installed, &lt;code&gt;python examples/fastapi_editor.py&lt;/code&gt; also works. The server listens on&#xA;localhost, port 8765. Press Ctrl+C to stop it.&lt;/p&gt;&#xA;&lt;p&gt;Each preview uses an application-owned &lt;code&gt;RendererPool&lt;/code&gt; through FastAPI. Two warm&#xA;renderers start with the application&amp;rsquo;s lifespan and retain the workspace&amp;rsquo;s&#xA;Markdown configuration. Inline assets support&#xA;code highlighting, Mermaid, and Chart.js without separate asset routes. A fresh&#xA;iframe document executes initialization scripts after each successful render.&#xA;The iframe permits scripts and keeps the preview separate from the editor origin.&#xA;Authored HTML and inline styles are enabled for this local authoring tool.&#xA;The preview remains isolated from the editor origin.&lt;/p&gt;&#xA;&lt;p&gt;The example limits input to 200,000 UTF-8 bytes and rendering to 15 seconds.&#xA;Errors preserve the last successful preview. A crashed or timed-out renderer is&#xA;replaced automatically; no new subprocess is started for ordinary requests.&#xA;This example is a local development tool. It does not include accounts or shared storage.&lt;/p&gt;&#xA;&lt;p&gt;Use the appearance button beside &lt;strong&gt;Download .md&lt;/strong&gt; to open Markata&amp;rsquo;s full picker.&#xA;Search color themes, switch light and dark modes, or select Style and Font tabs.&#xA;Selections apply to the preview and persist across edits. Markata supplies the&#xA;palette catalog, styles, scripts, and fonts. No site build runs during editing.&lt;/p&gt;&#xA;&lt;p&gt;The footer shows Markata time, request time, input bytes, document bytes, and frame&#xA;load time. Markata time includes queue wait, rendering, asset collection, and JSON parsing,&#xA;but normally excludes process startup. Request time also includes HTTP transfer and browser JSON parsing.&#xA;Frame load time measures iframe loading, not completed asynchronous diagrams.&#xA;The 250-millisecond typing delay is separate from these measurements.&lt;/p&gt;&#xA;&lt;p&gt;The preview uses the default site&amp;rsquo;s article wrappers, reading size, and spacing.&#xA;It previews article content. It does not add site navigation, feeds, or post metadata.&lt;/p&gt;&#xA;&lt;p&gt;Lucide shortcodes such as &lt;code&gt;:lucide-globe:&lt;/code&gt; and &lt;code&gt;:lucide/heart:&lt;/code&gt; display as inline&#xA;icons in prose and headings. Markata bundles all 2,118 icons from Markata&amp;rsquo;s pinned&#xA;Lucide pack, including its license. Code examples and unknown shortcodes stay unchanged.&lt;/p&gt;&#xA;&lt;p&gt;The Markdown pane uses bundled CodeMirror with syntax highlighting, line numbers,&#xA;line wrapping, and bracket matching. Select &lt;strong&gt;Keymap&lt;/strong&gt; above the editor to use&#xA;Default, Vim, Emacs, or Sublime bindings. Your choice persists in this browser.&#xA;With Vim selected, press &lt;code&gt;i&lt;/code&gt; to insert text and &lt;code&gt;Escape&lt;/code&gt; to return to normal mode.&#xA;Editor colors follow the appearance picker. CodeMirror requires no CDN requests.&lt;/p&gt;&#xA;&lt;h2 id=&#34;run-the-demo-integration-tests&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Run the demo integration tests&lt;/span&gt; &lt;a href=&#34;#run-the-demo-integration-tests&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Use a virtual environment containing the built Markata wheel, FastAPI, Uvicorn,&#xA;HTTPX, and Playwright. Run the endpoint checks against that installed wheel:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m unittest discover -s python/integration -v&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Install Chromium and run the browser checks:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m playwright install chromium&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python python/test_editor_browser.py -v&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If Chromium is already installed, set &lt;code&gt;MARKATA_TEST_CHROMIUM&lt;/code&gt; to its executable path.&#xA;The tests reserve an available localhost port and stop their server afterward.&#xA;They cover live edits, saved drafts, keymaps, initial appearance, picker changes,&#xA;Lucide icons, responsive rails, and full-width desktop and mobile layouts.&#xA;The wheel workflow runs both suites against the installed Linux wheel.&lt;/p&gt;&#xA;&lt;p&gt;The first render returns the full preview document. Later requests set&#xA;&lt;code&gt;include_document&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;, so the server returns only the rendered fragment,&#xA;conditional styles, scripts, and metrics. The browser keeps its document and&#xA;appearance styles loaded, then replaces the article content in the existing&#xA;sandboxed frame. This avoids sending the large site CSS payload or reloading&#xA;theme stylesheets after every edit.&lt;/p&gt;&#xA;&lt;p&gt;See &lt;a href=&#34;/docs/guides/renderer-integration-benchmarks/&#34;&gt;integration benchmarks&lt;/a&gt; for measured fixture timings and reproduction steps.&lt;/p&gt;&#xA;&lt;h2 id=&#34;shared-editor-behavior&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Shared editor behavior&lt;/span&gt; &lt;a href=&#34;#shared-editor-behavior&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Use &lt;strong&gt;Open .md&lt;/strong&gt; to import a Markdown file. An oversized file leaves the current draft intact.&#xA;Use &lt;strong&gt;Download .md&lt;/strong&gt; to keep a copy outside browser storage.&#xA;The footer reports whether the draft was saved. Storage failures leave editing and downloads available.&#xA;See &lt;a href=&#34;/docs/guides/renderer-integration-benchmarks/#shared-editor-features-and-runtime-differences&#34;&gt;shared editor features and runtime differences&lt;/a&gt; for the comparison.&lt;/p&gt;&#xA;&lt;h2 id=&#34;insert-markdown-commands&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Insert Markdown commands&lt;/span&gt; &lt;a href=&#34;#insert-markdown-commands&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Select &lt;strong&gt;Commands&lt;/strong&gt; or press &lt;strong&gt;Ctrl+Shift+P&lt;/strong&gt; (&lt;strong&gt;Cmd+Shift+P&lt;/strong&gt; on macOS).&#xA;Search for special syntax, then press &lt;strong&gt;Enter&lt;/strong&gt; to insert it at your selection.&#xA;See the &lt;a href=&#34;editor-command-palette.md&#34;&gt;command palette guide&lt;/a&gt; for the catalog and keyboard controls.&lt;/p&gt;&#xA;&lt;h2 id=&#34;language-assistance&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Language assistance&lt;/span&gt; &lt;a href=&#34;#language-assistance&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The Python and Go editors connect to Markata&amp;rsquo;s LSP through a same-origin WebSocket.&#xA;The server selects the workspace with &lt;code&gt;MARKATA_LSP_WORKSPACE&lt;/code&gt;; browser messages cannot change it.&#xA;The endpoint accepts &lt;code&gt;localhost&lt;/code&gt; and loopback IP hosts only. It is intended for local examples.&lt;/p&gt;&#xA;&lt;p&gt;Both editors complete wiki links and Markdown document paths. They also complete&#xA;command-catalog containers, their known attributes, and Mermaid diagram syntax.&#xA;Press &lt;strong&gt;Ctrl+Space&lt;/strong&gt; to request suggestions at the cursor. File-tree navigation&#xA;is a separate feature.&lt;/p&gt;&#xA;&lt;p&gt;To run the browser checks against both servers, build the Go binaries and set&#xA;&lt;code&gt;MARKATA_LSP_BINARY&lt;/code&gt; and &lt;code&gt;MARKATA_WORKBENCH_BINARY&lt;/code&gt; as shown below:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go build -o /tmp/markata-editor-lsp ./cmd/markata-go&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go build -o /tmp/markata-editor-workbench ./cmd/markata-workbench&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MARKATA_LSP_BINARY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/tmp/markata-editor-lsp &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MARKATA_WORKBENCH_BINARY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/tmp/markata-editor-workbench &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python python/test_browser_lsp.py -v&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;workspace-files&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Workspace files&lt;/span&gt; &lt;a href=&#34;#workspace-files&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Set &lt;code&gt;MARKATA_LSP_WORKSPACE&lt;/code&gt; to a cloned site before starting the server.&#xA;The Files tree uses Markata glob and load plugins through the bundled Go binary.&#xA;Select a file to edit a browser draft; download it to keep a copy. See&#xA;&lt;a href=&#34;./renderer-site-tree/&#34;&gt;workspace navigation&lt;/a&gt;.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Render Markdown in Python and FastAPI</title>
    <id>https://markata.dev/docs/guides/python-renderer/</id>
    <updated>2026-10-27T00:00:00Z</updated>
    <published>2026-10-27T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/python-renderer/" rel="alternate" type="text/html"></link>
    <summary type="text">Use Markata&#39;s renderer with feature signals and bundled CSS and JavaScript</summary>
    <content type="html">&lt;p&gt;Install the official Go-based &lt;code&gt;markata&lt;/code&gt; wheel containing this API (available with&#xA;the release that includes this feature):&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;uv add markata fastapi uvicorn&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Render a complete response with conditional CSS and JavaScript inlined:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;fastapi&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FastAPI&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;fastapi.responses&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HTMLResponse&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;markata&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render_async&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FastAPI&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@app.get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response_class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;HTMLResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render_async&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Hello&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;!!! note&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;    Rendered by Markata.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;inline_assets&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HTMLResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;My app&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;render()&lt;/code&gt; offers the same options for synchronous applications. Both use the&#xA;existing Go Markdown renderer shipped inside the Python wheel. Each call launches&#xA;one process, so cache repeated content in your application. &lt;code&gt;render_async()&lt;/code&gt; uses&#xA;async subprocess I/O, terminates the process on timeout or cancellation, and does&#xA;not block the ASGI event loop. &lt;code&gt;timeout&lt;/code&gt; defaults to 30 seconds. Failures raise&#xA;&lt;code&gt;markata.RenderError&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;fragments-and-signals&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Fragments and signals&lt;/span&gt; &lt;a href=&#34;#fragments-and-signals&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;markata&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;```go&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;fmt.Println(42)&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;```&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;inline_assets&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;# Article markup&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;features&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;          &lt;span class=&#34;c1&#34;&gt;# code, admonitions, roads, mermaid, chartjs, ...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;head_html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;         &lt;span class=&#34;c1&#34;&gt;# Ordered style tags&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;feature_head_html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Only styles specific to this fragment&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;body_end_html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;     &lt;span class=&#34;c1&#34;&gt;# Ordered scripts&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In an existing layout, insert &lt;code&gt;head_html&lt;/code&gt; into the head, &lt;code&gt;html&lt;/code&gt; inside an&#xA;&lt;code&gt;&amp;lt;article class=&amp;quot;post-content&amp;quot;&amp;gt;&lt;/code&gt;, and &lt;code&gt;body_end_html&lt;/code&gt; after the article. These&#xA;strings contain generated HTML; use the appropriate trusted-markup mechanism in&#xA;your template engine. &lt;code&gt;document(title=&amp;quot;...&amp;quot;, lang=&amp;quot;en&amp;quot;)&lt;/code&gt; creates that layout for&#xA;you and escapes the title and language.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;feature_head_html&lt;/code&gt; returns only conditional styles, without the shared variables,&#xA;main, and component styles. The renderer returns core theme CSS plus only the optional assets the content&#xA;requires. Mermaid and Chart.js use Markata&amp;rsquo;s vendored browser libraries; inline&#xA;mode includes them too, without CDN requests. Inlining diagrams can make a&#xA;response considerably larger. &lt;code&gt;external_urls&lt;/code&gt; identifies any external browser&#xA;dependencies; for the currently supported bundled features it is empty. Authored&#xA;images and links still refer to their authored URLs.&lt;/p&gt;&#xA;&lt;p&gt;Core theme CSS includes global styles. For an application with its own design,&#xA;select the assets you want from &lt;code&gt;result.assets&lt;/code&gt; and supply compatible CSS variables&#xA;and &lt;code&gt;.post-content&lt;/code&gt; styling. This API does not configure a site&amp;rsquo;s theme palette.&lt;/p&gt;&#xA;&lt;h2 id=&#34;serve-assets-separately&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Serve assets separately&lt;/span&gt; &lt;a href=&#34;#serve-assets-separately&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The default &lt;code&gt;inline_assets=False&lt;/code&gt; emits links under &lt;code&gt;/markata-assets&lt;/code&gt;, or your&#xA;&lt;code&gt;asset_base&lt;/code&gt;. Each asset is a dictionary containing &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt;, &lt;code&gt;placement&lt;/code&gt;,&#xA;and &lt;code&gt;content&lt;/code&gt; (or &lt;code&gt;url&lt;/code&gt; for external assets). Asset IDs are suitable for caching&#xA;and deduplication; scripts must keep their manifest order.&lt;/p&gt;&#xA;&lt;p&gt;A small app can precompute its content and serve the bundled assets directly:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;fastapi&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FastAPI&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HTTPException&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;fastapi.responses&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HTMLResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Response&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;markata&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;app&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FastAPI&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;page&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Example&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;```python&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;print(&amp;#39;hello&amp;#39;)&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;```&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asset_base&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/md-assets&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;assets&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;asset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asset&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asset&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assets&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;asset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@app.get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/md-assets/{asset_id:path}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;asset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;asset_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;item&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;asset_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;item&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;raise&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;HTTPException&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status_code&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;404&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;media_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;item&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;style&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;item&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;media_type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;media_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nd&#34;&gt;@app.get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response_class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;HTMLResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;page&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Example&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For multiple pages, combine their bundled assets by ID and retain each page&amp;rsquo;s&#xA;ordered generated initialization scripts. Generated chart IDs are local to one&#xA;render result: render all Markdown for a document together. Do not deduplicate&#xA;generated scripts across unrelated results. If browser content is replaced after&#xA;page load, the application must execute its initialization scripts; simply&#xA;assigning &lt;code&gt;innerHTML&lt;/code&gt; does not execute them.&lt;/p&gt;&#xA;&lt;h2 id=&#34;scope-and-trusted-content&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Scope and trusted content&lt;/span&gt; &lt;a href=&#34;#scope-and-trusted-content&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Supported: Markata&amp;rsquo;s Markdown extensions, syntax highlighting, containers,&#xA;admonitions, Mermaid, Chart.js, roads, sortable tables, and opt-in checklists. Rendering does not run a site build;&#xA;site-dependent link resolution, embeds, image transforms, and other lifecycle&#xA;plugins are outside this API.&lt;/p&gt;&#xA;&lt;p&gt;Raw authored HTML is disabled by default. Set &lt;code&gt;unsafe=True&lt;/code&gt; only for trusted&#xA;content. Rich Markdown output is &lt;strong&gt;not an HTML sanitizer&lt;/strong&gt;; sanitize untrusted&#xA;content using your application&amp;rsquo;s policy. Inline styles and scripts also require&#xA;a compatible Content Security Policy. Applications with strict CSP should serve&#xA;assets themselves and apply their own nonce/hash policy to initialization scripts.&lt;/p&gt;&#xA;&lt;h2 id=&#34;cli-protocol&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;CLI protocol&lt;/span&gt; &lt;a href=&#34;#cli-protocol&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The Python API uses the same machine-readable interface available to other languages:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;# Hello\n&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; markata render --json --inline-assets&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Without &lt;code&gt;--json&lt;/code&gt;, &lt;code&gt;markata render&lt;/code&gt; emits just the HTML fragment. &lt;code&gt;--unsafe&lt;/code&gt; enables&#xA;raw HTML; &lt;code&gt;--asset-base /static/markdown&lt;/code&gt; changes linked bundled asset URLs. This&#xA;command reads stdin without discovering a site configuration or writing files.&lt;/p&gt;&#xA;&lt;h2 id=&#34;reuse-the-site-s-appearance-controls&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Reuse the site’s appearance controls&lt;/span&gt; &lt;a href=&#34;#reuse-the-site-s-appearance-controls&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Load the catalog once when the application starts:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;markata&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;appearance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render_async&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;presentation&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;appearance&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;asset_base&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/markata-assets&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render_async&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Hello&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;inline_assets&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;html&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;appearance&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;presentation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;palette&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ayu-dark&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;dark&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;presentation.picker_html&lt;/code&gt; contains the site&amp;rsquo;s appearance controls. Insert&#xA;&lt;code&gt;presentation.controls_head_html&lt;/code&gt; in the host page&amp;rsquo;s head and &lt;code&gt;presentation.body_end_html&lt;/code&gt;&#xA;after its content. Serve &lt;code&gt;presentation.assets&lt;/code&gt; through exact path lookup.&#xA;&lt;code&gt;controls_head_html&lt;/code&gt; omits site page-layout styles. Complete preview documents&#xA;use &lt;code&gt;head_html&lt;/code&gt; internally. Each asset value is bytes. Use CSS, JavaScript, or WOFF2 response types as appropriate.&#xA;The asset base also applies to font URLs. No site build or filesystem writes occur.&lt;/p&gt;&#xA;&lt;p&gt;The controls reuse the site&amp;rsquo;s palette, aesthetic, font, size, and loading catalogs.&#xA;&lt;code&gt;document()&lt;/code&gt; now uses site article wrappers. Set &lt;code&gt;mode&lt;/code&gt;, &lt;code&gt;palette&lt;/code&gt;, &lt;code&gt;aesthetic&lt;/code&gt;,&#xA;&lt;code&gt;fontpack&lt;/code&gt;, and &lt;code&gt;text_size&lt;/code&gt; to select appearance. Unknown catalog values raise&#xA;&lt;code&gt;ValueError&lt;/code&gt;. Lucide shortcodes render through Markata&amp;rsquo;s existing icon implementation.&lt;/p&gt;&#xA;&lt;p&gt;For an isolated preview iframe, set &lt;code&gt;appearance_bridge=True&lt;/code&gt;. The parent can send&#xA;&lt;code&gt;{type: &amp;quot;appearance&amp;quot;, attributes: {...}}&lt;/code&gt; with &lt;code&gt;data-theme&lt;/code&gt;, &lt;code&gt;data-palette&lt;/code&gt;,&#xA;&lt;code&gt;data-aesthetic&lt;/code&gt;, &lt;code&gt;data-fontpack&lt;/code&gt;, and &lt;code&gt;data-text-size&lt;/code&gt; choices. The bridge accepts&#xA;messages from its parent and validates values against the catalogs. Keep the&#xA;iframe sandboxed with &lt;code&gt;allow-scripts&lt;/code&gt; and without &lt;code&gt;allow-same-origin&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For live edits, the parent can also send &lt;code&gt;{&amp;quot;type&amp;quot;: &amp;quot;markdown-render&amp;quot;, &amp;quot;html&amp;quot;: &amp;quot;...&amp;quot;, &amp;quot;feature_head_html&amp;quot;: &amp;quot;...&amp;quot;, &amp;quot;body_end_html&amp;quot;: &amp;quot;...&amp;quot;}&lt;/code&gt;. The bridge replaces&#xA;&lt;code&gt;.post-content&lt;/code&gt;, updates render-specific styles, loads new feature scripts once,&#xA;runs generated scripts, and dispatches &lt;code&gt;view-transition-complete&lt;/code&gt;. It does not&#xA;replay &lt;code&gt;DOMContentLoaded&lt;/code&gt;. The host can therefore keep shared preview stylesheets&#xA;loaded between renders.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://github.com/WaylonWalker/markata/blob/main/examples/fastapi_editor.py&#34;&gt;single-file editor example&lt;/a&gt;&#xA;contains CodeMirror and application behavior. Markata supplies its preview document,&#xA;icons, appearance picker, and assets. Applications must explicitly enable&#xA;&lt;code&gt;unsafe=True&lt;/code&gt; to render authored HTML and style blocks.&lt;/p&gt;&#xA;&lt;h2 id=&#34;installation-size-and-offline-icons&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Installation size and offline icons&lt;/span&gt; &lt;a href=&#34;#installation-size-and-offline-icons&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The renderer retains the full pinned &lt;code&gt;lucide-static&lt;/code&gt; 1.48.0 catalog for offline icon shortcodes.&#xA;This provides consistent icon availability without downloads or a configurable subset.&#xA;The catalog contains 2,118 SVG files: 1,026,506 source bytes, or approximately 0.98 MiB.&#xA;Compressing their concatenated bytes with gzip produces approximately 97 KiB.&#xA;These asset measurements do not measure the catalog&amp;rsquo;s exact contribution to a compiled binary or wheel.&#xA;A stripped Linux amd64 CLI built with Go 1.26.3 measured approximately 66 MiB before wheel compression.&#xA;The complete CLI also contains themes, fonts, browser libraries, and build features.&#xA;Wheel sizes vary by operating system and architecture.&lt;/p&gt;&#xA;&lt;p&gt;Lucide&amp;rsquo;s ISC and derived Feather MIT notices remain embedded in the binary.&#xA;Wheels also provide readable notices in &lt;code&gt;markata-&amp;lt;version&amp;gt;.dist-info/licenses/lucide.txt&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;An installed POSIX binary with its executable bit preserved can render from read-only site-packages.&#xA;Rendering does not require permission changes in that installation.&#xA;If another installer removes the executable bit, reinstall the official wheel with executable permissions.&#xA;The permission-repair fallback needs permission to change the binary&amp;rsquo;s mode.&lt;/p&gt;&#xA;&lt;p&gt;Each Python render call starts a subprocess. The measured benchmark post took approximately 137 ms through the Python API.&#xA;For frequent live edits, use the persistent Go workbench instead of starting a subprocess for every request.&#xA;See &lt;a href=&#34;/docs/guides/renderer-integration-benchmarks/&#34;&gt;integration benchmarks&lt;/a&gt; for timing boundaries and reproduction commands.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Go module import path cutover</title>
    <id>https://markata.dev/docs/guides/go-module-cutover/</id>
    <updated>2026-10-27T00:00:00Z</updated>
    <published>2026-10-27T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/go-module-cutover/" rel="alternate" type="text/html"></link>
    <summary type="text">The canonical Go source module for Markata (still on the 0.x line) is</summary>
    <content type="html">&lt;p&gt;The canonical Go source module for &lt;strong&gt;Markata&lt;/strong&gt; (still on the 0.x line) is&#xA;&lt;code&gt;github.com/WaylonWalker/markata&lt;/code&gt;, following the October 18, 2026&#xA;GitHub repository swap. It is independent of the original Python module,&#xA;which now lives at &lt;a href=&#34;https://github.com/WaylonWalker/markata-py&#34;&gt;WaylonWalker/markata-py&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;existing-users&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Existing users&lt;/span&gt; &lt;a href=&#34;#existing-users&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Using the CLI or builder containers:&lt;/strong&gt; you can keep the&#xA;&lt;code&gt;markata-go&lt;/code&gt; binary alias, &lt;code&gt;markata-go.toml&lt;/code&gt;, &lt;code&gt;[markata-go]&lt;/code&gt;,&#xA;&lt;code&gt;MARKATA_GO_*&lt;/code&gt; and legacy GHCR names for now. See the&#xA;&lt;a href=&#34;name-migration.md&#34;&gt;naming migration guide&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Importing Go packages:&lt;/strong&gt; replace imports starting with&#xA;&lt;code&gt;github.com/WaylonWalker/markata-go/&lt;/code&gt; with&#xA;&lt;code&gt;github.com/WaylonWalker/markata/&lt;/code&gt;, and run &lt;code&gt;go mod tidy&lt;/code&gt;.&#xA;The Go module&amp;rsquo;s own declaration has changed as well.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Pinned historical Go consumers:&lt;/strong&gt; existing historical tags for&#xA;&lt;code&gt;github.com/WaylonWalker/markata-go&lt;/code&gt; have not been deleted.&#xA;Avoid depending on both the historical and new module paths in the&#xA;same dependency graph; they describe the same source with different&#xA;module identities and may result in duplicate packages.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Python users:&lt;/strong&gt; historical pinned Python releases remain available on PyPI, but&#xA;current PyPI releases install the Go CLI after a version break. A&#xA;Go CLI install must not silently overwrite an existing Python&#xA;&lt;code&gt;markata&lt;/code&gt; executable.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;canonical-source-install&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Canonical source install&lt;/span&gt; &lt;a href=&#34;#canonical-source-install&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go install github.com/WaylonWalker/markata/cmd/markata@main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Legacy Go executable remains available from the canonical module:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go install github.com/WaylonWalker/markata/cmd/markata-go@main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For reproducible installations, pin an already published, verified release&#xA;tag rather than &lt;code&gt;@main&lt;/code&gt; when that tag supports your command and module path.&#xA;The name migration does &lt;strong&gt;not&lt;/strong&gt; authorize any new release, prerelease or tag.&#xA;Validate Go imports, installer compatibility, builder images, Argo CD sources&#xA;and representative site builds independently while remaining on 0.x.&lt;/p&gt;&#xA;&lt;h2 id=&#34;change-control&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Change control&lt;/span&gt; &lt;a href=&#34;#change-control&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The module path migration changed only tracked Go files, &lt;code&gt;go.mod&lt;/code&gt;,&#xA;and GoReleaser&amp;rsquo;s linker symbol package paths. The deterministic rewrite&#xA;script lives at &lt;code&gt;scripts/migrate-go-module-path.py&lt;/code&gt;; the dedicated&#xA;PR workflow fails if any old module import remains.&lt;/p&gt;&#xA;&lt;p&gt;These are &lt;strong&gt;not&lt;/strong&gt; reasons to rename Kubernetes PVCs, releases, secrets,&#xA;Helm chart names, historical Docker tags, old Go binaries, or Python&#xA;PyPI distributions.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Accessible Chart.js figures and fallbacks</title>
    <id>https://markata.dev/docs/guides/markdown-chart-fallback/</id>
    <updated>2026-10-26T00:00:00Z</updated>
    <published>2026-10-26T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/markdown-chart-fallback/" rel="alternate" type="text/html"></link>
    <summary type="text">Add titles, captions, and JavaScript-free data to charts</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;chartjs&lt;/code&gt; fenced blocks render a standard HTML &lt;strong&gt;data table at build time&lt;/strong&gt;.&#xA;They retain a JavaScript-free representation even if the Chart.js CDN is&#xA;unavailable, the reader disables JavaScript, or interactive rendering fails.&lt;/p&gt;&#xA;&lt;p&gt;The theme adds a Chart.js canvas alongside an expanded &lt;strong&gt;Chart data&lt;/strong&gt; disclosure.&#xA;For charts using the options below, successful Chart.js initialization collapses&#xA;the disclosure, which remains available for exact values or screen-reader users.&#xA;If the library fails to load, the table keeps its configured state.&lt;/p&gt;&#xA;&lt;h2 id=&#34;example&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Example&lt;/span&gt; &lt;a href=&#34;#example&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;div class=&#34;chartjs-container&#34;&gt;&#xA;  &lt;canvas id=&#34;chartjs-1&#34; hidden role=&#34;img&#34; aria-label=&#34;Chart visualization; expand Chart data for exact values&#34;&gt;&lt;/canvas&gt;&#xA;  &lt;div id=&#34;chartjs-1-data&#34;&gt;&lt;details class=&#34;chartjs-data&#34; open&gt;&lt;summary&gt;Chart data&lt;/summary&gt;&lt;table&gt;&lt;caption&gt;Chart data&lt;/caption&gt;&lt;thead&gt;&lt;tr&gt;&lt;th scope=&#34;col&#34;&gt;Label&lt;/th&gt;&lt;th scope=&#34;col&#34;&gt;Build seconds&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th scope=&#34;row&#34;&gt;Full&lt;/th&gt;&lt;td&gt;46&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th scope=&#34;row&#34;&gt;Incremental&lt;/th&gt;&lt;td&gt;21&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/details&gt;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The renderer emits semantic table headers and cells without a second chart&#xA;library or a network request. For unusual configurations such as scatter&#xA;charts with object-valued &lt;code&gt;x&lt;/code&gt;/&lt;code&gt;y&lt;/code&gt; entries, the original JSON remains&#xA;available in a &lt;strong&gt;Chart configuration&lt;/strong&gt; disclosure instead of fabricating&#xA;tabular labels. Huge tables (more than 200 labels or 12 datasets) also fall&#xA;back to the original configuration to bound generated HTML.&lt;/p&gt;&#xA;&lt;p&gt;Chart data is treated as untrusted Markdown input: HTML labels are escaped&#xA;and chart JSON is safely encoded before inclusion in an inline script.&lt;/p&gt;&#xA;&lt;h2 id=&#34;titles-captions-and-compact-figures&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Titles, captions, and compact figures&lt;/span&gt; &lt;a href=&#34;#titles-captions-and-compact-figures&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Add plain-text &lt;code&gt;title&lt;/code&gt; and/or &lt;code&gt;caption&lt;/code&gt; keys at the top level of the chart JSON:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```chartjs&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;title&amp;#34;: &amp;#34;Build time&amp;#34;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;caption&amp;#34;: &amp;#34;Seconds per build; lower is better.&amp;#34;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;data_display&amp;#34;: &amp;#34;collapsed&amp;#34;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;type&amp;#34;: &amp;#34;bar&amp;#34;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;data&amp;#34;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;labels&amp;#34;: [&amp;#34;Full&amp;#34;, &amp;#34;Incremental&amp;#34;],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;datasets&amp;#34;: [{&amp;#34;label&amp;#34;: &amp;#34;Seconds&amp;#34;, &amp;#34;data&amp;#34;: [46, 21]}]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;options&amp;#34;: {&amp;#34;indexAxis&amp;#34;: &amp;#34;y&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The built-in theme renders a responsive surface card with a left-aligned,&#xA;non-italic figcaption. Its title is &lt;strong&gt;not a heading&lt;/strong&gt;, so it does not enter the&#xA;TOC. The canvas is labelled by the title and references the figcaption.&#xA;Short horizontal bar figures (up to four labels) use a compact canvas, capped at&#xA;130px; other figures retain normal Chart.js sizing. You do not need page CSS or&#xA;JavaScript. Neither title nor caption interprets HTML or Markdown.&lt;/p&gt;&#xA;&lt;p&gt;These authoring keys are stripped before Chart.js receives the JSON. We use JSON&#xA;metadata rather than fence attributes because the Markdown renderer retains&#xA;the language but not arbitrary fence-info options (the legacy CSV HTML matcher&#xA;is not a reliable authoring path for this). Chart.js&amp;rsquo;s own chart title remains&#xA;available separately under &lt;code&gt;options.plugins.title&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;initial-data-disclosure-state&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Initial data disclosure state&lt;/span&gt; &lt;a href=&#34;#initial-data-disclosure-state&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;markata-go&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;chartjs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;data_display&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;open&amp;#34;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;# default; or &amp;#34;collapsed&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Set top-level &lt;code&gt;&amp;quot;data_display&amp;quot;: &amp;quot;open&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;data_display&amp;quot;: &amp;quot;collapsed&amp;quot;&lt;/code&gt; in an&#xA;individual chart to override the site default, with or without a figure.&#xA;Collapsed details still have a visible, keyboard-operable summary without JS.&#xA;Successful rendering of an opted-in chart collapses the disclosure regardless&#xA;of its initial state; a loading/rendering error leaves that state intact.&#xA;Invalid values produce a configuration error (site setting) or a visible chart&#xA;error (per chart).&#xA;With no new options, existing chart markup and the default-open fallback remain&#xA;unchanged.&lt;/p&gt;&#xA;&lt;p&gt;Legacy charts without these options also retain their original initialization&#xA;script: it attempts to collapse the wrapper div rather than the disclosure,&#xA;so their data stays open. Add a title, caption, or per-chart &lt;code&gt;data_display&lt;/code&gt; (or&#xA;set the site&amp;rsquo;s &lt;code&gt;data_display&lt;/code&gt; to &lt;code&gt;&amp;quot;collapsed&amp;quot;&lt;/code&gt;) to opt into corrected behavior.&lt;/p&gt;&#xA;&lt;h2 id=&#34;behavior&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Behavior&lt;/span&gt; &lt;a href=&#34;#behavior&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;No-JavaScript: canvas is hidden; table or configuration is reachable in details&#xA;(expanded by default).&lt;/li&gt;&#xA;&lt;li&gt;JavaScript working: canvas becomes visible; opted-in charts collapse the data&#xA;disclosure, which can always be reopened.&lt;/li&gt;&#xA;&lt;li&gt;Chart.js loading or rendering error: canvas remains hidden; fallback remains&#xA;reachable in its configured initial state.&lt;/li&gt;&#xA;&lt;li&gt;Multiple charts per post: each chart has its own fallback.&lt;/li&gt;&#xA;&lt;li&gt;Pages without &lt;code&gt;chartjs&lt;/code&gt; blocks are unchanged.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This is an accessibility and progressive-enhancement improvement to the&#xA;existing Chart.js plugin. It is &lt;strong&gt;not&lt;/strong&gt; a new chart data format, SVG exporter,&#xA;or automatic visual data verification.&lt;/p&gt;&#xA;&lt;h2 id=&#34;horizontal-bar-defaults&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Horizontal bar defaults&lt;/span&gt; &lt;a href=&#34;#horizontal-bar-defaults&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A horizontal bar chart with one dataset and up to five labels uses thin, rounded bars and a compact aspect ratio by default. Set bar geometry such as &lt;code&gt;barThickness&lt;/code&gt; or &lt;code&gt;borderRadius&lt;/code&gt; in the dataset, &lt;code&gt;options&lt;/code&gt;, &lt;code&gt;options.datasets.bar&lt;/code&gt;, or &lt;code&gt;options.elements.bar&lt;/code&gt; to use your own geometry. Set &lt;code&gt;options.aspectRatio&lt;/code&gt; or &lt;code&gt;options.maintainAspectRatio&lt;/code&gt; to control chart sizing. Charts with multiple datasets or more than five labels keep Chart.js defaults.&lt;/p&gt;&#xA;&lt;p&gt;Dataset &lt;code&gt;indexAxis&lt;/code&gt; overrides &lt;code&gt;options.datasets.bar.indexAxis&lt;/code&gt;, which overrides &lt;code&gt;options.indexAxis&lt;/code&gt;. Compact defaults apply only to the resulting horizontal orientation.&lt;/p&gt;&#xA;&lt;p&gt;Default bars have a maximum thickness of 14 pixels. They shrink on narrow screens to prevent overlap.&lt;/p&gt;&#xA;&#xA;&lt;script src=&#34;/assets/vendor/chartjs/chart.min.js&#34;&gt;&lt;/script&gt;&#xA;&lt;script&gt;&#xA;(function() {&#xA;const initCharts = function() {&#xA;  (function() {&#xA;    const ctx = document.getElementById(&#39;chartjs-1&#39;);&#xA;    if (!ctx || typeof Chart !== &#39;function&#39;) return;&#xA;    ctx.hidden = false;&#xA;    try {&#xA;      new Chart(ctx, {&#34;data&#34;:{&#34;datasets&#34;:[{&#34;data&#34;:[46,21],&#34;label&#34;:&#34;Build seconds&#34;}],&#34;labels&#34;:[&#34;Full&#34;,&#34;Incremental&#34;]},&#34;type&#34;:&#34;bar&#34;});&#xA;      const data = document.getElementById(&#39;chartjs-1-data&#39;);&#xA;      if (data) data.open = false;&#xA;    } catch (error) {&#xA;      ctx.hidden = true;&#xA;    }&#xA;  })();&#xA;};&#xA;if (document.readyState === &#39;loading&#39;) {&#xA;  document.addEventListener(&#39;DOMContentLoaded&#39;, initCharts, {once: true});&#xA;} else {&#xA;  initCharts();&#xA;}&#xA;})();&#xA;&lt;/script&gt;</content>
  </entry>
  <entry>
    <title>URL mentions provider integration (initial foundation)</title>
    <id>https://markata.dev/docs/architecture/url-mentions-integration/</id>
    <updated>2026-10-22T00:00:00Z</updated>
    <published>2026-10-22T00:00:00Z</published>
    <link href="https://markata.dev/docs/architecture/url-mentions-integration/" rel="alternate" type="text/html"></link>
    <summary type="text">The pkg/urlmentions package consumes version 1.0 of the public URL mentions protocol.</summary>
    <content type="html">&lt;p&gt;The &lt;code&gt;pkg/urlmentions&lt;/code&gt; package consumes version 1.0 of the public URL mentions protocol.&lt;/p&gt;&#xA;&lt;p&gt;Provider indexes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://listen.waylonwalker.com/.well-known/url-mentions.json&#34;&gt;https://listen.waylonwalker.com/.well-known/url-mentions.json&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://brainrot.waylonwalker.com/.well-known/url-mentions.json&#34;&gt;https://brainrot.waylonwalker.com/.well-known/url-mentions.json&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;code&gt;urlmentions.Client.Fetch(ctx, endpoint)&lt;/code&gt; retrieves all pages and returns a map&#xA;from provider-supplied &lt;code&gt;references[].normalized_url&lt;/code&gt; to source entries.&#xA;It bounds response sizes and page counts, rejects non-HTTPS starting URLs,&#xA;and disallows cross-origin pagination. The caller should use an HTTP client&#xA;with redirects restricted to the same origin and enforce a build-time budget.&lt;/p&gt;&#xA;&lt;p&gt;This is &lt;strong&gt;phase one only&lt;/strong&gt;. The package is not registered as a build plugin,&#xA;does not fetch either provider automatically, and does not render UI yet.&#xA;Follow-up work: align canonical URL normalization with the provider protocol;&#xA;cache provider pages/ETags; configure providers; map post canonical, external&#xA;target, and reader URLs; SSR accessible favicon badges with no-JS fallbacks;&#xA;graceful offline builds and snapshot tests.&lt;/p&gt;&#xA;&lt;p&gt;Do not treat this PR as production feature-complete.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Markdown example preview and source</title>
    <id>https://markata.dev/docs/guides/markdown-source-disclosure/</id>
    <updated>2026-10-21T00:00:00Z</updated>
    <published>2026-10-21T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/markdown-source-disclosure/" rel="alternate" type="text/html"></link>
    <summary type="text">A source disclosure can follow any rendered Markdown example. Markata renders</summary>
    <content type="html">&lt;p&gt;A source disclosure can follow any rendered Markdown example. Markata renders&#xA;this as native HTML &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;, so it supports mouse, keyboard, and&#xA;screen readers &lt;strong&gt;without JavaScript&lt;/strong&gt;. No new JS bundle is necessary.&lt;/p&gt;&#xA;&lt;p&gt;The source is explicitly authored: this feature does not automatically&#xA;duplicate Markdown, execute snippets, or copy untrusted HTML into the page.&lt;/p&gt;&#xA;&lt;h2 id=&#34;basic-example&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Basic example&lt;/span&gt; &lt;a href=&#34;#basic-example&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: md-layout&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::: md-card&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### Preview&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is &lt;span class=&#34;gs&#34;&gt;**bold**&lt;/span&gt; and this is &lt;span class=&#34;sb&#34;&gt;`inline code`&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::: md-source {data-label=&amp;#34;See how it is written&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```markdown&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### Preview&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is &lt;span class=&#34;gs&#34;&gt;**bold**&lt;/span&gt; and this is &lt;span class=&#34;sb&#34;&gt;`inline code`&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Use a longer backtick fence (four backticks or more) around an example&#xA;containing nested triple-backtick code fences, as in other Markdown guides.&lt;/p&gt;&#xA;&lt;p&gt;The label is optional and defaults to &lt;strong&gt;Show Markdown source&lt;/strong&gt;. Any authored&#xA;label is escaped before being inserted in the disclosure summary.&lt;/p&gt;&#xA;&lt;h2 id=&#34;output-and-compatibility&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Output and compatibility&lt;/span&gt; &lt;a href=&#34;#output-and-compatibility&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Static semantic HTML only; no JavaScript is required to open the source.&lt;/li&gt;&#xA;&lt;li&gt;Source code uses the existing fenced-code highlighter and copy controls&#xA;when those optional enhancements are present.&lt;/li&gt;&#xA;&lt;li&gt;Source text is explicitly duplicated by the author, not extracted&#xA;automatically from the preview. This helps avoid hidden dynamically&#xA;generated markup and makes it easy to inspect what a post actually teaches.&lt;/li&gt;&#xA;&lt;li&gt;The source disclosure is marked &lt;code&gt;data-markata-ui=&amp;quot;source-preview&amp;quot;&lt;/code&gt;&#xA;so the rich post-copy command can omit its UI and avoid duplication there.&lt;/li&gt;&#xA;&lt;li&gt;Search indexes and ordinary feed readers may still include explicitly&#xA;authored source content; use this for deliberate educational examples,&#xA;not every sentence of an article.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Interactive Markdown checklists</title>
    <id>https://markata.dev/docs/guides/markdown-checklists/</id>
    <updated>2026-10-21T00:00:00Z</updated>
    <published>2026-10-21T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/markdown-checklists/" rel="alternate" type="text/html"></link>
    <summary type="text">Ordinary GFM task lists in Markata remain static, disabled, readable checkboxes.</summary>
    <content type="html">&lt;p&gt;Ordinary GFM task lists in Markata remain static, disabled, readable checkboxes.&#xA;To let a reader check off tasks, wrap one or more task lists with the&#xA;&lt;code&gt;md-checklist&lt;/code&gt; container:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: md-checklist {data-id=&amp;#34;deployment&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;- [x]&lt;/span&gt; Back up the configuration&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;- [ ]&lt;/span&gt; Run the build&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;- [ ]&lt;/span&gt; Verify the live site&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The built HTML remains ordinary semantic Markdown list items with disabled&#xA;checkboxes. On pages containing an &lt;code&gt;md-checklist&lt;/code&gt;, Markata conditionally&#xA;loads a small JavaScript enhancer that enables just those checkboxes. There is&#xA;no global checklist runtime or JavaScript requirement for ordinary task lists.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;data-id&lt;/code&gt; is optional. Supply a &lt;strong&gt;stable and unique ID per list in a page&lt;/strong&gt;&#xA;to save progress in the browser&amp;rsquo;s local storage under that page&amp;rsquo;s pathname.&#xA;Without &lt;code&gt;data-id&lt;/code&gt;, the list is interactive in the current session but does&#xA;not persist. If storage is unavailable, checking tasks still works and&#xA;nothing is uploaded to a server.&lt;/p&gt;&#xA;&lt;p&gt;The task labels and original check states remain in the published Markdown.&#xA;Local progress does not rewrite the site, user account, feeds or shared copy.&#xA;The browser&amp;rsquo;s native checkbox provides keyboard and screen-reader support;&#xA;list text is attached to each checkbox as an accessible label.&lt;/p&gt;&#xA;&lt;h2 id=&#34;graceful-fallbacks&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Graceful fallbacks&lt;/span&gt; &lt;a href=&#34;#graceful-fallbacks&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;JavaScript disabled or blocked: boxes stay disabled and the list is readable.&lt;/li&gt;&#xA;&lt;li&gt;JavaScript enabled: only &lt;code&gt;md-checklist&lt;/code&gt; containers become interactive.&lt;/li&gt;&#xA;&lt;li&gt;Partial-page navigation: newly loaded checklists initialize once.&lt;/li&gt;&#xA;&lt;li&gt;Content changes: if the count of tasks changes, outdated saved state is&#xA;ignored rather than applied to the wrong items.&lt;/li&gt;&#xA;&lt;li&gt;Privacy: only a boolean completion array is stored locally; no task text&#xA;is persisted and no network request is made.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Roads</title>
    <id>https://markata.dev/docs/guides/roads/</id>
    <updated>2026-10-20T00:00:00Z</updated>
    <published>2026-10-20T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/roads/" rel="alternate" type="text/html"></link>
    <summary type="text">Turn a list of links into a scroll-drawn road: timelines, step-by-step guides, roadmaps, cycles, and git histories</summary>
    <content type="html">&lt;p&gt;A road is a path that draws itself as the reader scrolls. Each milestone on the&#xA;path is a link from your post. Use roads for roadmaps, release histories,&#xA;onboarding paths, project timelines, or any sequence that readers walk through.&lt;/p&gt;&#xA;&lt;p&gt;Roads are built in to the default theme. You need no template, config, or&#xA;plugin. Write a &lt;a href=&#34;/docs/guides/markdown-containers/&#34;&gt;Markdown container&lt;/a&gt; named&#xA;&lt;code&gt;road&lt;/code&gt;, and put a list of links inside it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;quick-start&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Quick start&lt;/span&gt; &lt;a href=&#34;#quick-start&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Install markata-go&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/docs/getting-started/&lt;/span&gt;) Step one&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Configure your site&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/docs/guides/configuration/&lt;/span&gt;) Step two&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Pick a theme&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/docs/guides/themes/&lt;/span&gt;) Step three&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Publish feeds&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/docs/guides/feeds/&lt;/span&gt;) Step four&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That renders as:&lt;/p&gt;&#xA;&lt;div class=&#34;road&#34;&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/getting-started/&#34;&gt;Install markata-go&lt;/a&gt; Step one&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/configuration/&#34;&gt;Configure your site&lt;/a&gt; Step two&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/themes/&#34;&gt;Pick a theme&lt;/a&gt; Step three&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/feeds/&#34;&gt;Publish feeds&lt;/a&gt; Step four&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;Each list item is one milestone:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;The link&lt;/strong&gt; is the milestone title, and clicking it opens the page.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;The text after the link&lt;/strong&gt; is a small label, such as a date or step number.&#xA;It is also shown in the hover card.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Wikilinks work too. A milestone written as &lt;code&gt;[[my-post]]&lt;/code&gt; uses that post&amp;rsquo;s&#xA;title, and its hover card shows the post&amp;rsquo;s description.&lt;/p&gt;&#xA;&lt;h2 id=&#34;set-fixed-progress&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Set fixed progress&lt;/span&gt; &lt;a href=&#34;#set-fixed-progress&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Use fixed progress for a roadmap whose completion does not depend on scrolling.&#xA;The normal scroll-driven progress remains the default.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road timeline {data-road-progress-mode=&amp;#34;static&amp;#34; data-road-progress=&amp;#34;65&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Design&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/design/&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Build&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/build/&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Release&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/release/&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road steps {data-road-progress-mode=&amp;#34;milestones&amp;#34; data-road-current=&amp;#34;2&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Design&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/design/&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Build&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/build/&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Test&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/test/&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Release&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/release/&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;static&lt;/code&gt; accepts a percentage from 0 to 100, with or without a &lt;code&gt;%&lt;/code&gt; suffix.&#xA;&lt;code&gt;milestones&lt;/code&gt; accepts the number of completed entries. Values are clamped to the&#xA;road&amp;rsquo;s range. Invalid values fall back to scroll progress. Fixed progress stays&#xA;the same after scroll, resize, and view transitions. The original links remain&#xA;available if JavaScript does not run.&#xA;At 0, no entries are active. At 100%, or when all milestones are complete, all&#xA;entries are active.&lt;/p&gt;&#xA;&lt;h2 id=&#34;choose-a-style&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Choose a style&lt;/span&gt; &lt;a href=&#34;#choose-a-style&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Put the style name after &lt;code&gt;road&lt;/code&gt;. The default style is &lt;code&gt;winding&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Style&lt;/th&gt;&#xA;&lt;th&gt;Good for&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;winding&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Journeys, reading paths, story arcs&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;timeline&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Dated events, changelogs, history&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;steps&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Short processes of three to six steps&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;snake&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Long ordered sequences, such as courses or series&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;cycle&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Processes that repeat, such as sprints or seasons&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;constellation&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Loosely related ideas or a &amp;ldquo;see also&amp;rdquo; map&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;git&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Branching work, such as release trains or experiments&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;editorial&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Timelines where each entry has paragraphs, lists, or images&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h3 id=&#34;timeline&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Timeline&lt;/span&gt; &lt;a href=&#34;#timeline&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road timeline&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Project announced&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/blog/announcement/&lt;/span&gt;) Jan 2026&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Public beta&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/blog/beta/&lt;/span&gt;) Apr 2026&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Version 1.0&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/blog/v1/&lt;/span&gt;) Jul 2026&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Plugin marketplace&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/blog/plugins/&lt;/span&gt;) Oct 2026&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&#34;road timeline&#34;&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/getting-started/&#34;&gt;Getting started&lt;/a&gt; Day 1&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/markdown/&#34;&gt;Markdown features&lt;/a&gt; Day 2&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/templates/&#34;&gt;Templates&lt;/a&gt; Day 3&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/feeds/&#34;&gt;Feeds&lt;/a&gt; Day 4&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/div&gt;&#xA;&lt;h3 id=&#34;steps&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Steps&lt;/span&gt; &lt;a href=&#34;#steps&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Steps read from left to right. On narrow screens they change to a timeline.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road steps&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Draft&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/handbook/draft/&lt;/span&gt;) write&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Review&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/handbook/review/&lt;/span&gt;) edit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Publish&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/handbook/publish/&lt;/span&gt;) ship&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Share&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/handbook/share/&lt;/span&gt;) promote&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&#34;road steps&#34;&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/getting-started/&#34;&gt;Install&lt;/a&gt; setup&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/configuration/&#34;&gt;Configure&lt;/a&gt; config&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/themes/&#34;&gt;Theme&lt;/a&gt; style&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/deployment/&#34;&gt;Deploy&lt;/a&gt; ship&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/div&gt;&#xA;&lt;h3 id=&#34;snake&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Snake&lt;/span&gt; &lt;a href=&#34;#snake&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The snake style wraps a long list back and forth across rows, like a board&#xA;game.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road snake&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Variables&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/course/variables/&lt;/span&gt;) 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Functions&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/course/functions/&lt;/span&gt;) 2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Loops&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/course/loops/&lt;/span&gt;) 3&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Structs&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/course/structs/&lt;/span&gt;) 4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Interfaces&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/course/interfaces/&lt;/span&gt;) 5&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Errors&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/course/errors/&lt;/span&gt;) 6&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Testing&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/course/testing/&lt;/span&gt;) 7&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Concurrency&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/course/concurrency/&lt;/span&gt;) 8&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;cycle&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Cycle&lt;/span&gt; &lt;a href=&#34;#cycle&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road cycle&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Plan&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/process/plan/&lt;/span&gt;) week 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Build&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/process/build/&lt;/span&gt;) week 2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Review&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/process/review/&lt;/span&gt;) week 3&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Retro&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/process/retro/&lt;/span&gt;) week 4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&#34;road cycle&#34;&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/markdown/&#34;&gt;Write&lt;/a&gt; draft&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/reference/cli/&#34;&gt;Build&lt;/a&gt; preview&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/content-diagnostics/&#34;&gt;Review&lt;/a&gt; check&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/deployment/&#34;&gt;Publish&lt;/a&gt; ship&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/div&gt;&#xA;&lt;h3 id=&#34;constellation&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Constellation&lt;/span&gt; &lt;a href=&#34;#constellation&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The points sit in fixed, scattered positions joined by fine lines. The layout&#xA;is the same on every visit.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road constellation&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [[on-writing-clearly]] essay&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [[notes-on-focus]] note&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [[a-reading-list]] list&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [[why-plain-text]] essay&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;git&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Git&lt;/span&gt; &lt;a href=&#34;#git&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The git style draws a commit graph with branches and merges. List the commits&#xA;in order, and write the branch after each link:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;After the link&lt;/th&gt;&#xA;&lt;th&gt;Meaning&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;main&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;A commit on &lt;code&gt;main&lt;/code&gt;. A new branch name starts a branch from the first branch (the trunk).&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;fix/typo from feat/search&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Starts &lt;code&gt;fix/typo&lt;/code&gt; from the latest commit on &lt;code&gt;feat/search&lt;/code&gt;.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;main &amp;lt;- feat/search&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Merges &lt;code&gt;feat/search&lt;/code&gt; into &lt;code&gt;main&lt;/code&gt;. You can also write &lt;code&gt;←&lt;/code&gt;.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road git&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Initial commit&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#init&lt;/span&gt;) main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Add search index&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#search&lt;/span&gt;) feat/search&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Update README&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#readme&lt;/span&gt;) main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Search results page&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#results&lt;/span&gt;) feat/search&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Dark mode&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#dark&lt;/span&gt;) feat/dark-mode&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Merge search&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#merge-search&lt;/span&gt;) main &amp;lt;- feat/search&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Try a new palette&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#palette&lt;/span&gt;) spike/palette from feat/dark-mode&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Dark mode polish&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#polish&lt;/span&gt;) feat/dark-mode&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Keep the palette&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#keep&lt;/span&gt;) feat/dark-mode &amp;lt;- spike/palette&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Release 1.0&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/changelog/#v1&lt;/span&gt;) main &amp;lt;- feat/dark-mode&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first commit&amp;rsquo;s branch is the trunk. Each branch gets its own lane and&#xA;color. A merged branch frees its lane for the next branch.&lt;/p&gt;&#xA;&lt;h3 id=&#34;editorial&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Editorial&lt;/span&gt; &lt;a href=&#34;#editorial&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Use the editorial style when each entry needs more than a title. Write a&#xA;heading for each entry, then any Markdown under it: paragraphs, lists,&#xA;checklists, quotes, images, or code.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road editorial&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### [Discovery](/projects/redesign/discovery/) March&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;We interviewed twelve readers and found three common problems.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;- [x]&lt;/span&gt; interviews&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;- [x]&lt;/span&gt; survey&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;- [ ]&lt;/span&gt; analytics review&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### [Prototype](/projects/redesign/prototype/) May&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&#34;ge&#34;&gt;Smaller pages, bigger type, fewer clicks.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### [Launch](/projects/redesign/launch/) August&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&#34;road editorial&#34;&gt;&#xA;&lt;h4 id=&#34;markdown-write&#34;&gt;&lt;a href=&#34;/docs/guides/markdown/&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Markdown&lt;/span&gt;&lt;/a&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt; Write&lt;/span&gt; &lt;a href=&#34;#markdown-write&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h4&gt;&#xA;&lt;p&gt;Write posts in Markdown with frontmatter.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;input checked=&#34;&#34; disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; headings and lists&lt;/li&gt;&#xA;&lt;li&gt;&lt;input checked=&#34;&#34; disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; admonitions and containers&lt;/li&gt;&#xA;&lt;li&gt;&lt;input checked=&#34;&#34; disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; wikilinks&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;templates-shape&#34;&gt;&lt;a href=&#34;/docs/guides/templates/&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Templates&lt;/span&gt;&lt;/a&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt; Shape&lt;/span&gt; &lt;a href=&#34;#templates-shape&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h4&gt;&#xA;&lt;p&gt;Change the layout with templates, or keep the defaults.&lt;/p&gt;&#xA;&lt;h4 id=&#34;deployment-ship&#34;&gt;&lt;a href=&#34;/docs/guides/deployment/&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Deployment&lt;/span&gt;&lt;/a&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt; Ship&lt;/span&gt; &lt;a href=&#34;#deployment-ship&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h4&gt;&#xA;&lt;p&gt;Build static HTML and host it anywhere.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;How editorial entries work:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The text after the heading link (&lt;code&gt;March&lt;/code&gt;) becomes a small label above the&#xA;title.&lt;/li&gt;&#xA;&lt;li&gt;The rail fills in as the reader moves through the entries.&lt;/li&gt;&#xA;&lt;li&gt;The headings stay real headings, so they keep their anchor links and appear&#xA;in the table of contents. Use a heading level below your section heading, so&#xA;the table of contents stays tidy. For example, use &lt;code&gt;###&lt;/code&gt; entries under a &lt;code&gt;##&lt;/code&gt;&#xA;section.&lt;/li&gt;&#xA;&lt;li&gt;A road whose first item is a heading uses the editorial style automatically,&#xA;even when you write &lt;code&gt;::: road&lt;/code&gt; or &lt;code&gt;::: road timeline&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;editorial-stories-icons-and-reveal&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Editorial stories, icons, and reveal&lt;/span&gt; &lt;a href=&#34;#editorial-stories-icons-and-reveal&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h3&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road editorial story reveal&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### :lucide-key-round: RSA migration and faster job views&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;*2026 Q3*&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;A lead paragraph explaining what changed and why it matters.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Faster job views&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Simpler key rotation&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Clearer audit trails&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Fewer manual steps&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;### A quieter milestone without an icon&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;*2026 Q4*&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The ordinary rail dot still works.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A leading &lt;code&gt;:lucide-name:&lt;/code&gt; icon becomes a badge on the rail, muted until the&#xA;entry is active. An emphasis-only paragraph immediately after a heading becomes&#xA;the eyebrow above its title. Both work on all editorial roads, without &lt;code&gt;story&lt;/code&gt;.&#xA;If the heading already has a beside-link label, it takes precedence and the&#xA;emphasis paragraph stays in the body. Mixed-content paragraphs are not labels.&lt;/p&gt;&#xA;&lt;p&gt;Add &lt;strong&gt;&lt;code&gt;story&lt;/code&gt;&lt;/strong&gt; for larger balanced titles, a larger opening paragraph, generous&#xA;spacing, and a prose measure of about 64 characters. Direct unordered lists&#xA;without task checkboxes become diamond-bullet highlights with a top rule.&#xA;Lists of four or more items use two columns at viewport widths of 1100px or&#xA;more. Cards, stats, and figures can use the wider entry body. Without &lt;code&gt;story&lt;/code&gt;,&#xA;existing editorial typography stays unchanged.&lt;/p&gt;&#xA;&lt;p&gt;Add &lt;strong&gt;&lt;code&gt;reveal&lt;/code&gt;&lt;/strong&gt; independently for scroll-triggered entry fades and gentle&#xA;upward motion. It works with or without &lt;code&gt;story&lt;/code&gt;, respects reduced motion, and&#xA;does not animate print, anchor targets, or keyboard-focused entries. Entries&#xA;stay readable without JavaScript or IntersectionObserver, even if the&#xA;enhancement fails: reveal animates arriving content rather than hiding it&#xA;until a callback runs.&lt;/p&gt;&#xA;&lt;h2 id=&#34;more-than-one-road&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;More than one road&lt;/span&gt; &lt;a href=&#34;#more-than-one-road&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A post can have any number of roads, in any mix of styles. Each road draws on&#xA;its own as it scrolls into view.&lt;/p&gt;&#xA;&lt;h2 id=&#34;options&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Options&lt;/span&gt; &lt;a href=&#34;#options&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Use the container attribute block for options:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: road {data-road=&amp;#34;timeline&amp;#34; data-road-spacing=&amp;#34;80&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Alpha&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/releases/alpha/&lt;/span&gt;) v0.1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; [&lt;span class=&#34;nt&#34;&gt;Beta&lt;/span&gt;](&lt;span class=&#34;na&#34;&gt;/releases/beta/&lt;/span&gt;) v0.5&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Option&lt;/th&gt;&#xA;&lt;th&gt;Description&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;data-road=&amp;quot;STYLE&amp;quot;&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Selects the style. This is the same as &lt;code&gt;::: road STYLE&lt;/code&gt;.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;data-road-spacing=&amp;quot;N&amp;quot;&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Sets the vertical space for each milestone, in pixels.&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;To change the colors, set CSS custom properties in your site CSS:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;road&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;--road-accent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;#3fb68b&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c&#34;&gt;/* progress line, active dots, labels */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;--road-muted&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;#4a4f5a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;   &lt;span class=&#34;c&#34;&gt;/* the path before it is drawn */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The defaults come from your palette&amp;rsquo;s &lt;code&gt;--color-primary&lt;/code&gt; and&#xA;&lt;code&gt;--color-border-strong&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;using-html-instead-of-a-container&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Using HTML instead of a container&lt;/span&gt; &lt;a href=&#34;#using-html-instead-of-a-container&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A raw HTML &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; also works. Leave a blank line after the opening tag and&#xA;before the closing tag, so the list inside is parsed as Markdown:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;road&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;data-road&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;timeline&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- [Kickoff](/notes/kickoff/) Jan 2026&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- [Launch](/notes/launch/) Jun 2026&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;accessibility-and-fallbacks&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Accessibility and fallbacks&lt;/span&gt; &lt;a href=&#34;#accessibility-and-fallbacks&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Without JavaScript, a road shows as the ordinary list or headings that you&#xA;wrote.&lt;/li&gt;&#xA;&lt;li&gt;While a road loads, its space is reserved, so the raw list does not flash and&#xA;the page does not jump. If the script fails, the list shows after 2.5 seconds.&lt;/li&gt;&#xA;&lt;li&gt;Every milestone stays a real link that works with the keyboard.&lt;/li&gt;&#xA;&lt;li&gt;When the reader asks for reduced motion, roads appear fully drawn, with no&#xA;animation.&lt;/li&gt;&#xA;&lt;li&gt;Roads keep working when readers move between pages with&#xA;&lt;a href=&#34;/docs/guides/view-transitions/&#34;&gt;view transitions&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;how-roads-load&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;How roads load&lt;/span&gt; &lt;a href=&#34;#how-roads-load&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The road CSS and JavaScript load only on pages that contain a road. markata-go&#xA;finds roads when it renders the post. CSS purge keeps the road styles in&#xA;production builds, with no extra configuration.&lt;/p&gt;&#xA;&lt;h2 id=&#34;troubleshooting&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Troubleshooting&lt;/span&gt; &lt;a href=&#34;#troubleshooting&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;The road shows as a plain list.&lt;/strong&gt; Check that the container closes with a&#xA;line that contains only colons (&lt;code&gt;:::&lt;/code&gt;). For a raw &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, check for the blank&#xA;lines around the list. After you change shared CSS or templates, do a clean&#xA;rebuild.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Some list items are missing.&lt;/strong&gt; Only list items that contain a link become&#xA;milestones.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;The git graph joins the wrong branches.&lt;/strong&gt; Branch names must match exactly.&#xA;A merge (&lt;code&gt;main &amp;lt;- feat/x&lt;/code&gt;) must come after at least one commit on both&#xA;branches.&lt;/p&gt;&#xA;&lt;h2 id=&#34;see-also&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;See also&lt;/span&gt; &lt;a href=&#34;#see-also&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/markdown-containers/&#34;&gt;Markdown containers&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/markdown/&#34;&gt;Markdown features&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;/docs/guides/themes/&#34;&gt;Themes&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Releasing Markata and rolling out every site</title>
    <id>https://markata.dev/docs/guides/releasing/</id>
    <updated>2026-10-20T00:00:00Z</updated>
    <published>2026-10-20T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/releasing/" rel="alternate" type="text/html"></link>
    <summary type="text">Maintainer release gates, PyPI publication, GitOps pins, canaries and verified site builds.</summary>
    <content type="html">&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Historical release documentation:&lt;/strong&gt; These instructions describe the PyPI handoff before it occurred. Current PyPI releases install the Go CLI after the version break; older pinned releases are the Python implementation. See &lt;a href=&#34;/docs/installation/&#34;&gt;installation&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;release-and-deployment-runbook&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Release and deployment runbook&lt;/span&gt; &lt;a href=&#34;#release-and-deployment-runbook&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A release is complete only when &lt;strong&gt;the tested tag, published artifacts, pinned workloads, completed content builds, and live sites agree&lt;/strong&gt;. Creating a GitHub Release or updating a container tag is not enough.&lt;/p&gt;&#xA;&lt;h2 id=&#34;1-freeze-a-tested-source-revision&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;1. Freeze a tested source revision&lt;/span&gt; &lt;a href=&#34;#1-freeze-a-tested-source-revision&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Choose the exact main-branch commit after CI passes; record the 40-character SHA and release version. Maintain Go on &lt;code&gt;0.x&lt;/code&gt;; the next intended version after v0.13.0 is &lt;strong&gt;v0.14.0&lt;/strong&gt;, not 1.0.&lt;/li&gt;&#xA;&lt;li&gt;Require green lint, Linux core/CLI/site integration shards, macOS and Windows tests, and the snapshot package check. No unresolved red CI jobs.&lt;/li&gt;&#xA;&lt;li&gt;In particular, &lt;code&gt;TestCacheDeterminism_ColdVsHot_WithFeedsAllFormats&lt;/code&gt; must not depend on whether a public CDN happened to answer. If the test fails due to an intermittent download, investigate and rerun; record the diagnosis and a durable fix rather than treating a red run as pass.&lt;/li&gt;&#xA;&lt;li&gt;Check any open release-affecting PRs and verify the approved source contains the intended code and docs.&lt;/li&gt;&#xA;&lt;li&gt;Do not tag a moving &lt;code&gt;main&lt;/code&gt; branch by accident: record the exact commit and compare it to the final release ref.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Local maintainer commands (Go 1.27 required):&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git fetch origin --tags&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git checkout main&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git pull --ff-only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt; -race ./...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go vet ./...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;goreleaser check&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go run ./scripts/rendering-contract --check&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# See the dedicated snapshot workflow and check-rc-artifacts.sh.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git rev-parse HEAD&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After &lt;em&gt;all&lt;/em&gt; checks pass, an authorized maintainer creates and pushes an &lt;strong&gt;annotated&lt;/strong&gt; version tag:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git tag -a v0.14.0 &amp;lt;verified-full-commit-sha&amp;gt; -m &lt;span class=&#34;s2&#34;&gt;&amp;#34;Markata v0.14.0&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git push origin v0.14.0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Do not push that tag while the release CI is red.&lt;/strong&gt; This repository&amp;rsquo;s tag-driven &lt;a href=&#34;https://github.com/WaylonWalker/markata/actions/workflows/release.yml&#34;&gt;Release workflow&lt;/a&gt; tests the tagged Go source, uses GoReleaser, and publishes signed binaries/checksums and SBOMs. The &lt;a href=&#34;https://github.com/WaylonWalker/markata/actions/workflows/docker.yml&#34;&gt;Docker workflow&lt;/a&gt; publishes tagged GHCR images including compatibility aliases.&lt;/p&gt;&#xA;&lt;h2 id=&#34;2-verify-artifacts-and-document-the-release&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;2. Verify artifacts and document the release&lt;/span&gt; &lt;a href=&#34;#2-verify-artifacts-and-document-the-release&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Check the canonical &lt;a href=&#34;https://github.com/WaylonWalker/markata/releases&#34;&gt;GitHub Release&lt;/a&gt;, specifically that it is not draft or failed and points to the expected commit.&lt;/li&gt;&#xA;&lt;li&gt;Confirm &lt;code&gt;markata_0.14.0_*&lt;/code&gt; and &lt;code&gt;markata-go_0.14.0_*&lt;/code&gt; archives for Linux, macOS and Windows, checksums, Cosign signatures and SBOMs. Validate one installed binary of each name.&lt;/li&gt;&#xA;&lt;li&gt;Confirm &lt;code&gt;ghcr.io/waylonwalker/markata-builder:0.14.0&lt;/code&gt; and its &lt;code&gt;markata-go-builder:0.14.0&lt;/code&gt; compatibility alias, as well as applicable search image sources. Do &lt;strong&gt;not&lt;/strong&gt; infer publication solely from a workflow that was queued.&lt;/li&gt;&#xA;&lt;li&gt;Include a curated summary, important compatibility notes, upgrade/rollback instructions and a link to &lt;a href=&#34;/docs/releases/v0.14.0/&#34;&gt;v0.14.0 release notes&lt;/a&gt; in the published GitHub release body; the autogenerated commit changelog is supplemental.&lt;/li&gt;&#xA;&lt;li&gt;Never replace a published tag with a different commit. Issue a subsequent patch release for corrections.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;3-publish-pypi-independently-if-its-handoff-gate-is-ready&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;3. Publish PyPI independently, if its handoff gate is ready&lt;/span&gt; &lt;a href=&#34;#3-publish-pypi-independently-if-its-handoff-gate-is-ready&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The current PyPI project name &lt;code&gt;markata&lt;/code&gt; historically belongs to &lt;strong&gt;Python Markata&lt;/strong&gt;. Publishing Go wheels is an intentional breaking installation-path handoff with its own review gate. See &lt;a href=&#34;/docs/guides/pypi-binary-wheels/&#34;&gt;PyPI binary wheels&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Verify PyPI trusted publisher for owner &lt;code&gt;WaylonWalker&lt;/code&gt;, repo &lt;code&gt;markata&lt;/code&gt;, workflow &lt;code&gt;pypi-go-wheels.yml&lt;/code&gt; and environment &lt;code&gt;pypi&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Verify protected GitHub &lt;code&gt;pypi&lt;/code&gt; environment and freeze/disable the old Python repository&amp;rsquo;s publishing workflow.&lt;/li&gt;&#xA;&lt;li&gt;Run &lt;a href=&#34;https://github.com/WaylonWalker/markata/actions/workflows/pypi-go-wheels.yml&#34;&gt;Go Markata PyPI wheels&lt;/a&gt; on &lt;code&gt;main&lt;/code&gt; with version &lt;code&gt;0.14.0&lt;/code&gt;, &lt;code&gt;publish=true&lt;/code&gt; and the workflow&amp;rsquo;s required confirmation only after the above prerequisites are satisfied.&lt;/li&gt;&#xA;&lt;li&gt;Confirm all eight native wheel files on PyPI and test a &lt;em&gt;new&lt;/em&gt; virtual environment with &lt;code&gt;python -m pip install --only-binary=:all: markata==0.14.0&lt;/code&gt;, &lt;code&gt;markata version&lt;/code&gt; and &lt;code&gt;python -m markata version&lt;/code&gt;. Unsupported platforms may otherwise fall back to an older Python package.&lt;/li&gt;&#xA;&lt;li&gt;Keep GitHub Release and PyPI states separately labelled until both have succeeded.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;4-deploy-one-immutable-release-through-argo-cd&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;4. Deploy one immutable release through Argo CD&lt;/span&gt; &lt;a href=&#34;#4-deploy-one-immutable-release-through-argo-cd&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Never change production GitOps to reference an unbuilt tag or a mutable &lt;code&gt;latest&lt;/code&gt; image.&lt;/strong&gt; In each multi-source Helm Application pin the chart &lt;code&gt;targetRevision: v0.14.0&lt;/code&gt; and align every Markata fetch, builder and search image &lt;code&gt;tag: &amp;quot;0.14.0&amp;quot;&lt;/code&gt; with that source. Preserve other application settings, storage modes, secrets and feature flags. If search is intentionally independently pinned, verify the compatible search version first; record the exception explicitly.&lt;/p&gt;&#xA;&lt;p&gt;Use a separate GitOps PR that can be held until all artifacts are verified. Progressive rollout:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Order&lt;/th&gt;&#xA;&lt;th&gt;Surface&lt;/th&gt;&#xA;&lt;th&gt;GitOps source&lt;/th&gt;&#xA;&lt;th&gt;Expected action&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;1&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;go.waylonwalker.com&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;argo-apps/apps/go-waylonwalker-com.yaml&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Canary chart/builder/search pins; rebuild and smoke&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;2&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;waylonwalker.com&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;argo-apps/apps/waylonwalker-com-prod.yaml&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Full site build; smoke archive/images/sidebar/navigation&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;3&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;rhiannonwalker.com&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;argo-apps/apps/rhiannonwalker-com-prod.yaml&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Build via Builder Admin and confirm site&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;4&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;wyattbubbylee.com&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;argo-apps/apps/wyattbubbylee-com-prod.yaml&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Build via Builder Admin and confirm site&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;5&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;recipes.waylonwalker.com&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;&lt;code&gt;k8s/recipes-waylonwalker-com/deployment.yaml&lt;/code&gt; and &lt;code&gt;site-config.yaml&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Replace both mutable &lt;code&gt;latest&lt;/code&gt; references with &lt;code&gt;0.14.0&lt;/code&gt;; confirm recipe build&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;The &lt;code&gt;markata-docs&lt;/code&gt; Deployment uses a &lt;strong&gt;separate Python-based documentation generator&lt;/strong&gt; and separately versioned docs images; it is &lt;strong&gt;not&lt;/strong&gt; a Markata CLI runtime and should not be falsely counted as an old Markata deployment. &lt;code&gt;platgo&lt;/code&gt; currently has an &lt;em&gt;example/commented&lt;/em&gt; Markata builder setting, not an active runtime. A historical &lt;code&gt;rhiannonwalker&lt;/code&gt; source-seed bootstrap Job has a pinned image; audit it only if bootstrap is still required.&lt;/p&gt;&#xA;&lt;p&gt;For each Argo Application: compare desired manifests with running pod image &lt;strong&gt;digests&lt;/strong&gt; and chart revision; confirm it synced successfully and is healthy. On Builder Admin, compare running binary revision with most recent &lt;strong&gt;successfully published build&lt;/strong&gt;. If the feature&amp;rsquo;s automatic build-on-new-revision does not run, invoke a full build through the authenticated builder. Verify site content before counting it complete.&lt;/p&gt;&#xA;&lt;p&gt;Example read-only checks (use your configured &lt;code&gt;kubectl&lt;/code&gt; context; do not assume remote cluster access from CI):&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kubectl -n argocd get applications&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kubectl -n waylonwalker-com-prod-notes get deployments,pods&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kubectl -n go-waylonwalker-com-notes get deployments,pods&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kubectl -n rhiannonwalker-com-prod-notes get deployments,pods&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kubectl -n wyattbubbylee-com-prod-notes get deployments,pods&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kubectl -n recipes-waylonwalker-com get deployments,pods&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -fIsS https://waylonwalker.com/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -fIsS https://waylonwalker.com/archive/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -fIsS https://waylonwalker.com/images/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;5-rollback-and-closeout&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;5. Rollback and closeout&lt;/span&gt; &lt;a href=&#34;#5-rollback-and-closeout&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Before each promotion, record old chart SHA, old image digests, the most recent good site release identifier and an application-specific rollback procedure. If the new build fails, pause further promotions, restore the old immutable chart/image pins in GitOps, reconcile, and activate the last known-good site release. A content rollback and a binary rollback are &lt;strong&gt;different operations&lt;/strong&gt;; verify both.&lt;/p&gt;&#xA;&lt;p&gt;Keep a deployment record with: release version, tag commit, binary artifacts, PyPI status, container digests, Argo commit, per-site desired/running image, build revision, site release ID, full-build result, public smoke results and timestamp. Mark each site &lt;strong&gt;verified&lt;/strong&gt;, &lt;strong&gt;blocked&lt;/strong&gt;, or &lt;strong&gt;not applicable&lt;/strong&gt;; never call the release &amp;ldquo;deployed everywhere&amp;rdquo; with unknowns.&lt;/p&gt;&#xA;</content>
  </entry>
  <entry>
    <title>Status badges, metrics, gauges, and sparklines</title>
    <id>https://markata.dev/docs/guides/markdown-metrics/</id>
    <updated>2026-10-20T00:00:00Z</updated>
    <published>2026-10-20T00:00:00Z</published>
    <link href="https://markata.dev/docs/guides/markdown-metrics/" rel="alternate" type="text/html"></link>
    <summary type="text">Author static-first status reports, before/after stats, accessible meters, and trend sparklines with Markdown.</summary>
    <content type="html">&lt;h2 id=&#34;status-metrics-gauges-and-sparklines&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Status, metrics, gauges, and sparklines&lt;/span&gt; &lt;a href=&#34;#status-metrics-gauges-and-sparklines&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Markata&amp;rsquo;s Markdown containers can render compact, theme-aware operational&#xA;summaries without using JavaScript. Combine these components with the&#xA;&lt;a href=&#34;/docs/guides/markdown-containers/&#34;&gt;responsive layout primitives&lt;/a&gt; to produce&#xA;the same kind of dashboard-like reporting found in modern chat interfaces.&lt;/p&gt;&#xA;&lt;p&gt;The components are &lt;strong&gt;presentation&lt;/strong&gt;, not automatic monitoring. Authors supply&#xA;the measurements; Markata does not calculate or verify them.&lt;/p&gt;&#xA;&lt;h2 id=&#34;components&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Components&lt;/span&gt; &lt;a href=&#34;#components&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;&lt;thead&gt;&#xA;&lt;tr&gt;&#xA;&lt;th&gt;Container&lt;/th&gt;&#xA;&lt;th&gt;Role&lt;/th&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/thead&gt;&#xA;&lt;tbody&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-status&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Compact inline status with an optional semantic tone&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-stat&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;First paragraph is label; second is large value; third is optional secondary label&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-delta&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Side-by-side comparison caption and emphasized result&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-meter&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Native HTML &lt;code&gt;&amp;lt;meter&amp;gt;&lt;/code&gt; for measurements like free disk space&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-progress&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Native HTML &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt; for partially completed tasks&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;tr&gt;&#xA;&lt;td&gt;&lt;code&gt;md-sparkline&lt;/code&gt;&lt;/td&gt;&#xA;&lt;td&gt;Static inline SVG trend line from a short series of numbers&lt;/td&gt;&#xA;&lt;/tr&gt;&#xA;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;&lt;code&gt;data-tone=&amp;quot;success&amp;quot;&lt;/code&gt;, &lt;code&gt;data-tone=&amp;quot;caution&amp;quot;&lt;/code&gt;, and&#xA;&lt;code&gt;data-tone=&amp;quot;danger&amp;quot;&lt;/code&gt; use the site&amp;rsquo;s existing semantic palette colors.&#xA;Unknown tones use the ordinary theme accent. Both gauges require finite&#xA;numbers &lt;code&gt;data-value&lt;/code&gt; and &lt;code&gt;data-max&lt;/code&gt; where max is positive and&#xA;0 ≤ value ≤ max. They also &lt;strong&gt;require&lt;/strong&gt; a descriptive &lt;code&gt;data-label&lt;/code&gt;, which&#xA;becomes the accessible label on the native HTML element.&lt;/p&gt;&#xA;&lt;p&gt;When an attribute is missing or invalid, the container still renders its&#xA;Markdown body normally and no graphical gauge is added. The text should&#xA;always include the exact value so the page is understandable in text-only&#xA;readers and feeds.&lt;/p&gt;&#xA;&lt;h2 id=&#34;verified-result-badge&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Verified result badge&lt;/span&gt; &lt;a href=&#34;#verified-result-badge&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: md-status {data-tone=&amp;#34;success&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NVMe cleanup verified&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Do not use green color alone to communicate success: include the literal&#xA;status wording, as above.&lt;/p&gt;&#xA;&lt;h2 id=&#34;before-after-metrics-and-native-meters&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Before/after metrics and native meters&lt;/span&gt; &lt;a href=&#34;#before-after-metrics-and-native-meters&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: md-layout&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Falcon3 NVMe — before and after cleanup&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::: md-columns&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::: md-stat {data-tone=&amp;#34;caution&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Before&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gs&#34;&gt;**83 GiB**&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;18% free&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::::: md-meter {data-value=&amp;#34;18&amp;#34; data-max=&amp;#34;100&amp;#34; data-label=&amp;#34;Before cleanup: 18 percent free&amp;#34; data-tone=&amp;#34;caution&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::: md-stat {data-tone=&amp;#34;success&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;After&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gs&#34;&gt;**212 GiB**&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;45% free&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::::: md-meter {data-value=&amp;#34;45&amp;#34; data-max=&amp;#34;100&amp;#34; data-label=&amp;#34;After cleanup: 45 percent free&amp;#34; data-tone=&amp;#34;success&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::: md-delta {data-tone=&amp;#34;success&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Space recovered&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ge&#34;&gt;**&lt;/span&gt;+129 GiB**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These remain normal Markdown paragraphs and nested containers. Use longer&#xA;colon fences for deeper nesting, and place blank lines before bare closers.&lt;/p&gt;&#xA;&lt;h2 id=&#34;trend-sparklines&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Trend sparklines&lt;/span&gt; &lt;a href=&#34;#trend-sparklines&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A sparkline shows the shape of a series next to the number it explains.&#xA;Give &lt;code&gt;data-values&lt;/code&gt; as two or more finite numbers, separated by spaces or&#xA;commas, and a descriptive &lt;code&gt;data-label&lt;/code&gt;. The line is drawn at build time as an&#xA;inline SVG, so it needs no JavaScript. The Markdown body stays as a visible&#xA;caption.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: md-stat {data-tone=&amp;#34;success&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Jobs run&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gs&#34;&gt;**222,421**&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Year 4 ran 3x the jobs of year 3&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::: md-sparkline {data-values=&amp;#34;8120 21400 48300 144601&amp;#34; data-label=&amp;#34;Jobs per year, years 1 to 4&amp;#34; data-tone=&amp;#34;success&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Years 1–4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The sparkline draws only a line by default. Add the &lt;code&gt;area&lt;/code&gt; modifier class to&#xA;shade the area under the line:&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: md-sparkline area {data-values=&amp;#34;12 18 15 31 44&amp;#34; data-label=&amp;#34;Jobs per week&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Last five weeks&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The line fills the container width and scales between the lowest and highest&#xA;values. It does not start at zero, so it shows shape, not size. Put the exact&#xA;numbers in the text or a table when the reader needs them. The SVG&amp;rsquo;s&#xA;accessible name gives the label, point count, first and last values, low, and&#xA;high.&lt;/p&gt;&#xA;&lt;p&gt;A sparkline accepts up to 500 points. With fewer than two points, a missing&#xA;label, or a value that is not a finite number, no line is drawn and the&#xA;caption renders as normal.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-build-progress-bar&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;A build progress bar&lt;/span&gt; &lt;a href=&#34;#a-build-progress-bar&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;A task-completion indicator is not the same as a measured storage percentage.&#xA;Use &lt;code&gt;md-progress&lt;/code&gt; only when a process is underway.&lt;/p&gt;&#xA;&lt;pre class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: md-progress {data-value=&amp;#34;7&amp;#34; data-max=&amp;#34;10&amp;#34; data-label=&amp;#34;Build steps completed&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;7 of 10 build steps finished.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;:::&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;full-report-with-a-normal-markdown-table&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Full report with a normal Markdown table&lt;/span&gt; &lt;a href=&#34;#full-report-with-a-normal-markdown-table&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Use the &lt;a href=&#34;/layout-metrics/&#34;&gt;example page&lt;/a&gt; for the complete composition,&#xA;including the existing semantic GFM table. Future sortable table behavior&#xA;will work independently of these static metrics and should never be needed&#xA;to see the content.&lt;/p&gt;&#xA;&lt;h2 id=&#34;compatibility-and-accessibility&#34;&gt;&lt;span class=&#34;heading-wear-glyph&#34;&gt;Compatibility and accessibility&lt;/span&gt; &lt;a href=&#34;#compatibility-and-accessibility&#34; class=&#34;heading-anchor&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Fully rendered at build time; no component JavaScript or network requests.&lt;/li&gt;&#xA;&lt;li&gt;The source Markdown body and numeric labels remain readable in plain text.&lt;/li&gt;&#xA;&lt;li&gt;Native &lt;code&gt;meter&lt;/code&gt; and &lt;code&gt;progress&lt;/code&gt; provide standard accessible semantics.&lt;/li&gt;&#xA;&lt;li&gt;Sparklines are &lt;code&gt;role=&amp;quot;img&amp;quot;&lt;/code&gt; SVGs with a generated accessible summary.&lt;/li&gt;&#xA;&lt;li&gt;Color tones inherit from the active theme, including alternate palettes.&lt;/li&gt;&#xA;&lt;li&gt;Nested grids stack at mobile widths using the layout primitives.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content>
  </entry>
</feed>