every Tech Blog

株式会社エブリーのTech Blogです。

Cursor Custom modes を利用した cursor-memory-bank のワークフローを試してみる

はじめに

こんにちは。リテールハブ開発部の池です。

エブリーは 2025/05/02 にプレスリリースを出した通り Cursor を全エンジニアとプロダクトマネージャーに導入し、AI活用による生産性の向上に積極的に取り組んでいます。

corp.every.tv

現在、世の中では Cursor のような開発支援ツールを使ってLLMをベースとしたエージェントの開発ワークフローを構築する動きが進んでいます。

エージェントに安定した挙動をさせるには、一貫したコンテキストの提供が必要であり、永続的なルールやファイルを用いてその振る舞いを制御するアプローチが一般的になりつつあります。 これには単なるドキュメント整備ではなく、ルールの構造化された設計が必要です。

  • どのような種類のファイルが必要か
  • どのフォーマット・テンプレートで記述するのか
  • エージェントはどのタイミングでそれを参照するのか
  • どのように内容を更新して永続化し続けるのか

こうしたルール設計は現状はまだ標準が存在せず、黎明期にあると感じています。

そのような環境において、私にとって有用な情報源となっているのが Reddit や Discord、X などの Cursor コミュニティです。 コミュニティでは多くのユーザーが日々の試行錯誤を共有しあっているため、ユーザーの実体験に基づいた新しい知見をキャッチアップするには非常に役立ちます。

この記事では、コンテキスト管理の必要性を説明した後、コミュニティの中で興味を持った Cursor Custom modes を活用したワークフローの手法 vanzen01/cursor-memory-bank について、試してみたいと思います。

※ Cursor 公式のワークフローではないのでご注意ください。

LLMを活用した開発における課題

まず前提として、LLMは、コンテキストウィンドウを超えた情報を保持できず、基本的には直近のトークンのみ参照します。 つまり、一定のトークン数を超えると文脈が途切れ、過去のやりとりを忘れてしまうような現象が起こります。 (ただし、モデルによっては古い情報が影響を弱めながら残るケースもあるようです。)

この問題は、プロジェクトの開発を進める中で頻繁に起こるので、文脈の持続が求められるタスクにおいて進捗を悪くする要因になります。 そのため、コンテキストを効率よく管理して適切な量の情報をLLMに渡すことが鍵となってきます。

コンテキストウィンドウとは

コンテキストウィンドウとは、モデルが一度のプロンプトや会話履歴として「認識・参照」できるトークンの最大量のことです。

コンテキストサイズの比較表(2025年5月時点)は次のようになっています。このウィンドウサイズに収まるようにコンテキスト管理を行うことが重要です。 また、コード生成において、コンテキストサイズを超えずとも回答精度が悪くなるという声もあるため、コンテキスト量を抑えることが大事になります。

2025年5月時点における、主要なモデルのウィンドウサイズは以下のようになっています。

モデル名 コンテキストウィンドウサイズ リリース時期
GPT-4.1 1,000,000トークン 2025年4月
GPT-4.5 128,000トークン 2025年2月
o3 200,000トークン(入力)/100,000トークン(出力) 2025年4月
o4-mini 200,000トークン(入力)/100,000トークン(出力) 2025年4月
o4-mini-high 200,000トークン(入力)/100,000トークン(出力) 2025年4月
Claude 3.5 Sonnet 200,000トークン 2024年6月
Claude 3.7 Sonnet 200,000トークン 2025年2月
Gemini 2.5 Pro 1,000,000トークン 2025年4月

また、トークン数に加えて各モデルにおいて得意/不得意な作業があるため、それを考慮してモデル選択を行うことが大事です。

コンテキスト管理のアプローチ

コンテキスト管理は様々なアプローチが考えられます。

1. タスクの分割と設計

トークン制限を考慮して、タスクを小さく分割し、それぞれのタスクに必要なコンテキストだけを提供することで、精度を保つことができます。

詳しくは本記事では触れませんが、タスク管理については claude-task-master を活用する事例をコミュニティで よく目にするので、よかったら参照してください。

2. メモリバンクの活用

メモリバンクとは、エージェントが参照すべき知識や振る舞いのルールを構造化して保存する仕組みです。 ここで扱っているメモリバンクはあくまで外部ドキュメントを明示的にコンテキストとして毎回渡す設計であり、モデル自体に永続的に記憶されるわけではありません。

詳しくはCline Memory Bankを参照ください。

上記はClineが提唱するメモリバンクですが、Cline専用の機能ではなく方法論であるため、同じ仕組みをCursorに適用することができます。

3. モデルの使い分け

