Cursor で Agent を使うと、「あと少しで終わるはず」が1時間経っても終わらない、という経験をした人は多いはず。会話が長くなるほど指示が薄れる・以前の制約を忘れる・同じ修正を繰り返す、といった症状が出てくる。
ループエンジニアリング(Ralph Loop とも呼ばれる)は、これを避けるためのやり方。1回の Agent 実行を短く区切り、状態はファイルと Git に残し、終了条件は LLM の「完了しました」ではなくテストや grep で判定する。
この記事では、Cursor ユーザー向けにループエンジニアリングの考え方と、今日から試せる最小構成をざっくり整理する。C# / ASP.NET Core プロジェクトを例に触れる。
関連: Agent 設定フォルダ構成 / Skills ベストプラクティス / AGENTS.md ベストプラクティス
dotnet test / grep / 型チェックなど外部ツールで決めるcursor-agent -p)+ Bash ループ、のどちらかから始められるもともと Geoffrey Huntley 氏の Ralph Wiggum テクニック(Simpsons の Ralph から。間違えても諦めない、という意味合い)として知られるパターン。Cursor コミュニティでも Ralph Loop として再実装・プラグイン化されている。
1回のループはだいたい次の流れ。
ポイントはチャット履歴を引き継がないこと。前の会話の要約に頼らず、progress.md や prd.json、Git log から「今どこまで終わったか」を毎回読み直す。
従来の長い Agent セッション ループエンジニアリング
────────────────────────────────────────────────────────────
コンテキストが膨らむ 各イテレーションは新規コンテキスト
「さっき言った制約」を忘れる 制約は AGENTS.md / タスク JSON に固定
「完了しました」で終わる dotnet test / grep で終了判定
人間がずっと見張る 夜間・バックグラウンド実行もしやすい
全部いきなり入れなくてよい。自分の環境に合う1つからで十分。
Subagent は Markdown で定義する専門 Agent。呼び出すたびに独立したコンテキストになるので、ループの「1イテレーション = 1 Agent」に向く。
.cursor/agents/ralph-loop.md … 次の未完了ストーリーを1件だけ実装する Executor.ralph/prd.json … ユーザーストーリー一覧(passes: true/false、優先度).ralph/progress.md … 失敗パターン・学びを次のイテレーションへ引き継ぐチャットで /ralph-loop のように明示呼び出しする運用が多い。1回呼ぶ = 1ストーリー完了まで、を人間またはスクリプトが繰り返す。
Cursor の Marketplace 向けプラグインとして Ralph Loop が公開されている(Claude Code 版の移植)。Hooks で Agent の終了をフックし、同じプロンプトを再注入してループする。
.cursor/ralph/scratchpad.mdralph-loop(開始)、cancel-ralph(中断)、ralph-loop-help「自分で Bash を書きたくない」なら、まずプラグインから試すのが楽。
ヘッドレスの cursor-agent を print モード(-p)で起動すると、プロンプトを読んでファイル編集・シェル実行のあとプロセスが終了する。この「終了」をフックに Bash で回すのが CLI 版 Ralph Loop。
#!/usr/bin/env bash
MAX=20
for i in $(seq 1 $MAX); do
remaining=$(grep -rl "TODO(migrate)" src/ | wc -l)
if [ "$remaining" -eq 0 ] && dotnet test --no-build -q; then
echo "Done."
exit 0
fi
cursor-agent -p --model auto "Read AGENTS.md and progress.md. Fix ONE file. Run dotnet test."
done
echo "Max iterations reached."
exit 1
長時間バッチ(大規模リネーム、警告ゼロ化、テスト追加)向き。各イテレーションで –resume は使わないのが原則。継続性は Git と progress ファイルが担う。
架空の受注 API OrderNest(AGENTS.md 記事と同じ例)で、警告ゼロ化をループに載せる想定。
「リファクタして」ではなく、1イテレーション = 1ファイル or 1警告種別まで分解。Plan Mode で次を出させる。
dotnet build -warnaserror / dotnet test.ralph/
prd.json # ストーリー一覧(id, title, passes, priority)
progress.md # 失敗理由・次に気をつけること
AGENTS.md # ビルドコマンド・触ってはいけない領域
prd.json の例(抜粋):
[
{
"id": "warn-01",
"title": "OrderController.cs の nullable 警告を解消",
"passes": false,
"priority": 1
},
{
"id": "warn-02",
"title": "OrderService.cs の nullable 警告を解消",
"passes": false,
"priority": 2
}
]
毎回同じ指示を渡す。変えるのはディスク上の状態だけ。
1. .ralph/prd.json を読み、passes:false のうち priority が最小の1件を選ぶ
2. なければ ALL STORIES ARE COMPLETE と出力して終了
3. その1件だけ実装。スコープ外は触らない
4. dotnet build -warnaserror && dotnet test を実行
5. 成功したら passes を true に更新し progress.md に1行追記
6. git commit(メッセージに story id を含める)
ループエンジニアリングは無人で merge までがゴールではない。git log と CI 相当のコマンドで確認し、変な方向に行っていたら progress.md にガードレールを足して再実行、が現実的な運用。
ループは必ず上限を付ける。無限ループは Agent でも人間でも起きる。
ループに載せる前に Plan Mode で検証可能な粒度まで落とせるかが判断基準。
役割 ループでの使い方
────────────────────────────────────────────
AGENTS.md 毎イテレーション必読。ビルド・禁止事項
Skills ralph-loop 開始手順、cancel、障害時の調査
Rules 触ってよいパスの glob 制限
Subagents 1ストーリー executor / 任意で verifier
Git 真の進捗ログ。progress.md は補助
詳細は フォルダ構成記事 を参照。ループエンジニアリングはこれらの上に載る運用パターンと考えると整理しやすい。
長い1本のチャットに頼るより、「1タスク終わったら Agent を一度降ろす」方が、C# の大規模ソリューションでも安定しやすい。まずは手元の警告1種類を prd.json に載せて試してみるのがおすすめ。