RevComm Tech Blog

コミュニケーションを再発明し 人が人を想う社会を創る

AI エージェント開発で設計の一貫性をどう守るか ― フロントエンドにおける Agent Skill の実践

RevCommの熊谷です。

AIエージェントを使った開発が当たり前になり、コーディングの速度は確かに上がりました。一方で、フロントエンドは自由度が高いぶん、油断するとすぐに設計がブレるという次の問題も見えてきます。今回は、それをどうやって抑えているかを書いてみます。私たちのチームではルールを文章で書き下すよりも、「参考実装を指す」ことを軸にしています。

困っていたこと

紹介するのは、MiiTel Admin という管理画面での話です。自社サービス「MiiTel(ミーテル)」を支える、Vue 3 + Nuxt 4 + TypeScript で作られた Web アプリケーション。ミーテルの成長とともに機能が増え続け、現在は 92 ページの大規模な管理画面になっています(ここ半年で 8 ページ増えてる...!)。

このプロダクトはフロントエンド専任ではない開発者(バックエンド・モバイル・音声 AI エンジニア)も気軽に機能追加に入ってくれます。それ自体はありがたいのですが、そのぶん設計のブレが起きやすい環境でもあります。

エージェント導入前は、既存のページをコピペして少し直すような書き方が多かったんですよね。コピペにはもちろん問題もあるのですが、結果として構成が大きく外れにくく、書く速度もそこまで速くなかったので、設計のずれはレビューで拾えていました。

ところが、エージェントが入ってから一気に状況が変わりました。

  • みんな書く速度が一気に上がった
  • 設計のブレがレビューで追いつかない量で発生するようになった
  • 開発者ごとに使うエージェント・モデルが違う(Copilot / Claude / Cursor / Devin、モデルもいろいろ)

このまま放っておくとカオスになる、というのが課題感でした。

基本方針

打ち手はいくつかあるのですが、根っこの方針はシンプルです。

  • エージェント・モデルは開発者の好きなものを使ってOK(強制しない)
  • ただし「何を見て書くか」だけは全エージェント共通にする
  • 人間がレビューで都度直すのではなく、書かれる前に方向を揃える

エージェントを「設計のブレ防止装置」として使うイメージです。本業で使い慣れたエージェントをそのまま使える方が、開発者にとっても嬉しいですしね。

やっていること

エージェント向けのドキュメント整備は ルールを文章で書き下す アプローチが多いと思いますが、私たちはむしろ 参考実装そのものを指す アプローチを軸にしています。文章のルールはどうしても実装とズレていきますが、コードは常に最新だからです。以下の 3 つは、その方針から派生した工夫です。

1. リファレンス実装と「参考の優先順位」を明示する

1ページを徹底的にリファクタしてお手本にする、というやり方です。前回のブログでも書いたパターンですね。

現在は SMS テンプレート機能 src/pages/sms-template/ を参照実装にしていて、エージェントが見る .github/copilot-instructions.md にも明記しています。

## 作業の進め方(最優先) - 変更行数が合計 20 行を超える場合は必ず守ること。
1. コードを書く前に対応するスキルを呼び出す
2. 使用するスキルが 3 つを超える場合は、作業分割をユーザーに提案する — ユーザーが「そのまま進めて」と回答すれば継続してよい
3. 既存のコンポーネント構造・設計に従う
4. 明示的な指示がない場合は新しい設計パターンの導入はしない
5. 判断に迷った場合は、一般的なベストプラクティスに従うよりも、既存コードの設計・パターンに合わせることを優先する

## 参考実装の優先順位
1. `src/pages/sms-template/`(composable 分離・Pinia Setup Store・vee-validate・i18n が揃ったパターン)
2. `src/pages/softphone-setting/`(Pinia 移行済みの最新実装)
3. 同カテゴリの既存画面(同じユースケース・UI 構成)
4. `src/composables/`、`src/components/organisms/` の既存実装

参考実装の場所さえ明示しておけば、エージェントは常に最新のコードを見にいってくれます。ドキュメントの更新が遅れても、自然と最新パターンに揃っていくというのが、このやり方のいちばん効いている点です。

「既存パターンを優先する」と明文化しておくと、エージェントがプロジェクト側に寄せてくれやすくなります。バックエンドエンジニアもフロントを触る体制なので明示的に書いていますが、フロント専任メンバーで固まっているチームでは、ここまで強く書く必要はないかもしれません。

2. コンテキストに乗せる情報を絞る

ドキュメントは育てると肥大化しがちです。とくに先ほどの参考実装アプローチでは、エージェントが skill / instructions に加えて実コードまで読みにいくので、コンテキストはなおさら膨らみやすい。コンテキストが膨らむと、エージェントの注意がそれて、長いルールほど読み飛ばされやすくなる。動作そのものも遅くなります。なので、「何を読ませないか」もセットで設計しています。

  • トピックごとに skill に分割: state-management / i18n-rules / vee-validate-form など。関連する作業のときだけ読み込ませる
  • 小規模変更ではスキップ可能に: 「変更行数が 20 行を超える場合は必ず skill を呼ぶ」のように、軽微な編集では読み込みを省略できる逃げ道を書いておく
  • 人間向けドキュメントと分離: 設計ドキュメント (docs/architecture.md など) は人間向けに保ち、エージェント向けは簡潔な技術用語の羅列に近い形に