モデルごとに特性やコンテキストウィンドウサイズが異なるため、タスクの性質に応じて最適なモデルを選択することで、コンテキスト効率と精度の両方を向上させることができます。

私は直近では以下の二つを使い分けています。

  • Claude 3.7 Sonnet:比較的小さいコンテキストで高精度が求められる場面、特にコード理解や分析タスク
  • Gemini 2.5 Pro:大規模な設計・全体構成把握など、複雑なプロジェクト構造の理解

4. ワークフローの定義

ワークフローを明確に定義し、作業ごとのコンテキストを効率的に引き継ぐことが重要です。 例えば、「計画→実装→テスト→レビュー」という流れで、各ステップに必要な情報だけを選択的に提供することで、トークン消費を抑えながら一貫性を保てます。

5. 外部からコンテキストを取得する

コンテキスト管理からは少し外れますが、MCPやRAG(検索拡張生成)などを利用して、社内の文書管理システムやFigmaの設計データなどを動的に検索・取得し、必要に応じてLLMに渡すことで、リポジトリ外の情報も活用できます。 リポジトリで管理できない社内ドキュメントや、テキストとしてコピーしづらいようなFigmaデザインデータなどをMCPやRAGなどを通じて取得・更新すると便利です。

Cursor Custom modes を利用した cursor-memory-bank を試す

以上のコンテキスト管理の必要性とアプローチ方法を踏まえつつ、ここからは2025年3月 Cursor v0.48 で搭載されたカスタムモードを利用したコンテキスト管理のワークフローについて、私が興味を持った下記プロジェクトの手法を試してみます。

github.com

このプロジェクトではCursorのカスタムモードを活用し、AIがセッション間での記憶を維持しながら、構造化された開発ワークフローを実現することを目的としています。

本記事は Cursor v0.48 時点での設定方法に基づいています。以降のバージョンでUIや設定項目が変更される可能性があるのでご注意ください。

また、cursor-memory-bank も v0.6-beta 時点のワークフローに基づいており、ちょうど執筆時点で v0.7-beta にアップデートされていたため、最新のワークフローとは多少異なっています。

Cursor Custom modes とは

Custom modes とは、Cursor のモードを独自に定義できる機能です。使用するツール、モデル、ルール等を設定した独自のモードを作成することができます。

このカスタムモードを活用することで、例えばコード生成時とコードレビュー時で異なるルールセットを適用できるため、それぞれのワークフローに特化した作業を行わせることができるようになります。

Custom modes 始め方

1. Cursor Settings > Features の Custom modes を許可する

2. Chatセクションのモード選択 > Add custom mode を選択

3. 必要なルールを設定する

cursor-memory-bank を試してみる

cursor-memory-bank は Cursor のカスタムモードを通じて、以下の4つの開発フェーズに対応するモードを提供します。

  • VANモード:プロジェクトの初期化とメモリバンクの設定
  • PLANモード:タスクの計画と戦略の立案
  • CREATIVEモード:設計とアイデアの創出
  • IMPLEMENTモード:実装と進捗の管理

これにより、各ワークフローに特化した一貫性のある開発を行います。

※ v0.6-beta 時点のワークフローです。

VAN → PLAN → CREATIVE → IMPLEMENT という順に実行して開発を行います。

設定方法

cursor-memory-bank をプロジェクトに適用する手順は以下の通りです:

1. リポジトリのクローン

cursor-memory-bankをクローンし、作業するプロジェクトに移します。

git clone https://github.com/vanzan01/cursor-memory-bank.git

2. Custom modes の設定

各開発フェーズのモード(VAN, PLAN, CREATIVE, IMPLEMENT)を作成します。

例)PLANモードの設定

エージェントへの指示もPLANモード用の内容をカスタムモードに設定します。

詳細な設定方法はcursor-memory-bankのREADMEに記載があるのでそちらを参照ください。

実行方法

次に、各モードを使った実際の実行例を紹介します。

サーバー側で、モバイルアプリの強制アップデートが必要かどうかを判定するミドルウェア機能を実装するタスクが、ちょうど良い大きさのタスクだったので、その機能の実装で試します。

VANモード

カスタムモードで設定したVANモードを選択して「VAN」と入力すると、プロジェクト全体を読み込み、メモリバンクの初期化を行います。

ただし、今回は使い方や設定に誤りがあったのか、この方法ではメモリバンクの各ファイルの内容が生成されませんでした。

そこで、今回は gemini-2.5-pro-exp-03-25 モデルを利用し、チャット上で指示をしてプロジェクト全体のコンテキストをドキュメント化しました。

