<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: mermaid</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/mermaid.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2026-07-31T23:13:22+00:00</updated><author><name>Simon Willison</name></author><entry><title>Stateless MCP has recaptured my interest (and inspired mcp-explorer and datasette-mcp)</title><link href="https://simonwillison.net/2026/Jul/31/stateless-mcp/" rel="alternate"/><published>2026-07-31T23:13:22+00:00</published><updated>2026-07-31T23:13:22+00:00</updated><id>https://simonwillison.net/2026/Jul/31/stateless-mcp/</id><summary type="html">
    &lt;p&gt;Tuesday was &lt;a href="https://x.com/ade_oshineye/status/2082129440943866149"&gt;Stateless MCP day&lt;/a&gt; - the rollout of MCP 2.0, or &lt;a href="https://blog.modelcontextprotocol.io/posts/2026-07-28/"&gt;the 2026-07-28 Model Context Protocol specification&lt;/a&gt; to use the more formal but less memorable name. This is the most significant change to the MCP spec since it first launched, and has also served to reignite my personal interest in the protocol.&lt;/p&gt;
&lt;p&gt;For background: MCP is the Model Context Protocol, which describes a standard way to expose new tools to LLM-powered agent frameworks. It was introduced by Anthropic back &lt;a href="https://www.anthropic.com/news/model-context-protocol"&gt;in November 2024&lt;/a&gt;, had a &lt;em&gt;huge&lt;/em&gt; spike of interest through much of 2025, and then became somewhat eclipsed by &lt;a href="https://simonwillison.net/2025/Oct/16/claude-skills/"&gt;Skills&lt;/a&gt; (another Anthropic invention) when it became apparent that an agent harness with access to a terminal and &lt;code&gt;curl&lt;/code&gt; could do most of what MCP did in a more flexible way. I wrote about that &lt;a href="https://simonwillison.net/2025/Dec/31/the-year-in-llms/#the-only-year-of-mcp"&gt;in my review of 2025&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm coming back around to MCP now. Giving an agent a shell environment with the ability to access the internet is &lt;a href="https://simonwillison.net/2026/Jul/22/openai-cyberattack/"&gt;fraught with risk&lt;/a&gt;, and requires a strong model that is capable of effectively driving such an environment. MCP tools are easier to audit and control, and simple enough that smaller models that run on a laptop can still drive them reasonably well.&lt;/p&gt;
&lt;p&gt;The new stateless MCP specification also greatly decreases the complexity of implementing both clients and servers for the protocol. I built three of those this week!&lt;/p&gt;
&lt;h4 id="what-s-easier-with-stateless-mcp"&gt;What's easier with stateless MCP&lt;/h4&gt;
&lt;p&gt;The best demonstration of the difference between stateful and stateless MCP is in this &lt;a href="https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/"&gt;May 21st blog post&lt;/a&gt; that introduced the RC for the new specification. It included a clear before-and-after example.&lt;/p&gt;
&lt;p&gt;The older stateful MCP (I'm going to call it "legacy MCP") required two HTTP requests - the first to initialize a session and obtain a &lt;code&gt;Mcp-Session-Id&lt;/code&gt;, and the second to actually call the tool:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /mcp HTTP/1.1
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
    },
    "clientInfo": {
      "name": "my-app",
      "version": "1.0"
    }
  }
}

