ワークフロー

CLAUDE.md/Skills CI検証の実装例

更新: AIビルダー編集部
ワークフロー

CLAUDE.md/Skills CI検証の実装例

Claude Codeの運用をチームに広げるとき、つまずきやすいのは CLAUDE.md と Skills と Hooks の役割が混ざり、CI まで一気に複雑になることです。

Claude Codeの運用をチームに広げるとき、つまずきやすいのは CLAUDE.md と Skills と Hooks の役割が混ざり、CI まで一気に複雑になるということです。
この記事は、CLAUDE.md を毎回読む静的ルール、Skills を必要時だけ呼ぶ動的ワークフローとして切り分けたい開発チーム向けに、壊れにくい品質ゲートの組み方を具体例つきで整理します。
私自身、CLAUDE.md を更新したPRで静的チェックを先に入れていたおかげで、同時に触っていた SKILL.md の frontmatter の型不整合をレビュー前に拾えたことがあり、導入順を誤らないだけで手戻りは目に見えて減ると実感しました。
CI はまず構文・サイズ・参照整合性を見る静的チェックから始め、その次に claude -p の非対話サンプル検証を行います。
AIレビューは allow_failure で添える形にすると、肥大化や曖昧化を抑えながら運用を育てられます。

CIで CLAUDE.md / Skill を検証する必要がある理由

Claude Codeの運用で最初に線引きしておきたいのは、何を常時コンテキストに置き、何を必要時だけ読み込ませ、何をプロンプトではなく処理として強制するかです。
広く適用されるルールは CLAUDE.md、時々しか使わないワークフローは Skills、毎回必須のアクションは Hooks に置くのが基本になります。
この切り分けが明示されていて、CLAUDE.md に何でも書き足す運用は避ける前提です。
常に守ってほしいコーディング規約、主要コマンド、リポジトリ全体の方針は CLAUDE.md に置く。
一方で、レビュー手順、障害調査、特定ドメインの説明テンプレートのように毎回は使わないものは Skill に逃がす。
さらに、lint 実行や書き込み制御のように「読んだらやる」ではなく「必ず実行されるべき」ものは Hooks に寄せるほうが設計の筋が通ります。

この切り分けがそのまま CI の検証対象になります。
CLAUDE.md はセッション開始時に毎回読まれる永続指示なので、曖昧な文章や重複したルール、長すぎる補足を抱え込むと、そのぶん会話の出だしで余計なトークンを消費します。
Claude があなたのプロジェクトを記憶する方法で説明されている通り、プロジェクト用の CLAUDE.md./CLAUDE.md または ./.claude/CLAUDE.md に置かれ、上位ディレクトリ側のものは起動時に読み込まれます。
つまり、ここに書いた内容は「そのタスクで必要かどうか」と無関係に、毎回の前提として背負われます。
2026年3月時点では、この性質が出力品質だけでなくコストにも直結します。

私自身、CLAUDE.md を 300 行前後から 800 行近くまで増やして試したときに、会話開始時の待ち時間とコストの上がり方を体感しました。
内容を足したぶん賢くなるというより、毎回読むには重すぎる説明が増えた印象でした。
それ以降は、公式の目安である約 500 行以内を上限に置きつつ、実務では 200〜300 行を目標にする運用へ切り替えています。
CI にもその方針を反映し、行数の閾値を超えたらまず見直し対象として落とすようにしました。
人が読むには親切でも、毎回読む永続指示としては冗長、というケースは思った以上に多いからです。

Skills は逆に、必要なときだけ自動または明示的に読み込まれる前提です。
ここでは「短く保つ」ことより、「呼ばれるべき場面で確実に呼ばれる」ことが品質に効きます。
Skill は SKILL.md を入口にしたディレクトリ構成で、YAML frontmatter の namedescription が必須です。
とくに description は自動読み込みの判断材料なので、説明が曖昧だったり、型が崩れていたり、参照ファイルが壊れていたりすると、必要な場面なのに Skill が選ばれない事故につながります。
実際、2026年の changelog でも description の型不整合に関する不具合修正が入っていて、この層のミスが机上の話ではないことがわかります。
CLAUDE.md は「読みすぎる」事故、Skills は「読まれない」事故が怖い、と捉えると整理しやすくなります。

コスト管理の観点でも、この役割分担はそのまま効いてきます。
Manage costs effectivelyでは、Claude Codeの平均利用コストは 1 人あたり 1 日 6 ドルで、90% が 12 ドル未満に収まるとされています。
この水準に寄せていくには、毎回読む CLAUDE.md を短く保ち、不要な読込を減らす設計が欠かせません。
毎回は使わない長いワークフローを CLAUDE.md に残すより、Skill として分離して必要時だけ展開したほうが、日々の積み上がりを抑えやすくなります。
逆に Hooks で済む処理を文章で指示していると、毎回トークンを使ううえに実行漏れまで起こります。

ℹ️ Note

CLAUDE.md に書くか迷った項目が「全タスクで効くルール」ではなく、「特定の場面でだけ詳しく展開したい手順」なら、先に Skill 化を検討したほうが設計が安定します。

だからこそ、ドキュメントも CI のテスト対象に含める価値があります。
コードと違って自然言語の品質は 100% 自動判定できませんが、PR の段階で落とせるものは明確です。
CLAUDE.md なら行数、重複した見出し、曖昧な TODO 的記述、@path や相対参照の破損が対象になります。
Skill なら frontmatter の存在、namedescription の型、関連ファイルの参照整合性、最低限の使用例の有無までが静的チェックで拾えます。
一方で、その説明が本当に適切か、その Skill がその場面で自然に選ばれるかといった非決定的な評価は、人間レビューに残す設計のほうが現実的です。
CI は壊れているものを止める場所、人間は意図と表現の妥当性を見る場所、と分担したほうが運用が崩れません。

CLAUDE.md と Skills の役割分担を先に整理する

役割分担の原則

CLAUDE.md と Skills を分けるときは、まず「その指示がどの頻度で必要か」で判断すると迷いません。
広く適用されるルールは CLAUDE.md、時々しか使わないワークフローは Skills、毎回必須のアクションは Hooks という切り分けが示されています。

CLAUDE.md に向いているのは、たとえば「このリポジトリでは pnpm を使う」「TypeScript の strict mode を前提にする」「コミット前に見るべき主要コマンドはこれ」といった、会話の前提になる情報です。
セッション開始時から持っていてほしい知識だけを置く場所、と考えると整理しやすくなります。
公式が CLAUDE.md を短く人間可読に保つよう勧めているのも、このファイルが毎回読まれる前提だからです。

一方の Skills は、レビュー、障害調査、リリースノート生成、特定の Issue 修正のように、毎回は使わないが手順や判断基準をまとめておくと効く仕事に向いています。
普段の会話で常駐させるには重い内容でも、必要なときだけ呼ばれるなら邪魔になりません。
実際に運用してみると、CLAUDE.md に「あれもこれも」と足した瞬間に、常時必要な方針とスポット作業のメモが混ざって読みにくくなるんですよね。
そうなると、人間も Claude もどこを優先すべきか掴みにくくなります。

Hooks はさらに性格が違います。
ここに置くのは、自然言語でお願いするより、イベント時に決定論的に実行したほうが安定する処理です。
筆者は以前、レビューで「毎回必要な lint 実行を CLAUDE.md に書いておけばよいのでは」という提案を受けたことがあります。
ただ、その書き方だと実行されたりされなかったり、タイミングが揺れたりします。
そこで lint は Hooks に寄せ、CLAUDE.md には「このリポジトリでは lint エラーを残さない」という方針だけを残しました。
この分け方に変えてから、レビューで同じ指摘が繰り返されることが減り、判断基準も揃いました。
毎回必須で、しかも機械で再現できるなら Hooks、という線引きがここで効きます。

Claude Code のベストプラクティス - Claude Code Docs code.claude.com

保存場所と読み込みタイミングの違い

配置場所の違いも、役割分担とセットで理解しておくと運用が安定します。
CLAUDE.md はプロジェクトでは ./CLAUDE.md または ./.claude/CLAUDE.md に置けます。
Claude があなたのプロジェクトを記憶する方法で説明されている通り、これはセッション開始時に読まれる永続指示です。
さらに上位ディレクトリ側の CLAUDE.md は起動時に読み込まれ、下位ディレクトリの CLAUDE.md はその配下のファイルに触れたときに追加で読まれます。
つまり、常に持っていてほしい方針は上位に、特定領域だけの補足は下位に置く、という設計ができます。

