Diagram
← Developer reference

Repo setup and CI

Let Claude Code, Codex, Cursor, or any coding agent keep diagrams in the repo and publish them to stable links over MCP, and keep them current from CI.

Coding agents like Claude Code, Codex, Cursor, and Gemini CLI connect to Diagram over MCP, the same way chat apps do. The agent draws a diagram as HTML, saves it in the repo, publishes it, and hands you a link. The next time it changes the diagram, the link stays the same.

Connect the agent

Sign in and open Get started (or a project's page), then pick your tool. For terminal agents it's one command that connects Diagram and starts the agent with the first message. For editors it's one click or a short settings snippet. Manual steps for every tool are in Connect your app.

Set up the repo

The first message asks the agent to call the Diagram tool setup_repo for your project. It creates the project if needed and returns the files for the agent to write:

  • diagrams/ for the diagram files, with a diagrams/README.md that tells agents how to draw and publish them (below).
  • A short section in CLAUDE.md and/or AGENTS.md pointing agents at that README. AGENTS.md is created if neither exists.

Nothing secret goes in the repo: the key lives in the tool's MCP settings. Each published file keeps its diagram id in a <meta name="diagram-id"> tag, so any agent that publishes it again updates the same link. Commit the whole folder.

The section added to CLAUDE.md / AGENTS.md:

<!-- diagram -->
## Diagrams

This repo publishes diagrams to Diagram, project `my-app`. They live in `diagrams/`. Before drawing or changing one, read `diagrams/README.md` and follow it.
<!-- /diagram -->

diagrams/README.md:

<!-- diagram:readme — written by Diagram setup; ask your agent to set up Diagram again to refresh -->
# Diagrams

This folder holds the diagrams for this repo. Each one is published to Diagram in the project `my-app`: https://diagram.la/p/my-app

## For agents

Publish with the Diagram MCP tools (`publish_diagram`, `get_diagram`). If they aren't available, ask the user to connect Diagram. In Claude Code that's `claude mcp add -s user --transport http diagram https://diagram.la/mcp`, then `/mcp` → diagram → Authenticate to sign in with Google; for other tools, https://diagram.la/start

1. **One file per diagram.** Save it here as a single self-contained HTML file named after what it shows, e.g. `diagrams/architecture.html` or `diagrams/checkout-flow.html`.
2. **Everything inline.** CSS, JS, and SVG go in the file. Scripts from a CDN such as jsDelivr are fine (Mermaid: `import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs'`). The page runs in a sandbox, so it can't load other files from the repo, use cookies or localStorage, or submit forms.
3. **Add a `<title>`.** It becomes the diagram's title and the text in link previews.
4. **Match the brand.** Diagrams should look like this product. The first time, read the app's styles (CSS variables, theme or Tailwind config, fonts, logo) and write `diagrams/brand.md` with its colors, fonts, and light or dark look; if it's unclear, ask the user what the product looks like. After that, style every diagram from `diagrams/brand.md` (inline, since diagrams can't load repo files). Guide: https://diagram.la/docs/drawing
5. **Keep it small and readable.** Under 900KB. Prefer inline SVG or HTML/CSS boxes and arrows over embedded images. Give it a title and subtitle, flow in one direction, label every arrow, group related parts. Full guide: https://diagram.la/docs/drawing
6. **Show it locally while you work.** After writing or changing a diagram, open the file in the user's browser so they see it right away: `open diagrams/<name>.html` on macOS, `start diagrams\<name>.html` on Windows, `xdg-open diagrams/<name>.html` on Linux. Open it the first time; after that, tell them to refresh the tab. Edit as many times as the request needs.
7. **Publish once per request.** When you've finished the changes the user asked for (not after every edit), publish with `publish_diagram`, passing the whole file as `html`. The cloud copy is then never more than one request behind, and each version in its history is one request:
   - If the file has `<meta name="diagram-id" content="...">`, pass that value as `id`. The link stays the same and a new version is kept.
   - If not, pass `project: "my-app"`, then add `<meta name="diagram-id" content="<the returned id>">` to the file's `<head>` so later publishes update it.
   Give the user the link it returns. Anyone with the link open sees the new version appear on its own.
8. **Private by default.** Only make a diagram public when the user asks (`set_visibility`).
9. **No keys in the repo.** The Diagram connection lives in the AI tool's MCP settings.

What a good diagram file looks like

  • One .html file with everything inline, or scripts loaded from a CDN such as jsDelivr. The page can't load files that sit next to it in the repo.
  • A <title>. It becomes the diagram's title, and public diagrams show it in link previews.
  • 900KB or less. Inline SVG is usually far smaller than embedded images.
  • It shouldn't need cookies, localStorage, or forms. Diagrams run in a sandbox that blocks those (see Security).

Mermaid, D2, Graphviz, Excalidraw exports, hand-written SVG, and plain HTML with CSS all work. The Mermaid guide has a template.

CI can't use MCP, so it publishes over the HTTP API. Each file's diagram-id tag says which diagram it is, so CI updates the same links your agent published. Add an API key as a repository secret and publish changed diagrams on every merge. For GitHub Actions:

name: diagrams
on:
  push:
    branches: [main]
    paths: ['diagrams/**']
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Publish diagrams
        env:
          DIAGRAM_API_KEY: ${{ secrets.DIAGRAM_API_KEY }}
        run: |
          for f in diagrams/*.html; do
            id=$(grep -o 'name="diagram-id" content="[^"]*"' "$f" | sed 's/.*content="//; s/"$//')
            if [ -z "$id" ]; then echo "skip $f (not published yet)"; continue; fi
            jq -Rs '{html: .}' "$f" | curl -fsS -X PUT "https://diagram.la/api/v1/diagrams/$id" \
              -H "Authorization: Bearer $DIAGRAM_API_KEY" -H 'content-type: application/json' -d @- > /dev/null
            echo "published $f"
          done

Publishing unchanged HTML is a no-op, so sending every file on every run is safe. Files without a diagram-id tag are skipped: publish new diagrams from your agent first, then commit them with their tag.

Over HTTP

Anything that can make an HTTP request can publish. GET https://diagram.la/api/v1 returns a plain-text-friendly index of every endpoint, and there is a full OpenAPI description. See the API reference for curl examples.