check-mdx
MDX ファイルの構文・frontmatter・リンク・SVG・法令引用・関連キーワード・note リンク・過去問解説等を rule ベースで検査する統合 Evaluator スキル。10 rule を `--rules` フラグで選択可能。 pre-commit hook からも利用される。 Use when user asks to [MDX検査, lint MDX, 構文チェック, リンクチ
SKILL.md.claude/skills/quality/check-mdx/SKILL.md
GitHubMDX 品質に関する 10 種類の検査ルールを 1 つのスキルに統合した Evaluator。旧 /check-mdx /check-frontmatter /check-links /audit-staging /audit-exam-explanations /audit-svg /check-related-keyword-inline /check-legal-citations を吸収。
引数
/check-mdx [path] --rules <rule1,rule2,...|all>
| 引数 | 説明 |
|---|---|
path |
対象ファイル or ディレクトリ(省略時は git diff --name-only HEAD の MDX) |
--rules |
実行ルールをカンマ区切りで指定。all で全ルール |
--fix |
自動修正可能なルール(links / legal-citations)で適用。デフォルトは検出のみ |
--stdin |
ステージ済み MDX を対象(pre-commit 互換) |
--json |
JSON 形式で出力 |
--severity |
指定重大度のみ報告(HIGH / MEDIUM / LOW / ALL) |
ルール一覧
| Rule | 重大度 | 対象 | 検査内容 | 実装 |
|---|---|---|---|---|
syntax |
ERROR/WARN | MDX 全般 | MDX 構文({} エスケープ、<> タグ、見出し階層、テーブル、数式、未対応記法の混入) |
Claude 読解 |
frontmatter |
HIGH/MEDIUM/LOW | frontmatter | zod スキーマ + 内容(description 長・publishedAt・tags allowlist) | .claude/scripts/lint-frontmatter.mjs |
links |
HIGH/INFO | 外部・内部リンク | HTTP HEAD で外部 URL 死活、内部 /docs/・/category/ slug 存在+#anchor 断片検証(note ドラフトも対象) |
scripts/rules/links/ |
svg |
HIGH/MEDIUM/LOW | 埋込 SVG | 文字クリップ、必須属性、viewBox 幅、font-size、テキスト重なり、色トークン | scripts/rules/svg/ |
staging |
— | Obsidian ステージング | 公開準備度(5 軸 15 点評価) | Claude 読解 |
explanations |
HIGH/MEDIUM | 過去問解説 | 破損解説パターン(P1-headless / P2-examPoint-empty) | scripts/rules/explanations/ |
empty-container |
HIGH | MDX 全般 | 中身が空の <Callout>(空白・コメントのみ)= タイトルだけの無意味な枠(E1-empty-callout)。bulk リンク削除等でコンテナの中身だけ消えて枠が残る事故の再発防止 |
scripts/rules/empty-container/ |
related-keyword |
MEDIUM | キーワードページ | 末尾「関連キーワード: [A]、[B]」列挙パターン(ルール 8-1) | .claude/scripts/lint-mdx-mobile.mjs |
legal-citations |
LOW | 法令引用 | e-Gov 法令検索リンク化されているか(ルール 8-2) | scripts/rules/legal-citations/ |
note-link |
MEDIUM | note リンク | note 記事リンク(note.com/dobokunote/n/)が <NoteLink> 外(生 markdown・<Callout>・<LinkCard>)で書かれていないか(ルール 8-3) |
.claude/scripts/lint-mdx-mobile.mjs |
全体スキーム
- 重大度統一ポリシー: 各ルールは独自の重大度体系を持つ。本スキルは統一せず、そのまま転記する
- HIGH は pre-commit でブロックされる。MEDIUM/LOW は警告表示のみ
- Evaluator 専任: 修正は Generator 側(
/improve-article,/keyword-page revise等)が行う。例外:--fix指定時のlinks/legal-citationsのみ自動修正を許可
使い方の例
# 基本: 全 rule を変更 MDX に適用
/check-mdx --rules all
# 特定ファイル
/check-mdx some-file.mdx --rules frontmatter,syntax
# ディレクトリ単位
/check-mdx content/site/pe-comprehensive-management/ --rules related-keyword
# SVG のみ
/check-mdx --rules svg --severity HIGH
# pre-commit 相当
/check-mdx --stdin --rules frontmatter
# 自動修正(対応 rule のみ)
/check-mdx --rules legal-citations --fix
# 一括監査の JSON 出力
/check-mdx --all --rules all --json > /tmp/audit.json
ルール別の詳細
syntax — MDX 構文検証(Claude 読解)
next-mdx-remote / MDX v3 のビルドエラーを未然に防ぐ。
検査項目:
- frontmatter:
---で囲まれた YAML、title / description の存在 - MDX 構文:
{}のエスケープ(JSX 式誤解釈)、<>のタグ誤解釈、import 文 - 見出し階層: h1 不使用(title が h1)、階層スキップなし
- リンク・画像: 内部パス存在、画像パス存在、
/static/絶対パス禁止 - 数式(KaTeX):
$$...$$ブロック前後の空行、$...$内改行なし - 既知の落とし穴:
**[text](url)**の太字リンク、ローマ数字見出しアンカー(#Ⅰ-) - テーブル: ヘッダー行・セパレーター・列数一致
- 未対応記法の混入:
:::note(Docusaurus admonition・本サイトは<Callout>)や Mermaid は next-mdx-remote で描画されないため混入を検出、<div>閉じ
出力: ERROR / WARN / INFO。Claude が MDX を読んで判定。
frontmatter — zod + lint(.claude/scripts/lint-frontmatter.mjs)
構造(zod)+ 内容(独自 lint)の 2 層検証。
| 重大度 | コード | 内容 |
|---|---|---|
| HIGH | zod |
zod スキーマ違反(必須フィールド欠落、enum 不正) |
| HIGH | parse |
YAML パース失敗 |
| MEDIUM | desc-short |
description < 50 文字 |
| MEDIUM | publishedAt-missing |
published: true なのに publishedAt 未設定 |
| MEDIUM | publishedAt-range |
年が 2020-2030 範囲外 |
| MEDIUM | publishedAt-future |
未来日(8 日以上先) |
| LOW | desc-long |
description > 200 文字 |
| LOW | tags-empty |
tags 空 |
| LOW | tags-unknown |
src/config/tags.json の受理綴り(name・slug・aliases・canonical)外。正規表記は日本語名(content-taxonomy.md §5) |
| LOW | sections-missing |
exams 複数なのに sections 未設定 |
| LOW | sections-incomplete |
sections に未登録 exam |
実行: node .claude/scripts/lint-frontmatter.mjs <target>
links — 外部 URL + 内部リンク
外部 URL(check-external-links.mjs)
HTTP HEAD(並列 10 / タイムアウト 15 秒)で検証。対象は content/site/**。
分類:
- ❌ リンク切れ(404/410)→ 要修正
- ⚠️ エラー(403 等)→ 要確認(bot 拒否の可能性)
- ⏱️ タイムアウト → 要確認(政府サイトは遅い場合あり)
- ✅ OK
自動修正: --fix 指定時、リンク切れに対して WebSearch で代替 URL 検索 → Edit 提案
内部リンク(check-links.mjs)
決定的検証(ネットワーク不要・誤検出ゼロ)。content/site/** と content/note/**/article.md の両方を走査。
対象リンク形式: 相対 [text](/docs/slug)、絶対 [text](https://doboku-note.com/docs/slug)、新 URL [text](https://doboku-note.com/exam/...)(public/_redirects で旧 slug へ戻して同じ検査にかける)、裸 URL(note リンクカード形式)。
検証内容:
BROKEN_SLUG(HIGH):/docs/{slug}の slug がcontent/site由来の有効 slug 集合に無いBROKEN_ANCHOR(HIGH):#anchor断片がリンク先ページの見出し ID 集合に無い(#lib/heading-id.mjsで一般版・過去問変種の両 ID を許容)BROKEN_CATEGORY/BROKEN_STATIC(HIGH):/category/{slug}・静的ページの存在確認PLACEHOLDER(INFO): note.com マガジンのPLACEHOLDER_*(未発売プレースホルダ。ブロック対象外)
フラグ:
--scope note|site|all(既定all)--json—{ meta, summary, findings[] }を stdout 出力--report <dir>—audit-{timestamp}.json+latest-report.mdを書き出す
実行:
- 外部:
node .claude/skills/quality/check-mdx/scripts/rules/links/check-external-links.mjs - 内部:
npm run check-links(=check-links.mjs。-- --scope note等を付与可)
定期監査(link-audit.yml)
.github/workflows/link-audit.yml が毎週土曜 07:00 JST に npm run check-links-audit(--scope all --report)を実行し、.claude/state/link-audit/ に結果を蓄積して develop へ [skip ci] commit する。Issue は起票せず、latest-report.md 自体が記録。
svg — 埋込 SVG 品質
content/site/**/img/*.svg の静的解析。
| ID | 重大度 | 内容 |
|---|---|---|
| P1-text-clip | HIGH | テキストが viewBox はみ出し |
| P2-text-overlap | MEDIUM | テキスト bbox 重なり |
| P3-missing-role | MEDIUM | role="img" 欠落 |
| P3-missing-aria | MEDIUM | aria-label 欠落 |
| P3-missing-maxwidth | HIGH | style="max-width:Xpx;width:100%" 欠落 |
| P4-tiny-font | LOW | font-size < 11px |
| P5-wide-viewbox | MEDIUM | viewBox 幅 > 400px(figure-*--wide.svg は landscape 16:9=640 幅が正のため P5 免除。固定キャンバス適合は npm run check-figure-canvas が担保。→ figure-canvas-policy.md) |
| P6-color-drift | MEDIUM | svg-tokens.json colorsAllowList 外 |
| P7-missing-font-family | MEDIUM | font-family 未指定 |
| P8-dark-bg | HIGH | 濃色 fill + 白/薄色テキスト(design-system.md §8 違反) |
| P11-concept-title | MEDIUM | 最上部中央の大見出し(font≥14・y≤26・中央)=概念名タイトル(figure-canvas-policy.md §2.4 違反。SNS ヘッダーと二重化) |
| P12-exam-hint | HIGH | 図内に受験対策注記(試験ポイント/引っかけ/出題ポイント)=概念図に入れない(content-principles §5・figure-canvas-policy §2.5 #5。試験原図は h*-primary 除外) |
出力: .claude/state/svg-audit.json(全件走査のときだけ更新。--file / --path / --severity の部分実行は所見を標準出力へ出し、state は書き換えない)
ギャラリー生成(目視 QA):
npm run svg-gallery # site/note 図版を 1 枚 HTML で(site/note タブ+資格別フィルタ・site は svg-audit.json 重大度バッジ)
node .claude/skills/quality/check-mdx/scripts/rules/svg/build-gallery-comment.mjs # 旧: GitHub コメント用 Markdown
npm run svg-gallery はローカル目視用(.tmp/svg-gallery.html・--open でブラウザ起動・svg-figure-auditor の視覚確認の足場)。上部タブで「サイト/note」を切替え、各タブ内で資格別(カテゴリ)に絞り込む。build-gallery-comment.mjs は GitHub Issue/PR コメント用 Markdown(.tmp/svg-gallery-comment.md)で用途が別。
実行: node .claude/skills/quality/check-mdx/scripts/rules/svg/audit.mjs
staging — Obsidian 公開準備度(Claude 読解)
~/obsidian/exam/1doboku/ の status: review / ready ノートに対して 5 軸ルーブリックで評価(15 点満点、10 点以上で ready 推奨)。
| 軸 | 重み | チェック内容 |
|---|---|---|
| 構造正確性 | 30% | 見出し階層、論理構成 |
| テキスト忠実度 | 25% | 出典明記、内容正確性 |
| 表・図・数式 | 20% | テーブル・KaTeX 正当性 |
| MDX 互換性 | 15% | Obsidian 固有記法([[]], ![[]])残存チェック |
| メタデータ品質 | 10% | title / tags / exam-topic / source |
出力: promote 候補リスト(推奨順)。Claude が Read で読んで判定。
explanations — 過去問破損解説
| ID | パターン | 例 |
|---|---|---|
| P1-headless | 解説文頭が閉じカギから始まる | 1. 」と規定されている ✅ |
| P2-examPoint-empty | ExamPoint summary 欠落 |
summary="」とされている" |
出力: .claude/state/broken-explanations.json
引数: --category civil-construction-1 / --topic 港則法 で絞り込み
実行: node .claude/skills/quality/check-mdx/scripts/rules/explanations/audit.mjs
pre-commit 連動: scripts/pre-commit-mdx.mjs が detect.mjs を import し、warning 表示(既存 64 件があるためブロックはしない)
related-keyword — 関連キーワード末尾列挙
キーワードページ末尾の 関連キーワード: [A]、[B] パターンを検出(lint-mdx-mobile.mjs ルール 8-1)。
移行アプローチ:
- type-1: 本文中に既にキーワード名がある → インライン化で対応
- type-2: 本文中にないが関連性が強い → 1 文追加してインライン化
- type-3: 関連性が弱い → 削除してよい
禁止アプローチ: sed -i '/^関連キーワード[::]/d' のような完全自動置換は 絶対に使わない(データ消失リスク)。
実行: node .claude/scripts/lint-mdx-mobile.mjs <target> 2>&1 | grep "8-1"
legal-citations — e-Gov 法令リンク
MDX 本文の「〇〇法第◯条」が e-Gov 法令検索にリンクされているか検査(lint-mdx-mobile.mjs ルール 8-2)。
URL 形式: https://laws.e-gov.go.jp/law/{法令番号}#Mp-At_{条番号}
枝番条文(第38条の3 等): e-Gov リンクを付けない(公式アンカー形式未確定)。太字のみで留める。
自動修正(--fix):
# dry-run
node .claude/skills/quality/check-mdx/scripts/rules/legal-citations/fix-legal-citations.mjs --dry-run
# 適用(バックアップは /tmp/fix-legal-citations-backup/ に保存)
node .claude/skills/quality/check-mdx/scripts/rules/legal-citations/fix-legal-citations.mjs --apply
法令番号辞書: fix-legal-citations.mjs の LAW_ID_MAP(2026-04-13 時点で 31 件登録、HTTP 200 で検証済み)。新法令追加は LAW_ID_MAP に '{法令名}': '{法令番号}' を足してから実行。
note-link — note 記事リンクのコンポーネント統一(lint-mdx-mobile.mjs ルール 8-3)
note.com 記事へのリンク(note.com/dobokunote/n/)は <NoteLink> コンポーネントに統一する規約(→ .claude/knowledge/reference/content-authoring.md「リンク系コンポーネントの使い分け」)。生 markdown リンク・<Callout type="reference"> 内・<LinkCard> で note 記事リンクを書いている箇所を MEDIUM で検出する。
- magazine リンク(
note.com/dobokunote/m/)は<MagazineCard>(SoT 解決・既定 hero)担当のため対象外 - フェンスコードブロック内は対象外
- 修正は Generator 側(
<NoteLink>への置換)が行う。Evaluator は検出のみ
実行: node .claude/scripts/lint-mdx-mobile.mjs <target> 2>&1 | grep "8-3"
出力フォーマット
基本(テキスト)
=== /check-mdx: <対象> ===
[syntax] <ファイル>
ERROR L42: エスケープされていない `{`
WARN L15: 見出しレベル h2 → h4 のスキップ
[frontmatter] <ファイル>
HIGH: zod スキーマ違反(必須フィールド `title` 欠落)
MEDIUM: description が 42 文字(50 文字未満)
[links] <ファイル>
HIGH: https://example.com/gone (404)
[svg] <ファイル>
HIGH P1-text-clip: 「航路内の禁止」が viewBox 外
MEDIUM P3-missing-aria: aria-label 欠落
...
=== Summary ===
Files checked: 12
HIGH: 3 / MEDIUM: 8 / LOW: 21
OK: 6 files
JSON(--json)
{
"meta": { "generated_at": "...", "rules": ["syntax", "frontmatter"] },
"summary": { "files_checked": 12, "HIGH": 3, "MEDIUM": 8, "LOW": 21 },
"findings": [
{ "file": "...", "rule": "syntax", "severity": "ERROR", "line": 42, "message": "..." }
]
}
pre-commit hook との連動
scripts/pre-commit-mdx.mjs は以下を import して利用:
scripts/rules/explanations/detect.mjs→detectBrokenExplanations(warning 表示)scripts/rules/svg/detect.mjs→auditSvgFile(warning 表示)#shared/lint-frontmatter.mjs→lintFrontmatter(HIGH はブロック)
ステージ済み MDX に対して自動走行。
アンチパターン
- 修正まで実行しない(
--fix指定の links / legal-citations を除く)。Evaluator 専任 - 重大度を統一しようとしない: 各ルールの体系(HIGH/Critical/ERROR 等)はそのまま転記
- related-keyword の一括 sed 削除: データ消失リスクのため絶対禁止(アプローチ A)
- 枝番条文の e-Gov リンク付与: 公式アンカー未確定のため禁止
旧スキルからの移行対応表
| 旧スキル | 新呼出 |
|---|---|
/check-mdx |
/check-mdx --rules syntax(または rule 省略でデフォルト syntax) |
/check-frontmatter <target> |
/check-mdx <target> --rules frontmatter |
/check-links |
/check-mdx --rules links |
/check-links --fix |
/check-mdx --rules links --fix |
/audit-staging [path] |
/check-mdx [path] --rules staging |
/audit-exam-explanations --category X |
/check-mdx --rules explanations --category X |
/audit-svg --severity HIGH |
/check-mdx --rules svg --severity HIGH |
/check-related-keyword-inline |
/check-mdx --rules related-keyword |
/check-legal-citations --fix --apply |
/check-mdx --rules legal-citations --fix --apply |
参照
.claude/scripts/lint-frontmatter.mjs— frontmatter rule 実装.claude/scripts/lint-mdx-mobile.mjs— related-keyword (8-1) / legal-citations (8-2) 検出ロジック.claude/scripts/lib/mdx-io.mjs— CRLF 保持 I/O(--fix系で使用)scripts/rules/{rule}/— rule 別スクリプト実装scripts/pre-commit-mdx.mjs— pre-commit hook 連動.claude/knowledge/reference/content-authoring.md— MDX 作成詳細ルール.claude/skills/authoring/keyword-page/SKILL.md— 関連 Generator(作成規約).claude/skills/authoring/improve-article/SKILL.md— 関連 Generator(対話型修復)