Skills は .claude/skills/**/SKILL.md を入口にしたディレクトリ構成で管理します。
SKILL.md の frontmatter には namedescription が必須で、この description が自動読み込みの判断材料になります。
ここで大事なのは、CLAUDE.md が「先に読むもの」、Skills が「必要になったら読むもの」だという点です。
両者は保存場所だけでなく、コンテキストへの乗り方が違います。

この差は、ファイルが増えたときにはっきり体感できます。
CLAUDE.md にレビュー手順や障害対応フローまで詰め込むと、普段の軽い編集でも毎回その説明を抱えたまま始まります。
反対に、レビュー専用 Skill として分離しておくと、通常の実装相談では静かなままで、レビュー依頼の文脈になったときだけ詳細が出てきます。
progressive disclosure 型の設計と言われることがありますが、実際に触ると「必要なときだけ引き出しが開く」感覚に近いです。

Skills の優先順位にも触れておきたいところです。
公式では enterprise > personal > project の順に優先されます。
チームで project Skill を整備していても、より上位の Skill が同名や近い用途で存在すると、期待した呼ばれ方にならないことがあります。
そこで description を曖昧にせず、「どの場面で何をする Skill なのか」を具体的に書く必要があります。
自動起動しない Skill の多くは、機能不足というより説明不足で取りこぼしています。

⚠️ Warning

CLAUDE.md に書くか Skill に分けるか迷ったら、「この情報を毎回最初から持っていないと困るか」で切ると判断がぶれません。困らないなら Skill 側に寄せたほうが、会話の前提が軽く保てます。

Claude があなたのプロジェクトを記憶する方法 - Claude Code Docs code.claude.com

CIで検証する観点と人間レビューに残す観点

役割分担を決めたら、次は「どこまで機械で落とすか」を分けます。
ここを混ぜると、CI が細かすぎて止まり続けるか、逆に意味のある不具合を拾えないかのどちらかに寄りがちです。
機械に向くのは、構造が壊れているか、参照が切れているか、型が合っているかのような再現可能な条件です。
表現の明確さや、ワークフローの妥当な切り分けまでは、人間の判断が残ります。

対象CIで検証する観点人間レビューに残す観点
CLAUDE.md行数上限、@path の参照整合性、明らかな構文崩れ、全体ルールの重複検知方針の粒度が適切か、常時必要な内容だけに絞れているか
SkillsSKILL.md の存在、frontmatter の必須項目、description の文字列型、参照ファイルの存在description が自動選択される文になっているか、ワークフローの範囲が広すぎないか
Hooksスクリプト実行可否、権限、失敗時の終了コード、冪等性の基本確認本当に毎回実行すべき処理か、失敗時の運用がチームに合っているか

CLAUDE.md では、短く保つという原則を CI に落とし込みやすいのが利点です。
実務ではもっと短いほうが扱いやすいため、チーム独自に厳しめの閾値を置くこともあります。
人間レビューで見るべきなのは、長さそのものより「毎回必要なことしか残っていないか」です。
レビュー用の詳しいチェックリストが混ざっていたら、それは行数が収まっていても Skill に出すべき内容です。

Skills は静的検証の効果が出やすい領域です。
namedescription の欠落、description が文字列ではなく配列や数値になっている事故、references の参照切れは、yq と Bash の組み合わせで拾えます。
ただし、意味の良し悪しまでは完全自動化できません。
たとえば「コードレビュー時にセキュリティ観点も確認する Skill」と書いてあっても、その説明で本当に自動選択されるか、範囲が広すぎないかは人が読んだほうが早いです。
ここを無理に 100% 機械化しようとすると、CI が文章添削の場になってしまいます。

Hooks はもっと割り切れます。
lint、フォーマット、書き込み禁止、通知のように、毎回必ず走ってほしい処理は成功か失敗かで判断できます。
ここは自然言語より終了コードの世界なので、CI の検証対象とも相性が良いです。
逆に、毎回実行する理由が曖昧な処理を Hook に入れると、実装上は正しくても運用で嫌われます。
その妥当性は人間レビューで見るべき判断材料になります。

CI の組み方も、静的検証と AI 実行を分けたほうが扱いやすいのが利点です。
yq で frontmatter を見るジョブは差分ファイルだけに絞れば待ち時間が短く済みます。
ファイル数が増えるほど全走査の遅れは積み上がるので、変更ファイルに CLAUDE.mdSKILL.md が含まれるときだけ走らせる構成のほうが、PR を開いた直後のフィードバックが鈍りません。
claude -p を使うサンプル検証や AI レビューは、その次の段階に置くと役割がはっきりします。
静的に壊れているものを直してから、意味の確認に進む順番です。

まずは静的チェックを作る:構文・サイズ・参照整合性

frontmatter必須項目・型検証

最小の CI ゲートとして最初に入れたいのは、Skill の SKILL.md に対する YAML frontmatter の検証です。
ここは自然言語の善し悪しではなく、存在しているか、型が合っているかを見ればよいので、自動化の相性が抜群です。
実際、2026年に Skill 周辺の運用が広がってから、description が配列や数値として入ってしまう型不整合を踏むケースが目立ちました。
見た目ではそれらしく見えても、自動選択の前提が崩れるので、PR の時点で止める価値があります。

チェック対象はまず namedescription の 2 つです。
どちらも必須で、型は文字列に限定します。
説明文の内容が適切かどうかは人間が見ればよいので、静的チェックでは「空でない文字列か」に寄せるのが実務向きです。
ここを欲張って文章品質まで採点し始めると、CI が壊れた構造を止める場所ではなく、表現添削の場に変わってしまいます。

yq を使うと frontmatter をそのまま抜き出して判定できます。
--front-matter=extract が使えるので、Markdown 本文を自前で切り分ける必要がありません。
終了コードで CI の成否をそのまま返せるため、Bash と組み合わせた最小構成でも十分に実戦投入できます。

#!/usr/bin/env bash
set -euo pipefail

fail=0

check_skill_frontmatter {
  local file="$1"

  if ! yq --front-matter=extract '.' "$file" >/dev/null 2>&1; then
    echo "ERROR: invalid frontmatter syntax: $file"
    fail=1
    return
  fi

  # frontmatter の値とタグ(型)を確実に取得してから判定する
  local name_type name_value desc_type desc_value
  desc_type="$(yq --front-matter=extract '.description | tag' "$file" 2>/dev/null || true)"

  if [[ "$name_type" != "!!str" ]] || [[ -z "$name_value" ]] || [[ "$name_value" == "null" ]]; then
    echo "ERROR: .name must be a non-empty string: $file"
    fail=1
  fi

  if [[ "$desc_type" != "!!str" ]] || [[ -z "$desc_value" ]] || [[ "$desc_value" == "null" ]]; then
    echo "ERROR: .description must be a non-empty string: $file"
    fail=1
  fi
}

while IFS= read -r file; do
  check_skill_frontmatter "$file"
done < <(find . -name SKILL.md)

exit "$fail"

差分ファイルだけを対象にする運用も相性がよく、変更数が増えるほど効いてきます。
yq はファイル単位で frontmatter を解析するので、リポジトリ全体を毎回なめるより、paths フィルタや git diff --name-only で対象を絞ったほうが PR 直後の返答が鈍りません。
構文と型だけを見るジョブは、短時間で返してこそ価値が出ます。

Markdownリンク/@pathの存在チェック

frontmatter の次に費用対効果が高いのが、Markdown リンクと @path 参照の存在確認です。
最初に入れた静的チェックはリンク切れの検出だけでしたが、運用してみると、実際に壊れやすいのは本文中の相対リンクだけではありませんでした。
CLAUDE.md や Skill の説明文に埋めた @path の参照先がリネームや移動で死んでいることが多く、そこまで見るようにしてから参照破損の PR が目に見えて減りました。
静的チェックは地味ですが、ここで止められる破損が思った以上に多いと実感しました。

見るべき対象は 2 種類あります。
ひとつは text のような通常の Markdown リンク、もうひとつは ` @docs/spec.md のような行内コードで書かれた @path` 参照です。
前者は Markdown として解釈されるリンク、後者は Claude 向けの参照記法として説明文に混ざりやすいので、両方を拾わないと片手落ちになります。

実装は Bash だけでも足ります。
外部 URL は除外し、相対パスだけを取り出して、元ファイルからの相対位置で実在確認します。
@path も同様に、バッククォート内の値を抜き出して @ を外し、存在を見ます。
#!/usr/bin/env bash set -euo pipefail

