Rendering diagrams in Claude Code
Claude’s Artifacts support a fixed set of natively-rendered content — HTML, SVG,
Mermaid diagrams, React components, code — with no plugin mechanism to register a new
file extension or “artifact type” and hand it to a custom renderer. There is no
equivalent of a browser’s MIME-type handler registry here. So a .c4 (or any other
custom extension) file does not get intercepted and routed to this library
automatically the way, say, a .md file is.
What is available, and is what this integration uses, is that Claude reads plain SVG
natively. So the trick isn’t getting Claude to recognize a new file type — it’s getting
it to run this library’s renderer before it builds an Artifact, and paste the
resulting <svg> markup directly into the page, instead of hand-drawing an
approximation of a C4 diagram or reaching for Mermaid’s (partial, non-conforming) C4
support.
There are two ways to make that happen, and they compose — use either or both:
1. A Skill (what’s shipped here)
integrations/claude-code/skills/render-c4-diagram/
is a ready-to-copy Claude Code skill. It tells Claude: when you see C4-PlantUML source
(a fenced ```c4 block, a .puml file, pasted text using Person/System/
Container/Rel macros), pipe it through
npx --package=@liminis/diagrams --package=react --package=react-dom -- render-c4 --stdin and embed the resulting SVG
rather than drawing your own.
Install it by copying the directory into a skills folder Claude Code loads from — either
project-local (.claude/skills/render-c4-diagram/ in the repo you’re working in) or
your personal one, so it applies across every project:
cp -r integrations/claude-code/skills/render-c4-diagram ~/.claude/skills/This only works in Claude Code, which can execute shell commands (npx) — plain
Claude.ai or Claude Desktop chat without Code has no shell to invoke the CLI from, which
is what the MCP tool below is for.
2. An MCP tool
For Claude Desktop, Claude.ai, or any other MCP-connected client — not just Claude
Code — expose the renderer as an MCP tool instead of a shelled-out CLI. This library
already has a consumer doing exactly that: the doc comment on
renderC4DiagramToSVG notes it’s “used by the
app_render_c4_diagram MCP tool for Confluence publishing” in @liminis/editor. That
tool isn’t part of this repo, but the shape is a small wrapper:
import { renderC4DiagramToSVG } from '@liminis/diagrams/server';
server.tool( 'render_c4_diagram', { code: z.string(), isDarkMode: z.boolean().optional() }, async ({ code, isDarkMode }) => { const { svg, errors } = renderC4DiagramToSVG(code, isDarkMode); if (errors.length > 0) { return { content: [{ type: 'text', text: JSON.stringify(errors) }], isError: true }; } return { content: [{ type: 'text', text: svg }] }; },);An MCP tool is the more portable option — it works anywhere the client is MCP-connected, without a shell — and is the right choice if you want this to work outside Claude Code specifically. The skill above is the lighter-weight option when you’re already in Claude Code and don’t want to stand up and host an MCP server.
Both point at the same CLI
Whichever path you take, the actual rendering goes through render-c4
(@liminis/diagrams’s bundled CLI — see
the GitHub integration page for its full flag reference) or
the renderC4DiagramToSVG function it wraps. Neither the skill nor the MCP tool
reimplements any parsing or layout logic; they’re both thin adapters onto the same
engine this package already ships.