はじめに
ACCESS Advent Calendar 2025の19日目の記事です。
今日は仕様駆動開発(Spec-Driven Development; SDD)ツールの一つである OpenSpec を、実際の生成物を交えて紹介していきます。
SDDとは何か
AIコーディングアシスタントを使った開発が当たり前になってきた昨今、皆さんもこんな経験はないでしょうか。
「なんとなくAIに指示を出したら、思っていたのと全然違うコードが生成された」
これは俗に「Vibe coding」と呼ばれる開発スタイルで起こりがちな問題です。AIに任せきりにした結果、開発者の意図と乖離したコードが生まれてしまう。AIは優秀ですが、私たちの頭の中にある要件を正確に読み取ることはできません。
そこで登場したのが仕様駆動開発(SDD)です。考え方はシンプルで、「AIと対話しながら仕様を先に固め、それに基づいてコードを生成する」というもの。従来はコードが真実の源泉でしたが、SDDでは仕様書(Spec)がその役割を担います。AIは仕様書を参照しながらコードを生成するため、意図との乖離が起きにくくなります。
2025年現在、SDDを実践するためのツールがいくつか公開されています。GitHub公式の Spec Kit、日本人開発者による cc-sdd、MCPで実現する Spec Workflow MCP、そして本記事で紹介する OpenSpec などがあります。
なぜOpenSpecを選んだか
数あるSDDツールの中から、私がOpenSpecを選んだ理由を紹介します。
まず、生成されるドキュメントの量が比較的少ないことが挙げられます。OpenSpecで機能を作成すると、以下のようなファイルが生成されます。
openspec/
└── changes/
└── {change-spec-id}/
├── proposal.md # なぜ・何を変更するか
├── tasks.md # 実装チェックリスト
├── design.md # 技術的な設計判断(オプショナル)
└── specs/
└── {capability}/
└── spec.md # 仕様の差分
一方、GitHub Spec Kitでは初期化時に5つのディレクトリ(memory、scripts、specs、templates、out)が生成され、より包括的なワークフローを提供します(公式リポジトリ参照)。どちらが良い悪いという話ではなく、今回は仕様がある程度決まっていたので、軽量なOpenSpecが適していると判断しました。
次に、Brownfield-firstというアプローチへの共感があります。これは都市計画由来の用語で、「既存の土地を優先的に再開発する」という考え方です。OpenSpecでは「既存プロジェクトにも適用可能なSDD」という意味で使われています。実際の業務では、ゼロから作るより既存コードベースに機能を追加することの方が多いですよね。OpenSpecはそういった現実的なシナリオを想定しています。
そして、Claude CodeやGitHub Copilotなど主要なAIツールに対応していることも重要でした。私の案件ではプロジェクト内で各人が異なるAIエージェントを使っている状況なので、ツールを統一できるのは大きなメリットです。
OpenSpecの基本ワークフロー
実践例に入る前に、OpenSpecの基本的な使い方を押さえておきましょう。
1. openspec init で初期化
2. /openspec:proposal で変更提案作成
3. Specレビュー・修正
4. /openspec:apply で実装
5. /openspec:archive でアーカイブ
ポイントは、これらのスラッシュコマンドを覚えなくても良いということです。「OpenSpecで設計して」と自然言語で指示すれば、同じことができます。ただし、「○○について設計して」だけだとOpenSpecを使わずに設計を始めてしまうことがあるので、OpenSpecを使いたい場合は明示的に指定した方が確実です。
また、実装完了後のアーカイブのタイミングは、組織の開発フローに合わせて決める必要があります。ポイントは、PRレビュー中に仕様が変わる可能性があるため、Approve前にアーカイブしないことです。私は以下のような流れが良いと考えています。
- 実装完了後、アーカイブせずにPRレビュー依頼
- レビュー(この段階で仕様変更があればSpecも修正)
- PRがApproveされる
- アーカイブ実行し、commit(それ以外の修正は行わない)
- マージ
実践:CloudTrail CDK実装で試してみた
では、実際にOpenSpecを使ってみた例を紹介します。今回はAWS CloudTrailのCDK実装を題材にしました。CloudTrailはAWSを使う上で全アカウントで設定すべき項目なので、馴染みがある方も多いのではないでしょうか。
もっと大きな単位で依頼することもできますが、今回はお試しということもあり、また実際の業務ではチケット単位で実装を進めることも多いと思うので、CloudTrailのみを対象としています。
実際に使用したプロンプト
以下は、私がClaude Codeに入力したプロンプトです。
(プロンプトの良し悪しについては目を瞑ってください…笑)
openspecを使ってcdk/appにCloudTrailの機能を追加したい。
コスト重視としてS3のみに保存しCloudWatchには保存しない。
ただしログファイル検証などセキュリティ的に重要な項目は有効化したい。
S3バケットは同じアカウントに作成し、システムログ用のバケットとして新しく作成することを考えている。
S3バケットの中身はS3-ITで自動コスト最適化を考えている。
AWSのベストプラクティスに従うような設定で作成したい。
このプロンプトを入力すると、OpenSpecが以下のようなドキュメントを生成してくれました。なお、以下はAI生成のままの内容です。実際の運用ではレビュー時に技術的な正確性を確認することが重要です。
proposal.md(変更提案書)
# Change: CloudTrailログ機能の追加
## Why
AWSアカウント内のAPIアクティビティを監査・追跡するため、CloudTrailを導入する。
これにより、セキュリティ監査、コンプライアンス要件への対応、およびトラブルシューティングが可能になる。
## What Changes
- cdk/app に CloudTrail Trail リソースを追加
- システムログ用の S3 バケットを新規作成(CloudTrail ログ保存先)
- コスト最適化: CloudWatch Logs への配信は行わず、S3 のみに保存
- セキュリティ強化: ログファイル検証(integrity validation)を有効化
- ストレージ最適化: S3 Intelligent-Tiering によるコスト自動最適化
## Impact
- Affected specs: なし(新規capability)
- Affected code:
- cdk/app/lib/stacks/GlobalStack.ts - CloudTrail と S3 バケットの追加
- cdk/app/lib/constructs/ - 新規 Construct の作成(SystemLogBucket, CloudTrailLogging)
design.md(技術設計書)
# Design: CloudTrailログ機能
## Context
AWSアカウント内のAPIアクティビティを監査・追跡するため、CloudTrailを導入する。
コスト効率を重視しつつ、セキュリティベストプラクティスに準拠した設計とする。
### 制約
- CloudWatch Logsへの配信は行わない(コスト削減)
- S3バケットは同一アカウント内に作成
- セキュリティ上重要な設定(ログファイル検証等)は有効化必須
## Goals / Non-Goals
### Goals
- AWSアカウント内の全APIアクティビティを記録
- ログファイルの完全性を検証可能にする
- ストレージコストを自動最適化する(S3 Intelligent-Tiering)
- AWSセキュリティベストプラクティスに準拠
### Non-Goals
- リアルタイムアラート(CloudWatch Logsを使用しないため)
- ログの長期アーカイブポリシーの詳細設計(将来の拡張として検討)
- 組織全体のCloudTrail(Organization Trail)
## Decisions
### 1. S3バケット設計
決定: システムログ専用のS3バケットを新規作成し、CloudTrailログを格納
設定内容:
- バケット名: {project-name}-{env}-system-logs
- 暗号化: SSE-S3(Amazon S3マネージドキー)
- パブリックアクセスブロック: 全て有効
- バージョニング: 無効(ログは上書きされないため不要)
- オブジェクトロック: 無効(コスト削減、必要に応じて将来追加)
代替案:
- SSE-KMS使用 → 追加コストが発生するため却下
- 既存バケット利用 → 責任分界点が不明確になるため却下
### 2. S3ライフサイクル設計
決定: S3 Intelligent-Tiering を使用したコスト自動最適化
設定内容:
- Archive Access Tier: 90日後
- Deep Archive Access Tier: 180日後
代替案:
- 固定ストレージクラス遷移 → アクセスパターンに依存するため柔軟性が低い
- ライフサイクルルールなし → 長期的にコストが増大
### 3. CloudTrail設計
決定: マルチリージョン対応のTrailをGlobalStack(us-east-1)に作成
配置理由:
- CloudTrailはグローバルサービスであり、us-east-1に配置するのがAWSのベストプラクティス
- マルチリージョントレイルは1つのリージョンから全リージョンのイベントを収集可能
- GlobalStackに配置することで、他のグローバルリソース(CloudFront等)と一貫性を保つ
設定内容:
- isMultiRegionTrail: true(全リージョンのイベントを記録)
- includeGlobalServiceEvents: true(IAM等のグローバルサービスを含む)
- enableFileValidation: true(ログファイル検証有効)
- sendToCloudWatchLogs: false(コスト削減)
- insightTypes: [](CloudTrail Insights無効、コスト削減)
### 4. Construct構成
決定: 2つのConstructに分離して実装
- SystemLogBucket.ts: システムログ用S3バケット
- CloudTrailLogging.ts: CloudTrail Trail
理由:
- 単一責任の原則に従う
- SystemLogBucketは将来他のログ(ALB、CloudFront等)にも利用可能
- テスタビリティの向上
## Risks / Trade-offs
| リスク | 影響 | 緩和策 |
|--------|------|--------|
| CloudWatch Logs無効によりリアルタイム監視不可 | 中 | 将来必要になった場合は追加設定で対応可能 |
| S3バケット削除時のログ消失 | 高 | RemovalPolicy.RETAIN を設定 |
| Intelligent-Tiering最小ストレージ期間(30日)によるコスト | 低 | アーカイブ層への移行で長期的にはコスト削減 |
tasks.md(実装タスクリスト)
# Tasks: CloudTrailログ機能の追加
## 1. システムログ用S3バケットの実装
- [x] 1.1 cdk/app/lib/constructs/SystemLogBucket.ts を作成
- S3バケットの作成(暗号化: SSE-S3、パブリックアクセスブロック有効)
- S3 Intelligent-Tiering ライフサイクル設定
- サーバーアクセスログの設定(オプショナル)
- [x] 1.2 cdk/app/lib/constructs/SystemLogBucket.test.ts を作成
- バケット暗号化のテスト
- Intelligent-Tiering設定のテスト
- パブリックアクセスブロックのテスト
## 2. CloudTrail Constructの実装
- [x] 2.1 cdk/app/lib/constructs/CloudTrailLogging.ts を作成
- CloudTrail Trail の作成
- マルチリージョン有効化
- グローバルサービスイベント有効化
- ログファイル検証有効化
- S3バケットへのログ配信設定
- CloudWatch Logs への配信は無効
- [x] 2.2 cdk/app/lib/constructs/CloudTrailLogging.test.ts を作成
- Trail設定のテスト
- ログファイル検証有効化のテスト
- S3配信設定のテスト
## 3. GlobalStackへの統合
- [x] 3.1 cdk/app/lib/stacks/GlobalStack.ts を更新
- SystemLogBucket の追加
- CloudTrailLogging の追加
- ※ CloudTrailはグローバルサービスのためGlobalStack(us-east-1)に配置
- [x] 3.2 ビルドとテストの実行
- pnpm -C cdk/app run build
- pnpm -C cdk/app run test
## 4. 検証
- [x] 4.1 CDK synth でCloudFormationテンプレートを確認
- [x] 4.2 セキュリティ設定の最終確認
プロンプトに書いた要件が、proposal.mdの「What Changes」にきちんと反映されていることが分かります。また、design.mdでは「なぜこの設定にしたか」「代替案として何を検討したか」が記録されており、後からレビューする際にも設計意図が伝わりやすくなっています。
所感・まとめ
OpenSpecを使うことで、レビュー負担が大きすぎないSDDを試すことができました。特に良かったのは、コードだけでは伝わりづらい設計判断(なぜこの設定値にしたか、なぜこの構成にしたか、など)をドキュメントとして残せる点です。
また、この後実装してもらったコードは大きな修正をすることなくマージできました。手戻りなく実装を進められたことで、SDDの有用性を実感できました。
一方で、いくつか気になる点もありました。OpenSpecを使う場合、チーム全体で導入しないとopenspec/*内のドキュメントと実装が乖離してしまう懸念があります(他の人がドキュメントを修正せずに実装だけを修正してしまうなど)。また、最近のClaude CodeのPlanモード自体もかなり有能なので、うまく使い分けを考えたいところです。
なお、SDDにおいてSpecが肥大化してレビュー負荷が大きくなることなど、様々な課題についてはcc-sdd作者のGota氏による仕様駆動開発の理想と現実、そして向き合い方が非常に分かりやすいので、ぜひ読んでみてください。
SDDツールは他にも Spec Kit や cc-sdd、Spec Workflow MCP などがあります。チームの開発スタイルやプロジェクトのフェーズに合わせて、自分たちに合ったツールを見つけてみてください。
おわりに
ACCESS Advent Calendar 2025、明日の担当は @Momijinn です。お楽しみに!