Gemini 2.5 Pro はコンテキストウィンドウサイズが1Mと大きく、プロジェクト全体を解釈して設計や計画立てを行うことが得意であるため、 メモリバンクのコンテキスト生成時に利用すると比較的詳細にドキュメント化してくれます。

PLANモード

PLANモードは memory-bank/tasks.md のタスク内容から設計や実装計画を作成します。

事前に要件や仕様を memory-bank/tasks.md に記述した上で、PLANモードを選択して「PLAN MODE」と入力すると、計画立てしてくれます。 実行する際は、新しいチャットを開いて行うのがおすすめです。

参考までに memory-bank/tasks.md の内容は以下です。 足りない部分はチャットしながら補う前提でざっくりとした記述となっています。

memory-bank/tasks.md を表示

## 要件・仕様

- OSごとに強制アップデートのバージョンを指定できる
- 強制アップデート条件
  - サーバーで設定されている強制アップデートバージョン > アプリバージョン

## 設計
- アプリ
  - 全APIのリクエストヘッダーに下記情報を付与
    - OS:XX-XXX-XXXX
      - `iOS`
      - `Android`
    - アプリバージョン:XX-XXX-XXXX
      - `1.0.0`
  - サーバーからHTTPステータスコード427が返却された場合に強制アップデートのダイアログを表示する

- サーバー
  - アプリ向けの全APIにおける共通処理のミドルウェアとして実装
  - リクエストヘッダーで必要な情報を受け取る
    - OS:XX-XXX-XXXX
    - アプリバージョン:XX-XXX-XXXX
  - OSもしくはアプリバージョン情報がリクエストヘッダーにない、もしくは不正だった場合はエラー
    - HTTPステータスコード 400?
  - OSおよびアプリバージョン情報をもとにバージョン判定を行う
    - 強制アップデート対象の場合 HTTPステータスコード427を返却

mermaid
flowchart TD
    A[バージョン要件を判定するミドルウェア] --> B[HTTPリクエストヘッダーからアプリのバージョン情報を取得]
    B --> C{バージョン情報が有効か}
    C -- No --> D[エラー HTTPステータスコード 400 返却]
    C -- Yes --> F[HTTPリクエストヘッダーから端末のOS情報を取得]
    F --> G{バージョン情報が有効か}
    G -- No --> D
    G -- Yes --> H{バージョン情報とOS情報から強制アップデート対象判定}
    
    H -- No --> J[ミドルウェア終了。次の処理に進む。]
    H -- Yes --> I[エラー HTTPステータスコード 427 Require Update 返却]
    
    subgraph バージョン判定ロジック
        K[OS情報からサーバーで定義されているiOSもしくはAndroid のminVersion を取得]
        K --> L{アプリバージョン < minVersion}
        L -- No --> M[Return False]
        L -- Yes --> N[Return True]
    end

    H --> |バージョン判定ロジック| K

入力内容はこちら。

以下が実行結果です。今回は1回の指示のみで詳細な計画を立ててくれました。 memory-bank/ 配下のファイルを詳細に記述しておくなど、前段の準備をしっかりしておくことで、チャットへの入力はほとんど無く詳細な結果を返却してくれます。

PLANモード 実行結果を表示

# 強制アップデート機能 実装計画(PLAN MODE)

## 1. 要件分析(Requirements Analysis)

- [x] OSごとに強制アップデートのバージョンをサーバー側で指定できる
- [x] サーバーで設定された強制アップデートバージョン > アプリバージョンの場合、強制アップデートを要求
- [x] 必要なリクエストヘッダー(RA-Device-OS, RA-App-Version)がない/不正な場合は400エラー
- [x] 強制アップデート対象の場合はHTTP 427(Require Update)を返却

### 技術的制約
- [x] サーバー側は全APIに対して共通ミドルウェアとして実装
- [x] バージョン情報・OS情報はリクエストヘッダーで受け取る
- [x] サーバー側でOSごとのminVersionを管理

---

## 2. コンポーネント分析(Component Analysis)

### 影響範囲
- APIサーバー(Laravel想定)
  - 共通ミドルウェア層(全APIに適用)
  - バージョン管理設定(config or DB)
  - エラーハンドリング(400, 427)
- クライアント(アプリ)
  - ヘッダー送信
  - 427受信時のダイアログ表示(※サーバー側計画外)

### 変更点・依存関係
- ミドルウェア新規作成
  - リクエストヘッダー検証
  - バージョン判定ロジック
  - エラー/強制アップデート応答
- 設定管理
  - OSごとのminVersionをどこで管理するか(configファイル or DB)
