CLAUDE.mdのテンプレートを作りました
こんにちは。
最近、プロプランで使えるようになったClaude Codeで "Vibe Coding" とのたまいつつ、Vibeできずに画面の前で暇そうにしているおじさんです。
Claude Codeを試して分かったことは、CLAUDE.mdがかなり重要な役割を持つということです。
なぜなら、Claudeはあくまで「一般公開されているかつ世間で頻出する実装"っぽいもの"」をしてくれるだけなので、技術的に最適と思える実装をしてくれないからです。
ちまちまプロンプトで軌道修正していくわけですが、その内容をCLAUDE.mdに記述していくことで、二度同じ失敗を繰り返すリスクがぐっと減ります。
また、これを繰り返すとCLAUDE.mdに知見が貯まっていくため、ナレッジの蓄積として非常にシンプルかつ強力という側面もあります。
今回は、そんなCLAUDE.mdのテンプレートを作ったので、フォーマットと運用についてお話していきます。
フォーマット
章立てとしてはこんな感じです。
# CLAUDE.md
## 設計
### モデル
### アプリケーション
### システム
設計セクションを置き、それが大きく分けて3つのセクションに分かれます。
- 設計
- モデル
- アプリケーション
- システム
モデル
モデルは、いわゆるドメインモデルで、ここだけは"形式言語"を利用しました。
具体的にはTypeScriptで、以下のようにしています。
export type UUIDv7 = string;
export type DateTime = Date;
export type Email = string;
export interface Account {
id: UUIDv7
email: Email
}
export interface Login {
id: UUIDv7
expiresAt: DateTime
accountId: Account['id']
token: string // hidden
}
export interface Todo {
id: UUIDv7
title: string;
note: string;
accountId: Account['id']
}
これがほぼそのままテーブルのスキーマになるわけですが、この部分を形式言語によって"なるべく厳密"に定義しておくことには意味があります。
形式的に構造を指定することで、プロダクトとしての基本的な制約を大きく逸脱しないための防波堤の役割を果たします。
テーブルの構造はこちらで決めておきたいという目論みもありますし、形式言語による記述が同等の内容の自然言語記述に比べて簡潔であるというメリットもあります。
アプリケーション
アプリケーションセクションには、自然言語でアプリケーションとしての仕様を書いていきます。
機能やバリデーションの内容などを記載していくわけで、こちらを先に書きたい人が多いかもしれません。
画面デザインや使用感もこちらで指定します。
細かく仕様を書くことで、意図した通りの結果が出やすくなります。
筆者は以下のように箇条書きで機能を書き、細かいバリデーションや制約を追加していきました。
- サインアップ
- LPから「ログイン」ボタンを押して、ログイン/サインアップ画面に遷移
- ログイン/サインアップ画面にてメールアドレスを入力
- 登録用メールが送信され、リンクを押して登録完了
- リンクの期限は30分
- アプリトップページに遷移
- ログイン
- LPから「ログイン」ボタンを押して、ログイン/サインアップ画面に遷移
- ログイン/サインアップ画面にてメールアドレスを入力
- ログイン用メールが送信され、リンクを押してログイン完了
- リンクの期限は30分
- アプリトップページに遷移
- ログアウト
- 右上にアカウントアイコンを置き、ポップアップメニューからログアウト
- ログアウト後はログイン/サインアップ画面に遷移
- TODO作成
- `title`は必須
- `note`は任意
- TODO一覧
- ログインしているアカウント紐づくTODOをリスト表示する
- TODO編集
- TODO削除
title
やnote
と書いてある箇所は、事前にモデルとして定義されていますから、Claude側も理解し易いわけです。
これを書いた後に、「TODO作成機能を作って」というように指示すれば、ここから汲み取ってくれます。
もし作られた機能に不満があれば、細かい記述を追加していけばいいため、最初から完璧な仕様を作る必要はありません。
システム
システムのセクションには、モデルやアプリケーションで定義した内容をソフトウェア的に実現する上で必要なシステム要素を記載していきます。
利用するライブラリ、DBや認証方式、メール送信のやり方、デプロイ方式、開発方針まで様々です。
具体的には、以下のような内容になります。
#### 開発コマンド
- `npm run dev` - Turbopackを使用して開発サーバーを起動
- `npm run build` - 本番用にアプリケーションをビルド
- `npm run start` - 本番サーバーを起動
- `npm run lint` - ESLintを実行してコード品質をチェック
- `npm run db:migrate` - データベースマイグレーションを実行
- `npm run db:generate` - Prismaクライアントを生成
- `npm run db:push` - スキーマ変更をデータベースにプッシュ
- `npm run db:studio` - データベース管理用のPrisma Studioを開く
#### セットアップ手順
1. Dockerサービスを開始: `docker-compose up -d`
2. 依存関係をインストール: `npm install`
3. データベーススキーマをプッシュ: `npm run db:push`
4. Prismaクライアントを生成: `npm run db:generate`
5. 開発サーバーを起動: `npm run dev`
開発中に送信されたメールを確認するには、http://localhost:8025 でMailHog Webインターフェースにアクセスしてください。
#### フレームワーク
- Next.js 15
- App Router
#### スタイリング
- Tailwind CSS v4 with PostCSS
- フォントはGeist SansとGeist MonoがCSS変数として設定済み
#### 言語
- TypeScript
- パスエイリアス(`@/*`はプロジェクトルートにマップ)を使用したStrictモードが有効
#### DB
- mysql
- prisma
- ローカルではdockerイメージを利用して、docker-compose.ymlに追加
#### SMTP
- ローカルではmailhogのdockerイメージを使用して、docker-compose.ymlに追加
#### 認証
- サインアップあるいはログインに成功すると、`Login`データが作成され、その`token`がクッキー内に設定される。
- 各リクエストにおいて、設定された`token`を元にDB検索を行い、期限切れをしていない`Login`データが存在すれば、認証成功とする。
- ユーザー情報が必要な場合は、`Login.accountId`を元に引いてくることができる。
- ログアウト時は、`Login`データを削除する。
- `token`は発行時にURLパラメータにのみ設定してよく、データベースから取得してはならない。クッキーから取得した`token`を絞り込み条件で比較するのはOK。
#### 開発方針
- `app`配下はサーバーコンポーネントを置き、機能固有のクライアントコンポーネントは`components/features`配下に置いてimportする
- 通信はなるべくサーバーアクションで行い、サーバーコンポーネントからクライアントコンポーネントにインジェクトする
ようするに、技術関連の事柄はすべて「システム」として詰め込んでしまうということになります。
Claude Codeに期待されていた方は、こういう内容こそ書かなくても勝手にやってくれよと思うわけですし、筆者もそう思っていましたが、やはり出来上がってくるソースコードの品質やセキュリティリスクを鑑みると、なるべく詳細に指定した方がいいと思います。
また、プロジェクト間で使いまわせる内容になるため、社内における共有資産としての価値は高いのではないかと思います。
あとは、Anthropicの記事にもあるように「毎回TypeCheckをしてね」みたいな指示をワークフローとして記載してもいいかもしれません。
感想
皆さん思ったかもしれませんが、「意外になんでもやってくれるわけではないんだな」と思いました。
最初筆者はCLAUDE.mdの重要性を理解しておらず、勝手に生成されたままにしてプロンプトを重ねてたわけですが、なかなか品質が安定しないためこの方式に落ち着きました。
普段からこの程度の設計はやっていたわけなので、正直全く苦にはなりませんが、素人が理解してできるかと言われると難しいでしょう。
あと、CLAUDEが作業している間がとてつもなく暇で、Vibe Coding中は携帯ゲーム機を持参することが推奨されるかもしれません。(冗談です)
一つ不便だったのは、ターミナルに出ているエラーを直接読み取ってくれるわけではないことでした。(もしかするとやり方があるかもしれません)
この点は、E2Eテストを作らせて、関連するテストを実行し、不具合を自動検知して修正するようにしてもいいかもしれません。(E2Eテストもアプリケーションセクションの情報から簡単に作ってくれるはず)
また、結構アグレッシブにプロセスをKillしたりもするので、ClaudeをDockerコンテナのようなサンドボックス環境で動かして、開発環境の構築・開発サーバーの起動・プロセス管理などもすべて任せられれば楽だなと思いました。
こちらは今後の取り組みにする予定です。
Discussion