【AI×PHP】CursorでLaravel開発を加速する|ルール設定・コンテキスト設計・実践テクニック

はじめに

注文を保存する store を Cursor の Agent に頼むと、マイグレーションに無いカラムや、コントローラ直書きのバリデーションを出すことがあります。ルールファイルを置いても、適用条件が違うと注文とは無関係なチャットにまで指示が載ってしまいます。

この記事では、プロジェクトルールの付け方、チャットへ渡すファイル、.cursorignore の届く範囲を整理します。対象は、Laravel 13(PHP 8.3 以上)を Cursor の Agent で書く人です。

記載は 2026-10-02 に確認した Cursor の Rules と Laravel 13 のリリースノート の範囲です。ルールの画面名はバージョンによって変わることがあります。コード例の Form Request は、このリポジトリでは実行していません。

背景:ルールが載る場所

言葉を先に定義します。Agent はチャット、Cursor Tab は、入力中に出る補完です。インライン編集は、エディタ上でその場の範囲を書き換える機能です。

Cursor のドキュメントでは、ルールは Agent のプロンプトへ繰り返し載せる指示です。同じドキュメントの FAQ では、ルールは Cursor Tab やその他の AI 機能には影響しない、とあります。入力中の補完を Laravel 向けに固定したい場合、ルールファイルだけでは足りません。

ルールの置き場所は次のとおりです。

種類場所届く範囲
Project Rules.cursor/rules/*.mdcそのリポジトリ。Git で共有できる
AGENTS.mdルートやサブディレクトリプレーンな Markdown。より近い階層が優先
User RulesCustomize の Rules自分の全プロジェクト。Agent(チャット)のみ
Team RulesチームのダッシュボードTeam と Enterprise。個人利用ならこの行は後でよい

競合したときの順は、Team Rules、Project Rules、User Rules です。該当するものはまとめて載り、先のものが優先されます。ルートの .cursorrules は旧形式で、ドキュメントでは非推奨とされています。

.cursor/rules では、拡張子 .mdc だけをルールとして読みます。同じ場所の .md は、先頭に設定を書いてもルールになりません。ファイルの種類で条件を分けない短い指示なら、ルートの AGENTS.md でも足ります。階層が近い AGENTS.md ほど優先されます。基準は、作業中のディレクトリに近いファイルです。

Laravel の Form Request にルールを付ける

ファイルの種類で分けたいので、ここでは AGENTS.md ではなく .mdc の globs を使います。

Form Request は、認可の authorize と入力チェックの rules を、コントローラから分けたクラスです。新規クラスは php artisan make:request StoreOrderRequest で作れます。

適用条件は、ファイル先頭の --- で挟んだ frontmatter に書きます。見る項目は alwaysApply、description、globs です。alwaysApply が true のときは、毎回のチャットに入り、globs と description は無視されます。alwaysApply が false で globs があるときは、パターンに合うファイルがコンテキストにあるときだけ付きます。この記事のコンテキストは、チャットで @ したファイルと、Agent が読み書きしているファイルを指します。どこまで含むかは版で差があり得ます。次の例では description は使いません。Agent に説明文で選ばせる方式は、今回の対象外です。

Form Request だけに寄せるなら、alwaysApply は false にします。

---
globs: app/Http/Requests/**/*.php
alwaysApply: false
---

- 新規の FormRequest は php artisan make:request で作る
- authorize と rules を空のまま残さない
- バリデーションはコントローラに書かず、rules に置く
- この注文例の金額は円の整数のまま扱う。float で税率を掛けたり足したりしない

ファイル名の例は .cursor/rules/laravel-form-request.mdc です。自分でそのパスへ保存しても同じです。チャットに /create-rule と送ると、Agent が frontmatter 付きのファイルを .cursor/rules に作る、とドキュメントにあります。Customize の Rules から Add Rule でも同じ場所に作れます。

このルールが想定するクラスは、次の形です。Laravel の Form Request 検証 では、authorize と rules をクラスに置きます。

<?php

declare(strict_types=1);

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

final class StoreOrderRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user() !== null;
    }

    /**
     * @return array<string, array<int, string>>
     */
    public function rules(): array
    {
        return [
            'total_yen' => ['required', 'integer', 'min:0'],
            'coupon' => ['nullable', 'string', 'max:32'],
        ];
    }
}

ドキュメントでは、1 ファイル 500 行未満に分け、繰り返す失敗だけを書くよう勧めています。スタイルガイドの全文や、Agent が既に知っている artisan の一覧は、ルールに写しません。

失敗例:ルールが毎回載る場合と、ファイルを渡さない依頼

次の frontmatter は、Form Request のときだけ効くように見えます。

---
globs: app/Http/Requests/**/*.php
alwaysApply: true
---

