はじめに
以前、こんな記事を書きました。
Claude Codeで「俺だけのナレッジベース」を作る
AIエージェントに技術のベストプラクティスを収集させ、
「人間向けドキュメント」と「AI向けスキルファイル」の2形式で蓄積する仕組みです。
今回は、そのスキルファイルを 実際のアプリ開発で使ってみた 話です。
バイブコーディングでやってみました。
前回記事で作ったナレッジベース(スキルファイル)をエージェントに持たせてバイブコーディングしてみた結論から言うと:
- 「動くものを作る」という目標は達成できた(設計書1枚 → 48ファイルが1日で生成)
- 「品質が担保されているか」は正直微妙だった
バイブコーディングの最大の落とし穴は、「追加・修正をぽんぽん投げていくうちに、最終的な仕様が何なのかわからなくなる」 ことです。
実機確認では動作不良が多発し、修正のたびにAIにまた投げて、また確認して……という繰り返しになりました。
この記事では、スキルファイルが実際に何に効いて、何に効かなかったか、そして次回どう改善するかを書きます。
作ったもの:QuickMemo Reminder
| 機能 | 内容 |
|---|---|
| Quick Settings Tile | Androidのクイック設定パネルからワンタップ起動 |
| メモ入力 | クイックボタン(30分後/1時間後/今夜/明日)+ドラムロール時刻ピッカー |
| タスクリスト | アクティブ/完了済みをタブ切り替え |
| 通知 | 指定時刻にローカル通知、完了・スヌーズアクション |
技術スタック
Flutter 3.x / Dart 3.3+
├── 状態管理: Riverpod 3.x(NotifierProvider)
├── ローカルDB: Hive 2.x(手動TypeAdapter)
├── 通知: flutter_local_notifications v20
├── ナビゲーション: go_router v17
└── セキュリティ: flutter_secure_storage(暗号化キー管理)
アーキテクチャは Clean Architecture + MVVM。
バイブコーディングの核心:スキルファイル
「AIは知識があっても適用しない」問題
バイブコーディングの最大のリスクは 品質の担保 です。
LLMは「Riverpodの使い方」も「OWASP Mobile Top 10」も知っています。でも、
明示的に要求しないと適用しない ことがほとんどです。
特に:
- ベストプラクティスより「とにかく動くコード」を選びがち
- セキュリティ要件は指示がなければ省略される
- バージョン差異(Riverpod 2.x vs 3.x 等)に気づかないまま古いコードを生成
これを解決するのが スキルファイル という仕組みです。
スキルファイルとは
技術領域ごとにまとめた「ベストプラクティス辞書」のMarkdownファイルです。
エージェントが作業前に必ず Read ツールで読み込み、内容を踏まえて実装します。
private-research-lab/skills/
├── mobile/
│ └── flutter.skills.md ← Flutterベストプラクティス
├── security/
│ └── security.skills.md ← セキュリティルール(全エージェント必須)
├── architecture/
│ └── architecture.skills.md ← 設計パターン
├── legal/
│ └── compliance.skills.md ← ライセンス・法務確認
└── ... (AI/ML, DevOps, Frontend, Backend, etc.)
スキルファイルの構造
各ファイルは RULES / PATTERNS / ANTI-PATTERNS / CHECKLIST の4セクションで構成されています。
# Flutter / Dart Skills
## RULES (必ず守ること)
- 状態管理は Riverpod を第一候補にする。setState はローカル UI 状態のみに限定する
- Widget は継承より合成。巨大な build メソッドは Widget 分割で対処する
- const コンストラクタを持つ Widget には必ず `const` を付ける
- ナビゲーションは GoRouter で宣言的に定義する
- Platform Channel は抽象インターフェースで包む。Widget から直接 MethodChannel を呼ばない
- `async` の `await` 後に `BuildContext` を使わない
## PATTERNS (推奨パターン)
# → 具体的なコードスニペット付きの推奨実装例
## ANTI-PATTERNS (やってはいけない)
# → アンチパターンと代替案のペア
## CHECKLIST
# → レビュー・リリース前の確認項目
AIエージェントにとって「何をすべきか」だけでなく「何をしてはいけないか」まで明示することで、
出力品質が安定します。
エージェントパイプライン
Claude Code の Agent ツールでサブエージェントを起動し、専門分野ごとに処理を分担させます。
設計書(Markdown)
↓
オーケストレーター(全体統括・タスク分解)
├─→ ソフトウェアアーキテクト ← architecture.skills.md 参照
├─→ Flutterエンジニア ← flutter.skills.md + security.skills.md 参照
├─→ 結合テストエンジニア ← cicd.skills.md 参照
├─→ ブラックハッカー ← security.skills.md(OWASP Mobile Top 10)参照
├─→ ホワイトハッカー ← security.skills.md 参照
└─→ 法務コンプライアンスチェッカー ← compliance.skills.md 参照
各エージェントは .agent.md という定義ファイルを持ち、
「作業開始前に対応するスキルファイルを必ず読み込む」 という制約が書かれています。
<!-- flutter-engineer.agent.md(抜粋) -->
## 作業開始前の必須手順
1. `flutter.skills.md` を Read ツールで読み込む
2. `security.skills.md` を Read ツールで読み込む
3. スキルファイルの RULES を遵守した上で実装する
エージェント定義の生成:Agent Foundry
エージェント定義ファイル(.agent.md)は手書きせず、Agent Foundry というパイプラインで生成します。
cd agent-foundry
python -X utf8 main.py "Flutterアプリを実装するシニアエンジニアエージェント"
Agent Foundry内部で4エージェントが連鎖して動きます:
RequirementsGatherer → Designer → Writer → Reviewer
Reviewerが品質基準を満たさないと判断した場合はWriterに差し戻し、
一定品質のエージェント定義が自動生成されます。
実際のバイブコーディング体験
やったこと
- 設計書(Markdown、約200行)を書く
- オーケストレーターエージェントに渡す
- 待つ
結果
生成ファイル数: 48ファイル
├── lib/ (Dartソース: 35ファイル)
├── android/ (Kotlinネイティブ: 5ファイル)
├── test/ (テスト: 5ファイル)
└── docs/ (README・プライバシーポリシー: 3ファイル)
flutter analyze の推移:
| 段階 | エラー数 | 主な内容 |
|---|---|---|
| 初回生成直後 | 17件 | StateProvider廃止、型エラー、deprecated API |
| パッケージ更新後 | 6件 | 通知API変更、型不一致 |
| 手動修正後 | 1件 | deprecated_member_use(外部パッケージ側の問題) |
| 最終 | 0件 |
// ignore: deprecated_member_use で対応 |
スキルファイルが効いた場面
セキュリティ:Hive暗号化キーの管理
スキルファイルの security.skills.md に以下のルールがあります:
シークレット(APIキー・DB接続情報)をコードにハードコードしない
このルールを読んだブラックハッカーエージェントが、初期実装の問題を指摘:
FIX-003: Hive暗号化キーをハードコード
final key = Hive.generateSecureKey();を毎回呼んでいる。
アプリ再起動のたびにキーが変わり、既存データを読めなくなる。
flutter_secure_storageでキーを端末内に永続化すること。
// Before(問題あり)
final key = Hive.generateSecureKey(); // 毎回新しいキーが生成される
// After(flutter_secure_storageで永続化)
final storage = const FlutterSecureStorage();
String? keyString = await storage.read(key: 'hive_key');
if (keyString == null) {
final newKey = Hive.generateSecureKey();
keyString = base64Url.encode(newKey);
await storage.write(key: 'hive_key', value: keyString);
}
final encryptionKey = base64Url.decode(keyString);
アーキテクチャ:Platform Channel の抽象化
flutter.skills.md に記載されているルール:
Platform Channel は抽象インターフェースで包む。
Widget から直接 MethodChannel を呼ばない
これを受けてFlutterエンジニアエージェントは、
MethodChannelを直接呼ぶのではなく BatteryService という抽象層を経由する設計で実装しました。
// Widget層からは抽象インターフェース経由でアクセス
abstract class BatteryService {
Future<int> getBatteryLevel();
}
// Platform Channel の詳細はここだけに閉じ込める
class BatteryServiceImpl implements BatteryService {
static const _channel = MethodChannel('dev.haaan.quickmemoreminder/battery');
@override
Future<int> getBatteryLevel() async {
return await _channel.invokeMethod<int>('getBatteryLevel') ?? -1;
}
}
法務:ライセンス確認
compliance.skills.md に記載されているルール:
ライブラリ・フォント・画像・音声・外部アセットを導入する際は、
実装前に必ずライセンスを調査・確認・記録すること。
「有名だから大丈夫」という判断は禁止。
アプリアイコンをPythonの Pillow ライブラリで生成した際も、
法務エージェントがライセンスを確認してレポートに記録:
Pillow: MIT License → 商用利用可能
生成した PNG はコード(MIT)から生成されたオリジナル画像 → 著作権はユーザー帰属
Flutter デフォルトアイコン(F ロゴ)は Google の商標 → 使用禁止 ✅ 置き換え済み
バイブコーディングの限界:実機で8件のバグ
「flutter analyze 0件・全テスト通過」でも、実機に載せると別の問題が出ました。
AIは「コンパイルが通るコード」と「実機で動くコード」を区別できない という学びです。
主なバグと原因
| # | バグ | 原因 | 対処 |
|---|---|---|---|
| 1 | ロック画面からメモ画面が開かない |
showWhenLocked/turnScreenOn 未設定 |
Manifest に属性追加 |
| 2 | QSタイルが点灯したまま |
STATE_INACTIVE に戻す処理なし |
updateTile() 追加 |
| 3 | 正確なアラームが動かない |
SCHEDULE_EXACT_ALARM 権限未設定(Android 12+) |
Manifest に権限追加 |
| 4 | 通知許可ダイアログが出ない |
POST_NOTIFICATIONS 明示的リクエスト未実装(Android 13+) |
requestNotificationsPermission() 追加 |
| 5 | キャンセルでホワイトアウト |
go('/memo') でスタックリセット → 白背景のMainActivityが見える |
push('/memo') に変更 |
| 6 | 起動が遅い(2〜3秒) | 初期化処理が直列 |
Future.wait で並列化 + FlutterEngineCache
|
| 7 | デフォルトアイコン(F ロゴ) | 生成コードはデフォルトのまま | Pillow でオリジナルアイコン生成 |
| 8 | 保存後の動作が固定 | UX要件の考慮漏れ | 設定画面で切り替え可能に |
Androidネイティブ層(Activity フラグ・権限・テーマ)は AI の生成精度が特に低い です。
この領域だけは手動での知識が必要でした。
Claude Code と GitHub Copilot、どう違うのか
Copilot も Agent モードがあり、.github/agents/ にMarkdownを置けばカスタムエージェントも作れます。
今回の開発で差を感じた場面を3つだけ挙げると:
- スキルファイルとの連携 — Copilot のエージェントはローカルファイルを Read できないため、「俺だけのナレッジベース」をエージェントに強制的に持たせられない
- 並列エージェント — 3エージェントを同時実行できるのは Claude Code だけだった
-
セッション記憶 —
MEMORY.mdで数日またいだ決定事項を引き継げる
詳細な比較は SDD でも開発を重ねた後に、改めて単独記事としてまとめる予定です。
バイブコーディングの正直な所感
よかったこと
Flutter Dart 層は AI 精度が高い
Clean Architecture の層分け、Riverpod によるDI、GoRouterのルーティング設定など、
Dartの世界で完結するコードはほぼそのまま使えるレベルで生成されました。
セキュリティレビューの網羅性が高い
人間が手動でOWASP Mobile Top 10を確認するより、エージェントの方が抜け漏れが少ない。
「知っているけど見落とす」という人間の弱点をカバーしてくれます。
設計の強制力
スキルファイルに「Platform Channel は抽象化する」と書いてあれば、
エージェントはそれを守る。人間チームで「コードレビューで指摘する」より確実です。
厳しかったこと:「最終的な仕様がわからなくなる」問題
バイブコーディング最大の問題は、仕様が霧散すること です。
「ここを直して」「あれも追加して」と繰り返しているうちに:
- 現在の実装が何をしているのか 把握できなくなる
- どこまでが意図した仕様で、どこからが場当たり修正なのか 境界が消える
- 修正が副作用を引き起こしても、影響範囲が読めない
コードを読まないバイブコーディングでは、この問題が特に深刻です。
「動いているように見えるが、本当に正しく動いているか?」という問いに答えられなくなります。
実機テストで発覚した動作不良(8件)もその典型
| 原因の根本 | 件数 |
|---|---|
| 設計書に書いていなかった仕様(AIが考慮しなかった) | 5件 |
| パッケージバージョン差異(AIの知識が古い) | 2件 |
| UX要件の考慮漏れ | 1件 |
「flutter analyze 0件・テスト全通過」でもこの結果です。
静的解析とユニットテストは「実機で動く」の代わりにはならない。
パッケージバージョン管理
AI のトレーニングデータのカットオフより新しいバージョンのAPIは知らない。
flutter_local_notifications v20 の named引数化、Riverpod 3.x の StateProvider廃止など、
バージョン差異の修正は人間が引き受ける 必要がありました。
スキルファイルを作るコスト vs 効果
「スキルファイルを書くのも結局人間の作業では?」という疑問はもっともです。
ただし:
- 一度書けば全プロジェクト・全エージェントで使い回せる(投資対効果が高い)
- チームの暗黙知を形式知化する作業と同じ(スキルファイル = チームの規約書)
- AIコレクターエージェント(
/ai-collector,/security-collector等)がベストプラクティスを収集してスキルファイルを更新する仕組みも組めば、半自動でメンテできる
まとめ
| 項目 | 内容 |
|---|---|
| 開発期間 | MVP生成1日 + 実機テスト・修正 2〜3日 |
| 生成ファイル数 | 48ファイル |
| 実機バグ数 | 8件(Androidネイティブ層に集中) |
| flutter analyze | 0 issues |
バイブコーディングは 「動くものを素早く作る」ことには強い が、
「品質を担保する」ことには構造的な弱さがある
まあ当然ですよね。
特に「仕様が霧散する」問題は、スキルファイルやエージェントパイプラインでは解決できませんでした。
スキルファイルは「どう作るか(How)」を担保するが、「何を作るか(What)」が定まっていないと機能しません。
その反省が、次の節の SDD につながります。
次回はSDD(仕様駆動開発)で製造する
バイブコーディングの反省を踏まえ、次回は SDD(Specification-Driven Development) で進めます。
バイブコーディングとの根本的な違いは 「先に仕様を完成させる」 ことです。
「追加・修正をぽんぽん投げる」のではなく、
実装を始める前に仕様書を完成させ、その仕様書からコードを生成する 順序に変えます。
仕様変更が発生した場合は、仕様を修正してその仕様を基に指示を出します。
バイブコーディング vs SDD
| バイブコーディング(今回) | SDD(次回) | |
|---|---|---|
| 出発点 | ざっくりした設計書 | 詳細な仕様書(画面・API・DB・権限すべて定義済み) |
| AIへの指示 | 「こんな感じで作って」「ここ直して」を繰り返す | 「この仕様書の通りに実装して」で完結 |
| 仕様の状態 | 開発中に変化し続ける、最終形が不明瞭 | 実装前に確定している |
| 人間の役割 | アイデア出し + 逐次修正指示 + 実機確認 | 仕様書の作成・確定 + 受け入れテスト |
| 実機バグの原因 | 仕様の曖昧さ・考慮漏れ | 仕様書に書いてあれば防げる |
今回発生した実機バグの大半は、platform/ セクションに
showWhenLocked・SCHEDULE_EXACT_ALARM などを先に書いておけば防げたものです。
仕様書に書いてあることは AI が守る。書いていないことは AI が考慮しない。それだけのことです。
スキルファイル × SDD の組み合わせ
SDD仕様書(詳細)
↓
オーケストレーター
↓
各エージェント(スキルファイルを参照しながら仕様書を実装)
↓
レビューエージェント(仕様書 vs 実装の乖離を検出)
スキルファイルが 「どう作るか」(How) を担保し、
SDD仕様書が 「何を作るか」(What) を担保する。
バイブコーディングは What が曖昧なまま How だけ整備しようとした。
それが「動くけど品質が微妙」という結果の本質的な原因でした。
次回はこの2本立てで製造します。
参考
Claude Code + 自作エージェントパイプライン + スキルファイルで開発した記録です。


