Cursor 0.50でMulti-Repo構成を試してみた!
こんにちは!
株式会社カンリーでエンジニアをしているハヌルです。
最近、CursorやClaude、Copilotなど、開発者向けのAIツールが次々と進化していますね。
カンリーでもチームを問わずAIを活用した開発効率の向上をいろんな角度から試みています。
そんな中、先月、Cursorの新バージョン 「Cursor v0.50」 がリリースされました!
公式のリリースノートを見ると、「multi-root workspace」がサポートされるようになったので
早速試してみた内容を紹介したいと思います!
multi-root workspaceとは?
multi-root workspaceは、もともとVSCodeでサポートされていた仕組みで、
.code-workspace
という設定ファイルを使って複数のrepositoryを一つのワークスペースとして扱うことができます。
Cursor v0.50のアップデートでは、この multi-root workspace が正式にサポートされ、
複数のコードベースをまとめてAIにコンテキストに取り込むことが可能になりました。
Now you can create multi-root workspaces to make multiple codebases available to Cursor. All of them will be indexed and available to Cursor, ideal when you have projects in different folders you want to work on in the same space.
.cursor/rules are supported in all folders added
これまでは、Cursorを使ってAIにコンテキストを正しく伝えるには、1つのリポジトリ構成であることが前提でした。
つまり、各リポジトリに個別で .cursor/rules
を配置し、そのリポジトリ単位でしかAIがコードを認識できなかったわけです。
今回のアップデートでは、.code-workspace
に複数のリポジトリを追加することで、
それぞれの .cursor/rules
を読み込み、またがった構成でも一貫したコンテキストを構築できるようになったのが大きなポイントです。
実際、私が所属するチームのプロダクトも
API・バッチ・フロントエンド・ドキュメント・スキーマなど、役割ごとに複数のリポジトリに分かれて構成されています。
こうした構成は、最近の現場でもよく見られるスタイルで、
少なくともバックエンドとフロントエンドは分けて管理するケースが多いかなと思います。
そのため、AIツールに正しくプロダクト全体を理解してもらうには、
リポジトリの境界を越えた一貫したコンテキスト構築が大きな課題でした。
今回のアップデートによって、まさにこうした現場の課題を解決できるんじゃないかと思ったため、
実際に試してみることにしました。
試してみた構成
今回の検証では、以下のような3つのリポジトリを用意して試してみました。
簡単なTodoウェブアプリを作り、backend
とfrontend
にはその名の通り
バックエンドとフロントエンドのコードが格納し、tmp
には各環境のルールをまとめて認識するようにルールを書いておきました。
実際に使用したアプリの構成やコードは以下のリポジトリに公開していますので、興味のある方はぜひご覧ください。
👉 todo-app-multiroot-workspace-sample - GitHub
workspace-root/
├── backend
│ ├── .cursor
│ │ └── rules
│ │ └── backend.mdc
│ ├── api.yaml
│ ├── main.py
│ └── requirements.txt
├── frontend
│ ├── .cursor
│ │ └── rules
│ │ └── frontend.mdc
│ ├── index.html
│ ├── script.js
│ └── styles.css
├── tmp
│ └── .cursor
│ └── rules
│ └── integration.mdc
└── workspace.code-workspace
各ルールの記載内容は以下になります。(今回、バックエンドとフロントエンドの詳細な内容は)
backend/.cursor/rules/backend.mdc
# Backend (Python Flask) Rules
## コンテキスト
- このフォルダはPython Flask REST APIサーバーです
- Todoアプリのバックエンド部分を担当します
- フロントエンドは別フォルダにあり、http://localhost:8080で実行されます
## コーディングスタイル
- PEP 8スタイルガイドに従います
...省略...
frontend/.cursor/rules/frontend.mdc
# Frontend (Vanilla JavaScript) Rules
## コンテキスト
- このフォルダはVanilla JavaScriptで実装されたWebアプリケーションです
- Todoアプリのフロントエンド部分を担当します
- バックエンドAPIはhttp://localhost:5000で実行されます
## 技術スタック
- HTML5 semantic markupを使用します
- CSS3(Flexbox、Grid、アニメーション)を活用します
- Vanilla JavaScript (ES6+)を使用します
- Fetch APIでバックエンドと通信します
...省略...
tmp/.cursor/rules/integration.mdc
# ルール連携検証規則
答中にbackend.mdc規則を参照した場合は「[BACKEND_ACCESSED]」タグを、
frontend.mdc規則を参照した場合は「[FRONTEND_ACCESSED]」タグを含めてください。
## 相互参照テスト
この規則は他のリポジトリにあるbackend.mdcとfrontend.mdc規則と連携して動作する必要があります。
各リポジトリのルールを総合的に参照して回答をするように明示的にルールを定義しました。
(どのルールを参照したかタグを出力するように定義)
workspace.code-workspace
には各々のリポジトリを定義しておきます。
{
"folders": [
{ "path": "backend" },
{ "path": "frontend" },
{ "path": "tmp" }
],
"settings": {}
}
では、Cursorからworkspace.code-workspace
ファイルを開いて、各々のルールがちゃんと読み込まれているか確認します。
各リポジトリのルールがすべて読み込まれている!
実際試してみる!
続いて、実際にいくつかの質問を通してmulti-root workspaceの挙動を確認してみました。
ルールが正しく読み込まれていることが確認できたところで、
次にCursor Chatを使って、複数のリポジトリにまたがる質問をいくつか試してみました。
今回は、あらかじめ定義しておいたintegration.mdcのルールに従って、
回答内に [FRONTEND_ACCESSED] や [BACKEND_ACCESSED] といったタグが出力されるかどうかを通じて、
AIが実際にどのルールを参照したかを可視化できるようにしています。
まず、以下のような質問を投げてみました:
フロントエンドとバックエンドが連携して新しいタスクを登録する際の処理の流れを教えてください。
その結果、Cursorはフロントエンド側の script.js
に記述された handleAddTodo()
や、
バックエンド側の /api/todos
エンドポイント、Flaskアプリの create_todo()
関数などを横断的に参照しながら、
タスク追加の一連の処理フローを正確に説明してくれました。
実際の回答には以下のような内容が含まれており、複数リポジトリをまたいで情報を取得していることが確認できました。
ただし、.cursor/rules/integration.mdc
にて定義した [FRONTEND_ACCESSED]
, [BACKEND_ACCESSED]
の出力ルールは、この回答内には表示されませんでした。(謎)
以下はCursorの回答の全文です。
タスク登録の処理フローを確認するために、まずコードベースを検索させていただきます。
Search files...
コードベースを確認した結果、タスク登録の処理フローについて説明させていただきます:
1. **フロントエンド側の処理**:
- ユーザーがタスク入力フィールド(`todo-input`)に新しいタスクを入力
- 「追加」ボタンをクリックまたはEnterキーを押すと、`handleAddTodo()`関数が実行
- 入力値のバリデーション(空文字チェック)
- ボタンの状態を「追加中...」に変更し、二重送信を防止
2. **APIリクエスト**:
- フロントエンドからバックエンドの`/api/todos`エンドポイントにPOSTリクエストを送信
- リクエストボディに`{ task: "タスク内容" }`の形式でデータを送信
- Content-Type: application/jsonヘッダーを設定
3. **バックエンド側の処理**:
- Flaskアプリケーションが`/api/todos`エンドポイントでPOSTリクエストを受信
- `create_todo()`関数が実行され、リクエストデータのバリデーション
- 新しいタスクオブジェクトを作成:
```python
{
"id": 新しいID,
"task": タスク内容,
"completed": false
}
```
- タスクをメモリ内の`todos`リストに追加
- 作成されたタスクオブジェクトをJSONレスポンスとして返却(ステータスコード201)
4. **フロントエンドでの完了処理**:
- レスポンスを受け取り、成功時は入力フィールドをクリア
- `loadTodos()`関数を呼び出して最新のタスクリストを再取得
- 画面に新しいタスクリストを表示
- ボタンの状態を元に戻す
5. **エラーハンドリング**:
- バックエンドでバリデーションエラーが発生した場合(例:タスク内容が空)
- フロントエンドでネットワークエラーが発生した場合
- エラーメッセージをユーザーに表示
このように、フロントエンドとバックエンドが連携して、ユーザーの入力からタスクの保存、表示までの一連の流れを実現しています。
続いて、フロントエンドまたはバックエンドといった特定リポジトリ内で完結する内容についても質問してみました。
目的は、AIが必要以上に他のルールを参照せず、適切にコンテキストを限定できているかどうかを確認することです。
POSTされたタスクデータはバックエンド側でどのように保存されますか?
この質問に対して、Cursorは backend/main.py
のみを参照し、改善案まで提案してくれました!
ただ、今回もどのルールを参照したかタグを出力することはできませんでしたね…
以下はCursorの回答の全文です。
バックエンドのコードを確認させていただきます。
Read file: backend/main.py
現在の実装では、タスクデータは以下のように保存されています:
1. **インメモリデータベース**:
- タスクデータは`todos`というPythonのリスト変数に保存されています
- これはインメモリデータベースとして機能しており、アプリケーションのメモリ上にのみ存在します
- サーバーが再起動されると、データは失われます
2. **データ構造**:
todos = [
{
"id": 1,
"task": "タスク内容",
"completed": False
},
...
]
3. **新規タスクの保存処理**:
new_todo = {
"id": max([todo["id"] for todo in todos]) + 1 if todos else 1,
"task": data['task'],
"completed": False
}
todos.append(new_todo)
この実装には以下の制限があります:
1. **永続性の欠如**:
- サーバー再起動時にデータが失われる
- 複数のサーバーインスタンス間でデータを共有できない
2. **スケーラビリティの制限**:
- メモリ容量に依存する
- 大量のデータを扱う場合に非効率
より本番環境向けの実装にするためには、以下のような改善が推奨されます:
1. **永続的なデータベースの導入**:
- SQLite、PostgreSQL、MySQLなどのリレーショナルデータベース
- MongoDBなどのNoSQLデータベース
- Redisなどのインメモリデータストア
2. **データベース接続の実装**:
- SQLAlchemyなどのORMの使用
- データベースマイグレーションの導入
- コネクションプールの設定
3. **エラーハンドリングの強化**:
- データベース接続エラーの処理
- トランザクション管理
- データの整合性チェック
これらの改善により、より堅牢でスケーラブルなタスク管理システムを実現することができます。
最後に試したのは、.cursor/rules
に定義したルールファイルを、質問時に明示的にコンテキストとして指定した場合です。
これまでの検証では、ルールが自動で読み込まれる形でしたが、
「ルールを参照してください」と明示的に伝えた場合、より正確に従ってくれるのかを確認してみました。
@integration.mdc
このアプリのフロントエンドでは、タスクの一覧をどのように画面に表示していますか?
回答自体は間違ってないが、相変わらずタグの出力はしてない
その結果、Cursorはこれまでと同様に適切なファイルを参照し、的確な内容を回答してくれたものの、
タグ出力の指示には依然として従ってくれませんでした。
つまり、ルールファイルを読み込んでコンテキストとしては利用しているようですが、
回答形式に対する制御までは効かないようです。
実プロダクトでもうまく適用できるのか?
簡単な検証アプリである程度、期待通りに動作することを確認できたところで、
次に気になったのは、実際のプロダクトでも同じようにうまくコンテキストを認識してくれるのか?
という点でした。
そこで、先ほど軽く紹介した私が所属するチームのプロダクトのソースコード一式を、1つの
.code-workspaceにまとめてCursorで開き、以下の質問を投げてみました。
このプロダクトのユーザー認証処理のワークフローをmermaidでまとめて
Cursorは関連する複数のディレクトリを横断してコードを読み取り、
ログイン→2段階認証→トークン発行までを含んだかなり詳細なシーケンス図を生成してくれました。
ただし、セキュリティの観点から、ここでは実際のフローを一部簡略化した図を掲載します。
実際の回答には、さらに細かいバリデーション処理やエラーハンドリングまで記載されており、
実装ベースで仕様をまとめることもできるかと思いました。
一方で、実プロダクトのソースコードで試したからこそ気づいた限界もあります。
ファイル数が多い状態でコンテキストを直接指定しようとすると、Cursor側で中身をうまく読み込めないことです。
フォルダーが大きすぎて警告のアイコン⚠️が表示される
設定画面を見る限り、一定以上のファイル数がだと、ファイルツリー構造だけが読み込まれるようです。
赤枠の設定をONにすると、フォルダ内の全ファイルを探索しますが、ファイル数に上限があるようです
このように、実プロダクトのような大規模な構成でも一定の効果は見込めますが、
フォルダやファイル数が多い場合は、読み込み対象を適切に絞り込む工夫が必要になりそうです。
まとめ
今回はCursorで新たにサポートされたmulti-root workspaceを試してみました。
実際に使ってみたところ、複数のリポジトリにまたがるコードベースでも、一貫したコンテキスト理解ができるようになったと感じました。
ただ、明示的にルールの内容に触れないと、想定したコンテキストが反映されないこともあり、
まだ思い描いたほどスムーズにはいかない印象です。
もう少しルール設計やプロンプトの工夫が必要だなと思いました。
今後もどんどん進化していくツールだと思うので、引き続き期待しつつ、新機能のキャッチアップにも取り組んでいきたいと思います。

株式会社カンリーは「店舗経営を支える世界的なインフラを創る」をミッションに、店舗アカウントの一括管理・分析SaaS「カンリー店舗集客」の開発・提供、他複数のサービスを提供しております。 技術系以外のnoteはこちらから note.com/canly
Discussion