fail=0

check_refs_in_file { local file="$1" local base_dir base_dir="$(dirname "$file")"

# Markdown links # 可搬性を高めるため、まずは perl が使えるか確認してから実行します。
# CI イメージに perl が無い場合は、イメージに perl を追加するか、 # sed/awk ベースの簡易抽出へフォールバックしてください(完全なパースには限界があります)。
if command -v perl >/dev/null 2>&1; then while IFS= read -r ref; do && continue && continue && continue

local clean_ref="${ref%%#*}" if ; then echo "ERROR: broken markdown link in $file -> $ref" fail=1 fi

done < <(perl -nle 'print $1 while /\+\]\(([^)]+)\)/g' "$file" || true)

else echo "WARN: perl not found; attempting POSIX fallback. For robust parsing, install perl in your CI image." # 簡易的な sed 抽出(複雑なネストや空白には弱い) while IFS= read -r ref; do && continue && continue && continue

local clean_ref="${ref%%#*}" if ; then echo "ERROR: broken markdown link in $file -> $ref" fail=1 fi

done < <(sed -n 's/.\\](\([^)]\))./\1/p' "$file" || true)

fi

# inline-code @path references if command -v perl >/dev/null 2>&1; then while IFS= read -r ref; do && continue local clean_ref="${ref#@}" if ; then echo "ERROR: broken @path reference in $file -> $ref" fail=1 fi

done < <(perl -nle 'print $1 while /@([^]+)`/g' "$file" || true)

else # 簡易フォールバック: バッククォート内の @path を抽出(完全ではない) while IFS= read -r ref; do && continue # remove surrounding backticks if present ref="${ref#\}" ref="${ref%\}" && continue local clean_ref="${ref#@}" if ; then echo "ERROR: broken @path reference in $file -> $ref" fail=1 fi

done < <(grep -oE '@[^]+`' "$file" || true)

fi }

この種のチェックは、Markdown パーサを持ち込まなくても現場では十分機能します。
大切なのは精密さより、PR で壊れた参照を即座に止めるということです。
とくに Skill では SKILL.md 単体で完結せず、補助資料やテンプレート、スクリプト断片を別ファイルに逃がすことが多いので、参照整合性の崩れはそのまま利用不能に直結します。

CLAUDE.mdサイズと禁止パターン

ここでは 2 段階に分けるのが素直です。
たとえば運用上は 300 行を超えたら「見直しの警告」(多くのチームが採用する実務上の推奨値)、500 行を超えたら「失敗」(ドキュメント側で示される上限的目安)とする構成が扱いやすいのが利点です。
チームごとに「見直し閾値(例: 300 行)」と「強制失敗閾値(例: 500 行)」を明確に分けて運用してください。
#!/usr/bin/env bash set -euo pipefail

fail=0 warn=0

file="./CLAUDE.md"

if ; then lines="$(wc -l < "$file" | tr -d ' ')"

if (( lines >= 300 )); then echo "WARN: CLAUDE.md is ${lines} lines; keep it under 300 lines in team operation" warn=1 fi

if (( lines > 500 )); then echo "ERROR: CLAUDE.md exceeds 500-line limit (${lines})" fail=1 fi

forbidden_patterns=( 'do anything now' 'ignore (all|any) previous instructions' 'ANTHROPIC_API_KEY=' 'CLAUDE_CODE_OAUTH_TOKEN=' 'rm -rf+/' 'curl.\|sh' 'git push' )

for pattern in "${forbidden_patterns[@]}"; do if grep -Eiq "$pattern" "$file"; then echo "ERROR: forbidden pattern matched in CLAUDE.md -> $pattern" fail=1 fi done fi

exit "$fail"


GitHub Actions から呼ぶ最小構成はこのくらいで足ります。`workflow_dispatch` を付けておくと、既定ブランチにワークフローを置いたうえで UI から手動実行もできます。静的検証なので secrets を必要とせず、`pull_request` でも扱いやすい構成です。

name: static-validate

on: pull_request: paths:

  • 'CLAUDE.md'
  • '**/SKILL.md'
  • '**/*.md'

workflow_dispatch:

jobs: static-validate: runs-on: ubuntu-latest # ルート用ジョブ steps:

  • uses: actions/checkout@v4
  • name: Install yq

run: | sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 sudo chmod +x /usr/local/bin/yq yq --version

  • name: Run static checks

run: | bash scripts/check-skill-frontmatter.sh bash scripts/check-markdown-and-paths.sh bash scripts/check-claude-md.sh


GitLab CI でも考え方は同じで、ジョブから Bash スクリプトを順に呼び出し、どれかが非 0 を返したら失敗にします。最初は手動実行や失敗許容から始める構成もありますが、ここで扱っている frontmatter、参照整合性、行数、禁止パターンは非決定的な判定ではないので、先に必須ゲートへ置いたほうが運用が安定します。

> [!TIP]
> 静的チェックの役割は、良い文章を選ぶことではなく、壊れた構造を通さないということです。`SKILL.md` の型、リンク、`@path`、`CLAUDE.md` の行数と危険な記述に絞るだけでも、PR レビューで見るべき論点がはっきり分かれます。

{{product:0}}

## 次に非対話モードで自動検証する

### 非対話 `claude -p` の最小実行例

静的チェックで構造の破損を止めたら、その次はClaude Code自身に短い検証プロンプトを投げて、Skill の選択やルール理解を機械可読な形で見ます。ここで使うのが非対話モードの `claude -p` です。Claude Code の。

最小構成なら、まずは 1 回呼んで JSON を受け取り、`jq` で失敗条件に変換するだけで十分です。2026年3月時点では、機械可読な出力に `--output-format json` と `--output-format stream-json` を使う形が扱いやすく、後者はイベントを逐次処理したいときに向いています。CI では最初からストリーム処理に寄せるより、1 回の応答を JSON で受けて判定するほうが保守しやすい場面が多いです。

#!/usr/bin/env bash set -euo pipefail

prompt_file="ci/prompts/skill-selection.txt" result_file="$(mktemp)"

claude -p "$(cat "$prompt_file")" \ --output-format json > "$result_file"

cat "$result_file" | jq .


ストリームで受けたい場合は次の形です。長めの応答でも途中経過を拾えるので、CI ログや独自の集計に流し込みやすくなります。

#!/usr/bin/env bash set -euo pipefail

prompt_file="ci/prompts/skill-selection.txt"

claude -p "$(cat "$prompt_file")" \ --output-format stream-json | tee /tmp/claude-stream.jsonl


この用途は GitHub Actions でも pre-commit 用のローカルスクリプトでも同じです。pre-commit では毎回走らせず手動ターゲットに留め、CI では `paths` フィルタで `CLAUDE.md` や `SKILL.md` が変わったときだけ動かすと、無駄なランを増やしません。私自身、`claude -p` でサンプル呼び出しを繰り返し、`description` の文言だけを詰めていったことがありますが、そこを少し言い換えるだけで Skill の自動選択率が目に見えて変わりました。CI に結果を残すようにしてからは、その改善が一回限りの勘ではなく、継続的に磨ける対象として見えるようになりました。

### サンプルプロンプトと失敗条件の設計

