APM でチーム共有パッケージを作ってみた
はじめに
gh skill install と同じようなものかと思いきや、skill 以外も共有できそうだったので試してみました。
APM とは
APM (Agent Package Manager) は Microsoft が公開している AI エージェント向けのパッケージマネージャーです。apm.yml に宣言した skills や agents、instructions、外部 MCP サーバーなどを apm install 一発で配布・再現できます。Claude Code / GitHub Copilot / Cursor など複数のエージェントに対応しており、同じパッケージを --target 指定で別のエージェント向けに展開できます。
パッケージ全体の構成イメージ
パッケージは .apm/ の自作ファイルと apm.yml に書かれた外部依存の 2 つから構成され、それぞれが .claude/ の各ディレクトリに展開されます。
APM を入れる
curl -sSL https://aka.ms/apm-unix | sh
自作パッケージを作る
ディレクトリ構造
my-team-package/
├── apm.yml
└── .apm/
├── skills/
│ ├── fact-check/
│ │ └── SKILL.md
│ └── textlint-runner/
│ └── SKILL.md
├── agents/
│ └── blog-writer.agent.md
└── instructions/
└── core.instructions.md
ファイル命名規則
.apm/ 内のファイルは正しい拡張子で配置する必要があります。
| プリミティブ | 正しい形式 |
|---|---|
| Instructions | *.instructions.md |
| Agents | *.agent.md |
| Prompts | *.prompt.md |
| Skills | <name>/SKILL.md |
Instructions の frontmatter
applyTo で適用対象を指定できます。Claude Code にインストールすると paths に自動変換されて .claude/rules/ に配置されます。
---
description: "コーディング規約"
applyTo: "**/*.swift"
---
# コーディング規約
- 関数名はキャメルケースで記述する
apm.yml
外部依存は apm.yml に列挙します。自作ファイルは .apm/ に置くだけで配信されるので記述不要です。
name: my-team-package
version: 1.0.0
dependencies:
apm:
- anthropics/claude-plugins-official/plugins/feature-dev
- AvdLee/Swift-Concurrency-Agent-Skill/swift-concurrency
mcp: []
パッケージを取り込んでみる
apm install my-org/my-team-package --target claude
推移的依存関係が解決され、自作パッケージと外部パッケージがまとめて入ります。

プライベートリポジトリでも GitHub のアクセス権があれば問題なく取り込めます。更新するときは --update をつけます。
マーケットプレイス経由で取り込む
事前にマーケットプレイスを登録しておけば、@marketplace-name 形式で簡潔に指定できます。
apm marketplace add anthropics/claude-plugins-official
apm install feature-dev@claude-plugins-official
apm marketplace browse でプラグイン一覧を見られます。
注意点と対策
実運用で気になる挙動や制約をまとめます。
プラグインが「プラグインとして」入らない
Claude Code 向けのプラグイン(feature-dev など)を APM 経由で入れると、plugin.json を持つプラグインでも中身が .claude/agents/ や .claude/commands/ にばらまかれます。Claude Code の /plugin list には出ず、名前空間(feature-dev:code-reviewer)も失われるので、自作の同名ファイルと衝突する可能性があります。
さらに、Claude Code ネイティブのプラグイン自動更新も走りません。ただのローカルファイル扱いになるため、プラグイン側が更新されても apm install --update を手動で叩かないと反映されないのです。/plugin install で入れていればマーケットプレイス経由で自動更新される分、APM 経由だと管理コストが上がります。
MCP は .vscode/mcp.json に書かれる
apm.yml の mcp: に追加すると .vscode/mcp.json(VS Code 形式)に書き込まれます。Claude Code は .mcp.json を読むため認識されません。MCP だけは claude mcp add で別管理するのが現実的です。
バージョン更新の仕組みが弱い
apm install --update という一見便利そうなオプションがあるのですが、実際には apm.yml に書かれた ref を書き換えずに、その ref 最新のコミット SHA を取りに行くだけ です。#v0.1.0 で固定していれば v0.2.0 が出ても追従しませんし、#<sha> で固定していれば当然変わりません。つまり新しいバージョンへ上げたければ apm.yml を手動で書き換える必要があります。
加えて Renovate や Dependabot は apm.yml に対応していないので、「新バージョンが出たら通知」する仕組みも標準ではありません。
Renovate の Custom Manager で更新検知する
apm.yml 向けの Renovate 設定は Custom Manager で実現できます。新しいバージョンが公開されてから一定期間経過するまで PR を作らないように minimumReleaseAge を併用すれば、撤回された不安定なバージョンの取り込みを避けられます。
実際に書いた renovate.json5 の抜粋です。
{
extends: ['config:recommended', ':timezone(Asia/Tokyo)'],
labels: ['dependencies'],
minimumReleaseAge: '14 days',
customManagers: [
{
customType: 'regex',
managerFilePatterns: ['/(^|/)apm\\.yml$/'],
matchStrings: [
'-\\s+(?<depName>[\\w.-]+/[\\w.-]+)(?:/[\\w./-]+)?#(?<currentDigest>[0-9a-f]{40})',
],
datasourceTemplate: 'git-refs',
packageNameTemplate: 'https://github.com/{{depName}}',
currentValueTemplate: 'main',
},
],
}
この設定で実際に Renovate が PR を作ってくれました。

