Skip to content
Connect an agent
Get started

Keep diagrams in sync in CI

How to fail a pull request whose diagram pictures no longer match their source, with the GitHub Action or the command line. It is for anyone who keeps Plotwork diagrams in Markdown or .diagram files in a repository.

For
  • GitHub Actions
  • GitHub

TL;DR

QuestionAnswer
What is checked?Every diagram fence in the files you name: a fence with no picture under it, a picture whose source or renderer changed, and source with mistakes. .diagram files are checked for mistakes.
What runs the check on GitHub?The action plotwork-official/plotwork-action, pinned by commit. The engine is bundled into it, so it installs nothing and needs no account, key, or token.
How does a failure show in a pull request?Each stale fence and each mistake is an error annotation on its line in the Files changed tab, and the job summary lists the files with the command that fixes them.
How do I fix a failure?Run the action with command: sync on the same files and commit the Markdown and the SVGs it writes, or run npx -y @buun_group/plotwork@0.1.0-beta.13 sync on your machine.
What else can the action do?sync redraws in the workspace and commits nothing, validate reports mistakes only, render draws .diagram files to SVG, and generate makes diagrams from Terraform, OpenAPI, Compose and other files and fails or opens a pull request when they drift (section 5).
What about other CI?The command line runs the same check: npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "docs/**/*.md". See CI usage.
Does the check send my diagrams anywhere?No. The action and the command line count nothing and, by default, make no request. Either can read an organisation's saved style rules when you name the organisation, and generate in write mode talks to GitHub to push and open a pull request, and to Plotwork only with publish: true. Both read your repository settings file on the machine they run on.

1. Check every pull request

Copy this workflow to .github/workflows/plotwork.yml:

yaml
name: plotwork
on:  pull_request:    paths: ['**/*.md', '**/*.diagram']
permissions:  contents: read
jobs:  diagrams:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v7        with:          persist-credentials: false      - uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14        with:          paths: |            README.md            docs/**/*.md

The samples pin the latest release of the Action by its commit. @v1 becomes available at the first stable release.

With no paths, the action reads every Markdown file in the repository. A line in paths that starts with ! leaves out what it matches, such as !docs/drafts/**. Pin actions/checkout to a full commit SHA too, as you would any third-party action.

A stale diagram looks like this in the log, and as an error on line 12 of the file in the pull request:

text
::error file=docs/architecture.md,line=12,title=Stale diagram::The picture under this diagram is missing or out of date.%0AFix: run plotwork-official/plotwork-action@v1.0.0-beta.14 with command: sync, then commit the Markdown file and the SVG files.

The job summary gives the same fix: run the action with command: sync and the same paths, then commit what it wrote. Once the command line is on npm, the summary and the annotation also give an npx command that pins the version built from the same engine as the action, so the pictures it draws pass the check.

2. The commands

commandReadsWritesFails when
check (default)paths and diagramsNothingA picture is missing or stale, or a diagram has an error
syncpathsThe Markdown files and their SVGs, in the workspaceA diagram has an error
validatepaths and diagramsNothingA diagram has an error, or a warning with fail-on: warning
renderdiagramsA light and a dark SVG per .diagram file, in out-dirA diagram has an error
generateThe sources of the settings fileNothing with mode: check; with mode: write, the diagrams, then a pull request or a commitA diagram drifted from its files (check mode), or a diagram has an error

Redraw and open a pull request

sync redraws the stale pictures in the runner's workspace and commits nothing; it never holds a token. To commit from a workflow, give the write permissions to the job and add a step that commits, such as peter-evans/create-pull-request:

yaml
name: plotwork-sync
on:  push:    branches: [main]    paths: ['**/*.md']
permissions:  contents: read
jobs:  sync:    runs-on: ubuntu-latest    permissions:      contents: write      pull-requests: write    steps:      - uses: actions/checkout@v7        with:          persist-credentials: false      - id: plotwork        uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14        with:          command: sync          paths: docs/**/*.md      - if: steps.plotwork.outputs.stale != '0'        uses: peter-evans/create-pull-request@v8        with:          branch: plotwork/sync          commit-message: 'docs: redraw stale diagrams'          title: 'docs: redraw stale diagrams'          add-paths: docs/**

The repository must allow GitHub Actions to create pull requests (Settings, Actions, General). Most teams keep check on pull requests and run the sync locally.

Report mistakes only

yaml
- uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14  with:    command: validate    diagrams: diagrams/**/*.diagram    fail-on: warning