POST /mcp HTTP/1.1
Mcp-Session-Id: 1868a90c-3a3f-4f5b
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "search",
    "arguments": {
      "q": "otters"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new stateless way uses a single HTTP request which looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search",
    "arguments": {
      "q": "otters"
    },
    "_meta": {
      "io.modelcontextprotocol/clientInfo": {
        "name": "my-app",
        "version": "1.0"
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is so much cleaner from both a client- and server-side implementation perspective. It's also a better fit for building scalable web applications, since now you don't need to maintain server-side state to keep track of those session IDs, or worry about routing the same session to the same backend machine.&lt;/p&gt;
&lt;h4 id="mcp-explorer"&gt;mcp-explorer&lt;/h4&gt;
&lt;p&gt;I couldn't find a great CLI tool for interactively probing an MCP server, so I had Codex help build my own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/simonw/mcp-explorer"&gt;mcp-explorer&lt;/a&gt;&lt;/strong&gt; is the result. It's a stateless Python CLI tool, so you don't even need to install it to try it out - it works with &lt;a href="https://docs.astral.sh/uv/guides/tools/#running-tools"&gt;uvx&lt;/a&gt; like this:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;uvx mcp-explorer list https://agentic-mermaid.dev/mcp&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This queries Ade Oshineye's &lt;a href="https://agentic-mermaid.dev/"&gt;agentic-mermaid.dev&lt;/a&gt; demo MCP. The above command returns the following list of tools:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;execute(code: string, timeoutMs?: integer) - Execute Mermaid SDK code
  Run JavaScript in an isolated sandbox; return a value.

describe_sdk(family: string, detail?: string) - Describe Mermaid SDK operations
  Return version-matched mutation operations for one diagram family.

render_svg(source: string, options?: object) - Render Mermaid as SVG
  Render a Mermaid source string to themeable SVG. Returns { ok, svg }.

render_ascii(source: string, useAscii?: boolean, targetWidth?: integer, options?: object) - Render Mermaid as text
  Render a Mermaid source string to text. Returns { ok, text }.

render_png(source: string, scale?: number, background?: string, fitTo?: object, options?: object) - Render Mermaid as PNG
  Rasterize a Mermaid source string to PNG. Returns { ok, png_base64 }.
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then to inspect a tool:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;uvx mcp-explorer inspect render_svg&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This outputs a whole bunch of information, including the JSON schema of the inputs and outputs.&lt;/p&gt;
&lt;p&gt;To call that tool and pass arguments to it:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;uvx mcp-explorer call \
  https://agentic-mermaid.dev/mcp \
  render_svg \
  -a &lt;span class="pl-c1"&gt;source&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;graph TD; A--&amp;gt;B&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; \
  -a options &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;{"padding":24}&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which returns:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{"ok":true,"svg":"&amp;lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get just the raw SVG try adding &lt;code&gt;| jq .svg -r&lt;/code&gt; to that command. I got back &lt;a href="https://gist.github.com/simonw/b07c62f0ce103be6932477659d5dd1ac"&gt;this image&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2026/mermaid-example.svg" alt="SVG of as A box on top of a B box with an arrow from A to B" style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;There are a &lt;a href="https://github.com/simonw/mcp-explorer/blob/main/README.md"&gt;few more commands&lt;/a&gt; in the README, but you get the general idea. I find building CLI tools like this to be a really productive way to get familiar with a specification, even if an agent writes most of the actual code.&lt;/p&gt;
&lt;h4 id="datasette-mcp"&gt;datasette-mcp&lt;/h4&gt;
&lt;p&gt;The second project is &lt;strong&gt;&lt;a href="https://github.com/datasette/datasette-mcp"&gt;datasette-mcp&lt;/a&gt;&lt;/strong&gt;, a Datasette plugin which adds a &lt;code&gt;/-/mcp&lt;/code&gt; endpoint to any Datasette instance.&lt;/p&gt;
&lt;p&gt;This is probably the fourth time I've tried building this plugin, but thanks to the new stateless MCP specification I finally have a version that feels good to release.&lt;/p&gt;
&lt;p&gt;It provides just three tools: &lt;code&gt;list_databases()&lt;/code&gt;, &lt;code&gt;get_database_schema(database_name)&lt;/code&gt;, and &lt;code&gt;execute_sql(database_name, sql)&lt;/code&gt;. They do exactly what you would expect them to do - though &lt;code&gt;execute_sql()&lt;/code&gt; is read-only for the moment.&lt;/p&gt;
&lt;p&gt;Wire these into an agent, or a chat tool like ChatGPT or Claude, and they'll gain the ability to run SQL queries against your hosted Datasette instance.&lt;/p&gt;
&lt;p&gt;So far I'm running it on the Datasette mirror of my blog, at &lt;a href="datasette.simonwillison.net/-/mcp"&gt;datasette.simonwillison.net/-/mcp&lt;/a&gt;. It took a bit of fiddling to figure out how to attach that to ChatGPT and Claude, but I got there in the end. Here's &lt;a href="https://til.simonwillison.net/llms/mcp-in-claude-and-chatgpt"&gt;a new TIL&lt;/a&gt; showing exactly how to do that.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://claude.ai/share/de1ad9bf-f7c2-4fb9-a9a0-2a1ae39995db"&gt;a shared Claude session&lt;/a&gt; where I asked it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;list tables in simonwillison.net&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And then:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;what has Simon said recently about MCP?&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It ran 7 separate SQL queries to figure out the answer.&lt;/p&gt;
&lt;h4 id="llm-mcp-client"&gt;llm-mcp-client&lt;/h4&gt;
&lt;p&gt;My &lt;a href="https://llm.datasette.io/"&gt;LLM tool&lt;/a&gt; is long overdue for an official MCP integration. The new alpha &lt;a href="https://github.com/simonw/llm-mcp-client"&gt;llm-mcp-client&lt;/a&gt; plugin is my attempt at exactly that:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;llm install llm-mcp-client
llm -T &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;MCP("https://datasette.simonwillison.net/-/mcp")&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;count the notes&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here's the output (including reasoning trace, I'm using &lt;a href="https://simonwillison.net/2026/Jul/30/llm-rc2/"&gt;LLM 0.32rc2&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Considering note count&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I see the question "count the notes" is probably asking me to tally up blog notes. It could also mean published notes or drafts, so there's some ambiguity there. I'll need to figure out the total number of notes, likely by querying the count for both published notes and drafts to get a clear answer. Let's execute that count!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There are &lt;strong&gt;151 notes&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And &lt;a href="https://gist.github.com/simonw/4e8f558766150658ce35eab4f0fc3e04"&gt;the output of llm logs&lt;/a&gt; for that prompt.&lt;/p&gt;
&lt;p&gt;Once this is fully baked, I'm considering bringing it directly into LLM core. I'm excited to experiment with MCP in &lt;a href="https://agent.datasette.io/"&gt;Datasette Agent&lt;/a&gt; and &lt;a href="https://github.com/simonw/llm-coding-agent"&gt;llm-coding-agent&lt;/a&gt; as well.&lt;/p&gt;
&lt;h4 id="mcp-is-a-safer-way-to-build-with-agents"&gt;MCP is a safer way to build with agents&lt;/h4&gt;
&lt;p&gt;A few months after MCP was first released, I wrote &lt;a href="https://simonwillison.net/2025/Apr/9/mcp-prompt-injection/"&gt;Model Context Protocol has prompt injection security problems&lt;/a&gt;, where I noted that the pattern of having end users mix and match tools pushed responsibility for avoiding data exfiltration attacks out to the users themselves. I hadn't coined &lt;a href="https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/"&gt;the Lethal Trifecta&lt;/a&gt; yet, but that was absolutely what I had in mind.&lt;/p&gt;
&lt;p&gt;Then general agents with arbitrary shell and &lt;code&gt;curl&lt;/code&gt; access came along, and that's so much harder to keep secure!&lt;/p&gt;
&lt;p&gt;Something I've come to appreciate about MCP is that it's much easier to reason about agent capabilities and what might go wrong than with arbitrary command execution in an open network environment - the default for most of today's general and coding agent tools.&lt;/p&gt;
&lt;p&gt;I plan to lean into MCP a whole lot more when I'm building sensitive applications on top of LLMs.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mermaid"&gt;mermaid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm"&gt;llm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/model-context-protocol"&gt;model-context-protocol&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="projects"/><category term="ai"/><category term="datasette"/><category term="mermaid"/><category term="generative-ai"/><category term="llms"/><category term="llm"/><category term="anthropic"/><category term="model-context-protocol"/></entry><entry><title>Mermaid to ASCII art (mermaid-ascii)</title><link href="https://simonwillison.net/2026/Jul/16/mermaid-ascii/" rel="alternate"/><published>2026-07-16T14:57:39+00:00</published><updated>2026-07-16T14:57:39+00:00</updated><id>https://simonwillison.net/2026/Jul/16/mermaid-ascii/</id><summary type="html">
    
        &lt;p&gt;&lt;strong&gt;Tool:&lt;/strong&gt; &lt;a href="https://tools.simonwillison.net/mermaid-ascii"&gt;Mermaid to ASCII art (mermaid-ascii)&lt;/a&gt;&lt;/p&gt;
        &lt;p&gt;After building the &lt;a href="https://simonwillison.net/2026/Jul/16/grok-mermaid/"&gt;Mermaid to ASCII tool based on Grok Build's Rust code&lt;/a&gt; I learned that there's an older, more fully-featured Go library called &lt;a href="https://github.com/AlexanderGrooff/mermaid-ascii"&gt;AlexanderGrooff/mermaid-ascii&lt;/a&gt; that implements a similar pattern, so I had Claude Fable 5 compile that one to WebAssembly as well so I could compare the two.&lt;/p&gt;
&lt;p&gt;This one includes support for colors!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screenshot of a Mermaid diagram editor web app. A row of tab buttons reads: Flowchart, Multiple links, Subgraphs, Multi-line labels, Colors (selected, highlighted blue), Sequence, Alt fragment, Loop + note, Parallel. Below is a text input area containing: &amp;quot;graph LR / Build:::good --&amp;gt; Test:::good / Test --&amp;gt; Deploy:::warn / Deploy --&amp;gt; Rollback:::bad / classDef good color:#3fb950 / classDef warn color:#e3b341 / classDef bad color:#ff7b72&amp;quot;. A control row shows an unchecked &amp;quot;ASCII only&amp;quot; checkbox, &amp;quot;Padding X: 5&amp;quot;, &amp;quot;Padding Y: 5&amp;quot;, &amp;quot;Box padding: 1&amp;quot;, and buttons &amp;quot;Copy as text&amp;quot; and &amp;quot;Copy link to this diagram&amp;quot;. At the bottom on a black background is the rendered left-to-right flowchart with four connected boxes: &amp;quot;Build&amp;quot; (green text), &amp;quot;Test&amp;quot; (green text), &amp;quot;Deploy&amp;quot; (yellow text), &amp;quot;Rollback&amp;quot; (red text), each linked by arrows." src="https://static.simonwillison.net/static/2026/mermaid-ascii.webp" /&gt;&lt;/p&gt;
    
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/go"&gt;go&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tools"&gt;tools&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webassembly"&gt;webassembly&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mermaid"&gt;mermaid&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="go"/><category term="tools"/><category term="webassembly"/><category term="mermaid"/></entry><entry><title>Mermaid to Unicode box art (grok-mermaid)</title><link href="https://simonwillison.net/2026/Jul/16/grok-mermaid/" rel="alternate"/><published>2026-07-16T00:33:18+00:00</published><updated>2026-07-16T00:33:18+00:00</updated><id>https://simonwillison.net/2026/Jul/16/grok-mermaid/</id><summary type="html">
    
        &lt;p&gt;&lt;strong&gt;Tool:&lt;/strong&gt; &lt;a href="https://tools.simonwillison.net/grok-mermaid"&gt;Mermaid to Unicode box art (grok-mermaid)&lt;/a&gt;&lt;/p&gt;
        &lt;p&gt;While &lt;a href="https://simonwillison.net/2026/Jul/15/grok-build/"&gt;exploring the codebase&lt;/a&gt; for the newly open-sourced Grok CLI coding agent I came across &lt;a href="https://github.com/xai-org/grok-build/blob/b189869b7755d2b482969acf6c92da3ecfeffd36/crates/codegen/xai-grok-markdown/src/mermaid.rs"&gt;xai-grok-markdown/src/mermaid.rs&lt;/a&gt;, a "self-contained terminal renderer for Mermaid diagrams" written in Rust.&lt;/p&gt;
&lt;p&gt;I figured it would be fun to try that out in a browser via WebAssembly. Here's &lt;a href="https://github.com/simonw/tools/pull/293#issue-4897479396"&gt;the prompt&lt;/a&gt; I ran in Claude Code for web (Fable 5), and this is what the resulting tool looks like:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screenshot of a Mermaid diagram editor showing source code and rendered flowchart. The code reads: graph TD Start[Request received] --&amp;gt; Auth{Authenticated?} Auth --&amp;gt;|yes| Rate{Rate limit OK?} Auth --&amp;gt;|no| R401[401 Unauthorized] Rate --&amp;gt;|yes| H(Handle request) Rate --&amp;gt;|no| R429[429 Too Many Requests] H -.-&amp;gt; Log[Audit log] H ==&amp;gt; Resp[200 OK]. Below the code are controls labeled Max width: Fit output panel, Copy as text, and Copy link to this diagram. The rendered flowchart on a dark background flows top-down: Request received leads to Authenticated?, which branches yes to Rate limit OK? and no to 401 Unauthorized. Rate limit OK? branches yes to Handle request and no to 429 Too Many Requests. Handle request connects with a dotted arrow to Audit log and a thick arrow to 200 OK." src="https://static.simonwillison.net/static/2026/grok-mermaid-wasm.png" /&gt;&lt;/p&gt;
    
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/tools"&gt;tools&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webassembly"&gt;webassembly&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mermaid"&gt;mermaid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/grok"&gt;grok&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/xai"&gt;xai&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="tools"/><category term="rust"/><category term="webassembly"/><category term="mermaid"/><category term="grok"/><category term="xai"/></entry><entry><title>Mermaid Gantt diagrams are great for displaying distributed traces in Markdown</title><link href="https://simonwillison.net/2024/Jul/16/mermaid-gantt-diagrams/" rel="alternate"/><published>2024-07-16T22:10:33+00:00</published><updated>2024-07-16T22:10:33+00:00</updated><id>https://simonwillison.net/2024/Jul/16/mermaid-gantt-diagrams/</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://brycemecum.com/2023/03/31/til-mermaid-tracing/"&gt;Mermaid Gantt diagrams are great for displaying distributed traces in Markdown&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Bryce Mecum demonstrates how Mermaid &lt;code&gt;gantt&lt;/code&gt; diagrams can be used to render trace information, such as the traces you might get from OpenTelemetry. I tried this out &lt;a href="https://gist.github.com/simonw/01c0440845516be42ddc4a9023181e75"&gt;in a Gist&lt;/a&gt; and it works really well - GitHub Flavored Markdown will turn any fenced code block tagged &lt;code&gt;mermaid&lt;/code&gt; containing a &lt;code&gt;gantt&lt;/code&gt; definition into a neat rendered diagram.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/markdown"&gt;markdown&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mermaid"&gt;mermaid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/opentelemetry"&gt;opentelemetry&lt;/a&gt;&lt;/p&gt;



</summary><category term="markdown"/><category term="mermaid"/><category term="opentelemetry"/></entry><entry><title>Datasette table diagram using Mermaid</title><link href="https://simonwillison.net/2022/Feb/14/datasette-table-diagram-using-mermaid/" rel="alternate"/><published>2022-02-14T19:43:15+00:00</published><updated>2022-02-14T19:43:15+00:00</updated><id>https://simonwillison.net/2022/Feb/14/datasette-table-diagram-using-mermaid/</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://observablehq.com/@simonw/datasette-table-diagram-using-mermaid"&gt;Datasette table diagram using Mermaid&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Mermaid is a DSL for generating diagrams from plain text, designed to be embedded in Markdown. GitHub just added support for Mermaid to their Markdown pipeline, which inspired me to try it out. Here’s an Observable Notebook I built which uses Mermaid to visualize the relationships between Datasette tables based on their foreign keys.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/simonw/status/1493305519481626626"&gt;@simonw&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/dsl"&gt;dsl&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/visualization"&gt;visualization&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/observable"&gt;observable&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mermaid"&gt;mermaid&lt;/a&gt;&lt;/p&gt;



</summary><category term="dsl"/><category term="github"/><category term="visualization"/><category term="datasette"/><category term="observable"/><category term="mermaid"/></entry></feed>