Claude CodeでPlantUMLの図を書かせ、構文検証してから書き出す
Claude CodeにPlantUMLのテキストを書かせ、--check-syntaxで構文を検証してからSVGに書き出す手順です。編集のたびに自動で検証するhookと、CLAUDE.mdの規約例も載せます。
PlantUMLは、@startuml から @enduml までのテキストを図に変換するツールです。Claude Codeに図のテキストを書かせ、PlantUMLのコマンドで構文を検証し、通ったものだけをSVGやPNGにする。この流れをhookで自動化すると、壊れた図をレビューに出さずに済みます。
要点は3つです。
- 検証は
java -jar plantuml.jar --check-syntaxで行い、終了コードで合否が分かる - 行番号付きのエラーは、画像を書き出す側のコマンドにしか出ない
.pumlを編集するたびに検証するPostToolUse hookを置けば、Claudeが自分で直す
PlantUMLの図はClaude Codeと相性がいいのか
図の中身が普通のテキストなので、Claude Codeの得意な「ファイルを読む・書く・差分を取る」にそのまま乗ります。ドラッグ操作の図ツールと違い、変更の差分がgitで読めます。
PlantUMLのコマンドは、渡されたファイルから @startXYZ を探し、図ごとにPNGを作るのが基本の動きです。ディレクトリを渡すと、.txt、.md、.puml などの拡張子のファイルを走査して、中の図をまとめて処理します。
コネクタ経由で図を作る方法とは、置き場所が違います。Eraserは図をサービス側に持つ方式で、手順はClaudeとEraserを連携してシステム構成図を生成・更新するにあります。Mermaidをチャット内に表示する方式はClaudeでMermaid Chartコネクタを使う手順に書きました。リポジトリ内のテキストで図を管理し、CIでも同じ検証を回したいなら、PlantUMLのコマンドラインが向きます。
実行環境を用意する
必要なのはJavaとPlantUMLのjarファイルです。Getting Startedのページは、Javaの最低推奨バージョンを11としています。
java -version
mkdir -p tools
# plantuml.jar を tools/ に置く(リリースページから取得)
java -jar tools/plantuml.jar --version筆者の環境では、--version が PlantUML version 1.2026.9 を返しました。以降のコマンドの出力は、この版での観察です。
Graphvizが要る図と要らない図
Graphvizの解説ページによると、Graphvizの dot が必要になるのは次の図です。
- ユースケース図
- クラス図
- オブジェクト図
- コンポーネント図
- デプロイメント図
- 状態遷移図
- 旧形式のアクティビティ図
これ以外の図には、GraphvizはCLIを含めて使われません。シーケンス図が中心なら、Graphvizなしで足ります。
dot が見つからない環境で --check-graphviz を実行すると、次のように出ました。
Error: Dot executable does not exist
Error: only sequence diagrams will be generateddot の場所を明示したいときは、環境変数 GRAPHVIZ_DOT で指定できます。Windowsでは、PlantUMLにコンパイル済みのGraphvizが同梱されているため、別途のインストールは不要とされています。
構文検証のコマンドと終了コード
検証だけを行うオプションは、新旧で名前が違います。
| 目的 | コマンド | 備考 |
|---|---|---|
| 構文だけ検証 | コマンド--check-syntax | 備考画像は作らない。CI向けの例がある |
| 旧名の構文検証 | コマンド-checkonly | 備考1.2026.9でも動いた |
| 図種の判定 | コマンド-syntax | 備考標準入力を読み、図種と要素数を出す |
| 最初のエラーで止める | コマンド--stop-on-error | 備考複数ファイルを渡すとき |
| 全体を先に検証 | コマンド--check-before-run | 備考全入力を先に検証し、エラーで早く止める |
| エラー画像を作らない | コマンド--no-error-image | 備考構文エラー時の画像出力を止める |
--check-syntax を含む新しいオプション体系はベータ版の案内として載っています(コマンドラインのページ)。従来のオプション(-failfast2 など)は、移行期間中は使えるが、今後は文書に載らないとも書かれています。長く使う設定には、新しい名前を選ぶほうが安全です。
合格と不合格を終了コードで見る
終了コードは「0が成功、0より大きければ構文エラーまたは処理失敗」と定められています。正常な図と壊した図で試した結果は次のとおりです。
java -jar tools/plantuml.jar --check-syntax docs/ok.puml
echo $? # 0
java -jar tools/plantuml.jar --check-syntax docs/bad.puml
# Some diagram description contains errors
echo $? # 200bad.puml には、ページの例と同じく participant "Famous Bob" aass Bob と、存在しないキーワードを書いています。1.2026.9のヘルプでは、終了コード200が「構文エラーのある図がある」と説明されていました。スクリプトでは「0かどうか」だけを見れば足ります。
行番号が要るなら画像生成側を使う
ここに落とし穴があります。--check-syntax のエラー出力は、メッセージ1行だけでした。「どの行が悪いか」は出ません。行番号は、画像を書き出す通常実行のほうに出ます。
java -jar tools/plantuml.jar --no-error-image --svg \
--output-dir /tmp/pu-check docs/bad.puml
# Error line 2 in file: docs/bad.puml
# Some diagram description contains errors-stdrpt オプションは、この出力を file1.pu:2:error:Syntax Error? のような1行形式に変えます。ただし筆者の環境では、--check-syntax と組み合わせた出力は変わりませんでした。エディタやCIに行番号を渡したいなら、--check-syntax でなく画像生成側で -stdrpt を試してください。
壊れた図でも画像が出る
--no-error-image を付けずに、壊れた図をそのまま書き出すと、エラーを描いた画像が出力されます。拡張子は .svg や .png なので、あとから見るとちゃんとした図に見えます。終了コードが200でも、ファイルは残ります。
標準入力から渡す --pipe でも同じ傾向でした。構文エラーのある入力でも、標準出力にはエラー表示の入ったSVGが流れます。ただ終了コードは200でした。パイプで書き出す処理では、終了コードを必ず確認してください。
Claude Codeに書かせる前に決めておく規約
Claudeは、PlantUMLの文法を一通り知っています。それでも、図の置き場所、検証コマンド、書き出し形式をCLAUDE.mdに書いておくと、毎回の指示が短く済みます。
## 図(PlantUML)
- 図のソースは docs/diagrams/*.puml に置く。@startuml と @enduml を必ず対にする
- .puml を作ったり直したりしたら、次を実行して終了コード0を確認する
`java -jar tools/plantuml.jar --check-syntax <ファイル>`
- 構文エラーが出たら、書き出しに進まず原因を直して再実行する
- 検証が通ったものだけ SVG に書き出す
`java -jar tools/plantuml.jar --svg --output-dir docs/diagrams/out <ファイル>`
- 書き出した SVG は out/ 配下に置き、手で編集しない規約は、検証コマンドそのものをコピーできる形で書くのがコツです。「構文を確認すること」だけでは、Claudeがどのコマンドを使うかを毎回推測することになります。
依頼の出し方
最初の依頼は、図の対象と図種を具体的に書きます。
docs/diagrams/order-flow.puml に、注文APIのシーケンス図を作ってください。
参加者は User、API Gateway、DB。POST /orders から 201 が返るまでを描きます。
作ったら CLAUDE.md の手順で構文を検証し、通ったらSVGを書き出してください。すると、Claudeは .puml を書き、検証コマンドを実行し、エラーがあれば読んで直します。ここまでは想定する流れです。Claudeの動きが毎回同じになるとは限りません。
編集の依頼も同じです。「DBの手前にキャッシュを足して」と頼めば、差分は数行になります。git diff で変更箇所が読めるのが、テキスト管理の利点です。
編集のたびに検証するhookを置く
CLAUDE.mdの規約は、守られないことがあります。確実に検証したいなら、PostToolUse hookで機械的に走らせます。hooksガイドは、Edit|Write にマッチさせて、編集後のファイルにコマンドを走らせる例を載せています。Lintやテストでの同じ使い方はPostToolUse hookのLint自動修正とClaude Code hooksでテストを自動実行するにあります。
検証用のスクリプトは次のとおりです。.claude/hooks/check-puml.sh として置きます。
#!/bin/bash
# PostToolUse(Edit|Write) 用。.puml 以外は何もしない
f=$(jq -r '.tool_input.file_path // empty')
case "$f" in *.puml) ;; *) exit 0 ;; esac
J="java -jar tools/plantuml.jar"
$J --check-syntax "$f" >/dev/null 2>&1 && exit 0
# 行番号は画像生成側のメッセージにしか出ないので、捨て先を指定して再実行する
tmp=$(mktemp -d)
echo "PlantUML の構文エラー: $f" >&2
$J --no-error-image --svg --output-dir "$tmp" "$f" >&2 2>&1
rm -rf "$tmp"
exit 2hookはイベントのJSONを標準入力で受け取るので、jq でファイルパスを取り出します。.puml 以外のファイルでは、何もせず終了します。
このスクリプトを、.claude/settings.json に登録します。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/check-puml.sh"
}
]
}
]
}
}手元でスクリプトを試した結果は、次のとおりです。壊れた図では終了コード2とエラーの行番号が出て、正常な図と .puml 以外のファイルでは何も出ずに終了コード0でした。
終了コード2は何を起こすか
hooksのリファレンスでは、PostToolUseの終了コード2は「標準エラー出力をClaudeに見せる」動作です。ツールはすでに実行された後なので、書き込み自体は取り消せません。
つまり、壊れた .puml はいったんディスクに書かれます。その直後にClaudeがエラー文を受け取り、次の編集で直す流れです。書き込みを事前に止める用途には向かないので、.puml が壊れたまま残るのを避けたいなら、書き出しコマンドの直前に --check-syntax を1回挟んでください。
一方、似た用途のFileChangedイベントもあります。hooksガイドは、Bash コマンドがファイルを書き換えた場合も拾いたいときに使うよう案内しています。Claudeがシェルのリダイレクトで .puml を作る運用なら、そちらも検討できます。
権限を絞って許可する
hookで検証するだけでなく、Claudeが書き出しコマンドを実行する場面もあります。毎回確認を挟みたくないときは、.claude/settings.json の permissions で、使うコマンドだけを許可します。
{
"permissions": {
"allow": [
"Bash(java -jar tools/plantuml.jar --check-syntax *)",
"Bash(java -jar tools/plantuml.jar --svg *)"
]
}
}Bashの許可ルールは、* より前の文字列をそのまま照合します。権限のページは、サブコマンドの後ろに * を置くよう勧めています。上の2行は、検証と書き出しだけを通す書き方です。
java -jar * のようにまとめて許可すると、任意のjarを実行できてしまいます。jarの場所とオプションを含めて指定してください。
よくあるつまずき
出力先が入力ファイルからの相対になる
--output-dir に相対パスを渡すと、現在のディレクトリでなく、入力ファイルのある場所からの相対で解釈されます。コマンドラインのページの説明どおりです。
筆者の環境でも、docs/ok.puml に --output-dir out を渡すと、出力は docs/out/ok.svg でした。カレントディレクトリ直下に出るつもりでいると、見つかりません。確実に1か所へまとめたいなら、絶対パスを指定します。同じページに、絶対パスなら全画像が1つのディレクトリに出ると書いています。
Markdownの中の図まで拾われる
ディレクトリを渡す実行は、.md ファイルも走査します。ドキュメントの中に、構文エラーの例として @startuml ブロックを書いていると、全体検証が落ちます。検証対象は docs/diagrams/*.puml のように、拡張子とパスを絞って渡してください。
同じページは、ワイルドカードで ** を使うと、下位のディレクトリを含められるとしています。パターンは、シェルに展開されないよう引用符で囲みます。
一部の図で書き出しだけ失敗する
--check-syntax は構文だけを見るので、通ったあとにGraphvizがなくて書き出しが失敗することは、原理上ありえます。クラス図などGraphvizが要る図種を扱うなら、CIの実行環境にも dot を入れておく必要があります。
!includeで外部ファイルを読む場合
PlantUMLには、セキュリティプロファイルがあります。セキュリティのページによると、既定は LEGACY で、古い版の動作を模したものです。将来のリリースでは、この既定のモードは削除され、より制限された既定に変わる予定とされています。
INTERNET では、ローカルファイルを読めません。許可リストを使えば、特定のパスだけを許可できます。生成物を共有サーバーで書き出すなら、プロファイルを PLANTUML_SECURITY_PROFILE で明示してください。
PLANTUML_SECURITY_PROFILE=INTERNET \
java -jar tools/plantuml.jar --check-syntax docs/diagrams/order-flow.puml信頼できないテキストを検証・書き出しするCIでは、プロファイルが UNSECURE だと、ローカルの全ファイルと任意のURLに図のテキストからアクセスできてしまいます。Claudeが書いた図であっても、外部から入ったテキストを含むなら、同じ注意が要ります。
同じ検証をCIでも落ちるようにする
hookが見るのは、Claudeが編集した .puml だけです。人が手で直した図や、Bash経由で書き換わった図、hookを設定していない環境のクローンは素通りします。最後の関門は、プルリクエストのCIに置きます。
name: plantuml-check
on:
pull_request:
paths: ["docs/diagrams/**/*.puml"]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: java -jar tools/plantuml.jar --check-syntax 'docs/diagrams/**/*.puml'--check-syntax は構文だけを見るので、このジョブにGraphvizは要りません。dot が要るのは、CIで画像まで書き出すときだけです。パターンを引用符で囲むのは、シェルに展開させず、PlantUML側に ** を解釈させるためです。終了コードが0以外ならステップが失敗し、プルリクエストはマージ前に止まります。
役割は次のように分かれます。hookはClaudeにその場で直させる即時の修正役で、CIは人間が手で入れた変更も含めて止める最終ゲートです。どちらか片方でも運用は回りますが、CIだけだとClaudeは直す手がかりを得るまでにプッシュが必要になり、hookだけだと手作業の変更が検証を通りません。
テキストで図を管理する利点は、レビューが差分で済むことです。構文検証を機械に任せれば、人間のレビューは「この関係は正しいか」という中身に集中できます。