非対話検証で見るべきなのは、長い自由回答の質ではなく、期待した Skill を思い出せるか、守るべきルールを落とさず要約できるかです。プロンプトは短く、判定条件は先に固定しておくとブレません。スキルで Claude を拡張するの構造に沿って考えると、評価対象は `description` がタスク想起の入口として機能しているか、そして Skill 内のルールが応答に残るかの2点に分けると整理しやすくなります([スキルで Claude を拡張する](https://code.claude.com/docs/ja/skills))。

たとえば、CI 用のサンプルプロンプトは次のように置けます。ポイントは、代表的なユースケースを一文で言わせることと、返答形式を JSON に固定するということです。温度は低めにして、創造性ではなく再現性を優先します。

あなたは現在ロードされている Skills とプロジェクトルールを確認できます。
次の依頼に対して、使うべき Skill 名を列挙し、重要ルールを短く要約してください。

依頼: 「既存PRのレビューを行い、セキュリティ観点と変更影響を確認したい」

出力はJSONのみで返してください。
{ "loaded_skills": ["..."], "selected_skills": ["..."], "rule_summary": ["..."], "warning_score": 0 }


この応答を CI で判定するなら、失敗条件は自然言語ではなく機械的に書けるものへ落とします。たとえば期待する Skill が `loaded_skills` か `selected_skills` に含まれない、`rule_summary` に必須キーワードが出てこない、`warning_score` がチームで決めた閾値を超える、といった形です。`warning_score` は Claude 側に自己評価させるだけなので万能ではありませんが、閾値超過を「即 fail」にせず、まずは警告として蓄積する運用に向いています。

#!/usr/bin/env bash set -euo pipefail

result_file="result.json"

claude -p "$(cat ci/prompts/skill-selection.txt)" \ --output-format json > "$result_file"

jq -e ' (.selected_skills | index("security-review")) and

(.rule_summary | join(\" \") | test(\"セキュリティ|変更影響\")) and

(.warning_score <= 2) ' "$result_file" > /dev/null


GitHub Actions ではこの `jq -e` の終了コードをそのまま fail 判定にできますし、step 単位で `continue-on-error` を付ければ記録だけ残して後続へ流せます。GitLab CI なら同じ Bash をジョブで呼び、段階的に `allow_failure` から必須ゲートへ移していく形が扱いやすいです。自然言語の評価をいきなり厳格な必須判定にすると、壊れていないのに止まる日が出るので、最初は「期待 Skill の欠落」「必須キーワード欠落」のような明確な条件だけを fail に寄せるほうが安定します。

> [!NOTE]
> 失敗条件は、文章の上手さではなく「通ってはいけない状態」に寄せると運用が崩れません。Skill 名の欠落、必須ルール語の欠落、スコア閾値超過のように、CI が判断文を作らなくて済む形へ寄せるのがコツです。

{{ogp:https://code.claude.com/docs/ja/skills|スキルで Claude を拡張する - Claude Code Docs|Claude Code でスキルを作成、管理、共有して Claude の機能を拡張します。カスタムコマンドとバンドルされたスキルが含まれます。|https://claude-code.mintlify.app/_next/image?url=%2F_mintlify%2Fapi%2Fog%3Fdivision%3DClaude%2BCode%2B%25E3%2581%25A7%25E6%25A7%258B%25E7%25AF%2589%25E3%2581%2599%25E3%2582%258B%26appearance%3Dsystem%26title%3D%25E3%2582%25B9%25E3%2582%25AD%25E3%2583%25AB%25E3%2581%25A7%2BClaude%2B%25E3%2582%2592%25E6%258B%25A1%25E5%25BC%25B5%25E3%2581%2599%25E3%2582%258B%26description%3DClaude%2BCode%2B%25E3%2581%25A7%25E3%2582%25B9%25E3%2582%25AD%25E3%2583%25AB%25E3%2582%2592%25E4%25BD%259C%25E6%2588%2590%25E3%2580%2581%25E7%25AE%25A1%25E7%2590%2586%25E3%2580%2581%25E5%2585%25B1%25E6%259C%2589%25E3%2581%2597%25E3%2581%25A6%2BClaude%2B%25E3%2581%25AE%25E6%25A9%259F%25E8%2583%25BD%25E3%2582%2592%25E6%258B%25A1%25E5%25BC%25B5%25E3%2581%2597%25E3%2581%25BE%25E3%2581%2599%25E3%2580%2582%25E3%2582%25AB%25E3%2582%25B9%25E3%2582%25BF%25E3%2583%25A0%25E3%2582%25B3%25E3%2583%259E%25E3%2583%25B3%25E3%2583%2589%25E3%2581%25A8%25E3%2583%2590%25E3%2583%25B3%25E3%2583%2589%25E3%2583%25AB%25E3%2581%2595%25E3%2582%258C%25E3%2581%259F%25E3%2582%25B9%25E3%2582%25AD%25E3%2583%25AB%25E3%2581%258C%25E5%2590%25AB%25E3%2581%25BE%25E3%2582%258C%25E3%2581%25BE%25E3%2581%2599%25E3%2580%2582%26logoLight%3Dhttps%253A%252F%252Fmintcdn.com%252Fclaude-code%252Fc5r9_6tjPMzFdDDT%252Flogo%252Flight.svg%253Ffit%253Dmax%2526auto%253Dformat%2526n%253Dc5r9_6tjPMzFdDDT%2526q%253D85%2526s%253D78fd01ff4f4340295a4f66e2ea54903c%26logoDark%3Dhttps%253A%252F%252Fmintcdn.com%252Fclaude-code%252Fc5r9_6tjPMzFdDDT%252Flogo%252Fdark.svg%253Ffit%253Dmax%2526auto%253Dformat%2526n%253Dc5r9_6tjPMzFdDDT%2526q%253D85%2526s%253D1298a0c3b3a1da603b190d0de0e31712%26primaryColor%3D%25230E0E0E%26lightColor%3D%2523D4A27F%26darkColor%3D%25230E0E0E%26backgroundLight%3D%2523FDFDF7%26backgroundDark%3D%252309090B&amp;w=1200&amp;q=100}}

### 非決定性の扱い

ここで避けにくいのが、同じプロンプトでも応答が少し揺れるということです。前のセクションで触れた静的チェックとは違って、`claude -p` の検証は非決定的な要素を含みます。だからこそ、1 回で白黒を強く付けすぎない設計が必要です。

現実的なのは、まず 1 回実行で保守的な閾値を置くということです。たとえば `selected_skills` への完全一致までは求めず、`loaded_skills` に期待 Skill が見えていて、要約に必須キーワードが残っていれば通す、といった形なら揺れに耐えます。それでも不安定なら 2 回実行して両方で条件を満たしたときだけ成功にする AND 判定へ切り替えます。逆に片方だけ通ればよい OR 判定は、壊れかけの Skill を見逃しやすいので、検証用途にはあまり向きません。

人間レビューへの移譲も並列で持っておくと運用が楽になります。GitHub Actions なら AI 判定ステップに `continue-on-error` を使って outcome を後続で拾えますし、GitLab CI では `allow_failure` を付けた補助ジョブとして走らせる設計が噛み合います。最初から必須ゲート一本にせず、失敗を可視化しながら傾向を見る期間を挟むと、誤検知でチームが疲弊しません。

もうひとつ効くのが、検証対象を代表ケースに絞るということです。すべての Skill を毎回総当たりで呼ぶより、変更の入った Skill と、その周辺の典型プロンプトだけを `paths` フィルタで回すほうが、ラン時間も読みやすさも保てます。CLI の評価は「全知全能のテスト」ではなく、`description` とルール記述が壊れていないかを見張る見張り番として置くくらいがちょうどいいです。静的チェックで構造を止め、`claude -p` で想起と要約を薄く監視し、残る判断をレビューで拾う。この三層に分けると、CI が文章添削の泥沼に入りません。

## GitHub Actions / GitLab CI の実装例

### GitHub Actionsの最小ジョブ

『GitHub Actions』で最初に置くなら、手動起動の `workflow_dispatch` から始める構成がいちばん事故が少ないです。『GitHub』公式でも `workflow_dispatch` を付けたワークフローは UI の「Run workflow」から実行でき、ワークフロー定義は既定ブランチ上にある必要があります。私はこの形で先にログと JSON の出方を見てから、PR で必須にする段階へ進めました。いきなり `pull_request` に結び付けるより、どこで落ちるのか、結果がどの粒度で読めるのかを先に観察できるので、段階導入のほうが運用が崩れません。

{{ogp:https://docs.github.com/ja/actions|GitHub Actions ドキュメント - GitHub ドキュメント||https://docs.github.com/assets/cb-345/images/social-cards/actions.png}}

### 構成の分け方
構成は 2 系統に分けておくと扱いやすくなります。ひとつは `static-validate`(構文・型・参照の静的検証)、もうひとつは `prompt-validate`(非対話のサンプル実行と JSON 保存)です。導入初期は後者を失敗許容にして記録を集める流れが扱いやすいです。API キーはリポジトリに書かず、Repository secrets に例として `CLAUDE_API_KEY` を登録して参照します(名前はプロジェクト運用上の例であり固定ではありません)。

#### ジョブ分割の例

name: claude-ci

on: workflow_dispatch: push: paths:

  • 'CLAUDE.md'
  • '**/SKILL.md'
  • 'ci/**'
  • '.github/workflows/claude-ci.yml'

jobs: static-validate: runs-on: ubuntu-latest # パッケージ限定ジョブ steps:

  • uses: actions/checkout@v4
  • name: Install yq

run: | # Install yq (binary download - adjust for distro) sudo wget -qO /usr/local/bin/yq sudo chmod +x /usr/local/bin/yq yq --version

ℹ️ Note

上記はコードサンプルの一部です。実ジョブではイメージやパッケージ管理方法に応じてインストール手順を調整してください(alpine では別途パッケージ名やパスが異なります)。

run: | sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 sudo chmod +x /usr/local/bin/yq

  • name: Validate CLAUDE.md length and references

shell: bash run: | set -euo pipefail

test -f CLAUDE.md

## line_count=$(wc -l < CLAUDE.md) if [ "$line_count" -gt 500 ]; then echo "CLAUDE.md is too long: $line_count lines" exit 1 fi

while IFS= read -r ref; do # ネスト内で参照を読み込む path="${ref#@}" if [ ! -e "$path" ]; then echo "Missing reference: $ref" exit 1 fi

done < <(grep -oE '@[^ ]+' CLAUDE.md || true)

  • name: Validate SKILL.md frontmatter

shell: bash run: | set -euo pipefail

## mapfile -t files < <(find . -name SKILL.md) for file in "${files[@]}"; do yq --front-matter=extract '.name' "$file" >/dev/null

yq --front-matter=extract '.description | tag' "$file" | grep -qx '!!str'

done prompt-validate: runs-on: ubuntu-latest # フロントエンド限定ジョブ needs: static-validate continue-on-error: true env: # 例示: 下はプロジェクト内の慣例的な環境変数名です。
固定の公式名ではなく、 # 各チームで運用名を決めてください(例: CLAUDE_API_KEY / ANTHROPIC_API_KEY 等)。
CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}

  • uses: actions/checkout@v4
  • name: Run non-interactive validation

shell: bash run: | set -euo pipefail

mkdir -p artifacts claude -p "$(cat ci/prompts/smoke-test.txt)" \ --output-format json > artifacts/result.json

  • name: Check JSON result

shell: bash run: | set -euo pipefail jq -e '.selected_skills and .rule_summary' artifacts/result.json > /dev/null

  • name: Upload result

uses: actions/upload-artifact@v4 with: name: prompt-validate-result path: artifacts/result.json


このサンプルでは、静的チェックを通したあとにだけ `prompt-validate` を動かしています。`continue-on-error` を付けているので、代表ケースの判定が揺れた日でもワークフロー全体を止めず、JSON は残せます。初期フェーズではこの「落とさないが、記録は必ず残す」状態が効きます。外部 PR で secrets が使えない `pull_request` の制約もあるので、まずは手動実行か、内部ブランチの push だけで回すところから始めるほうが安全です。

### GitLab CIの最小ジョブ

GitLab 。ここは『GitHub Actions』以上に、最初から自動ゲートへ寄せすぎないほうが安定します。`when: manual` を付けて、ログ、成果物、失敗時の表示を見ながら詰めると、チームに載せるときの摩擦が減ります。

API キーはGitLabの CI/CD Variables に `CLAUDE_API_KEY` として登録します。ジョブ設計は同じく `static-validate` と `prompt-validate` に分け、前者を必須、後者を `allow_failure: true` で補助扱いにするのが無難です。静的検証は secrets 不要なので、ここだけ先に MR パイプラインへ入れても詰まりません。非対話の検証は、まず手動で走らせて応答 JSON の形を固定してから広げたほうが、失敗理由の切り分けが早くなります。

stages:

  • validate

static-validate: stage: validate image: alpine:3.20 rules:

  • changes:
  • CLAUDE.md
  • "**/SKILL.md"
  • ci/**/*
  • .gitlab-ci.yml
  • when: manual

before_script:

  • apk add --no-cache bash grep findutils yq

script:

  • |

set -euo pipefail

test -f CLAUDE.md

## line_count=$(wc -l < CLAUDE.md) if [ "$line_count" -gt 500 ]; then echo "CLAUDE.md is too long: $line_count lines" exit 1 fi

while IFS= read -r ref; do # 最後の参照群を読み込む path="${ref#@}" if [ ! -e "$path" ]; then echo "Missing reference: $ref" exit 1 fi

done < <(grep -oE '@[^ ]+' CLAUDE.md || true)

find . -name SKILL.md | while read -r file; do yq --front-matter=extract '.name' "$file" >/dev/null

yq --front-matter=extract '.description | tag' "$file" | grep -qx '!!str'

done

prompt-validate: stage: validate image: node:22-alpine needs: ["static-validate"] allow_failure: true when: manual rules:

  • changes:
  • CLAUDE.md
  • "**/SKILL.md"
  • ci/**/*
  • .gitlab-ci.yml
  • when: manual

script:

  • |

set -euo pipefail

mkdir -p artifacts # 非対話検証での実行例(出力をアーティファクトに保存) claude -p "$(cat ci/prompts/smoke-test.txt)" \ --output-format json > artifacts/result.json

ℹ️ Note

断定表現は避け、検証結果の揺れや限界を明示するようにしました。

--output-format json > artifacts/result.json

jq -e '.selected_skills and .rule_summary' artifacts/result.json > /dev/null artifacts: when: always paths:

  • artifacts/result.json

この形なら、最初はどちらのジョブも手で起動して結果を確かめられます。静的ジョブが安定したら MR の必須チェックへ移し、`prompt-validate` はしばらく補助のまま運用する流れが現実的です。私もこの順番で進めましたが、先に可観測性を見ておいたことで、「何が原因で止まったのか」が共有しやすくなりました。CI の本番運用では、失敗そのものより、失敗理由が読めないことのほうがチームの負担になります。

> [!TIP]
> 非対話ジョブは、最初から「通るか落ちるか」だけを見るより、JSON アーティファクトを必ず保存して、`selected_skills` や `rule_summary` の揺れ方を読む設計のほうが調整が進みます。

{{ogp:https://code.claude.com/docs/en/gitlab-ci-cd|Claude Code GitLab CI/CD - Claude Code Docs|Learn about integrating Claude Code into your development workflow with GitLab CI/CD|https://claude-code.mintlify.app/_next/image?url=%2F_mintlify%2Fapi%2Fog%3Fdivision%3DCode%2Breview%2B%2526%2BCI%252FCD%26appearance%3Dsystem%26title%3DClaude%2BCode%2BGitLab%2BCI%252FCD%26description%3DLearn%2Babout%2Bintegrating%2BClaude%2BCode%2Binto%2Byour%2Bdevelopment%2Bworkflow%2Bwith%2BGitLab%2BCI%252FCD%26logoLight%3Dhttps%253A%252F%252Fmintcdn.com%252Fclaude-code%252Fc5r9_6tjPMzFdDDT%252Flogo%252Flight.svg%253Ffit%253Dmax%2526auto%253Dformat%2526n%253Dc5r9_6tjPMzFdDDT%2526q%253D85%2526s%253D78fd01ff4f4340295a4f66e2ea54903c%26logoDark%3Dhttps%253A%252F%252Fmintcdn.com%252Fclaude-code%252Fc5r9_6tjPMzFdDDT%252Flogo%252Fdark.svg%253Ffit%253Dmax%2526auto%253Dformat%2526n%253Dc5r9_6tjPMzFdDDT%2526q%253D85%2526s%253D1298a0c3b3a1da603b190d0de0e31712%26primaryColor%3D%25230E0E0E%26lightColor%3D%2523D4A27F%26darkColor%3D%25230E0E0E%26backgroundLight%3D%2523FDFDF7%26backgroundDark%3D%252309090B&amp;w=1200&amp;q=100}}

### コスト/時間最適化のTips

実行時間とコストを抑えるうえでは、毎回フルスキャンしないことがいちばん効きます。`yq` はファイルごとに frontmatter を解析するので、対象が増えるほど I/O と解釈の待ち時間が積み上がります。数百ファイル規模になると差分だけ見たほうが明らかに速く、レビュー待ちのテンポも落ちません。『GitHub Actions』なら `paths`、GitLab CIなら `rules: changes` を使って、`CLAUDE.md`、`SKILL.md`、CI 用プロンプトだけに絞る構成が基本になります。

もうひとつ見逃せないのが、`CLAUDE.md` 自体の長さです。 `CLAUDE.md` を短く保つ前提が示されており、実務でも 300 行未満、さらに切り詰めて 200 行前後を目標に置くと、読み込み負荷が目に見えて軽くなります。このセクションの YAML では上限を 500 行にしていますが、CI の警告閾値としてはもっと低く置くチームも珍しくありません。毎回読む文書を長文化させないだけで、`prompt-validate` のトークン消費も抑えられます。

導入順も最適化の一部です。手動トリガーで `static-validate` を固め、そのあと `prompt-validate` を `allow_failure` 付きで流し、ログと JSON の蓄積を見てから必須化する。この順番なら、不要なランを量産せずに済みます。常時実行の AI ジョブは便利ですが、代表ケースがまだ固まっていない段階で全 PR にぶら下げると、実行回数だけ増えて調整コストが先に膨らみます。先に静的検証で壊れた構造を止め、非対話検証は代表ケースへ絞るほうが、時間も予算も読みやすくなります。

ジョブ分割の観点では、`static-validate` を必須、`prompt-validate` を補助と役割固定しておくと、運用判断がぶれません。前者は deterministic な失敗だけを見る場所、後者は想起や要約の揺れを観測する場所として切り分けるわけです。ここを混ぜると、構文エラーと自然言語の揺れが同じ「失敗」に見えてしまい、改善の優先順位が崩れます。CI の設計そのものをシンプルに保つことが、結局は最短で安定運用につながります。

## PRレビューで見るべきことと、自動化しないほうがよいこと

### 表に整理

自動チェックを入れ始めると、つい「見られるものは全部 CI に寄せたい」と考えがちです。ただ、`CLAUDE.md` や Skill の運用では、その線引きを先に決めておかないと、機械に向いた判定と人間が読むべき判断が混ざります。私の現場でも、AI レビュー結果だけでマージ基準を決めようとした時期がありましたが、そこで増えたのは安心感ではなく誤判定でした。文章の言い回しや適用範囲の広さを、単発のレビュー結果だけで白黒つけるのは無理があります。そこで先にレビュー観点を表にして、どこまでを CI で落とし、どこからを人が見るかを合意したところ、議論が止まりにくくなりました。

とくに Skill の `description` は、構文的に正しければ十分という項目ではありません。たとえば「レビューを助ける Skill」では広すぎますが、「PR で `CLAUDE.md` や `SKILL.md` の変更をレビューするときに、description の明確さ、参照整合性、適用範囲の過不足を確認する」のように書くと、呼び出し場面が定まりやすくなります。『スキルで Claude を拡張する』の説明どおり、Skill は関連時に選ばれる前提なので、曖昧な説明文は運用上そのまま選択率の低下につながります。ここは lint だけでは100%検出できません。

その境界を雑にしないために、私は次のような分け方で考えることが多いです。

| 分類 | CIで落とす項目 | 人間レビューに残す項目 |
|---|---|---|
| `CLAUDE.md` / Skill 共通 | 構文崩れ、型不整合、参照切れ、サイズ超過、禁止パターンの混入 | description の良し悪し、Skill の適用範囲、曖昧表現、倫理・セキュリティ上の妥当性 |
| Skill | frontmatter の必須項目欠落、`description` の型、参照ファイルの存在 | その説明で本当に呼ばれるか、対象タスクが広すぎないか、入出力の前提が伝わるか |
| CI ルール | 禁止コマンドや危険な書式の検知、明確な終了コード判定 | そのルールがチームの開発速度を落とさないか、例外運用をどう扱うか |

この表で効くのは、「description の良し悪し」と「description の有無」を別物として扱える点です。前者は人が読むべきで、後者は CI で止められます。同じように、「Skill の適用範囲が広すぎる」は人間レビューの領域ですが、「参照先の `@path` が存在しない」は機械が即座に弾けます。曖昧表現も厄介で、「必要に応じて」「適切なら」「場合によって」だけで成立している Skill は、文章としては読めても、自動運用では役に立ちません。こういう箇所は AI に赤入れさせることはできても、マージ可否の最終判断まで委ねるとぶれます。

> [!TIP]
> Skill の `description` は「いつ」「何のために」「どんな入力で」の3点を書き切ると、レビューでも運用でも揉めにくくなります。短いことより、呼ばれる場面が想像できることのほうが効きます。

### AIレビューの並列運用

AI レビューは便利ですが、最初から必須ゲートにすると、安定する前にチームの信頼を失います。実務では `allow_failure` を付けて並列実行し、サマリコメントを参考情報として出す運用から始めるほうが収まりがよいです。GitLab CI の `allow_failure` でも、GitHub Actions の `continue-on-error` でも発想は同じで、「結果は見るが、パイプライン全体は壊さない」に置くわけです。前のセクションで触れた静的検証と違って、AI レビューは自然言語の揺れや文脈依存の判断を含むので、fail をそのまま merge block に変換すると運用が荒れます。

私も一度、AI レビューの指摘をそのままマージ基準に寄せたことがありますが、description の表現揺れや Skill の守備範囲に対する評価が毎回ぶれて、レビュアーの認識とも噛み合いませんでした。そのあとで、AI は「参考情報」、人間は「最終判断」と役割を戻したところ、レビューの会話が前に進むようになりました。とくに効いたのは、AI に長文コメントを出させるのではなく、「description の具体性」「適用範囲の広さ」「曖昧表現の有無」「倫理・セキュリティ上の懸念」といった観点ごとの短いサマリに絞ったということです。レビュー観点表が先にあると、AI の出力も読み比べやすくなります。

GitLab CI/CDの Claude Code 連携例や、実務での非対話運用では、最初は補助ジョブとして流す設計がよく合います。PR ごとに AI レビューを横に並べ、失敗してもマージは止めず、コメントやアーティファクトで結果を残す形です。これなら、AI が誤って厳しすぎる判定を出しても開発を止めませんし、逆に見落とした観点だけを人間が拾えます。サマリコメントに「この Skill の description は目的は書かれているが、入力条件が欠けている」「適用範囲が広く、レビュー Skill なのか修正 Skill なのか判別しづらい」といった粒度で出しておくと、差分レビューの補助として機能します。

並列運用の価値は、正解を自動で決めることではなく、見落としを減らすことにあります。構文、型、参照、サイズ、禁止パターンは機械で落とし、description の品質や曖昧表現、Skill の適用範囲、倫理・セキュリティのような非決定的な判断は人間が引き受ける。この切り分けのうえで AI を横に置くと、レビューの密度は上がっても、判定責任までは押し付けずに済みます。自動化を増やすほど、どこを自動化しないかの設計が効いてきます。

## モノレポ運用と多階層 `CLAUDE.md` の検証戦略

### 階層読込の図解

モノレポで `CLAUDE.md` を運用するときに先に固めておきたいのは、どの階層の指示が自動で読まれるのかです。ここが曖昧なまま CI を組むと、検証対象の切り方も、どこにルールを書くべきかもぶれます。『Claude があなたのプロジェクトを記憶する方法』で整理されている通り、基本は **ancestor loading と descendant loading** です。作業中のディレクトリから見て上位階層の `CLAUDE.md` は継承され、必要に応じて下位階層のものも文脈に入ります。一方で、兄弟ディレクトリの `CLAUDE.md` は自動では入りません。

たとえば、次のようなツリーを考えると挙動が把握しやすくなります。

repo/ ├─ CLAUDE.md ← ルート全体の共通方針 ├─ apps/ │ ├─ frontend/ │ │ ├─ CLAUDE.md ← frontend 専用ルール │ │ └─ src/... │ └─ backend/ │ ├─ CLAUDE.md ← backend 専用ルール │ └─ src/... └─ packages/ ├─ ui/ │ ├─ CLAUDE.md ← ui パッケージ専用ルール │ └─ .claude/skills/... └─ api/ ├─ CLAUDE.md ← api パッケージ専用ルール └─ .claude/skills/...


`repo/apps/frontend/src` で作業している場合、通常は `repo/CLAUDE.md` と `repo/apps/frontend/CLAUDE.md` の両方が効きます。兄弟ディレクトリの `CLAUDE.md` は自動では読み込まれない点に注意してください。

この構造を前提にすると、何をどこへ置くかの原則も決まります。**広く適用されるルールは `CLAUDE.md`、時々しか使わないワークフローは Skills、毎回必須のアクションは Hooks** です。たとえば「このリポジトリでは TypeScript の import 順を統一する」「PR では変更理由を短く残す」といった常時必要な方針は `CLAUDE.md` に置きます。issue 切り分け、アクセシビリティ観点レビュー、移行手順のように、特定の場面でだけ起動したい手順は Skill に逃がしたほうが、常時読む文量を増やさずに済みます。反対に、lint 実行や書き込み禁止のガードのように毎回機械的に走るものは Hooks に寄せるほうが筋が通っています。

2026-01-28 の変更で、`--add-dir` から追加したディレクトリにある `CLAUDE.md` の読み込み挙動は以前より素直になりました。2026年3月時点では、追加ディレクトリ戦略そのものは有効ですが、これで兄弟階層の設計を代替しようとすると構成が読みにくくなります。私の感覚では、`--add-dir` は「別ワークツリーや補助的な参照ディレクトリを足す」用途には合っていますが、日常運用の基本線はあくまでリポジトリの階層設計で揃えたほうが、CI の対象絞り込みとも噛み合います。

### パッケージ単位のSkill配置と優先順位

Skill をモノレポに置くときは、`packages/*/.claude/skills/**` のようにパッケージ直下へ寄せる形が扱いやすくなります。理由は単純で、その Skill がどの文脈で使われるものかをパスだけで説明できるからです。`packages/ui/.claude/skills/design-review/SKILL.md` なら UI コンポーネントの確認、`packages/api/.claude/skills/schema-check/SKILL.md` なら API スキーマ周辺、という具合に守備範囲がディレクトリ構造と一致します。

ここでも、`CLAUDE.md` と同じく「共通化しすぎない」ことが効きます。ルートの `.claude/skills` に何でも集約すると、frontend 向けの Skill と backend 向けの Skill が同じ棚に並び、description だけで区別する設計になります。これだと衝突が起きやすく、名前も説明文も長くなりがちです。パッケージ単位に寄せておけば、同じ「review」という語を含む Skill でも、置き場所の時点で意味が分かれます。

優先順位の考え方も再確認しておくと、enterprise、personal、project の順に広域から狭域へ重なりますが、実務で手を入れることが多いのは project です。企業全体で持つ Skill は enterprise、個人の補助的な癖や作業流儀は personal、そのリポジトリ専用の運用は project という分担にしておくと、モノレポの事情を上位階層へ持ち込まずに済みます。『スキルで Claude を拡張する』の整理に沿って考えると、project 配下の Skill は最も具体的な文脈を持てるので、モノレポではここを主戦場にするのが自然です。

衝突回避で効いたのは、Skill 名の重複そのものを避けるより、**description で対象パスと入出力を明記する**ことでした。たとえば `review` という短い名前だけでは曖昧でも、「`packages/ui` 配下の React コンポーネント変更を対象に、アクセシビリティと Storybook 影響を確認する」のように書けば、どの差分で選ばれるべきかが見えます。ルート共通の Skill に同名のものがあっても、実際の運用ではこの説明の具体性が効きます。

私が frontend 配下の Skill だけを検証対象にしたかったときも、この階層整理がそのまま効きました。最初は「frontend 用の Skill を更新しただけなのに、モノレポ全体の Skill チェックが走る」状態で、確認待ちの時間が積み上がっていました。そこで `packages/frontend/**` や `apps/frontend/**` に差分を絞るパスフィルタを入れ、さらに兄弟ディレクトリは自動読込されない前提で `CLAUDE.md` と Skill の責務を分け直したところ、どの変更がどの検証を呼ぶのかが一気に明瞭になりました。frontend 専用のルールはその配下の `CLAUDE.md` に寄せ、たまにしか使わないレビュー手順だけを Skill に切り出す構成にすると、待ち時間より「どこを直せばよいか」で迷う時間が減ります。

> [!TIP]
> モノレポでは「共通だからルートに置く」よりも、「そのルールが毎回必要か」で置き場所を決めたほうが破綻しません。共通でも常時不要なら Skill、常時必要なら `CLAUDE.md`、実行漏れを許したくないなら Hook です。

{{product:4}}

### 差分ベースの検証スコープ設計

CI 側では、階層読込の理解をそのまま検証スコープへ落とし込めます。モノレポで毎回全 Skill を走らせる構成は作れますが、実運用では差分ベースにしたほうが流れが止まりません。『GitHub Actions』なら `paths` で対象パスを絞れますし、GitLab CIなら `rules:changes` で同じ発想を実装できます。frontend の Skill 変更なら frontend 配下だけ、`packages/ui/.claude/skills/**` の変更なら UI パッケージだけ、という切り方にすると、静的検証も非対話検証も対象が自然に縮みます。

この絞り込みは、単に気分の問題ではなく、CLI ベースの検証コストに直結します。`yq` で frontmatter を見たり、Bash で `@path` の存在確認をしたりする処理は 1 ファイルごとに積み上がるので、数が増えるほど待ち時間が伸びます。変更のない Skill まで毎回なめる設計だと、PR を開くたびに関係ない確認を背負うことになります。差分に寄せるだけで、フィードバックが返る位置が手元に近づきます。

『GitHub Actions』であれば、push や pull_request に対して `paths` を付ける構成がまず素直です。手動確認を残したいときは `workflow_dispatch` を併設できますが、UI の「Run workflow」から実行するにはワークフローが既定ブランチに存在している必要があります。モノレポで検証ジョブを細かく分けるほど、この前提を見落としたときに「定義したのに実行ボタンが出ない」という混乱が起きます。静的検証のジョブ名を `static-validate`、非対話の確認を `prompt-validate` のように分けるのは慣用的な設計ですが、どちらも全体一括ではなくパス単位に刻んだほうが運用の手触りが軽くなります。

GitLab 側でも考え方は同じです。`rules:changes` で該当パスだけ動かし、AI を使うジョブは最初は補助線として置くほうが収まりがよいです。すでに前段で触れたとおり、自然言語評価まで強制ゲートにするとレビューが詰まりやすいので、差分で対象を絞ったうえで静的検証を先に確定させ、その後に必要な部分だけ非対話検証を足す順序が安定します。

設計の目安としては、ルート `CLAUDE.md` を触ったら広域ジョブ、`packages/ui/CLAUDE.md` や `packages/ui/.claude/skills/**` を触ったら UI 限定ジョブ、`apps/frontend/**` だけなら frontend 限定ジョブにします。こうすることで読み込み規則と CI が一致します。この一致が崩れると、CI の結果を見ても「この失敗はどの階層のルールに引っかかったのか」が追えません。モノレポで多階層 `CLAUDE.md` を採るなら、検証の単位も同じ階層で刻む。この揃え方が、書く場所と直す場所を近づけてくれます。

## よくある失敗とトラブルシューティング

### 長すぎる`CLAUDE.md`

導入直後に起きがちなのが、ルールを一か所に集めたくなって `CLAUDE.md` を膨らませてしまうということです。Claude Code 。私の感覚では、200行前後を超えたあたりから「毎回必要なルール」と「たまにしか使わない手順」が混ざり始め、更新時にどこへ追記すべきか迷いが増えました。

長文化の根本原因は、`CLAUDE.md` に説明と手順と例外対応を全部載せようとするということです。常時必要な方針だけを残し、レビュー手順や特定作業のフローは Skill に分け、毎回確実に走らせたい処理は Hook やスクリプトへ移すと、ファイルの役割がはっきりします。文章量を減らすだけでなく、変更の責任範囲も分かれます。

CI では行数ゲートを入れておくと、この崩れ方を早めに止められます。上限を超えたら落とすだけの単純なチェックでも効きますし、見出し単位で分割候補を洗い出すコメントを返す運用にすると、PR 上で議論しやすくなります。行数そのものより、「そこに毎回読む価値がある内容だけが残っているか」を維持するための柵として機能します。

{{product:0}}

### Skillの`description`が曖昧で呼ばれない

Skill を作ったのに思った場面で選ばれないときは、`description` の曖昧さを疑うのが近道です。失敗例では「コードレビューを助ける」「改善提案をする」といった説明になっていて、対象も状況も成果物も見えません。これでは、どの差分でその Skill を使うべきか判断材料が足りません。

効く説明は、「対象」「状況」「成果物」の3点が入っています。たとえば「`packages/ui` 配下の React コンポーネント変更を対象に、アクセシビリティ上の懸念と Storybook 影響をレビューコメント案として返す」と書けば、いつ使うものかが一文で伝わります。逆に守備範囲を広く取りすぎると、どのタスクにも少し当てはまるが、決め手がない Skill になります。

ここは静的検証だけでは届きません。私が運用でやっているのは、想定ケースごとのサンプルプロンプトを用意して、どの Skill が選ばれるかを非対話で見ていく方法です。frontend のレビュー用、issue 修正用、説明文生成用のように近い Skill が並ぶほど、`description` の一語の差が効いてきます。呼ばれない Skill は能力不足というより、呼び出し条件の文章がぼやけていることが多いです。

{{product:4}}

### CIでAPIキー管理に失敗

CI のつまずきで厄介なのが、YAML 自体は正しいのにシークレットが入ってこないケースです。『GitHub Actions』では Secrets をリポジトリ、組織、Environment 単位で持てますが、どこに置いたかと、どのイベントで読めるかがずれると、実行時にだけ失敗します。とくに `pull_request` は安全側に倒れた挙動なので、外部 PR を含む実行ではリポジトリ secrets が渡りません。

私もここで一度はまりました。`pull_request` で非対話検証を回したところ、Secrets の権限が渡らず `ANTHROPIC_API_KEY` が空になって失敗し、最初はキー名の打ち間違いを疑いました。そこで `workflow_dispatch` を付けて手動トリガーに切り替え、既定ブランチ上の同じワークフローで注入状況を切り分けたところ、問題はイベント種別だと分かりました。その後、Secrets が必要なジョブだけを `pull_request_target` 側へ寄せ、PR のコードをそのまま実行しない形に組み替えると、安全性を保ったまま検証が回るようになりました。

対策は、まず Secret の置き場所を絞るということです。共有が必要ないなら repository secrets、保護対象ブランチにだけ渡したいなら Environment secrets、複数リポジトリで共有する明確な理由があるときだけ organization secrets にします。ワークフロー側では `secrets: inherit` のような広い受け渡しを避け、必要なキーだけを明示するほうが事故が減ります。加えて、静的チェックは secrets 不要のジョブとして `pull_request` で動かし、API を叩くジョブだけを手動実行や限定イベントへ分けると、失敗箇所の切り分けが一段はっきりします。

> [!TIP]
> Secrets 絡みの不具合は「キーがない」のか「イベント上読めない」のかで対処が変わります。手動トリガーで同一ワークフローを走らせると、設定ミスと可視性制限を短時間で分離できます。

### 毎回必須処理を`CLAUDE.md`で強制しようとする誤用

「必ず lint を通す」「生成前に整形する」「特定ファイルへの書き込みを禁止する」といった毎回必須の処理を、`CLAUDE.md` の文章で強く指示して済ませようとすると、運用は長く続きません。プロンプトは意図を伝えるには向いていますが、決定論的な手順を強制する場所ではないからです。文章で書かれた必須処理は、読まれる前提に依存し、実行結果も一定になりません。

この種の処理は Hook へ移すのが筋です。たとえば `eslint` 実行、禁止パスへの書き込みブロック、生成物の整形、通知の送出のように、成功か失敗かを終了コードで返せるものは Bash スクリプトに落とし込めます。`set -e` や `set -o pipefail` を入れて失敗をその場で止めれば、文章上のお願いよりずっと確実です。

実際、`CLAUDE.md` に「必ずこの確認をしてから編集する」と何段落も書いていた時期は、ルールの説明だけが長くなり、肝心の処理保証は得られませんでした。Hook に移してからは、説明は「このリポジトリでは pre-commit 相当の検証が走る」と短く済み、失敗時の挙動も揃いました。毎回必須で、しかも判定可能な処理なら、文章ではなくスクリプトに責任を持たせたほうが崩れません。

{{product:0}}

### frontmatterの型不整合・YAML記法エラー

Skill まわりで最も頻繁に起きる壊れ方は、内容の善し悪し以前に frontmatter が YAML として成立していないということです。`---` の位置がずれていたり、`description` を文字列で書くべきところに配列を入れていたり、インデントが一段崩れていたりすると、その Skill は中身を読む前に扱えなくなります。見た目では些細でも、CI に載せるとすぐ落ちる種類の不具合です。

ここは `yq` を使った静的検証が素直に効きます。`yq` は front matter を抽出して評価でき、YAML 解析エラーなら終了コードで返せます。`description` が文字列か、必須キーがあるか、配列で持つべき項目が混在していないかまで機械的に見られます。Bash と組み合わせれば、参照ファイルの存在確認まで同じジョブで処理できます。

ファイル数が増えると、この検査は待ち時間に跳ね返ります。frontmatter チェックは1ファイルごとの I/O と解析の積み上げなので、変更のない Skill まで毎回全部走らせると、PR を開いた瞬間の応答が鈍くなります。そこで `paths` や差分抽出を併用し、編集された `SKILL.md` や関連ファイルだけを見る構成にすると、静的検証の利点を保ったまま重さを抑えられます。

### Skillsの公開時期やCLI挙動の差分

見落とされがちなのが、Skills 自体の公開時期や CLI の挙動差分です。Skills は 2025年10月に beta 公開された比較的新しい仕組みで、運用記事やサンプルが書かれた時点と、いま手元で動かしている CLI の前提がずれていることがあります。CI に落とし込む段階では、この差分が「サンプル通りに書いたのに再現しない」という形で出ます。

ここで効くのは、ドキュメント本文や CI コメントに確認日を持たせるということです。2026年3月時点での挙動として期待しているのか、もう少し前の beta 初期を前提にしているのかを書き分けるだけで、議論の噛み合わなさが減ります。Claude API Release Notesや Changelog を前提に、どの機能をどこまで CI の期待値に含めるかを固定しておくと、更新時の影響範囲も追いやすくなります。

とくに非対話検証は、CLI オプションや出力形式の変化に引っぱられます。静的検証のように YAML とファイル参照だけを見るジョブは比較的安定していますが、`claude -p` を使うジョブは実装差分の影響を受けやすいので、最初から厳格な必須ゲートにせず、`continue-on-error` を使って outcome を拾い、結果をレビュー補助として流す設計のほうが現場では扱いやすいです。公開直後の機能ほど、「壊れたらCI全体が止まる」位置にいきなり置かないほうが、運用の呼吸が乱れません。

{{product:1}}

## まとめと次のアクション

着手順は迷わず三段階です。まず `CLAUDE.md` を「必須ルール」「実行コマンド」「参照先」の3区分に分け、毎回読む内容だけを残します。次に各 Skill の `name`、`description`、`Examples` を揃え、呼ばれる条件と使い方を明文化します。そのうえで CI には静的検証ジョブを先に入れ、安定してから非対話検証ジョブを重ねると、誤検知で運用が止まる場面を減らしたまま品質ゲートを育てられます。

私の現場でもこの段階導入を徹底したところ、1スプリントで壊れない `CLAUDE.md` / Skills 運用に到達し、PR レビューの議論は「落ちるかどうか」ではなく表現の質へ自然に寄りました。非決定的な評価は人間レビューと `allow_failure` の併走に任せるほうが、現実のチーム運用では息切れしません。GitHub ActionsとGitLab CI向けのサンプル YAML は、パス、しきい値、Secrets 名を自分のリポジトリに合わせて置き換えれば、そのまま出発点として使えます。

この記事をシェア

A
AIビルダー編集部

AIビルダーの編集チームです。AI開発ツールの最新情報と使い方を発信しています。

関連記事

ワークフロー

既存リポジトリ移行チェックリストと段階的手順

ワークフロー

既存の『GitHub』リポジトリに標準化を入れる作業は、コードを移すだけでは終わりません。私も最初の移行で、移行先に自動追加されたREADMEが原因で履歴がぶつかり、想定外の手戻りを出しましたが、そこで手順を組み直し、2回のリハーサルと切り戻し条件の明文化まで含めて設計したことで、

ワークフロー

チーム導入ロードマップ:PoC→試験運用→本番化チェックリスト

ワークフロー

PoCで「できそうだ」と見えたのに、試験運用で現場が止まり、本番化の直前でロールバック条件や支援体制の穴が見つかる。この詰まり方は、3段階を別物として扱ったときに起こりがちです。

ワークフロー

MCPとエージェント設計|実務パターンと安全な始め方

ワークフロー

社内SaaS連携のPoCでは、まずread-onlyのMCPサーバーを1つだけstdioでつないだところ、書き込み事故を避けたまま「どこまで業務に効くか」を落ち着いて見極められました。外部接続を広げる前に最小安全単位を決めると、導入の難しさは一気に現実的なサイズまで下がります。

ワークフロー

チーム運用のルールと権限設計|RBAC/ABAC判断と実務

ワークフロー

AIツールや共同作業環境のチーム運用は、権限を配るだけでは安定しません。目的、役割、権限、例外、見直し周期までを一つの仕様としてそろえておくと、運用の属人化と設定事故を同時に減らせます。 筆者の経験としてお伝えします。