- テスト
  - 単体テスト(ミドルウェア)
  - 統合テスト(API経由)

---

## 3. 設計判断(Design Decisions)

### アーキテクチャ
- [x] LaravelのHTTPミドルウェアとして実装
- [x] 設定は `config/force_update.php` などで管理(初期はファイル、将来的にDB化も考慮)
- [x] バージョン比較はSemver互換の比較ロジックを実装

### UI/UX
- [ ] サーバー側は非該当(アプリ側で427時にダイアログ表示)

### アルゴリズム
- [x] バージョン比較ロジック(Semver対応)
- [x] ヘッダー検証ロジック

---

## 4. 実装戦略(Implementation Strategy)

### フェーズ1: ミドルウェア実装
- [ ] ミドルウェア新規作成(例:`ForceUpdateMiddleware`)
- [ ] ヘッダー検証
- [ ] バージョン判定ロジック実装
- [ ] 設定ファイル作成(`config/force_update.php`)

### フェーズ2: エラー・強制アップデート応答
- [ ] 400, 427レスポンスの実装
- [ ] エラーハンドリングの統一

### フェーズ3: テスト・ドキュメント
- [ ] 単体テスト(ミドルウェア)
- [ ] 統合テスト(API経由)
- [ ] API仕様書・README更新

---

## 5. テスト戦略(Testing Strategy)

- [ ] ヘッダーが正しい場合/不正な場合のテスト
- [ ] バージョンがminVersion未満/以上のテスト
- [ ] OSごとの分岐テスト
- [ ] 400, 427レスポンスの検証
- [ ] テストカバレッジの確認

---

## 6. ドキュメント計画(Documentation Plan)

- [ ] API仕様書(リクエストヘッダー、エラーコード追加)
- [ ] 実装手順・設定方法のREADME追記
- [ ] テストケース一覧

---

## 7. クリエイティブフェーズ要否(Creative Phase Identification)

- UI/UX: **不要**(サーバー側のみ)
- アーキテクチャ: **必要**(設定管理方法、バージョン比較ロジック設計)
- アルゴリズム: **必要**(Semver比較)

---

## 8. チェックリスト(Verification Checklist)

- [x] 要件がすべて網羅されている
- [x] 影響範囲・コンポーネントが明確
- [x] 設計判断・実装戦略が明記されている
- [x] テスト・ドキュメント計画がある
- [x] クリエイティブフェーズ(アーキテクチャ・アルゴリズム)が明示

---

### 次モード推奨

- **アーキテクチャ設計・バージョン比較ロジックの詳細設計が必要なため、次は「CREATIVE MODE」推奨。**

CREATIVEモード

PLANモードで、アーキテクチャ設計・バージョン比較ロジックの詳細設計が必要ということだったので、CREATIVEモードを用いてその作業を行います。 今まで同様に、CREATIVEモードを選択して「CREATIVE MODE」を入力します。

この際に、claude-3.7-sonnet の Thinking を設定することでより高精度な設計を行ってくれます。

CREATIVEモード 実行結果を表示(一部)

# 強制アップデート機能 バージョン比較アルゴリズム設計

🎨🎨🎨 ENTERING CREATIVE PHASE: ALGORITHM 🎨🎨🎨

Focus: 強制アップデート機能におけるバージョン比較ロジック
Objective: 正確かつ効率的なバージョン比較アルゴリズムを設計する
Requirements:
- 基本的なバージョン比較(X.Y.Z形式)
- リクエストヘッダーから取得したバージョン文字列の検証
- パフォーマンスを考慮した実装
- シンプルな実装を重視

## コンテキスト

### アルゴリズム要件
- バージョン形式: `X.Y.Z`(メジャー.マイナー.パッチ)の形式のみ
- 無効なバージョン文字列の検出と処理
- 単純なバージョン比較(新しいか古いか)

### 技術的制約
- PHPでの実装
- 高速な比較処理(全リクエストで実行されるため)
- LaravelミドルウェアからのAPIとしての利用しやすさ

## バージョン比較アルゴリズムのオプション

### オプション1:独自実装(カスタムロジック)
- **説明**: PHPの文字列操作と数値比較を用いた独自実装
- **手法**:
  1. バージョン文字列を`.`で分割
  2. メジャー、マイナー、パッチそれぞれを数値比較
- **長所**:
  - 完全にカスタマイズ可能
  - 外部依存がない
  - 特定のユースケースに最適化可能
- **短所**:
  - 実装の複雑性
  - エッジケースの見落としリスク
  - メンテナンスコスト
- **計算量**: O(n)(nはバージョン文字列の長さ)
- **実装複雑性**: 中

