Claude Codeでlycheeのリンク切れを直す — 検査結果を渡して修正案を出させる
lycheeでドキュメントのリンク切れを検査し、その結果をclaude -pに渡して修正させる手順です。終了コードの扱い、404の削除候補と付け替え案の分け方、権限の絞り方を扱います。
lychee(Rust製のリンクチェッカー)でドキュメントのリンク切れを洗い出し、その結果を claude -p に渡して修正案を作らせる流れを組みます。検査は決まった手順で回るlycheeに任せ、Claude Codeには「なぜ切れたか」の判断と書き換えだけを任せる分担です。
ビルド時のリンク検査との違いが出発点になります。VitePressのビルドが見るのはページ間のリンクで、Docusaurusも設定キーで内部リンクの扱いを決めます。外部サイトへのリンクが消えていても、ビルドは通ります。外部リンクまで含めて検査するのが、lycheeの役目です。
lychee単体で何ができるか
macOSではHomebrewの brew install lychee で入ります。GitHub Actionsでは、公式の lycheeverse/lychee-action が使えます。CIでlycheeを回す場合は、Actionで検査し、Claude Codeを呼ぶ段は別のジョブに切り分ける構成も取れます。
lycheeはディレクトリを渡すと、対応形式のファイルに含まれるリンクを再帰的に検査します。
# カレントディレクトリ以下の対応ファイルを再帰的に検査
lychee .
# 特定のファイルだけ検査
lychee README.md docs/guide.md終了コードは4種類です。Claude Codeに渡すかどうかの分岐は、この値で決めます。
| 終了コード | 意味 |
|---|---|
| 0 | 意味成功 |
| 1 | 意味入力の欠落、実行時の想定外の失敗、設定ミス |
| 2 | 意味リンク切れ。除外されていないリンクが1つ以上失敗 |
| 3 | 意味設定ファイルのエラー |
「2」だけがリンク切れを意味します。1や3は検査そのものが動いていない状態なので、修正に進まず止めます。
検査結果の形式は --format で選びます。選べるのは compact(既定)、detailed、json、junit、markdown です。--output を付けるとファイルに書き出せます。CIなど対話のない環境では、進捗バーを消す --no-progress が推奨されています。
検査結果をClaude Codeに渡す
非対話モードの claude -p は標準入力を読めます。ただし、パイプで渡せるのは10MBまでです。超えると、Claude Codeはエラーと0以外の終了コードで止まります。リンクの多いサイトではJSONが大きくなりやすいので、ファイルに書き出してパスを伝える形にします。
検査から修正案までの流れ
- 1
lycheeでJSONレポートを書き出す
終了コードを変数に取り、2以外ならそこで止めます。
- 2
Claude Codeに分類だけをさせる
編集権限は渡さず、レポートの読み取りと
curl -sIだけを許可します。 - 3
提案を人が読んでから書き換えさせる
付け替えだけを許可した2回目の呼び出しで、ファイルを直します。
手順1: 終了コードで分岐するスクリプト
#!/usr/bin/env bash
lychee --no-progress --format json \
--output lychee-report.json docs/
status=$?
if [ "$status" -eq 0 ]; then
echo "リンク切れなし"; exit 0
elif [ "$status" -ne 2 ]; then
echo "lycheeの実行エラー(終了コード $status)" >&2
exit "$status"
fidocs/ は例です。検査したいディレクトリに読み替えます。
手順2: 修正案を出させる
提案だけを出させる呼び出しでは、編集系のツールを許可リストに入れません。--allowedTools に書いたツールは確認なしで実行され、リストにないものは承認が要る場合に拒否されます。Bash(curl -sI *) の末尾の * は前方一致で、curl -sI で始まるコマンドだけが通ります。
claude -p "lychee-report.json を読み、失敗したリンクを分類して。
- 移動先が確認できるもの: curl -sI で返るLocationを根拠に、
ファイル名:行番号 / 旧URL / 新URL を一覧にする
- 404のままのもの: 削除か差し替えの候補として別の表にする
- 判断がつかないもの: 理由を添えて第三の表にする
ファイルは編集しない。" \
--allowedTools "Read,Bash(curl -sI *)"分類を3つに分けるのがこの流れの肝です。301の付け替えは機械的に直せますが、404の扱いは文脈で変わります。記述ごと削るのか、別の資料に差し替えるのかを、Claude Codeに黙って決めさせない設計にします。
落とし穴
リンク先が消えた理由までは検査結果に載らない
lycheeが返すのは「このURLは失敗した」という事実までです。移動先は誰も教えてくれないため、Claude Codeが自分で調べます。curl -sI の応答に移動先が出なければ、旧URLのまま「判断がつかない」の表に残させます。推測でURLを組み立てさせると、別のページを指す新しい誤リンクが生まれます。
手順3: 承認した範囲だけを書き換える
提案を読み、付け替えだけを実行する段階です。編集を許すツールを加え、同じセッションを引き継ぎます。
claude -p "さっきの表のうち、移動先を確認できた分だけ
旧URLを新URLに置き換えて。404の項目には触れない。" \
--continue --allowedTools "Read,Edit"--continue は直近の会話を引き継ぐオプションです。別のスクリプトから呼ぶなど、直近の会話が別物になりうる場合は --resume でセッションを明示します。
書き換えの後は、同じlycheeをもう一度回します。終了コード0が出れば完了で、2が残れば残りは人が判断する項目です。
CIや定期実行に載せるときの設定
スクリプトや定期ジョブで回す環境では、ホストのフックやプラグイン、CLAUDE.md を読み込まない --bare を付けるよう案内されています。人のいない環境では、承認待ちが起きないように --permission-prompts none も使えます。承認が必要になった操作は拒否され、実行は続きます。このフラグはv2.1.259以降が必要です。
提案と書き換えを分ける理由
1回で全部やらせる
lycheeの結果から分類、編集までを1回で済ませます。404の削除が混じっても止まりません。
2回に分ける
1回目は読み取り専用で表を出し、2回目で承認した行だけを編集します。誤った付け替えが差分に混ざりにくくなります。
誤検知を減らす検査設定
リンク切れの一覧に毎回同じ行が出ると、Claude Codeに渡す意味が薄れます。lycheeには検査から外す仕組みがあります。
| 目的 | 方法 |
|---|---|
| 特定のURLを検査しない | 方法--exclude に正規表現を渡す。または .lycheeignore に書く |
| ファイルやディレクトリを走査しない | 方法--exclude-path |
| 結果を再利用して速くする | 方法--cache。カレントに .lycheecache を作る |
| 一時的な接続不良を許す | 方法--accept-timeouts。タイムアウトだけなら終了コード0にする |
| GitHubのレート制限を避ける | 方法環境変数 GITHUB_TOKEN、または --github-token |
| 見出しへのリンクも検査する | 方法--include-fragments |
--include-fragments は、リンク先がMarkdownかHTMLで一般的な書き方に従っているときに働きます。JavaScript実行後にだけ現れるアンカーは検出できません。ビルド時の検査が止めない見出しのリンク切れの一部を、ここで拾えます。
--cache で保存される結果は、既定では1日で破棄されます(--max-cache-age)。外部リンクの検査を毎回するとサイトに負荷をかけるので、定期実行ではキャッシュを併用します。
移動先をClaude Codeに調べさせるときの注意
httpのリンクが https へ転送されているだけの場合は、--require-https が使えます。HTTPSが使えるのにhttpで書かれたリンクをエラーとして列挙するため、付け替えの対象を機械的に集められます。
一方で、lycheeは既定でリダイレクトを最大10回までたどります(--max-redirects)。転送されるだけのリンクが報告にどう載るかは、リポジトリの説明に書かれていません。手元のバージョンで、転送するURLを1つ含む小さなMarkdownを検査して確かめます。載らないなら、転送の洗い出しは --require-https と、curl -sI による個別確認で補います。
提案を機械で扱える形にする
表を目で読むだけなら自然文で足ります。提案を別のスクリプトに流したいなら、--output-format json と --json-schema を組み合わせます。スキーマに合う出力は、レスポンスの structured_output に入ります。
claude -p "lychee-report.json の失敗リンクを分類して" \
--allowedTools "Read,Bash(curl -sI *)" \
--output-format json \
--json-schema '{"type":"object","properties":{"relink":{"type":"array","items":{"type":"object","properties":{"file":{"type":"string"},"old":{"type":"string"},"new":{"type":"string"}},"required":["file","old","new"]}},"dead":{"type":"array","items":{"type":"string"}}},"required":["relink","dead"]}' \
| jq '.structured_output'relink が付け替えの候補、dead が404のままの候補です。注意点が2つあります。Claudeが要求を断るなどして有効な出力が得られなかったときは、structured_output フィールド自体が付きません。使う前に存在を確かめます。また、スキーマの format キーワードは注釈として扱われ、検証はされません。
CLAUDE.mdに書く運用ルール
毎回プロンプトに書くより、リポジトリの CLAUDE.md に置くほうが揺れません。ただし --bare を付けた実行では CLAUDE.md が読み込まれないので、CIで --bare を使うならルールはプロンプト側に持たせます。
## リンク切れの扱い
- `lychee-report.json` はlychee由来。リンクの正否はレポートを根拠にする
- 付け替えは、`curl -sI` で移動先を確認できたURLだけ
- 404のURLは削除せず、一覧にして報告する
- 外部サイトの記事タイトルや内容を推測してURLを組み立てない実行結果の読み方
提案の表は、次のような形が出る想定です(形のイメージであり、実際の出力ではありません)。
| 区分 | 場所 | 旧URL | 対応 |
|---|---|---|---|
| 付け替え | 場所docs/guide.md:42 | 旧URLhttp版のURL | 対応curl -sI で確認したhttps版に置換 |
| 削除候補 | 場所docs/intro.md:10 | 旧URL404のURL | 対応一覧に残し、人が差し替え先を決める |
| 判断不能 | 場所docs/faq.md:7 | 旧URL応答なしのURL | 対応タイムアウトの可能性。再検査 |
この分類があると、レビューで見るのは削除候補と判断不能の行だけになります。付け替えの行は、旧URLと新URLが同じ資料を指すかを、差分で確かめれば済みます。
検査範囲を絞って費用と時間を抑える
サイト全体を毎回検査すると、外部リンクの数だけ通信が走ります。プルリクエストで変えたMarkdownだけを渡す形にすると、検査も修正案も短く済みます。lycheeは個別のファイルを引数に取れるので、git diff で得た変更ファイルの名前を並べて渡せます。
lychee --no-progress --format json --output lychee-report.json \
$(git diff --name-only origin/main -- '*.md')全体の検査は、夜間の定期実行に回します。リンク先は、記事を直していなくても切れるためです。
つまずきやすい点
落とし穴
終了コード2を見ずにClaude Codeを呼ぶ
lychee自体が動いていない終了コード1でも、レポートファイルが古いまま残っていれば、Claude Codeは古い結果を読んで直し始めます。スクリプトの先頭で lychee-report.json を消してから検査します。
落とし穴
認証が要るページがリンク切れとして並ぶ
ログインが必要なページや、ボット対策で拒否されるサイトは、実際には存在していても失敗として出ることがあります。--accept で成功扱いにするステータスを広げるか、--exclude で外します。Claude Codeに「404ではないので放置」と判断させたいなら、プロンプトにその基準を書きます。
まとめ
lycheeの終了コード2を合図に、JSONレポートを読み取り専用でClaude Codeへ渡し、移動先が確認できたものと404のままのものを分けた表を作らせます。書き換えは承認した行だけを別の呼び出しで行わせ、最後に同じ検査を回して0を確かめます。
ビルド時の検査が内部リンクを守り、lycheeが外部リンクと見出しの壊れを拾う二段構えにすると、役割が重ならず、Claude Codeへ渡す一覧も短く保てます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。