最後の点は試行錯誤がありました。最初は copilot-instructions.md から docs/architecture.md を参照させていたのですが、結局コンテキストが膨らむだけで効果が薄かった。エージェント向けには「読みやすさ」より「短さ」を優先して、技術用語の羅列に近い形に分離したら、必要な情報だけ拾ってもらえるようになりました。

3. ライブラリの標準パターンに素直に乗る

2 はドキュメントを絞る工夫でしたが、もう一歩進めて、そもそもドキュメントを書かなくて済むようにする こともできます。エージェントがすでに知っている公式パターンに乗せれば、プロジェクト固有のルールを書く必要がありません。

これは、考え方が大きく変わったところです。

以前は「Nuxt/Vue 固有機能をバックエンドエンジニアにまで覚えてもらうのは忍びない」と思っていて、Vanilla 寄りの実装で吸収していました。たとえばページの表示条件は、各ページで router.push を使って書いていました。

// src/pages/sms-templates.vue (抜粋)
const router = useRouter();
const { isSmsAvailable } = usePermission();
onMounted(() => {
  if (!isSmsAvailable.value) router.push('/');
});

今は Nuxt の definePageMeta + middleware に置き換えました。各ページは宣言を 1 行書くだけです。

// src/pages/sms-templates.vue (抜粋)
definePageMeta({
  permission: (ctx: TenantContext) => ctx.isSmsAvailable,
});

判定の本体は middleware に集約。全ページぶんが、ざっくりこの数行で完結します。

// middleware/permission.global.ts (抜粋)
export default defineNuxtRouteMiddleware(to => {
  const ctx = usePermission();
  if (!to.meta.permission?.(ctx)) return navigateTo('/');
});

この設計は Vue Router 公式の route.meta + navigation guard パターン をほぼそのまま踏襲したもので、プロジェクト固有の語彙も permission / TenantContext の 2 つに絞れているので、エージェントは公式パターンの知識をほぼそのまま使って書けます。

振り返ると、MiiTel Admin は SSR を採用していないこともあり、これまで Nuxt らしい機能を十分に活かせていませんでした。それがエージェントの登場で逆転しました。エージェントが補完してくれるなら、標準パターンに乗る方がブレない。学習コストの高い固有機能も気軽に取り入れられるようになり、Nuxt を選んだメリットをようやく実感できているところです。

ルールを長く運用する工夫

一次ソースを 1 箇所に集約する

ドキュメントは長く運用すると、コピーが増えてあちこちでずれていく、というのが起きがちです。一次ソースを 1 ヶ所に集約して、各エージェントからは同じファイルを参照させるようにしています。.github/copilot-instructions.md.github/instructions/*.instructions.md を起点に、Claude 用 .claude/skills/ や Cursor からも同じファイルを参照。コピーを作らないので更新がずれません。一番制約がきつい Copilot(2026 年 5 月時点では外部ファイルを参照できず、.instructions.md 自体に内容を直接書く必要があります)に合わせて書いておけば、他のエージェントでも破綻しにくい、というのも分かってきました。

たとえば Claude 用の .claude/skills/i18n-rules/SKILL.md は、.github/instructions/ 配下の対応するファイルを cat するだけのシンプルな中継ファイルです。

---
name: i18n-rules
description: Use this skill when creating or editing i18n files (...).
---

!`cat ${CLAUDE_SKILL_DIR}/../../../.github/instructions/i18n-rules.instructions.md`

これで Claude も Copilot も結局は同じ .github/instructions/i18n-rules.instructions.md を見ているので、更新は 1 箇所で済みます。

PR レビューでルールを育てる

それでも、思ったような PR が出てこないことはあります。レビューで違和感を覚えるときって、実装した本人も「なんか変だな」と感じていることが結構あるんですよね。そんな時は、本人が使っているエージェント環境で、そのまま 「今回どの skill / instructions 読んだ?参考実装は何を見た?」と聞いてもらいます。自分の環境で再現するより速いし、本人もその場で原因を切り分けやすい。ルール自体が足りないのか、ルールへの導線が悪いのか、参考実装が古いのか。「あ、これ参照されてなかったね、書き足しておくね」みたいに、雑談ベースでドキュメント改善を回しています。

原因の切り分けが終わったら、その流れでエージェントに .github/instructions/ の修正 PR まで作ってもらうこともあります。違和感を覚えた人が、その場でルールを直す側に回れるのは、エージェント時代ならではの良さだなと感じています。

おわりに

エージェント時代のフロントエンド開発で効いたのは、「何を見て書くか」を揃えること だなと感じています。エージェントを厳しく縛るのではなく、既存設計に自然に合流できる道を整える。それができれば、速く作りながら長く保守できるプロダクトに近づけるはずです。

「スピードは出るようになったけど、設計がブレ始めた」というフェーズに入ったチームの参考になれば嬉しいです。