スキルの誤発火は、使っているだけでは見つからない。 今回、自分の agent skills リポジトリでトリガー評価の結果を確認したら、4スキル中2つの description が、発火すべきでない依頼に発火していた。 しかも、1つのスキルの評価結果は7月のまま更新されていなかった。
1日で、監査2回、トリガー評価、自己適用の1ラウンドを回し、4種類の問題を直した。 そのあと、この記事を書いたセッション自体を監査して、スキルをもう1段直した。
この記事で分かること
- スキルの誤発火が、なぜ使っているだけでは気づかないか
- トリガー評価の仕組みと、モデル依存という落とし穴
- 自己適用で見つかる、テストでは拾えないバグ
問題は誤発火だけではなかった
前回の記事 で、writing-ja を禁止語リストから事実・推測・判断を分ける型へ作り直した話を書いた。 今回は、その writing-ja を含むスキル一式をまとめて改善した。 対象は blog-ops、blog-idea-grilling、blog-writing-guide-ja、writing-ja の4スキルだ。
最初に気づいたのは、description の誤発火だ。 writing-ja は「この PR の日本語コメントが失礼でないかだけ確認して。本文は書き換えなくていい」という依頼に、67%の確率で発火していた。 「技術書の章全体を一文一行の形式に整形して、脚注の置き方も統一して」には、100%発火していた。 どちらも、スキルを参照すべきでない依頼だ。
誤発火は、使っているだけでは気づかない。 エージェントはスキルを読んで、余計な手直しを始める。 指示に「本文は書き換えなくていい」と書いても、エージェントはスキルの説明文を見て発火を判断するので、表面上は動いてしまう。 違和感として残るのは、直してもらった文章がなぜか変わる、という曖昧な印象だけだ。
発火しない側の問題も見えない。 エージェントがスキルを使わなかったとき、それを検知する方法はない。
評価結果も放置されていた。 writing-ja のトリガー評価は7月17日に18/20で、8月5日まで再評価されていなかった。 ほかの3スキルは再評価済みで、writing-ja だけが取り残されていた。
スクリプトにもバグがあった。 check_style.py の「同じ語尾が3文連続」の検出は、行単位で判定していた。 一文一行で書かれた原稿でしか発火しない。
設定を変更した。ログを確認した。原因を特定した。
当時の実装では、この1行に3文入れた入力で、検出は0件だった。 SKILL.md には「同じ語尾の3文連続」と書いてあるので、説明と実装がずれていた。
監査1: 壊れているものと穴を数える
まず skill-creator の観点で、リポジトリ全体を監査した。 壊れているものと、構造的な穴を探す。
スクリプトのバグは、実際に入力を与えて再現した。 語尾の検出は、句点で文に分割してから判定するよう直した。
構造的な穴は、事実確認の担い手がいないことだった。 企画カードは「境界と要確認事項」として未確認の事実を出すのに、受け取る先がどこにもない。 技術レビューは「数字とベンチマークが正しいか」をチェック項目に挙げるのに、確認手順がない。 「一次情報で確認する」と書くスキルはあっても、その方法を定義しているスキルはなかった。
この穴を埋めるため、fact-check-ja を新設した。 確認すべき主張の種類に応じた出典の当たり方と、確認できなかったときの書き方を、1つのスキルにまとめた。 判定は最初3段階だった。 レビューで「3段階では足りない」と指摘され、7種類に増やした。 確認できた、不正確、否定された、古くなった、情報不足、確認不能、対象外だ。
公開済み記事の更新フローもなかったので、update-post.md を追加した。 これまで「記事を直して」と言われたら、その場で判断していた。 判断基準をリファレンスに書き、ワークフロー表にも行を足した。
監査2: 重複と description を削る
2回目の監査は、writing-great-skills の観点で4スキルを横断した。 重複、情報階層、description のコンテキスト負荷、完了条件、否定形の5つを見る。
LLM らしい文章を直す指針が、複数のスキルに重複して書かれていた。 同じ指針が別の場所にあると、直すたびに片方だけ直して食い違いが生まれる。 レビュー手順も本体内に埋まっていた。 これは references/review.md に切り出し、完了条件(全項目を仕分けた時点で終える)もそこに加え、本体からはポインタだけを残した。
description も圧縮した。 否定形の指示は、正の指示に言い換えた。 「〜しない」と並べるより、何をすべきかの方がエージェントに伝わる。 ただし、事実の捏造を禁じる2箇所は、安全のため負の形のまま残した。
重複の統合、description の圧縮、否定形の言い換えなど、修正は7項目になった。 テスト17件はすべて通った。
誤発火が直ったことはトリガー評価で証明する
監査で直しどころは見つかるが、誤発火が直ったことは別の道具で証明する。 このリポジトリには、description の選択を評価する仕組みがある。
evals/trigger/ に、スキルごとのテストセットを置く。 各セットは、発火すべき依頼10件と、発火すべきでない依頼10件で構成する。 fact-check-ja のセットには、次のようなクエリが並ぶ。
記事で「v3 からデフォルトで有効」と書いている箇所、うろ覚えなので公式ドキュメントで裏を取ってほしい。 → 発火すべき
この記事、章立てが読者の疑問順になってない気がする。構成を作り直して。 → 発火すべきでない
評価は Codex に一括で任せる。 Codex の裏で動くモデルは、時期によって切り替わる。 description とクエリ20件を渡し、「このスキルを参照すべきか」を boolean の配列で返させる。 依頼を実行せず、ファイルも調べないことをプロンプトで明示する。 20件の発火率が、1回の実行で分かる。
writing-ja は、過去の評価で18/20だった。 description に除外条件が1つもなかったのが原因だ。 ほかの3スキルは「〜には使用しない」を明記しているのに、writing-ja だけが「blog-writing-guide-ja の担当」しか書いていなかった。 書式の整形だけ、言葉づかいの確認だけ、翻訳だけの依頼を除外条件に足して再評価したところ、20/20になった。
blog-writing-guide-ja も誤発火していた。 「Hugo の新規記事を作るので slug、date、tags、画像の置き場所を決めて。」という依頼に、67%で発火する。 slug や front matter の準備は blog-ops の担当だ。 除外リストに front matter と slug を足して、これも20/20にした。
評価はモデルに依存する
この修正には、評価がモデルに依存するという発見が隠れていた。
blog-writing-guide-ja の誤発火は、当時の評価モデル gpt-5.4-mini で再現した。 ところが、新しい既定モデル gpt-5.6-luna では、修正前の description でも20/20だった。 つまり、この誤発火は「そのモデルでの」誤発火だった。
モデルは変わる。 今回も、7月の評価から8月の再評価までの間に、Codex の既定モデルが切り替わっていた。 description をモデル任せにせず、どちらのモデルでも発火しない形に直した。 修正後は、両方のモデルで20/20を確認した。
評価結果にはモデル名と日付が付く。 ただし、このリポジトリでは results/ を Git で追跡していない。 履歴が残らないので、評価結果の変遷は遡れない。
natural-japanese は読みやすさの原則だけ移植する
writing-ja の改善では、回りくどい言い回しと難しい言葉のルールを強化した。 セッションログから実例を集めて、標語、比喩、回りくどい表現、硬い言葉に分類した。 「public exportはコミットメントだ」のような標語や、「パッケージの入口からexportしたもの」のような回りくどい表現がそれだ。
そのとき、自然な日本語を直すスキル natural-japanese を見つけた。 最初は、取り込める点があれば取り込みたいと思った。 ライセンスを確認し、中身を読んだ。
読みやすさの原則だけを移植することにした。 理由は3つあった。 writing-ja は本文の手直しだけを担当し、natural-japanese は企画から執筆までを1つのスキルで扱う。 役割が衝突する。 description が競合すると、トリガー評価の精度が落ちる。 依存も重い。 writing-ja の検査スクリプトは標準ライブラリだけで動くのに、natural-japanese の検査は100MB級の形態素解析辞書が必要だ。
3つ目は、独立したスキルとして追加すれば、natural-japanese はそのまま併用できることだ。 原則だけなら、自分の検査スクリプトと整合させながら組み込める。
自分のルールを自分に適用する
監査と評価に加えて、自己適用が最後の1本になった。 自分のスキルを自分で使うと、テストでは見つからないバグが出る。
check_style.py を、新しく書いた fact-check-ja の SKILL.md に回したとき、テーブル行を段落として数える誤検出を見つけた。 テストは通っていた。 テストがカバーするのは、自分が想定した書き方のごく一部だからだ。
自己適用はスキル自体の整合性も調べる。 writing-ja は、SKILL.md と examples.md と SOURCES.md を突き合わせ、5件の不整合を直した。 ルールの説明と実例が食い違っていると、エージェントはどちらを信じてよいか分からない。 writing-great-skills の観点で writing-ja を個別に監査し、6件の重複と古い記述を直した。 200行から190行になった。
執筆セッションを監査したら、スキルは一度も読まれていなかった
この記事の執筆が一段落したあと、別のセッションで執筆ログを監査した。 改善したばかりのスキルが、実際にどう使われたかを見るためだ。
1つの事実が目についた。 writing-ja と fact-check-ja の SKILL.md は、セッション中に一度も読まれていなかった。 それでも、TODO の「writing-ja 規範で本文を執筆」と「fact-check-ja で事実を裏取り」は完了になっていた。
原因は、検査スクリプトの実行を工程の代わりにしていたことだ。 check_style.py を回したから writing-ja を読んだことにし、check_posts.py を回したから publish-check.md を読まずに済ませていた。 fact-check-ja はスクリプトを持っていない。 だから、何も読まずに完了にしていた。
この記事の誤りも、それで残っていた。 監査の時点で、記事の冒頭は「5スキル中2つ」と書かれていたが、実際は4スキルだった。 自己適用の節は「記事の下書きに回した」と書いていたが、実際に回したのは新しく書いた fact-check-ja の SKILL.md だった。 「記事全体の内容の整合性を確認して」と頼むまで、こうした誤りは見つからなかった。 その確認で、7件の誤りが見つかった。
スキルの側を直した。 blog-ops に「受け渡しは読み込みで行う」という節を足した。 工程名をタスクに書くことは、工程を実行したことにならない。 検査スクリプトが0件で通っても、スキルを読んでいなければ、その段階は終わっていない。
記事全体の整合性にも担当を明示した。 レビューのチェックリストに、記事内で繰り返される数、固有名、時系列が全箇所で一致しているかの項目を足した。 数を1箇所直したら、その値で全文を検索して残りを潰す。 「4種類」と直したのに見出しが「5つの観点」のまま、という取りこぼしはここで防ぐ。
もう1つ、別の気づきがあった。この記事の手直しで直した語が、スキル自身の規則の穴だったことだ。 書き方を語るための言葉が本文に漏れていた。 「直り」のように、動詞を名詞の形で使っていた。 見出しの主語が欠けていることも、指摘されるまで気づかなかった。 どれも指摘されてから直したが、指摘されるまでスキルは検出できなかった。
check_style.py の語彙リストに、書き方を語るための言葉2語を足した。 writing-ja には「道具の用語を本文へ持ち出さない」「動詞の連用形を名詞にしない」「見出しと結論文では主語を省かない」の3つを規則として書き加えた。 「指摘は例であって、全件の一覧ではない」も足した。 指摘された語だけを直して、同じ種類の硬い言葉が残り、もう一度指摘される往復を防ぐためだ。
fact-check-ja の中身は直さなかった。 呼ばれなかったことが問題で、直すべきは呼び出し側の blog-ops だと判断したからだ。 テストは25件に増え、すべて通った。
natural-japanese の記事レベルの手順も blog-writing-guide-ja に移植した
ここまでの作業のあと、natural-japanese を blog-writing-guide-ja にも突き合わせた。 writing-ja への移植は読みやすさの原則に限っていたが、記事レベルの手順にも参考にできるものがあった。
採用したのは、次の4点だ。
1つ目は、リライトで直す箇所を選ぶ手順だ。 着手前に見出しと節を一覧し、keep か change を割り振る。 既定は keep で、change に倒すのは、そこを直すことで読者の得を具体的に言える場合だけにする。 change が全体の3割を超えるなら、理由を書き残す。 元の記事が未確定のまま置いている論点に著者の見解を書き足すのは、捏造にあたる。 review.md に「直す箇所を選ぶ」という節を足した。
2つ目は、時系列と演出の切り分けだ。 書き手の発見順を読者に追わせることと、「思い込み→異変→種明かし→回収」を演出することは別物だ。 記事全体の筋書きを扱うので、文レベルの writing-ja には渡せない。 SKILL.md に「時系列と演出を混ぜない」という節を足した。
3つ目は、素材不足の判定基準だ。 段落から固有名詞、数値、実例をすべて抜いても文意が変わらないなら、その段落は一般論で止まっている。 これは書き方ではなく素材の問題なので、言い回しを直すループを回しても解決しない。 SKILL.md に「一般論になっていないか検査する」という節を足した。
4つ目は、濃淡設計だ。 節ごとの厚みは、書き始める前に割り振る。 構成案の段階で全部の節が同格に見えるなら、そこが直す地点になる。 「構成は読者の疑問に沿わせる」に追記した。
見送ったものもある。 診断スコアは、「共有されるか」テストと二重になる。 outline.py は、review.md が同じ抽出を人手で指示済みだ。 判断台帳は、既存の仕分け手順で足りる。 readability 層と lint は writing-ja の担当で、すでに移植済みだ。 style-profile は、テンプレートと抽出フローの新設コストが見合わない。 作業ファイルの後片付けは、blog-ops の担当範囲だ。
移植のあと、writing-ja との棲み分けを確認した。 境界の問題が3件見つかり、直した。
「予告」という語が、2つの意味で衝突していた。 新しく足した節では「予告、伏線、種明かし、回収」と書いた。 しかし writing-ja の「予告」は、本文に書く予告文を指す。 同じ語で違う操作を指すと、エージェントが取り違える。 「先のほのめかし」に置き換え、両スキルを通じて「予告」は予告文の意味だけに固定した。
「一律に直さない」と writing-ja の「全件走査」も、矛盾して見えた。 区別を1段落足した。 同じ語の表記揺れや、同じ種類の言い回しは全件そろえてよい。 選んで直すのは、見出しの型、箇条書きの扱い、語り口のような、記事の構造と声に関わる変換のほうだ。
素材集めの分岐には、捏造の歯止めがなかった。 「素材を持っているのは書き手なので、手元になければ尋ねる。もっともらしい説明で埋めない」を足した。
採用にあたって、出典も明記した。 SOURCES.md に natural-japanese の節を足し、LICENSE に Copyright (c) 2026 coji を追記した。
テストは25件、すべて通った。 check_style.py の警告は既存分と同数で、増分はなかった。
持ち帰れる4つの観点
1回目の1ラウンドで、4種類の問題が見つかった。 壊れているもの、構造的な穴、重複と情報階層、発火の正確さだ。 この4つが、自分のスキルを点検するときの観点になる。 壊れているものは実測とテストで閉じ、構造的な穴は新設したスキルで埋め、重複と情報階層は参照の切り出しで解消し、発火の正確さはトリガー評価で証明した。
監査は直しどころを見つける。 評価は、誤発火が直ったことを証明する。 自己適用は、想定の外にあるバグを見つける。 この3つは別々の道具で、どれか1つで代用できない。 自己適用の実例は、この記事の執筆セッションの監査だった。
自分のスキルに1つだけ持ち帰るなら、should/should-not のセットを作ることだ。 20件のクエリを書くだけで始められる。 評価結果にモデル名と日付を付けて残せば、スキルを変えるたびに発火の正確さを測れる。 もう1つは、工程の受け渡しだ。 工程名をタスクに書くことは、工程を実行したことにならない。
リポジトリは https://github.com/j1nn0/skills で公開している。 トリガー評価のセットと実行スクリプトは evals/trigger/ に置いた。
