Claude Media
Claude Codeでlycheeのリンク切れを直す — 検査結果を渡して修正案を出させる

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. 1

    lycheeでJSONレポートを書き出す

    終了コードを変数に取り、2以外ならそこで止めます。

  2. 2

    Claude Codeに分類だけをさせる

    編集権限は渡さず、レポートの読み取りと curl -sI だけを許可します。

  3. 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"
fi

docs/ は例です。検査したいディレクトリに読み替えます。

手順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へ渡す一覧も短く保てます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/headless
  2. github.com/lycheeverse/lychee
この記事を共有:XはてブLinkedIn