Claude CodeでQuartoレポートを作る — quarto renderで失敗を拾わせる
Claude CodeにQuartoのレポートを書かせるとき、quarto renderの成否を完了条件にする手順です。CLAUDE.mdの規約とStop hookの例を載せます。
Quartoのレポートは「書けた」ではなく「renderが通った」で判定する
Quarto(.qmd)は、Markdownの中にPythonやRのコードチャンクを埋め込み、quarto render のたびにそのコードを実行してHTMLやPDFを作ります。つまりレポートの正しさは、文章よりも先に「全チャンクが最後まで実行できるか」で決まります。
Claude Codeにレポートを書かせると、文章と図の体裁は整った .qmd がすぐ出てきます。ただし、書いた本人であるClaudeが実行していなければ、列名の打ち間違いやライブラリ未導入のような失敗は、あなたが初めてrenderした瞬間に出ます。
そこで、「renderが成功するまで終わりにしない」という条件をClaudeに持たせます。この記事の進め方は次の3段階です。
render成功を完了条件にする3段階
- 1
CLAUDE.mdに規約を書く
変更後に
quarto renderを実行し、エラーが消えるまで直すよう明文化します。 - 2
renderの引数を決める
対象ファイルと出力形式を固定し、必要ならキャッシュ更新とデバッグ出力のフラグを足します。
- 3
Stop hookで強制する
指示を忘れても、renderが失敗している間はClaudeが止まれないようにします。
失敗を拾えるかどうかはQuartoの既定動作で決まる
Quartoの実行オプションには error があります。error: true を指定すると、コードの実行エラーを出力に含めたうえで、文書の処理を止めません。逆に言えば、既定ではチャンクのエラーでrenderが止まります。Claudeに失敗を拾わせるには、この既定のままにしておくのが前提です。
「renderが通った」と言えるのは、コードが実際に実行されたときだけです。実行されない、または前回の結果を使い回す条件が3つあります。
renderが通っても実行されていない3つの条件
ipynbは既定で実行されない
.ipynbをrenderするとき、セルは既定では実行されません。実行するには--executeを付けます。ノートブックを入力にするなら、この指定が要ります。freezeが有効
execute: freeze: trueを指定した文書は、プロジェクト全体のrenderで再実行されません。freeze: autoは、ソースが変わったときだけ再実行します。ファイル単体のrenderでは常に実行されます。cacheが有効
execute: cache: trueでは、チャンクのソースが変わらない限り前回の結果が使われます。入力データだけが変わったときは--cache-refreshで更新します。
Claudeにチェックさせるときは、ファイルを1つずつ指定して quarto render を呼ばせます。プロジェクト全体の再renderでは freeze に守られた文書を素通りするので、検証として弱くなります。
CLAUDE.mdに書く規約
次のような断片をプロジェクトの CLAUDE.md に置きます。例として、Python版のレポートを想定した書き方です。
## Quarto レポート
- `.qmd` を変更したら、完了前に必ず `quarto render <file>.qmd --to html` を実行する
- render が失敗したら、エラー出力の最終行とチャンクの位置を読み、原因を直して再実行する
- 失敗を隠すために `error: true` や `eval: false` をチャンクに足さない
- 図や表の数値を文章に書くときは、render した出力の値を転記する(推測で書かない)最後の項目は、文章と計算結果のずれを防ぐためのものです。Quartoにはコードの値を文中に埋め込むインラインコードもありますが、まず転記ルールを置くだけでも、Claudeが記憶で数値を書く場面は減ります。
renderの引数と、失敗時に読む出力
quarto render の基本形は次のとおりです。対象ファイルは、コマンドラインの最初の引数に置きます。
quarto render report.qmd --to html
quarto render report.qmd --to html --cache-refresh
quarto render report.qmd --to html --execute-debug形式を省くと、文書のYAMLに書かれた全形式をrenderし、何も書かれていなければHTMLを作ります。--to pdf のように指定すれば形式を絞れます。チェック用途なら、最も軽い形式を1つ決めておくと速く回ります。
失敗の調査には次のフラグが使えます。
| フラグ | 役割 |
|---|---|
--execute-debug | 役割コード実行時のデバッグ出力を表示する |
--cache-refresh | 役割実行キャッシュを強制的に更新する |
--no-cache | 役割キャッシュを使わない |
--debug | 役割render後も中間ファイルを残す |
--log <path> / --log-level | 役割ログをファイルへ書き、レベルを debug 〜 critical から選ぶ |
--quiet | 役割コンソール出力を抑える |
Claudeに読ませたいのは失敗の原因なので、--quiet は付けません。ログが長いときは、末尾を読むよう指示するか、--log でファイルに逃がします。
Stop hookでrender成功を強制する
CLAUDE.mdは「お願い」です。確実にしたいときは、Claude Codeのhooksで Stop イベントにrenderを掛けます。Stop hookの終了コードが2だと、Claudeは止まれず作業を続けます。標準エラー出力に書いた内容が、続行の理由としてClaudeに渡されます。
.claude/hooks/quarto-render-check.sh の例です。変更された .qmd だけをrenderします。
#!/bin/bash
# 変更・追加された .qmd だけを render して、失敗したら Claude に戻す
files=$(git status --porcelain -- '*.qmd' | awk '{print $2}')
[ -z "$files" ] && exit 0
for f in $files; do
if ! out=$(quarto render "$f" --to html 2>&1); then
echo "quarto render に失敗しました: $f" >&2
echo "$out" | tail -n 30 >&2
exit 2
fi
done
exit 0chmod +x で実行権限を付け、.claude/settings.json に登録します。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/quarto-render-check.sh"
}
]
}
]
}
}このスクリプトは、renderが失敗したときに終了コードが0以外になることを前提にしています。登録する前に、わざとチャンクを壊した .qmd で quarto render を実行し、echo $? で終了コードを確かめておくと安全です。
無限に続けさせないための上限
Stop hookが続行を指示し続けると、ループになりかねません。Claude Codeには、Stop hookによる続行が連続で8回に達すると次のブロックを無視して終了させる上限があります。ツールを呼ぶたびに連続回数はリセットされます。上限は環境変数 CLAUDE_CODE_STOP_HOOK_BLOCK_CAP で変更できます。
Stop hookの入力には stop_hook_active というフラグもあり、すでにhookによる続行中のときは true になります。「2回目以降は検証しない」と割り切るならこの値で分岐できます。ただし、直した結果を再度renderで確かめたいレポート用途では、分岐を入れずに上限に任せるほうが目的に合います。
編集のたびではなく、止まる直前に回す
編集直後に走る PostToolUse で .qmd ごとにrenderすることもできます。ただしデータの読み込みが重いレポートでは、1回の作業中に何度もrenderが走り、待ち時間が積み上がります。PostToolUse でのexit 2は、すでに実行済みのツールの結果を変えず、標準エラー出力をClaudeに見せるだけです。作業の区切りで一度だけ確かめたいレポートには、Stop が向いています。
テストを回す用途との使い分けはhooksでテストを自動実行する記事で扱っています。Lintを編集直後に直す構成はPostToolUse hookのLint自動修正が参考になります。
renderコマンドの許可を先に出しておく
Claudeが作業中に自分で quarto render を呼ぶときは、通常のBashコマンドとして許可を求められます。確認を省きたい場合は、.claude/settings.json の許可ルールでコマンドを限定します。
{
"permissions": {
"allow": ["Bash(quarto render *)"]
}
}許可は quarto render に限り、任意のシェルコマンドまで広げないのが要点です。
つまずいたときの切り分け
renderが失敗する、あるいは成功しているのに結果がおかしいときは、上から順に確かめます。
renderが通らない・結果が古いときの切り分け
- Qエラー出力にチャンクの位置が出ていますか?答えが出ていない答えがはい
--execute-debugを付けて再実行し、コード実行時のデバッグ出力を出させます。 - Q同じ環境でPythonやRのパッケージが読み込めますか?答えが読み込めない答えがはい
PythonのチャンクをrenderするにはPython 3と
jupyterパッケージが要ります。ClaudeにはCLAUDE.mdで、使う仮想環境を有効化してからrenderするよう伝えます。 - Q図や表が古いままではありませんか?答えが古いまま答えがはい
cache: trueなら--cache-refreshを、freezeを使っているなら_freezeディレクトリの削除を検討します。
render成功を再現できる状態
同じコマンドを誰が実行しても、同じ成否になります。
{python} と {r} のチャンクが同じ文書に混在していると、QuartoはKnitrエンジンとreticulate Rパッケージで両方を実行します。意図せず別のエンジンが選ばれて失敗する場合は、YAMLに engine: jupyter か engine: knitr を書いて固定できます。
作業ディレクトリにも注意が要ります。プロジェクト内の文書をrenderするとき、作業ディレクトリは既定でその文書のあるディレクトリです。data/input.csv のような相対パスは、.qmd からの位置で書きます。プロジェクトのルート基準にしたいときは、_quarto.yml に project: execute-dir: project を書きます。Claudeがルートから quarto render sub/report.qmd を呼んでも、相対パスの解決先が変わらないよう、先にここを決めておきます。
まとめ
ここまでの内容を一言でいうと、Quartoは「実行できたかどうか」をrenderの成否に集約できる形式です。その成否をClaudeの完了条件にする仕組みが、CLAUDE.mdの規約とStop hookの組み合わせです。error: true・freeze・cache が検証をすり抜ける3つの経路なので、規約にはこの3点を先に書いておくと、後から「通ったのに中身が古い」という手戻りを減らせます。
Jupyterノートブックを直接編集させる場合の仕組みは、Claude CodeでJupyterノートブックを編集する仕組みにまとめています。
関連する記事
Claude Code をもっと見る →Claude Codeとは — できること・料金・始め方と使い方の全体像
Claude CodeでWPFアプリを作る — dotnet buildとViewModelテストで検証する
Claude CodeでROS 2パッケージを作る — colcon buildとlaunch_testの反復
Claude CodeでMQTT検証 — mosquittoでpublishとsubscribeを機械的に確かめる
Claude CodeでMkDocs Materialの文書を書く — build --strictで検証
Claude CodeでHaskellを書く — stack buildとhlintを検証ループに固定