TECH MEMO / FIELD NOTECodex・Gemini・Claudeで共有するAgent Skillsの設計と配布
Agentごとのコピー管理をやめたかった
Codex、Gemini CLI、Claude Codeを使い分けていると、どのAgentにも伝えたい知識が増えていきます。設計原則、読みやすいコードの基準、テスト方針、コードレビューの観点、既存変更を壊さないための作業手順などです。
最初は、必要な内容を各Agentの設定ファイルやプロジェクトの指示へ書けばよいと考えていました。しかし、同じ知識を複数の場所へコピーして管理し始めると、一方だけを更新してしまったり、少しずつ表現が変わったりします。どれが最新なのか分からなくなるのも時間の問題でした。
一方で、すべての知識を一つの巨大な指示ファイルへ集める方法にも無理があります。バックエンドの設計を相談しているときにSREの障害対応手順まで読み込ませる必要はありません。共有ルールが強すぎると、導入先リポジトリのビルド方法やGit運用と衝突するおそれもあります。
そこで、再利用できる知識をAgent Skills形式のSKILL.mdへ集約しました。配布にはAgent Package Manager(APM)を使います。Codex、Gemini CLI、Claude Codeへ配布するプライベートなスキル管理リポジトリを作り、ここではskills-repoと呼びます。
目標は、3つのAgentに同じ設定ファイルを読ませることではありません。再利用できる知識の正本を一つだけ持ち、各Agentが理解できる場所へ再現可能な形で届けることです。
共通化の範囲を4つの層に分けた
知識の正本を作る前に決めたのは、「どこまで共通化するか」です。共通化できそうな内容を何でもpackageへ入れると、導入先のルールより共有packageの都合が強くなってしまいます。
このスキルリポジトリでは、扱う知識を次の4層に分けました。
| 層 | 主な内容 | 管理する場所 |
|---|---|---|
| core | CS基礎、設計、可読性、テスト、レビュー、リファクタリング | 共通package |
| module | backend、infra、SRE固有の判断や手順 | 専門module |
| repository | ビルド、デプロイ、ブランチ、Issue運用、ドメイン固有ルール | 導入先リポジトリ |
| personal | 個人の好みやローカル設定 | 共有packageの外 |
たとえば、作業前にgit statusを確認することや、既存の変更を勝手に上書きしないことは、多くのリポジトリで再利用できます。変更内容に応じてテストし、最後に変更ファイルと検証結果を報告する流れも同様です。
その一方で、ビルドコマンド、デプロイ手順、GitHub Projectの運用方法はリポジトリごとに異なります。これらは導入先のAGENTS.mdやコントリビューションガイドへ残します。共通instructionは、どこでも安全に使える既定値にとどめ、導入先のルールを上書きしない方針にしました。
coreと専門moduleを分ける
coreには、言語、フレームワーク、クラウドに依存しない知識を置きます。責務や依存方向を考える設計原則、名前や式を読みやすくする基準、テスト範囲の決め方などです。
特定領域の判断はmoduleへ分離しました。
common-core
├── core-foundations
├── core-code-review
└── core-refactoring
modules
├── backend
├── infra
└── sre
たとえば、一般的な依存関係の考え方はcoreに置けます。その一方で、データベースのトランザクション境界、Terraformのstate管理、SLOやインシデント対応は、それぞれbackend、infra、SREが責任を持つ内容です。
当初、専門moduleは別リポジトリのsubmoduleとして管理する案も考えました。ただ、責務を分けることと、リポジトリを分けることは同じではありません。個人で管理する現状では、coreとmoduleをまたぐ変更を一つのPull Requestで扱える利点を優先し、通常のディレクトリとしてmonorepoに置いています。packageの境界は、各moduleのmanifestで維持します。
SKILL.mdを知識のルーターにした
Agent Skillは、SKILL.mdと必要に応じた補助ファイルで構成します。
skill-name/
├── SKILL.md
├── references/
├── scripts/
└── assets/
SKILL.mdへすべての知識を書けば、最初は一元管理できて扱いやすく見えます。しかし、内容が増えるほどファイルが長くなり、Agentはタスクと関係のない説明まで読み込むことになります。また、似た知識をどの章で扱うべきかも、更新時に判断しにくくなります。
そこで、SKILL.mdを必要な知識へ案内するルーターにしました。OpenAIのSkill作成ガイドでも、SKILL.mdを簡潔に保ち、詳細資料をreferences/、テンプレートなどをassets/、決定的な処理をscripts/へ置く構成が案内されています(参考:Build skills)。
descriptionへ「使わない条件」も書く
core-foundationsのfrontmatterは次のようにしています。
---
name: core-foundations
description: Use this skill for cross-domain engineering foundations such as computer science, design principles, readable code, testing principles, and Web protocol semantics. Do not use it for backend-, infrastructure-, or SRE-specific practices.
---
descriptionには、Skillが提供する知識だけでなく、backend、infra、SRE固有の判断には使わないことも書きました。
Skillの品質は、知識の量だけでは決まりません。必要な場面でだけ呼ばれることも重要です。対象外の条件を書いておけば、専門moduleとの責任が重なるのを防ぎやすくなります。
必要なreferenceだけを読む
core-foundations/SKILL.mdでは、判断の種類に応じて読むreferenceを分けています。
計算・状態・複雑性 -> cs-fundamentals.md
責務・境界・依存方向 -> design-principles.md
命名・式・局所的な可読性 -> readable-code.md
テスト範囲・信頼性 -> testing-principles.md
HTTP・URI・cache -> web-fundamentals.md
Agentには、タスクに関係するreferenceだけを読むよう指示しています。設計とテストの両方が必要なら2つを読みますが、毎回すべてを読み込むことはしません。
この構造にすると、どのreferenceがどの判断を担うのかが明確になります。referenceを個別に更新しやすくなり、Skillが大きくなっても、タスクごとに読み込む範囲を抑えられます。
Agent固有metadataはadapterとして分けた
3つのAgentで共有する正本は、SKILL.mdとreferences/です。ここには、特定のAgentだけで意味を持つ情報をなるべく入れません。
一方、OpenAI向けにはagents/openai.yamlを置き、表示名、短い説明、既定の起動promptを補足できます。core-foundationsでは次の内容を設定しています。
interface:
display_name: Core Foundations
short_description: CS, design, testing, Web, and readable-code foundations.
default_prompt: Use $core-foundations to apply the relevant foundations to this task.
このファイルはSKILL.mdから自動生成せず、必要なSkillだけ手で管理する任意のadapterとしました。Skillの発見条件や実行手順まで重複させると、SKILL.mdとのずれが起きるためです。
Gemini CLIは、workspaceの.agents/skills/もSkillの探索先として扱います(参考:Managing Agent Skills)。Claude CodeもSKILL.mdと補助ファイルからなるSkillを利用できます(参考:Extend Claude with skills)。共通部分は標準的な構造へ寄せ、Agent固有の拡張だけを外側へ足す方が、正本を保ちやすいと考えました。
APMで3つのAgentへ配布した
スキル管理リポジトリ(skills-repo)のcore packageは、次の構成です。
skills-repo/
├── apm.yml
├── apm.lock.yaml
├── .github/
│ └── workflows/
│ └── ci.yml
├── .claude-plugin/
│ └── plugin.json
├── .apm/
│ ├── skills/
│ │ ├── core-foundations/
│ │ ├── core-code-review/
│ │ └── core-refactoring/
│ └── instructions/
│ └── engineering-conventions.instructions.md
├── modules/
└── tools/
.apm/だけを配布内容の正本とし、生成されたbuild/や各Agentへのinstall結果は管理対象から外します。
manifestでは、Codex、Gemini CLI、Claude Codeに加え、特定のAgentへ閉じないagent-skillsもtargetとして宣言しています。
name: common-core
version: 0.1.0
description: Common core engineering skills and instructions.
author: Example Org
license: MIT
targets:
- codex
- gemini
- claude
- agent-skills
type: hybrid
includes: auto
dependencies:
apm: []
mcp: []
APMは、skillsやinstructionsなどの配布対象をapm.ymlで宣言し、targetに応じた場所へ展開するパッケージマネージャーです。対応targetと配置先は更新されるため、利用時は公式のTargets matrixを確認してください。
APM 0.32.0で確認した配置
この記事では、APM CLIのバージョンを0.32.0に固定して検証しました。以下は、test-package.shでAgentごとに一時ディレクトリを作り、installしたときの結果です。
| Target | Skillの配置先 | 共通instructionの扱い |
|---|---|---|
| Codex | .agents/skills/ | install後にapm compileでAGENTS.mdを生成 |
| Gemini | .agents/skills/ | AGENTS.mdと、それをimportするGEMINI.mdを生成 |
| Claude | .claude/skills/ | .claude/rules/へ配置 |
APMの現行仕様や配置先は今後も変わる可能性があります。この表には、0.32.0の環境で実際に検証した結果を記載しています。
packはwrapper scriptから実行します。
./tools/pack.sh
生成したbundleは次の構成になりました。
build/common-core-0.1.0/
├── plugin.json
├── apm.lock.yaml
├── skills/
│ ├── core-foundations/
│ ├── core-code-review/
│ └── core-refactoring/
└── instructions/
└── engineering-conventions.instructions.md
リモートのリポジトリから導入する場合は、次のようにtargetを指定できます。
apm install <org>/<repo> --target codex
apm compile --target codex
refを省略すると、更新によって導入内容が変わる可能性があります。再現性が必要な利用先ではcommit SHAを指定します。tagを使う場合は、移動や再作成を禁止する運用とし、解決結果を記録したapm.lock.yamlもバージョン管理へ含めます。
apm install <org>/<repo>#<tag-or-commit-sha> --target codex
以下は、一時ディレクトリでCodex向けにinstallした後、Gemini向けにcompileしたときのログです。個人環境のユーザー名や非公開情報はマスクしています。
[user@test]$ apm install <org>/<repo> --target codex
[*] Created apm.yml
[i] Targets set: codex (persisted to apm.yml)
[*] Validating 1 package...
[+] <org>/<repo>
[*] Updated apm.yml with 1 new package(s)
[>] Installing 1 new package...
[>] Resolving <org>/<repo>...
[i] Targets: codex (source: --target flag)
[+] <org>/<repo> #main @4efffc54
|-- 3 skill(s) integrated -> .agents/skills/
[i] Added apm_modules/ to .gitignore
[i] Instructions installed for codex. Run 'apm compile' to update AGENTS.md.
[!] 1 dependency unpinned: <org>/<repo> -- add #tag or #sha to prevent drift
[i] Skipped inactive experimental resolver for target 'copilot-cowork' during lockfile reconciliation.
[i] Skipped inactive experimental resolver for target 'copilot-app' during lockfile reconciliation.
[*] Installed 1 APM dependency in 2.4s.
[user@test]$ ls -la
drwxr-xr-x user staff 256 B Wed Sep 30 11:51:28 2026 .
drwx------ user staff 480 B Wed Sep 30 11:50:55 2026 ..
drwxr-xr-x user staff 96 B Wed Sep 30 11:51:28 2026 .agents
drwxr-xr-x user staff 64 B Wed Sep 30 11:51:28 2026 .codex
.rw-r--r-- user staff 33 B Wed Sep 30 11:51:28 2026 .gitignore
.rw------- user staff 6.5 KB Wed Sep 30 11:51:28 2026 apm.lock.yaml
.rw-r--r-- user staff 442 B Wed Sep 30 11:51:27 2026 apm.yml
drwxr-xr-x user staff 96 B Wed Sep 30 11:51:28 2026 apm_modules
[user@test]$ apm compile --target gemini
[*] Starting context compilation...
[i] Targets: gemini (source: --target flag)
[i] Compiling for GEMINI.md + .gemini/commands/ + .gemini/skills/ + .gemini/settings.json (MCP/hooks) - explicit --target flag
[i] Analyzing project structure...
|- 1 directories scanned (max depth: 0)
|- 2 files analyzed across 2 file types (yaml, yml)
+- 1 instruction patterns detected
Optimizing placements...
Pattern Source Coverage Placement Metrics
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
(global) engineering-convent… 1/1 ./AGENTS.md rel: 100%
Generated 1 AGENTS.md file
+- Context efficiency: 100.0%
+- Generation time: 1ms
Placement Distribution
+- . 1 instruction from 1 source
[i] Generated GEMINI.md (imports AGENTS.md)
[+] Compilation completed successfully!
[!] Compilation completed with 1 warning(s):
[!] apm_modules/<org>/<repo>/.apm/instructions/engineering-conventions.instructions.md: No 'applyTo' pattern specified -- instruction will apply globally
[user@test]$ ls
AGENTS.md apm.lock.yaml apm.yml apm_modules GEMINI.md
ログを見ると、Codex向けにinstallした時点で .agents/skills/ 配下へ3つのSkillが配置され、依存関係が apm.lock.yaml に記録されています。続けて apm compile --target gemini を実行すると、共通instructionから AGENTS.md が生成され、それを参照する GEMINI.md も期待どおり作成されました。
pack成功ではなくinstall結果まで検証した
Agent Skillの本体はMarkdownですが、packageとして壊れる箇所は少なくありません。
- YAML frontmatterがない
nameとディレクトリ名がずれているSKILL.mdやreferenceが空になっている- Markdownの相対リンクが壊れている
agents/openai.yamlの階層や型が誤っている- packageに必要なファイルが入っていない
- 配布対象外のファイルが混入している
そこで、Skill自体の静的検証と、packageのsmoke testを分けて用意しました。
Skillの構造を静的に検証する
validate-skills.shでは、各Skillのfrontmatter、名前、ファイル内容、相対リンク、OpenAI向けmetadataなどを検査します。
./tools/validate-skills.sh
python3 -m unittest tools/test_validate_skills.py
validatorにも回帰テストを用意しました。正常なSkillに加え、前掲の不備を含むSkillも用意し、それぞれを検出できることを確認しています。
ただし、静的検証だけでは、正しいファイルがbundleへ入り、各Agentへ期待どおり配置されることまでは保証できません。
一時ディレクトリで3つのtargetへinstallする
tools/test-package.shでは、作業リポジトリを汚さないように一時ディレクトリを作り、packからinstallまでを確認します。
./tools/test-package.sh
検証の流れは次のとおりです。
- APM CLIのversionを確認する
- 一時ディレクトリへpackageを作る
- manifestのnameとversionを確認する
- bundle内のlockfileにファイルhashがあることを確認する
- sourceとbundleのSkill・instructionをbyte単位で比較する
personal/やmodules/がbundleへ混入していないことを確認する- Codex、Gemini、Claudeごとに別のconsumer projectへinstallする
- install後のファイルをsourceと比較する
- CodexとGeminiでは
apm compileの生成結果も確認する - 一時ディレクトリを削除する
ここまで確認することで、「packコマンドが終了コード0を返した」だけでは見つからない欠落や配置ミスを検出できます。
Pull Requestで同じ検証を実行する
ローカルだけで成功しても、必要なツールがすでに入っていたり、作業中のファイルに依存していたりする可能性があります。そこで、GitHub Actionsへ次の2つのjobを追加しました。
Skill validation: validatorとunit testを実行するPackage smoke test: APM CLI 0.32.0を新規導入し、3 targetへのpackとinstallを確認する
workflowの権限はcontents: readだけにし、repository secretは使用しません。最後にgit statusも確認し、テストが生成したbundleや一時ファイルをcheckoutへ残した場合は失敗させます。
初回のPull Requestでは、Skill validationが約6秒、Package smoke testが約30秒、workflow全体の経過時間は約32秒でした。手元のmacOSだけでなく、Linux runnerへAPM CLIを新規導入した状態でも配布できることを確認できました。
APM CLIの挙動差を検証へ組み込んだ
packageを作る過程では、APM CLI 0.32.0の挙動をいくつか確認しました。回避策だけを入れると、将来CLIの挙動が変わっても、不要になった対応が残り続けます。そのため、既知の挙動をtest-apm-compatibility.shで再現し、変化を検知できるようにしています。
コメントだけのlockfileは無効だった
依存関係がなかったため、最初のapm.lock.yamlはコメントだけにしていました。packすると、次のエラーになりました。
Error: Lockfile root must be a mapping
依存がない場合も、lockfileにはschemaに沿ったmappingが必要でした。
lockfile_version: '1'
apm_version: 0.32.0
dependencies: []
deployments: []
「依存がない」と「lockfileの構造がなくてよい」は別でした。空の状態も、ツールが解釈できる形で表現する必要があります。
独自の.apm/contextはpack対象にならなかった
当初は、複数のSkillから参照する用語集を.apm/context/glossary.mdへ置こうとしていました。明示的なincludeへ追加すると、0.32.0では次のエラーになりました。
Explicit include path is not a packable primitive: .apm/context/glossary.md
そこで、空だった用語集を削除し、manifestをincludes: autoへ変更しました。packageの構成は、APMが扱うprimitiveへ合わせています。
target未指定のbundleをlocal installできなかった
手元で取得したstandalone版の0.32.0では、targetを指定せずにpackすると、bundle内のlockfileへpack.target: minimalが記録されました。このbundleをlocal installすると、'minimal'に関するエラーで失敗しました。
現在は、このstandalone版への互換対応としてwrapper scriptから次を実行しています。
apm pack --force --target all
ただし、同じ0.32.0でも配布経路によって挙動が異なります。現行の公式ドキュメントでは、packしたbundleはtargetに依存しないと説明されています(参考:apm pack)。この記事では実行ファイルのcommitやchecksumまで示していないため、0.32.0というversion番号だけで同じ挙動を再現できるとは限りません。この回避策を0.32.0全体へ一般化せず、外せる時期が分かるように、compatibility testで次の状態を確認しています。
- target未指定のpackが
minimalになる - そのbundleのlocal installが失敗する
--target allで作ったbundleはinstallできる
将来APM CLI側で挙動が変われば、テストが失敗します。その時点でversion固定とworkaroundをまとめて見直す方針です。
同じversionでも配布経路による差があった
ローカルで使ったstandalone版と、GitHub ActionsへPyPIから入れたAPM CLIは、どちらも0.32.0でした。それでも、apm --versionの表示形式や、--rootと相対bundle pathを組み合わせたときの挙動に差がありました。
この結果から、CIでは両方の環境で成功する絶対bundle pathを使ったsmoke testを合格条件にしました。standalone版固有の失敗は、workaroundを見直すためのlocal diagnosticとして分離しています。
ツールのversion番号を固定しても、実行ファイルの配布方法や周辺環境まで完全に同じになるとは限りません。最終的に必要な操作が成功するかを確認するテストを、互換性の基準にしています。
APMを使った配布で分かった勘所
今回、実際にpackageを作って3つのAgentへ配布したことで、APMへ任せられる範囲と、自分で設計しなければならない範囲が見えてきました。
APMが揃えるのは配布経路であり、知識の境界は自分で決める
APMを使うと、一つのmanifestからtargetごとの場所へSkillやinstructionを展開できます。一方、何をcoreに置き、何を専門moduleや導入先へ残すかは、利用者が決める必要があります。
この境界が曖昧なままpackageを作ると、共通ルールへ際限なく知識を追加しがちです。結果として、どのタスクでも大量の文書を読むSkillになったり、導入先のルールと衝突したりします。APMで配り始める前に、知識の責任と適用範囲を決めることが重要でした。
targetごとの差を消そうとせず、配布層で受け止める
Codex、Gemini CLI、Claude Codeは、Skill本体に同じSKILL.mdを使えても、instructionの扱いや配置先まで同じとは限りません。この差を共通ファイルの中へ持ち込むと、Agent固有の条件分岐が増えて正本が読みにくくなります。
portableな知識は共通に保ち、配置先やcompileの有無はAPMとtarget別の検証へ任せる。この分担にすると、Agentが増えてもSkill本文を複製せずに済みます。
配布できたかどうかはinstall後の状態で判断する
apm packの成功は、bundleを生成できたことしか保証しません。必要なreferenceが欠けている、配布対象外のファイルが混ざっている、targetごとの配置が想定と違うといった問題は、実際にinstallするまで分からない場合があります。
そのため、配布の完了条件を「packが成功した」から「空のconsumer projectへinstallし、必要なファイルとcompile結果を確認できた」へ変えました。source、bundle、install先を比較するsmoke testが、packageの実質的な契約になっています。
workaroundには外す条件も用意する
CLIの挙動に合わせた回避策は、導入時には必要でも、将来のversionでは不要になる可能性があります。理由が分からないままwrapper scriptへ残ると、更新を妨げる新しい負債になります。
今回は、手元のAPM 0.32.0で起きる失敗を互換性テストで再現するようにしました。CLIの挙動が変わるとテストが失敗し、--target allや絶対pathの制約を見直す時期が分かります。回避策そのものと一緒に、「どの状態になったら外すか」を残すことが大切でした。
APMを使って得られた一番大きな学びは、Agent Skillsにもソフトウェアと同じ管理が必要なことです。正本と責任境界を定め、配布、互換性、回帰テストまで扱う必要があります。
共有すべきなのは、Agent固有の設定ファイルをコピーしたものではありません。再利用できる知識の正本と、それを各Agentへ安全に届ける仕組みです。まずは小さなcore Skillから始め、実際のタスクで発火条件と出力を確かめながら、専門moduleへ広げていきます。
今後の展望:AI活用の格差を仕組みで縮める
今後は、個人で作ったAgent Skillsを組織へ安全に配布するには、どのような仕組みが必要かを考えていきます。
組織内のAI活用には、同じモデルを使っていても差が生まれます。日頃から試行錯誤している人は、タスクの渡し方、確認すべき点、失敗しやすい条件を知っています。一方、使い始めたばかりの人は、同じ失敗を一から経験しなければなりません。これは個人の能力だけの問題ではなく、組織で得られた知識を再利用できる形にしていないことも原因だと思います。
レビューの観点、テストの基準、安全な作業手順、ドメイン固有の判断をAgent Skillsとして整備し、APMで配布します。そうすれば、メンバーはAgentやリポジトリが変わっても共通の土台から始められます。新しく参加した人も、詳しい人が暗黙的に使っている判断基準へ早い段階でアクセスできます。狙いは、最低限の品質と安全性を組織の標準として底上げすることです。
そのためには、配りやすさだけでなく、誰がSkillを管理するのか、変更をどうレビューするのか、バージョンをどう固定するのか、問題が起きたときにどう戻すのかも決める必要があります。Skillにはscriptを同梱でき、Agentの権限でファイルへアクセスする場合もあるため、配布元のリポジトリを信頼境界として扱います。古い知識や誤った手順まで広く配布すれば、格差を縮めるどころか、同じ誤りを組織全体へ広げてしまいます。
目指すのは、組織で蓄積した知識を誰もが同じスタートラインから安全に使える状態です。そのために、レビュー済みのSkillを配布し、利用結果をもとに更新し、問題があれば切り戻せる仕組みを考えていきます。
