TL;DR
- 同じ仕事をする Skill が 2 本入っていると、エージェントは名前と description だけでどちらかを選びます。arXiv 2610.11647(2026-10-08)は、似た Skill が約 5 回に 1 回インストールした Skill の代わりに使われ、タスクの完了率は下がらなかったと報告しています(arXiv)。
- 片方にしか無い制約は、その回では守られません。論文の例は「git に触れない」という禁止です。成功判定は通るので、完了だけを見る評価では見えません。
- このリポジトリで、判定条件を先に決めてから数えました。ref
122597adの追跡済み SKILL.md は 91 本で、ディレクトリ名の役割語が共通する群は 5 つ、入った Skill は 22 本です(社内データ)。 - そのうち
article-reviewとarticle-reviewerの 1 組を読み比べると、Thesis Gate・UNVERIFIED・freshness ヘッダの 3 つの制約はarticle-reviewにしかありませんでした。 - 対策として、群ごとに「片方にしか無い制約」の表を作り、評価はその制約を採点します。削除の判断はその後です。
はじめに:成功したのに、守るはずの制約が消えていた
こんにちは、みねです。
Skill を足していくと、同じ仕事をする Skill が別の経路から入ってきます。自分で書いたもの、コピーした集合、プラグイン。どれも description はもっともらしく、どれを選んでもタスクは終わります。
問題は、終わったタスクの中で何が守られなかったかです。この記事は、一次資料の測定と、このリポジトリで数えた記録をつなげて、その見え方を整理します。提言ではなく、数えた条件と結果の記録です。
近い記事との違いを先に書きます。
| 既存記事 | 主題 | この記事との違い |
|---|---|---|
| AI Harnessの技術的負債と削る基準 | Skill や AGENTS.md が増え続けることと、削る基準(参照エッジ 0・二面検証) | 増えた結果、同じ役割の 2 本が共存したときに何が消えるかを扱う。削る前の洗い出し |
| 同じことを二度と言わないための「スキル定義ファイル」 | 1 本の SKILL.md の書き方 | 1 本ではなく 2 本の間の選択を扱う |
| Claude Skills対Subagents使い分け5軸 | Skill と Subagent のどちらにするか | 同じ種類(Skill 同士)の重複を扱う。当時の 87 skill と本記事の 91 本は ref が違う |
| Agent Evalでprompt・skill変更をCIで止める | prompt・skill の変更を eval と CI で止める | eval が完了だけを採点すると、この失敗は通る。採点対象に排他的な制約を足す |
1. 一次資料:似た Skill が選ばれても、タスクは成功する
何を測った論文か
"One Skill Too Many: How Co-Installed Skills Conflict in Coding Agents"(Yan ほか、arXiv 2610.11647v1、2026-10-08 投稿、cs.SE)は、コーディングエージェントに似た Skill が共存したときの挙動を測っています。以下は論文の abstract の記述です(確認日 2026-10-14)。
| 項目 | 値 |
|---|---|
| 対象 | 20,947 リポジトリのスナップショット、候補の類似ペア 822,109 組 |
| 判定 | LLM の判定器で層化抽出した 3,754 組を見て、確定した 312 組 |
| 実行 | 3 モデルで 6,368 回、ツール呼び出し 169,294 回、542 agent-hours |
| 共存の頻度 | インストールされた Skill のおよそ 4 本に 1 本が、同じ仕事をする Skill と共存。判定した Skill の 37% はコピーされた集合の中にある |
| 置き換わり | 似た Skill が約 5 回に 1 回、インストールした Skill の代わりに使われ、完了率は下がらない |
| 制約の喪失 | 似た Skill を先に開いた回は、インストールした Skill にしか無い中核機能の 3 分の 1 超を失う |
| 何で決まるか | 置き場所が効き、一覧の並び順はほとんど効かない。勝敗は最初に Skill を読んだ時点で決まる |
| 見えにくさ | 置き換わった回で、最終応答が使った Skill の名前を挙げたのは 0.9% |
| 回復 | 最初の Skill 読み込みの時点に pre-tool hook を置くと、排他的な中核機能の再現度が、インストールした Skill を先に開いた回の水準まで戻った |
衝突しやすいペアの多くは、何をしてはいけないかを書く normative な Skill で、次が capability の Skill だった、とも書かれています。
なぜ名前と description で決まるのか
Anthropic の Agent Skills の解説(2025-10-16)は、起動時にはすべての Skill の name と description だけをシステムプロンプトに読み込み、関係がありそうなときに SKILL.md 全体を読む、と書いています。Agent Skills の仕様も同じ段階的な読み込みを書き、description には「何をするか」と「いつ使うか」を書くよう求めています。
つまり、本文に書いた制約は、選ばれた後にしか効きません。選ぶ時点で比べられるのは description だけです。
同名なら優先順位、別名なら description の勝負
Claude Code の Skills のドキュメントは、同じ名前の Skill の解決順を書いています。enterprise が personal に、personal が project に勝ちます。プラグインの Skill は /plugin-name:skill-name の名前空間に入るので、両方が読み込まれます。
同名なら規則で片方に決まります。名前が違えば両方が一覧に並び、description で選ばれます。論文の「置き場所が効く」は前者に近く、「約 5 回に 1 回置き換わる」は後者に近い、というのは筆者の対応づけです。論文のいう置き場所は、同名の解決順に限らない可能性があります。
2. このリポジトリで数えた:判定条件を先に決める
判定条件
数える前に、条件を次のように固定しました。
- 対象: ref
122597ad71aaae46f6cb98b31f5d4c08f1408fb0(以下122597ad)でgit ls-tree -r --name-onlyに出るパスのうち、/SKILL.mdで終わるもの。作業ツリーの未追跡ファイルは数えない - Skill の名前: SKILL.md の親ディレクトリ名
- 役割語: ディレクトリ名をハイフンで区切った語が、次の表のどれかに完全一致したとき、その役割に入れる。1 本が複数の役割に入ることがある
- 群: 同じ役割語を持つ Skill が 2 本以上あるもの
- 別に数えるもの: frontmatter の
nameが完全一致する組と、nameが親ディレクトリ名と違うもの
| 語 | 役割 |
|---|---|
review / reviewer | review |
writing / writer / rewriter | write |
research | research |
finalize / finalizer | finalize |
plan / planner / planning | plan |
役割語の表は筆者が選びました。この表に無い語(checker、audit など)で同じ仕事をしている Skill は数えていません。逆に、群に入っても役割が同じとは限りません。この件数は「読み比べる候補」の数で、「重複している Skill」の数ではありません。
数えるスクリプト
文字列の比較は Python の == と in で行い、sort | uniq は使っていません(BSD の uniq はロケールの照合順で別の行を同一視することがあるため)。
# count-skill-roles.py <repo> <ref>
import re, subprocess, sys
from collections import defaultdict
ROLE_MAP = {
"review": "review", "reviewer": "review",
"writing": "write", "writer": "write", "rewriter": "write",
"research": "research",
"finalize": "finalize", "finalizer": "finalize",
"planner": "plan", "plan": "plan", "planning": "plan",
}
def git(repo, *args):
return subprocess.run(["git", "-C", repo, *args],
capture_output=True, text=True, check=True).stdout
repo, ref = sys.argv[1], sys.argv[2]
skills = sorted(p for p in git(repo, "ls-tree", "-r", "--name-only", ref).splitlines()
if p.endswith("/SKILL.md"))
print("tracked SKILL.md:", len(skills))
roles, names = defaultdict(list), defaultdict(list)
for p in skills:
d = p.split("/")[-2]
for tok in d.split("-"):
if tok in ROLE_MAP:
roles[ROLE_MAP[tok]].append(d)
m = re.search(r"^name:\s*['\"]?([^'\"\n]+)", git(repo, "show", f"{ref}:{p}"), re.M)
names[m.group(1).strip() if m else None].append(d)
members = set()
for r in sorted(roles):
if len(roles[r]) >= 2:
members.update(roles[r])
print(f"role={r} n={len(roles[r])}: {' '.join(sorted(roles[r]))}")
print("skills in any cluster:", len(members))
print("duplicate name:", sum(1 for v in names.values() if len(v) >= 2))
print("name != dir:", sum(1 for n, v in names.items() for d in v if n != d))
結果(ref 122597ad、取得日 2026-10-14、社内データ)
tracked SKILL.md: 91
role=finalize n=2: article-finalize finalizer-agent
role=plan n=4: plan-writing planner-agent queue-planning skill-ops-planner
role=research n=2: article-research research-agent
role=review n=11: article-4p-review article-multi-review article-review article-reviewer article-self-review code-review-checklist codex-review post-publish-review pr-reviewer reviewer-agent self-review
role=write n=4: article-rewriter article-writing plan-writing writer-agent
skills in any cluster: 22
duplicate name: 0
name != dir: 0
plan-writing は plan と write の両方に入るので、群の合計 23 に対して Skill は 22 本です。name の重複と、name と親ディレクトリ名の不一致はどちらも 0 件でした。同名の衝突は無く、あるのは名前の違う候補の並びです。第 1 節の区別でいえば、規則で決まる側ではなく description で選ばれる側にあたります。
review の群には、記事のレビュー・コードのレビュー・PR のレビューが混ざっています。queue-planning や skill-ops-planner も、planner-agent と同じ仕事ではありません。ここから先は群ごとに本文を読む作業で、数では決まりません。
3. 1 組を読み比べる:片方にしか無い制約
review の群から、名前が最も近い article-review と article-reviewer を読み比べました。description は次のとおりです(ref 122597ad)。
article-review: 「完成した本文を独立評価するChecker用マスタープロンプト。企画の勝ち筋との整合に加え、Thesis Gate(主題保持)と図表の意味整合を判定し、到達できなかった検査はUNVERIFIEDとして残す。」article-reviewer: 「記事を品質・構成・SEO・技術正確性の観点から独立評価し、修正提案だけを返すread-only Checkerスキル。」
どちらも「完成した記事を独立評価する Checker」と読めます。制約を表す語を決めて、それを含む行を SKILL.md ごとに数えました。
| 制約を表す語 | article-review | article-reviewer |
|---|---|---|
Thesis Gate | 2 行 | 0 行 |
UNVERIFIED | 5 行 | 0 行 |
review-freshness | 1 行 | 0 行 |
READ-ONLY | 1 行 | 1 行 |
本文を直接修正 | 1 行 | 1 行 |
allowed-tools | 0 行 | 1 行 |
共通しているのは「読み取り専用」「本文を直接修正しない」です。article-reviewer が選ばれた回では、主題が薄まっていないかの判定(Thesis Gate)、到達できなかった検査を UNVERIFIED として残すこと、レビュー対象の版を記録する freshness ヘッダの 3 つが要求されません。 それでもレビューは採点つきで終わり、成功に見えます。論文の「完了率は下がらないまま、排他的な中核機能を失う」と同じ形です。
逆に、allowed-tools でツールを Read, Grep に絞っているのは article-reviewer だけです。どちらか一方が「正しい」のではなく、それぞれに片方にしか無い制約があるのが共存の厄介なところです。
なお、この 2 本がこのリポジトリの実際の実行でどちらの割合で選ばれているかは観測していません。ワークフローの定義が article-review を名指しする経路では、選択は起きません。起きるのは、名指しされずに description で選ばれる経路です。
4. 制約が消えないようにする手順
この節は筆者の手順で、一次資料が勧めている手順ではありません(第 3 段だけは論文の測定に対応します)。
flowchart LR
A["群を出す(判定条件を先に固定)"] --> B["1 組ずつ読み比べ片方にしか無い制約の表"]
B --> C["評価に足す排他的な制約を採点"]
C --> D["最初の Skill 読み込みでどれが選ばれたかを記録"]
D --> E["統合・削除の判断(参照エッジと二面検証)"]
1. 群を出す
第 2 節のスクリプトのように、条件を先に文章で決めてから数えます。数えた後で条件を変えると、件数は都合のよい方へ動きます。条件と ref は件数と一緒に残します。
2. 片方にしか無い制約の表を作る
群の中の 1 組ずつ、制約を表す語を決めて行数を数え、第 3 節のような表にします。語の選び方で表は変わるので、語の一覧も表に残します。
3. 評価は「完了」ではなく「排他的な制約」を採点する
論文は、完了だけを確かめるベンチマークではこの失敗を見落とすとして、排他的な中核機能を採点するよう提案しています。Agent Eval の記事 の eval dataset に足すなら、「Thesis Gate の判定欄が出力にあるか」「到達できなかった検査が UNVERIFIED として残っているか」のように、表の左列をそのまま採点項目にします。
4. どの Skill が読まれたかを、最終応答ではなくツール呼び出しで記録する
最終応答に Skill の名前が出るのは、置き換わった回の 0.9% でした。記録はツール呼び出しの側で取ります。Claude Code の hooks の PreToolUse は、ツール名で照合してツール呼び出しの前に実行され、呼び出しを止めることもできます。論文は、最初の Skill 読み込みの時点に置いた pre-tool hook で排他的な中核機能の再現度が戻ったと報告しています。どのツール名で照合するかは、実際の呼び出しを記録するフックで確かめてから決めます。
5. 統合・削除は最後に判断する
表ができる前に片方を消すと、消した側にしか無い制約も一緒に消えます。削る基準は AI Harnessの技術的負債と削る基準 の「参照エッジ 0 と二面検証」を使います。
5. この記録で言えないこと
- 数えたのは ref
122597adの追跡済み SKILL.md 91 本だけです。user・プラグインの Skill は数えていません。プラグインの Skill は名前空間が分かれて両方読み込まれるので、実際に一覧に並ぶ候補はこれより多くなりえます。 - 役割語の表は筆者が選んだもので、22 本は「読み比べる候補」です。同じ役割の Skill の本数ではありません。
- 読み比べたのは 1 組だけで、行数は語の出現を数えた値です。制約の意味までは数えていません。
- このリポジトリで置き換わりが実際に起きた回数は観測していません。第 3 節は「起きたら何が消えるか」の記録です。
- 論文の数値は abstract の記述で、本文の実験条件までは確かめていません(確認日 2026-10-14)。
- このリポジトリは非公開で、読者は数値を検証できません。ref と条件で再現の手順だけを示しました。
まとめ
- 似た Skill が共存すると、約 5 回に 1 回置き換わり、完了率は下がらないまま片方にしか無い制約が消える(arXiv 2610.11647)
- 選ぶ時点で比べられるのは name と description だけで、本文の制約は選ばれた後にしか効かない
- ref
122597adの追跡済み SKILL.md 91 本のうち、役割語の条件で 22 本が 5 群に入った。同名の衝突は 0 件 article-reviewにしか無い制約が 3 つ、article-reviewerにしか無い制約が 1 つあった- 手順は、群を出す → 排他的な制約の表 → 表を採点に足す → 読まれた Skill をツール呼び出しで記録 → 最後に統合・削除
次に測るのは、残りの 4 群の表と、ツール呼び出しの記録から見た実際の置き換わりの回数です。手元で試すなら、第 2 節のスクリプトを python3 count-skill-roles.py . HEAD のように ref を付けて実行してください(読み取りのみ)。並列エージェントの間で Skill 以外に共有されたまま残る資源は、worktreeで分けても並列エージェントは閉じない にまとめています。
FAQ
似た Skill が 2 本あると、何が起きますか
arXiv 2610.11647 は、似た Skill が約 5 回に 1 回、インストールした Skill の代わりに使われ、それでもタスクの完了率は下がらなかったと報告しています。片方にしか無い制約(例: git に触れない)は、その回では守られません。
タスクが成功しているなら、問題はないのでは
成功判定は制約が守られたかを見ていません。同論文は、完了だけを測るベンチマークではこの失敗を見落とすとして、片方にしか無い中核機能を採点するよう提案しています。
どちらの Skill が使われたかは、ログで分かりますか
最終応答から分かるとは限りません。同論文では、置き換わった回のうち最終応答が使った Skill の名前を挙げたのは 0.9% でした。ツール呼び出しの記録を見る必要があります。
同じ役割の Skill は、自分のリポジトリで何本ありますか
判定条件しだいで変わります。この記事では、ディレクトリ名に役割語(review / reviewer など)を含むことを条件にし、ref 122597ad の追跡済み SKILL.md 91 本のうち 22 本が 5 つの群に入りました。役割が実際に同じかは、群ごとに本文を読んで確かめます。
重複を見つけたら、すぐに片方を消すべきですか
この記事は削除を勧めません。先に、片方にしか無い制約の一覧を作ります。削る基準は別記事の「参照エッジ 0 と二面検証」で扱っています。
References
確認日はすべて 2026-10-14 です。
- Yan et al. — One Skill Too Many: How Co-Installed Skills Conflict in Coding Agents(arXiv 2610.11647v1)(2026-10-08)
- Anthropic Engineering — Equipping agents for the real world with Agent Skills(2025-10-16)
- Agent Skills — Specification
- Claude Code — Extend Claude with skills
- Claude Code — Hooks reference
