そのスキル、あなたのマシンでしか動かない
「今のやり方をスキル化して」——Claude Code や Codex にこう頼むだけで、再利用できる SKILL.md が手に入る時代になった。私もこれで手順を次々スキルにして、悦に入っていた。
問題は配ってからだ。自分の環境では動くのに、同僚の環境やCIでは黙って落ちる。覗くと理由はいつも同じだった。出力先が C:\Users\atlan\... になっている。codex を呼ぶのに入れる手順が書いていない。OPENAI_API_KEY が設定済み前提になっている。gpt-image-2 が直書きされている。
どれも「作った本人の環境」が焼き込まれた跡で、エラーにすらならず次の人の手元で静かに失敗する。これをCIで落とすリンタ、carrylint を作った。
標準は「形式」を可搬にしたが、「中身が動くか」は別
2025年12月に Agent Skills はオープン標準になり、一つの SKILL.md が Claude Code・Codex・Gemini CLI・Cursor など20以上のエージェントで動くようになった。形式の可搬性はもう解決済みだ。
だが標準が保証するのは器だけ。中に絶対パスや未宣言CLIが入っていれば、他人の環境では動かない。私の既存ツールと役割を並べると違いがはっきりする。
- reflint … 参照が実在するか
- skills-lint … スキルが衝突しないか・frontmatterが正しいか
- carrylint … 参照が別の環境・別のモデルで解決するか
他は「仕様として正しいか」、carrylint は「次の人がインストールして実際に動くか」を見る。
何を検出するか
わざと非可搬にしたサンプルを通すとこうなる。
✗ examples/bad/leaky-image-gen/SKILL.md — error 3 / warn 3
✗ :16 [abs-path] マシン固有の絶対パス `C:\Users\atlan\Downloads\out.png`
• :16 [undeclared-cli] `codex` を呼んでいますが、インストール手順も宣言もありません
• :25 [provider-env] `OPENAI_API_KEY` を前提にしています
✗ :27 [placeholder] 未解決のプレースホルダ `<FILL_ME>` が残っています
exit code: 1
誤検知はリンタが嫌われる唯一の理由だ。だから作者以外は確実に踏む、曖昧さゼロのものだけを error(PRを落とす)にしている。この線引きは公開後の実データ監査で大きく直した(後述)。
-
error: 作者環境前提の絶対パス(
C:\…/Users/<実名>/)/未完成マーカー(<FILL_ME>REPLACE_ME)。※$HOME・~・YOUR_API_KEY・/path/to/は可搬 or 文書慣習なので対象外 -
warn: 未宣言の外部CLI(ホストの
claude mcp add等は除外)/プロバイダ固有 env の生参照/TODO:残り - opt-in: モデルID直書き(意図的な固定は正当なので既定OFF)
実行時にLLMもAPIキーも使わない純静的解析だ。だからClaudeで書いてもCodexで書いても同じルールで動く(ツール自体がモデル非依存)。
CIで使う
name: carrylint
on: [push, pull_request]
jobs:
carrylint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hyuga611/carrylint@v0
error があればPRにインライン注釈が出てジョブが落ちる。人が意識しなくても毎PRで走る。手元なら npx @hyuga/carrylint で今すぐ動く。
公開した後、230の実在スキルに当てて、自分が85%誤検知していると知った
一番正直に書きたいところだ。公開したはいいが、宣伝する前に引っかかった。自作の examples と自作のテストが通るのは当たり前で、正しさの証明にはならない。 だからGitHubの公開リポから実在の SKILL.md / AGENTS.md を230件集めて当ててみた。
良い半分。作者しか動かないスキルは本当にあった。 あるスキルは /Users/guohao/Documents/...(作者のMacパス)を直書きし、別のスキルは C:/Users/vudrk/Desktop/AI Projects/ を全スクリプトの基準にしていた。carrylintが存在する理由は実データにあった。
まずい半分。でも、エラーの約85%は私の誤検知だった。 Bearer YOUR_API_KEY(API文書の慣習)を「未完成」と誤検知し、claude mcp add(ホスト自身)を「未宣言CLI」と誤検知し、$HOME/...(可搬な書き方)を「マシン固有」と誤検知していた。誤検知が死因だと書いておいて、宣伝する前にそれを浴びるところだった。
幸い実データが直す場所を名指ししていた。v0.1.1 で4点直した——$HOME/~/汎用名は可搬扱い、プレースホルダは埋め忘れマーカーだけ、ホストCLIの設定コマンドは除外、ホーム相対パスは廃止。同じ230件で ERRORの誤検知は約85%→ほぼ0%、本物は全部残った。 一度も見ていない別の70リポでも過学習でないこと(発火3%・全部本物)を確認し、実例は回帰テストに同梱した。
教訓はひとつ。自作テストが通ることは正しさの証明にならない。実データに、しかも宣伝する前に当てて初めて分かる。
正直な話
設計中に調べて気づいたが、SKILL.md リンタは既に7本以上あり、私の skills-lint もその一つだ。空き地ではなかった。ただ全部読んで確認した限り、「中身が実際に他環境で動くか」を見ているものは無かった。 carrylint はそこ一本に絞っている。
Claude と Codex を混ぜてスキルを配布共有するチームはまだ多くないから、需要は少し先回りかもしれない。それでも「配ったら自分しか動かなかった」に一度でも刺さった人には効くはずだ。
まとめ
標準は SKILL.md を形式として可搬にした。実際に動くかは別だ。carrylint はそこをCIで落とす。
npx @hyuga/carrylint- GitHub Action は
uses: hyuga611/carrylint@v0 - リポジトリ: https://github.com/hyuga611/carrylint