alwaysApply: true の行があるため、globs は無視されます。画面の文言を直すチャットにも、Form Request の指示が載ります。ファイルの種類で分けたいときは、alwaysApply を false にして globs だけを残します。

拡張子を .md にしたファイルも、ルールとしては読まれません。置いたのにチャットへ出ないときは、拡張子が .mdc かを先に見ます。

ここからは、ルールファイルではなくチャットの書き方です。失敗しやすい依頼は次のとおりです。

Order の保存 API を作って。

マイグレーションが次のとき、金額は total_yen という円の整数です。

Schema::create('orders', function (Blueprint $table) {
    $table->id();
    $table->unsignedInteger('total_yen');
    $table->string('coupon', 32)->nullable();
    $table->timestamps();
});

ファイルを指定しない依頼だと、次のようなコントローラを出すことがあります。これは記録した実出力ではなく、見る点を示す例です。

public function store(Request $request)
{
    $total = (float) $request->input('total') * 1.1;
    Order::create(['total' => $total]);
}

ずれは 3 つです。

  • カラム名が total_yen ではない
  • 円の整数に、税率の float を掛けている
  • 入力チェックの配列が Form Request の rules に無い

入力チェックの配列は StoreOrderRequest::rules に置きます。コントローラには書きません。$request->validate も、この例ではコントローラに残しません。

条件を固定した依頼の例は次のとおりです。@ のあとに、チャットへ載せるファイルを指定します。まだ Form Request のファイルが無い依頼では、上の globs は最初のメッセージに載りません。既存の Request が 1 つあるなら、それも @ してください。

@database/migrations/2026_03_17_000000_create_orders_table.php と @app/Models/Order.php を見て、StoreOrderRequest を追加してください。total_yen は円の整数のままです。税率は掛けたり足したりしないでください。入力チェックは rules にだけ書いてください。

コンテキストのヘルプ では、関係するファイルが分かっているときに @ を使い、不明なら Agent の検索に任せてよい、とあります。vendor/ や node_modules/ は依存パッケージのディレクトリなので、このルールの対象ファイルではありません。

秘密ファイルは無視リストだけでは止まらない

渡すファイルの次は、渡さないファイルです。

Cursor は .gitignore と .cursorignore の両方を、Agent、Tab、インライン編集、@ 参照から外します。Laravel の既定 .gitignore には .env が含まれることが多いです。意図を残すなら、ルートの .cursorignore にも書けます。記法は .gitignore と同じです。

.env
.env.*
storage/logs/

同じドキュメントには、Agent が使うターミナルと MCP は、.cursorignore では止められない、とあります。MCP は、Agent がチャットから呼ぶ外部ツールです。無視リストがあっても、「.env を表示して」と頼むと、コマンド経由で読める余地が残ります。秘密の値はチャットに貼らず、表示も頼まないでください。

まとめ

  • Form Request のルールは .cursor/rules/*.mdc に置き、alwaysApply: false と globs で対象を限る
  • スキーマを変えない依頼では、マイグレーションとモデルを @ で渡す
  • .env は無視リストに入れる。ターミナル経由では止まらないので、中身の表示は頼まない

次に試す手順は次のとおりです。

  1. 上の frontmatter と箇条書きを .cursor/rules/laravel-form-request.mdc に保存する
  2. 自分のマイグレーション 1 本を @ する。orders が無ければ、この記事の Schema::create を先に置く
  3. 既存の Form Request が 1 つあるなら、それも @ する
  4. 上の依頼文を、ファイル名だけ変えて送る。差分でカラム名と、チェック配列の置き場所を見る

関連書籍

Amazonのアソシエイトとして、Thousand Tech Blog は適格販売により収入を得ています。紹介リンクであることの開示です。

まとめの手順は、この本を読まなくても試せます。試したあと、マイグレーションとフォームリクエストの置き場所を本で確認するときの1冊です。

見る範囲は第7章と第8章です。第7章はマイグレーションです。第8章の 8-4-6 はフォームリクエストです。書名は これからはじめるLaravel実践入門(山田祥寛 著、SBクリエイティブ、2026年)です。出版社の記載では、対象は Laravel 12 以降と PHP 8.5 以降です。サンプルは Laravel 13 での動作を確認済みです。Cursor のルールファイルの書き方は、この本の範囲外です。

Source

  • Rules(.mdc、frontmatter、AGENTS.md、Tab には影響しない、という FAQ)
  • Rules(ヘルプ)(User Rules は Agent のみ。旧 .cursorrules)
  • @ mentions and context(@ でファイルやフォルダを渡す)
  • Ignore files(.cursorignore の対象と、ターミナルと MCP は対象外)
  • Release notes(Laravel 13 は 2026-03-17、PHP 8.3 以上)
  • Validation(Form Request の authorize と rules)

AIAI,Cursor,Laravel,PHP

Posted by 千原 耕司