### オプション2:既存のライブラリ活用(composer/semver)
- **説明**: Composerが提供する`composer/semver`パッケージを使用
- **手法**:
  1. `composer/semver`をインストール
  2. `Comparator`クラスの`lessThan()`/`greaterThan()`メソッドを使用
- **長所**:
  - 広く使われており信頼性が高い
  - SemVerの仕様に準拠
  - メンテナンスの心配がない
- **短所**:
  - 外部依存関係の追加
  - 多少のオーバーヘッド
  - シンプルなケースには過剰な機能
- **計算量**: ライブラリ内部実装に依存
- **実装複雑性**: 低

### オプション3:PHP標準関数 version_compare
- **説明**: PHPの標準関数`version_compare()`を使用
- **手法**:
  1. `version_compare($version1, $version2, $operator)`を呼び出し
  2. 結果に基づいて判定
- **長所**:
  - PHPに標準搭載
  - 追加依存関係が不要
  - シンプルなAPI
  - 高速な処理
- **短所**:
  - 複雑なバージョン比較ケースには不向き(今回は必要なし)
- **計算量**: O(n)(PHPの内部実装による)
- **実装複雑性**: 非常に低

## 決定

- **選択したオプション**: オプション3(PHP標準関数 version_compare)
- **理由**:
  - PHPに標準搭載されており外部依存関係が不要
  - シンプルで高速な実装が可能
  - 基本的なX.Y.Z形式のバージョン比較に十分対応
  - 追加のパッケージ導入が不要でプロジェクトが軽量化
  - 今回の要件に最適なシンプルさを提供

- **実装ガイドライン**:
  // バージョン比較
  public function isUpdateRequired(string $clientVersion, string $requiredVersion): bool
  {
      return version_compare($clientVersion, $requiredVersion, '<');
  }
  
  // バージョン検証(X.Y.Z形式のみ許可)
  public function isValidVersion(string $version): bool
  {
      // X.Y.Zの形式のみ許可する単純な正規表現
      $pattern = '/^\d+\.\d+\.\d+$/';
      return preg_match($pattern, $version) === 1;
  }

## 検証

- 要件の充足:
  - [✓] 基本的なバージョン比較(X.Y.Z形式)
  - [✓] バージョン文字列の検証
  - [✓] パフォーマンスへの配慮
  - [✓] シンプルな実装
- 技術的実現性: 高(PHP標準関数を使用)
- リスク評価: 低(PHPの標準機能に依存)

🎨 CREATIVE CHECKPOINT: アルゴリズム設計確定
- 進捗: バージョン比較ロジックの決定完了
- 決定: PHPの標準関数version_compareと単純な正規表現を使用
- 次のステップ: ForceUpdateMiddlewareの実装

🎨🎨🎨 EXITING CREATIVE PHASE 🎨🎨🎨
Summary: バージョン比較アルゴリズムとして、シンプルさと実装の容易さを考慮してPHPの標準関数`version_compare`を採用。基本的なX.Y.Z形式のバージョン検証のみを行う単純な実装アプローチを決定。
Key Decisions:
- PHPの標準関数version_compareを使用してバージョン比較を実装
- シンプルな正規表現によるX.Y.Z形式のみの検証
- 外部依存関係を減らしたシンプルな実装
Next Steps:
- ForceUpdateMiddlewareへの実装
- 単体テストによる検証 

複数の設計パターンを検討し、採用した設計の意思決定の内容まで記述してくれました。

IMPLEMENTモード

以上の実装計画と設計をもとに実装します。 IMPLEMENTモードを選択して「IMPLEMENT MODE」と入力すると実装に進みます。 ここで新しいチャットを開いて実行すると良いでしょう。

結果は長いので割愛しますが、1回のやり取りでは全て完璧な実装とはならず、テストまで全て成功するまでには何度かやり取りを繰り返しました。 ただ、計画のチェックリストに自動的にチェックをつけながら実装してくれるため、内容の網羅性が高く、また、効率的なやり取りを行えると感じました。

まとめ

今回は簡単な機能実装を例に Cursor Custom modes を利用した cursor-memory-bank のワークフローを試しました。 小さい内容のタスクであったため効率的に各フローを実行できましたが、もっと大きなプロジェクトで大きな課題に対して実行するとまた違った結果になるかと思います。また、今後も試してみたいと思います。

今回紹介した手法は、あくまで現時点でのアプローチの一例に過ぎません。重要なのは、自分たちのワークフローや開発スタイルに合わせて適切にカスタマイズし、継続的に改善していくことだと思います。

本記事が少しでも参考になれば幸いです。ありがとうございました!