ただし datasource: git-refs は releaseTimestamp を返さないため、minimumReleaseAge が実質機能しません。今回の設定でも 2 日前の最新コミットを指す PR が 14 days 設定下で作られました。これは Renovate 公式のドキュメントでも「datasource が release timestamp を返す必要がある」と明記されている挙動です。Discussion #39058 でもメンテナーから「digest 更新は timestamp を持たないのが正しい挙動。制御したければ matchUpdateTypes を使って individual 設定する」との公式方針が示されています。タグなしリポジトリを SHA で追う場合、Renovate 標準機能ではサプライチェーン対策としての待機期間を強制できず、人間によるレビューや別の仕組みを組み合わせる必要があります。
なお GitHub Actions workflow 向けの pinact は apm.yml を対象とできず、加えてタグベースのツールなのでタグなしリポジトリは本質的に対象外です。結局「タグなしリポジトリの自動追従」は既存ツールでは難しく、手動更新か GitHub Actions 自作ワークフローに頼る運用になります。
エージェント間の移行
--target を変えるだけで他のエージェントにも展開できます。
apm install my-org/my-team-package --target claude
apm install my-org/my-team-package --target copilot
apm install my-org/my-team-package --target all
.apm/instructions/ のルールは、Claude Code なら .claude/rules/、Copilot なら .github/instructions/ にそれぞれ変換されて配置されます。
利用想定
用途によって使い分けると良さそうです。
- 自作コンテンツ(
.apm/)を配りたい → APM の価値あり - 外部プラグインを取り込みたい → Claude Code ネイティブ(
/plugin install)の方が自動更新が効いて管理しやすい - プロジェクトごとに環境を固定したい →
apm.ymlとapm.lock.yamlをリポジトリにコミットし、共通パッケージをコミットハッシュで固定する
共通パッケージをプロジェクトから参照する構成
tag はミュータブルなので、サプライチェーン対策としてはコミットハッシュで固定するのが安心です。行末に # v1.2.0 のようにバージョンをコメントで残しておけば、後から読んでも何のバージョンで固定しているか分かります。
# project-A/apm.yml
name: project-a
dependencies:
apm:
- my-org/my-team-package#775a083d6f4a3c2e8b7d9f1a2b3c4d5e6f7a8b9c # v1.2.0
- anthropics/claude-plugins-official/plugins/feature-dev#bb7730114d873b91acd477e696066f217f882391 # v0.3.0
共通パッケージ側は git tag を切って公開し、利用側はそのタグに対応するコミットハッシュを apm.yml に書きます。
git tag v1.2.0
git push origin v1.2.0
この構成なら git clone && apm install だけで同じ環境が再現でき、破壊的変更もタグを上げるまで利用側に影響しません。
なお、新しいバージョンに上げるときは apm.yml を手で書き換える必要があります。自動化したい場合は前述の Renovate Custom Manager を組み合わせてください。
まとめ
apm install 一発でチーム全員に同じ環境を配れるのは便利でした。プラグインや MCP の扱いなど噛み合わない部分はありますが、自作の skills や agents をチームで共有したい場面では十分に実用的です。気になった方は触ってみてください。