Claude CodeでTypstの日本語PDFを組む — typst compileで文字化けを検証
Typstの技術文書をClaude Codeに書かせ、typst compileとtypst fontsで日本語フォントの指定漏れによる豆腐表示を検証させる手順です。権限設定とStopフックの例も載せます。
Claude CodeでTypstを使うと何が変わるのか
TypstはマークアップベースのPDF組版システムで、公式ドキュメントはLaTeXの代替として位置づけています。コンパイラは単一のCLIで、typst compileの1コマンドでPDFが出ます。LaTeXのように複数パスやパッケージの導入を気にする場面は少なく、Claude Codeに「書いて、コンパイルして、直す」を回させる相手として扱いやすい道具です。
ただし日本語には1つ罠があります。Typstは日本語の文字が1文字も出ないPDFでも、コンパイルを成功させることがあります。終了コードが0でも、紙面が豆腐(□)だらけという状態です。だから完了条件を「コンパイルが通ること」だけにすると、Claude Codeは崩れたPDFを見ずに完了を宣言できてしまいます。
この記事では、完了条件を次の3つに置きます。
typst compileが成功するtypst fontsで、指定した日本語フォントがTypstに見えている- 出力したPDFを読んで、日本語が実際に表示されている
LaTeX側の手順はClaude CodeでMarkdownを縦書き日本語PDFに変換する手順にあります。ここではTypstに絞ります。
日本語PDFが崩れる仕組み — 同梱フォントにCJKがない
崩れの原因は、フォントの探し方にあります。TypstのCLIに同梱されているフォントは、Libertinus Serif、New Computer Modern、New Computer Modern Math、DejaVu Sans Monoの4つです。どれも日本語の字形を持つフォントとしては挙げられていません。日本語を出すには、手元にインストール済みのフォントを使うか、フォントのディレクトリを追加で渡す必要があります。
フォントの探索順は--font-pathで渡したディレクトリ、システムフォント、同梱フォントの順です。TYPST_FONT_PATHS環境変数でも同じディレクトリを渡せます。
日本語フォントが見つからないとき
フォント名が合っていない
font:に書いた名前がTypstの見ているファミリー名と違うと、指定は効きません。フォントが探索範囲にない
システムにも
--font-pathにも無ければ、日本語の字形を持つフォントは見つかりません。最終手段の代替が働かない
fallback: falseだと、字形のない文字は豆腐のまま残ります。
もう1点、見落としやすい仕様があります。text関数のfallback引数は既定でtrueで、指定フォントに字形が無いとき、Typstは使えるフォントを総当たりで探して似たものを当てます。このため日本語フォントが何かしら入っている環境では、名前を間違えても意外と読めるPDFが出ます。逆にfallback: falseにすると、字形の無い文字は警告なしで豆腐になります。
つまり、手元のMacでは読めたPDFが、フォントの少ないCI環境や別の端末では豆腐になる、という差が出ます。再現性のある検証には、フォント名を明示したうえでtypst fontsの出力を確かめる工程が要ります。
準備 — インストールとフォントの確認
インストールはパッケージマネージャーで行います。インストールコマンドは、macOSならbrew install typst、Windowsならwinget install --id Typst.Typst、Rustの環境があればcargo install --locked typst-cliです。
brew install typst
typst --version
typst fonts | grep -i "noto\|ipa\|hiragino"typst fontsは、Typstが発見したフォントのファミリー名を一覧にします。ここに出た名前が、font:に書ける名前です。grepの語は一例なので、自分の環境に入れた日本語フォントに合わせて変えてください。何も出ないなら、フォントをインストールするか、ディレクトリを置いて--font-pathで渡します。
typst fonts --font-path ./fonts
typst compile --font-path ./fonts main.typ main.pdfプロジェクトにfonts/ディレクトリを置いてフォントを同梱すれば、環境差を減らせます。フォントのライセンスはあらかじめ確かめておきます。システムフォントの影響を完全に切りたいときは、--ignore-system-fontsも使えます。これを付けたtypst fontsで、--font-pathの分だけが見えていることを検査できます。
ひな型を書かせてコンパイルする
最初の依頼は、小さな文書で通します。Claude Codeには、次のように頼みます。
main.typ に日本語と英語が混ざった技術メモを書いてください。
フォントは typst fonts に出る名前から選び、
typst compile main.typ main.pdf が成功するまで直してください。できあがるファイルは、例えば次のような形になります(公式ドキュメントのtext関数の例に沿った書き方です)。
#set document(title: "技術メモ")
#set text(
lang: "ja",
font: (
(name: "Libertinus Serif", covers: "latin-in-cjk"),
"Noto Serif CJK JP",
),
size: 10.5pt,
)
#set page(paper: "a4", numbering: "1")
= はじめに
日本語の本文と English の単語が混ざる文章です。要点は3つです。
lang: "ja"は、文書の言語を日本語にします。言語の指定はハイフネーションやスマート引用符など言語依存の処理に効き、英語以外の文書では他の内容より前に書きます。font:に配列を渡すと、Typstは先頭から順に、必要な字形を持つフォントを探します。例の"latin-in-cjk"は、ラテン文字に存在する字形を除いた領域を指す定義済みの範囲で、公式の例ではラテン用フォントとCJKフォントの併用に使われています。"Noto Serif CJK JP"は例です。実際に使う名前はtypst fontsの出力から選びます。
和欧の間のスペースは、cjk-latin-spacingがautoならTypstが自動で挿入します。原稿で半角スペースを足していると、二重に空いて見えることがあります。この調整を依頼するなら、PDFを見てから決めます。
typst compileを完了条件にする
Claude Codeに完了条件を守らせるには、プロジェクトのCLAUDE.mdに書いておきます。CLAUDE.mdはセッション開始時に毎回読み込まれる指示ファイルです。
## Typst 文書のルール
- 文書は main.typ から組む。日本語フォントは typst fonts に出る名前だけを使う
- 変更のたびに typst compile main.typ main.pdf を実行する
- 完了の前に typst fonts でフォント名を確認し、main.pdf を読んで
日本語が豆腐になっていないことを確かめる
- フォントを足すときは fonts/ に置き、--font-path ./fonts を付ける次に、コマンドの許可を設定します。許可ルールは、.claude/settings.jsonのpermissions.allowに書きます。Bash(npm run *)のようにワイルドカードで書く形式で、末尾の*は:*とも書けます。
{
"permissions": {
"allow": [
"Bash(typst compile *)",
"Bash(typst fonts *)"
]
}
}Bash(typst fonts *)は、引数なしのtypst fontsにも一致します。プロジェクトの.claude/settings.jsonにある許可ルールは、そのフォルダーのワークスペースの信頼ダイアログを承認した後に適用されます。
出力したPDFを読ませて豆腐を見つける
typst compileが成功した後の検証は、PDFを読ませる工程です。Claude CodeはPDFを読めるので、次のように頼みます。
main.pdf を読んで、日本語が豆腐(□)になっていないか確認してください。
崩れていれば、typst fonts の結果と照らして font: の指定を直し、
もう一度 typst compile してください。読ませるPDFの枚数が多いときの扱いは、LaTeX版の手順にあるページ範囲の指定が同じように使えます。
フォントが埋め込まれているかを機械的に見たいなら、popplerに入っているpdffontsが使えます。出力に日本語フォントの名前が無ければ、指定が効いていない疑いが強くなります。ただし、これは補助の手段です。最終的な判断は、PDFの紙面を読ませて下します。
Stopフックで「豆腐が消えるまで止めない」を組む
CLAUDE.mdは守られないこともあります。確実に検証させたいなら、Stopフックのtype: "agent"を使えます。Claudeが応答を終えようとするたびにサブエージェントが起動し、ファイルの読み取りやコマンドの実行をして、結果をokとreasonで返します。ok: falseならreasonが次の指示になり、作業が続きます。公式の例はテストの実行ですが、プロンプトを差し替えれば組版の検証にも使えます。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "typst compile main.typ main.pdf を実行し、成功を確認する。typst fonts の出力に font: の日本語フォントが含まれることも確認する。$ARGUMENTS",
"timeout": 120
}
]
}
]
}
}agentフックは実験的な機能で、挙動や設定は今後のリリースで変わる可能性があります。本番の運用ではコマンドフックが優先です。
歯止めも知っておきます。Stopフックが連続で8回ブロックすると、Claude Codeはフックを上書きして止まります。コマンドフックなら、入力JSONのstop_hook_activeがtrueのときにexit 0で抜ける書き方が公式にあります。8回を超えて収束させたい場合は、CLAUDE_CODE_STOP_HOOK_BLOCK_CAPで上限を上げられます。Stopフックの設計はagent hookでテストが通るまで止めない手順が詳しいです。
指示の出し方で結果が変わる
Claude Codeは、指示に書いていないフォント名を記憶から補うことがあります。「Noto Serif CJK JPを使って」と書かれたTypstが出てきても、その名前が手元のtypst fontsに出るとは限りません。名前の出どころをtypst fontsに固定する指示を、最初から入れておきます。
フォント指定の依頼文
あいまいな依頼
日本語のレポートをTypstで作って。明朝体でお願い。
検証を含む依頼
日本語のレポートをTypstで作ってください。先にtypst fontsを実行し、出てきたファミリー名から明朝体を選んでfont:に指定します。typst compileの後にPDFを読み、豆腐が無いことまで確認してください。
左の依頼でも、環境によってはきれいなPDFが出ます。ただし、なぜ読めたのかが残りません。右の依頼は、フォント名の根拠がtypst fontsの出力として会話に残るので、別の環境で崩れたときに原因をたどれます。
typst watchは人が使い、Claude Codeは都度コンパイルする
typst watchはソースを監視し、変更のたびにインクリメンタルに再コンパイルするので、毎回ゼロから組むより速く終わります。人間がエディターで文章を直しながらプレビューを見るなら、この使い方が向いています。
Claude Codeに回させるなら、終わりのあるコマンドのtypst compileのほうが扱いやすくなります。監視コマンドは終了しないため、結果を受け取って次の判断をする流れに乗りにくいからです。人がtypst watchでプレビューを見ながら、Claude Codeには同じファイルを編集させて、仕上げにtypst compileで確かめさせる分担もできます。
つまずきやすい点
| 症状 | まず疑うこと | 直し方 |
|---|---|---|
| コンパイルは通るが紙面が豆腐 | まず疑うことfont:の名前がTypstの見ている名前と違う | 直し方typst fontsの出力から名前を選び直す |
| 手元では読めるがCIで豆腐 | まず疑うことCI環境に日本語フォントが無い | 直し方fonts/を同梱し--font-pathを付ける |
| 英数字の字形が想定と違う | まず疑うこと配列の先頭がCJKフォントになっている | 直し方latin-in-cjkでラテン用フォントを先頭に置く |
| 日本語の前後の空きが不揃い | まず疑うことcjk-latin-spacingと原稿のスペースが重なる | 直し方原稿側のスペースを外す |
| Webセッションで豆腐 | まず疑うこと実行環境のフォントが手元と違う | 直し方そのセッションでtypst fontsを実行して確かめる |
クラウド側の環境でtypstコマンドが使えるかどうかは、環境の作りに依存します。ローカルの端末で組版を回すのが、フォントの管理では一番単純です。
ドキュメントの文書をビルドして検証する流れは、MkDocsのstrictビルドで検証する手順にも共通します。「ビルドの成功に加えて、成果物の中身を検査する」という型です。Typstの場合、その検査がtypst fontsとPDFの目視になります。
完了条件を3段にする理由
typst compileの成功だけでは、日本語のPDFが読めることの証明になりません。成功は文法とファイルの解決を保証するだけで、字形の有無までは保証しないからです。フォント名をtypst fontsで突き合わせ、最後にPDFを読ませる。この3段にすると、Claude Codeが「通った」と報告したときの意味が、人間の期待に近づきます。
CIで回すなら、2段目は--ignore-system-fontsと--font-pathを付けたtypst fontsにします。手元のシステムフォントに助けられた「読めた」を、そこで弾けます。Stopフックの検査プロンプトにも同じコマンドを入れておくと、フォント環境の差が完了前に表に出ます。