Draw .diagram files

yaml
- uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14  with:    command: render    diagrams: diagrams/**/*.diagram    out-dir: build/diagrams

diagrams/flow.diagram becomes build/diagrams/diagrams/flow.svg and flow.dark.svg. Each SVG carries its source, so Editing an existing diagram works on it.

3. Inputs and outputs

InputDefaultMeaning
commandcheckcheck, sync, validate, render, or generate.
paths**/*.mdMarkdown files: one glob, file, or folder per line. node_modules and .git are never searched.
diagrams**/*.diagram.diagram files, in the same form. Set it to '' for none.
out-dirplotwork-svgWhere render writes, inside the repository.
fail-onerrorerror, warning, or never. Problems are annotated either way.
convert-mermaidfalseWhen true, check and sync treat each mermaid fence that converts as a diagram. See Migrating from Mermaid.
configemptyThe repository settings: header defaults every command applies, and rules check and validate apply. Empty looks for plotwork.config.json, then .plotwork/config.json, from working-directory up to the repository root; off reads none.
rules-orgemptyAn organisation whose saved style rules to apply instead of the file's rules, read with the key in PLOTWORK_API_KEY.
mode, on-drift, pr-branch, pr-title, commit-message, publish, github-tokengenerate only. See Diagrams as code, section 7.
summarytrueWrite the job summary.
working-directory.The folder to run in. Annotations still name files from the repository root.
OutputMeaning
staleDiagrams whose picture was missing or out of date.
errors, warningsThe problems found.
filesA JSON array: the files that need a sync (check), the files written (sync, render), or the files with an error (validate).
pull-request, publishedgenerate only: the pull request it opened or edited, and what it published.

check, validate, and render need only contents: read. generate in check mode does too; in write mode it needs contents: write, and pull-requests: write to open a pull request.

4. The command line

The npm package @buun_group/plotwork holds the bin plotwork, built from the same engine as the action. It runs the same check on any CI, as one command with an exit code:

sh
npx -y @buun_group/plotwork@0.1.0-beta.13 sync --check "docs/**/*.md"

Pin the version, so a new release cannot change your build without a change you review. The CLI tab has every command, with the pipeline for GitLab CI, Azure Pipelines, Jenkins, and CircleCI, the exit codes and output formats, and the command reference.

5. Diagrams made from files

When a diagram is made from files of the repository, such as a Terraform stack or an OpenAPI document, name it in sources in the settings file, and let generate keep it in step. The full guide is Diagrams as code.

A pull request check

yaml
name: diagrams
on:  pull_request:
permissions:  contents: read
jobs:  drift:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v7        with:          persist-credentials: false      - uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14        with:          command: generate

Regenerate on main and open a pull request

yaml
name: diagrams-regenerate
on:  push:    branches: [main]  schedule:    - cron: '0 4 * * *'
permissions:  contents: read
jobs:  regenerate:    runs-on: ubuntu-latest    permissions:      contents: write      pull-requests: write    steps:      - uses: actions/checkout@v7      - uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14        with:          command: generate          mode: write

The repository must allow GitHub Actions to create pull requests (Settings, Actions, General). A pull request opened with the workflow's own token starts no workflow; pass a GitHub App or personal token in github-token to have its checks run.

Publish to an organisation

yaml
name: diagrams-publish
on:  push:    branches: [main]
permissions:  contents: read
jobs:  publish:    runs-on: ubuntu-latest    permissions:      contents: write      pull-requests: write    steps:      - uses: actions/checkout@v7      - uses: plotwork-official/plotwork-action@dcec4036897b73bd3ea724b3991f4fd0ac880757 # v1.0.0-beta.14        with:          command: generate          mode: write          publish: true        env:          PLOTWORK_API_KEY: ${{ secrets.PLOTWORK_API_KEY }}

Each source with a publish section, such as { "organization": "acme", "folder": "Platform" }, is published with the organisation key in the secret. Only the generated diagram source is sent, never the files it was made from.

See also

PageWhy
Markdown and GitHubWhat a sync writes and why the pictures are committed
Migrating from MermaidConvert existing Mermaid fences first
Repository settingsDefaults for every header, and rules a pull request must pass
Diagrams as codeDiagrams made from Terraform, OpenAPI, Compose and other files, kept in step
Slack, email, Confluence, and NotionShare a picture outside the repository
Local usage sharingWhat the MCP package can count, which the command line and the action never do