700ファイル、差分は13,000行。
Jest から Vitest への移行。単純なテストファイルだけでなく、CI設定、ESLintルール、関連する設定ファイル諸々含めて 694ファイル、+6,782 / -6,728 の差分。手作業でやったら何日かかるでしょうか。
これを ralph-loop に任せて寝た。朝起きたら、全テストがグリーンのPRが出来上がっていましたとさ。
自己紹介
おはこんばんにちは!
株式会社ライトカフェ AI 駆動開発 G Group Manager の 仙波(@semba_yui)です。
本記事では、Claude Code で ralph-loop プラグインを使って Jest → Vitest へ移行した一部始終を記録しています。ralph-loop が何をしてくれたのか、どう準備したのか、実際に移行してわかった AI の真の価値とは。。。
TL;DR
Vitest 移行
そもそもなぜ Jest → Vitest なのか
これは単純明快。ESM 対応とテストの実行時間、そしてその時間に比例する Runner のコストですね。
今回移行したプロジェクトでは、Next.js と Fastify のモノレポプロジェクトでした。テストケース数がとても多く、PR のたびに設定されている CI テストの実行には15分かかることもザラです。
この AI 駆動開発時代に PR を出すまでの速度が上がっても、CI にいちいち時間を取られているとそこがボトルネックになってしまいます。
移行方針について
Jest → Vitest 移行自体の方針は明確でした。実際、移行事例はググると大量にヒットします。Vitest のコードは Jest と似ていて、ほとんどのケースではただ置換するだけです。
ただし、問題は「量」と「時間」です。
694ファイル。これを手で書き換えるのは、技術的に難しいわけではありません。ただ、ひたすら退屈で、時間がかかってやりたくない。やる時間もない。そして、こういう「パターンは同じだが量が多い」作業は AI の得意分野ですね。
Claude Code に任せてしまいましょう。
ralph-loop とは
ralph-loop とは、AIコーディングエージェント(Claude Code 等)をループで繰り返し実行し、タスクをすべて完了するまで自律的に作業を続けるエージェントです。
シンプソンズのキャラクター Ralph Wiggum にちなんで名付けられており、「何度失敗しても諦めずに繰り返す」という哲学がそのまま名前になっています。
ralph-loop の考え方
ralph-loop の考え方は以下です。
大体以下の6ステップ。これをタスク完了までループしてくれます。
- クリーンなAIインスタンスの起動: ループごとに、コンテキストが完全にクリーンな新しいAIのインスタンス(Claude CodeやAmpなど)を起動します。これにより、過去の不要な会話履歴による精度の低下(ダムゾーンへの突入)を防ぎます。
- 仕様書と計画の決定論的な読み込み: 毎回同じ順序で、プロンプト、仕様書、現在のタスク一覧(prd.jsonやfix_plan.md)、過去の学習内容(progress.txt)を読み込ませます。
- 1ループ=1タスクの原則: AIのコンテキストを節約しパフォーマンスを最大化するため、未完了のリストから「最も優先度の高い1つのタスク」だけを選ばせて実装させます。
- テストとバックプレッシャー: コードを実装後、必ずユニットテストや型チェックなどを実行します。これを「バックプレッシャー」と呼び、テストに合格するまで変更をコミットさせないことで、コードの品質を担保します。
- Gitへの保存と状態の更新: テストに合格したらGitに変更をコミット・Pushします。その後、タスクを完了済み(passes: true)としてマークし、コードベースに関する新しい発見があればAGENT.mdやprogress.txtに記録します。
- 完了条件: リスト上のすべてのタスクが完了するか、完了のシグナル(COMPLETEなど)が出力されるまで、このプロセスが自律的に繰り返されます
詳細は以下を参照してください。丁寧に解説されています。
上記を Notebook LM にまとめてもらったスライドは以下。
まとめると、ralph-loop とは LLM の記憶には頼らず、ファイルと git を「外部メモリ」として使う設計になってます。これにより、数十回のイテレーションを重ねてもパフォーマンスが劣化しないというわけです。
ハーネスエンジニアリングとフィードバックループの重要性について
ralph-loop がうまく機能するかどうかは、フィードバックループの質で決まります。AIが「自分の作業が正しいか」を客観的に判定できる仕組みがなければ、ループの完了後に待っているのはぐちゃぐちゃのソースコードです。
有効なフィードバックループの例
- 自動テスト実行: テストが通れば正しい、落ちれば修正が必要
- 型チェック: 型エラーがあれば検知
- 静的解析: コード規約違反を検知
- CI パイプライン: 上記を統合した最終チェック
つまり、上記で担保できないタスクには ralph-loop は向いていません。
逆に、今回のように完了条件が明確で、単純な書き換えが大半な移行タスクはうってつけというわけです。Jest への依存が削除され、Vitest への依存が追加された状態で、元と同じテストケースが通ればいいわけですね。カバレッジは計算方法が違うので多少前後で異なる可能性はありますが、誤差程度であれば見逃しておきましょう。
ここまでのまとめ
ralph-loop 実践編
Claude Code へのプラグイン導入
ralph-loop は Claude Code の公式プラグインとして提供されています。
プラグインの install は簡単です。
claude plugin install ralph-loop@claude-plugins-official
基本的な使い方
ralph-loop を実行する場合
/ralph-loop:ralph-loop <PROMPT> [OPTIONS]
オプション
- --max-iterations — 最大反復回数
- --completion-promise — 完了を示すフレーズ
例
/ralph-loop "キャッシュ層をリファクタリング" --max-iterations 20ralph-loop "テストを追加" --completion-promise "TESTS COMPLETE"
ralph-loop をキャンセルする場合
/ralph-loop:cancel-ralph
移行用の Agent Skills を作成する
ralph-loop で最も重要なのは、ループを回す前の準備フェーズです。
今回、Agent skills という形で対象プロジェクトに特化した、Jest → Vitest に移行する用の SKILLS.md を作成しました。
SKILLS.md の作成方法は、これまた Anthropic 公式の skill-creator に要件を伝えるだけです。これも簡単。
今回 Skills に含めたのは以下の3つです。
- 移行 TODO リスト
- Jest29 → Vitest4 API マッピング表
- モノレポ内のパッケージ毎の特徴とそれぞれに特化した進め方
1. 移行 TODO リストについて
TODO リストを作成し、これを移行作業における状態管理に使います。600以上のテストファイルを一度に移行するのではなく、TODO リスト駆動で小さなタスク単位に分割しています。Claude Code の1セッション(1会話)で1タスクだけ進め、完了したらチェックを入れて commit し、終了。次のセッションで次のタスクへ進みます。
TODO リストを状態管理に使う: セッション間の引き継ぎを markdown のチェックボックスで実現
2. Jest29 → Vitest4 API マッピング表
変換パターンを事前に調査しておき、Skills 内で辞書化することで、LLM が毎回ゼロから考えるのではなく、確立されたパターンを参照できるようにします。
-
API マッピング表:
jest.fn()→vi.fn(),jest.mock()→vi.mock()等の1対1マッピング
ちなみに、Vitest は 3→4で破壊的変更が入っていました。こういったライブラリは LLM にとってバージョンの誤認識が発生しやすいです。しかも、今回利用した Claude Opus 4.6 は Reliable knowledge cutoff が 2025/05 です。Vitest4 のリリースはそれよりも遅い、2025/10 のリリースだったので、Claude は Vitest4 についての知識は都度 WebFetch しないと得ることが出来ません。
こういったパターンでも、事前調査をしておくのはとても有効です。
変換パターンを辞書化する: LLM が毎回ゼロから考えるのではなく、確立されたパターンを参照
3. モノレポ内のパッケージ毎の特徴とそれぞれに特化した進め方
小さいパッケージ → 大きいパッケージ の順に進めるように設定し、まずは小さいパッケージだけで移行を試すことで、Agent Skills にフィードバックを実施。うまく実行できるまで何度か評価と改善(Eval)を行いました。
| Phase | 内容 | 考え方 |
|---|---|---|
| Phase 0 | 事前準備(依存追加) | Vitest と Jest の併存環境を構築 |
| Phase 1 | 小規模パッケージから移行 | テスト数が少ない共通パッケージで安全に検証 |
| Phase 2 | フロントエンド(jsdom環境) | ブラウザ環境テストの大規模移行 |
| Phase 3 | BFF(Node.js環境) | 外部依存(Redis等)があるテストの移行 |
| Phase 4 | クリーンアップ | Jest の完全除去、ESLint の jest 用設定ディレクトリ削除、CI 全ジョブの正常動作確認 |
フェーズ分割でリスクを段階的に下げる: 小さいパッケージで検証 → 大きいパッケージへ
MacBook がスリープしないようにする
ここまで来たら後はいよいよ実行するだけです!
が、その前にもう一つだけ、私が寝ている間に AI も Mac ごと寝てしまわないように設定しておきましょう。
私は Amphetamine を使いました。MacBook を閉じてもスリープしないようにしてくれるので便利です。
後は、充電も落ちないように電源コードもつけっぱなしにしておきましょう。
実行
ここまで設定したら後は寝るだけです。おやすみなさい。
結果確認
朝起きて commit ログと Claude Code を恐る恐る確認してみたところ…
ralph-loop の iteration は完了し、commit は以下のようになっていました。
00:21 → 03:30 まで、3時間↑の自走の結果、モノレポの package ごとに Jest → Vitest への移行を完了しきってくれています。
UT の実行ももちろん問題なく完了です。すごすぎる。
これが人間なら残業代に深夜手当まで払う必要がありますが、相手は AI。API 料金はいつ叩いても作業量(トークン消費量)に応じた金額です。
((え、これを実行させた私への残業代…?commit ログには残っているだけで、実際にはあえて寝る前に実行し、本当に寝ていただけなので、もちろんありません。AI の働きは私の働きということに言い換えて申請したい… orz))
Jest → Vitest に移行してわかったメリット
Vitest はデフォルトで “unhandled error” を検知するとそのテストを失敗扱いにしてくれます。その結果、Jest でテストが出来たフリになっていたテストがいくつか炙り出されました。
以下は Claude の移行ログから取ってきた実例です。
jsdom では getBoundingClientRect() が常に { width: 0, height: 0, ... } を返すため、setTimeout 内の expect(width).toBe(100) は本質的に成功しません。Jest ではこのエラーがタイミング的に無視されていましたが、Vitest は正しくキャッチします。
こういったテストのミスが見つかりつつも、その都度 AI が上手いこと判断し、Jset → Vitest 移行を終わらせてくれたというわけです。
終わりに
試してみたいと思ったあなたへ
ここまで読んで「自分のプロジェクトでもやってみたい!」と思ってくれた方向けに、最初の一歩をまとめておきます。
1. ralph-loop に向くタスクを選ぶ。
以下の条件を満たすものを選んでください。
- パターンが定型的で繰り返しが多い
- テストや lint で完了を機械的に検証できる
- 失敗しても安全(本番コードを壊さない)
具体例: ライブラリ移行、コード規約の一括適用、deprecated API の書き換え、テストの追加など。
2. 事前準備は丁寧に。入念に。
ループの質は 準備の質で決まります。スコープ、タスク分割、完了条件を明確に定義し、最初は小さなスコープで試し、検証していきましょう。
3. 小さく始めて改善する。
いきなり全ファイルの移行をやる必要はありません。まずは10〜20ファイル程度のスコープで ralph-loop の挙動を理解してから、スケールさせていきましょう。
まとめ
改めて、694ファイル、差分13,000行超の jest → vitest 移行を ralph-loop × Claude Code の力でたった一晩で完了してしまいました。私がやったのは SKILLS として要件を伝えたことと、朝起きて結果を確認することだけです。
私の周囲では、AI コーディングツールは「対話しながら1タスクずつ進める道具」として使っている人がまだまだ多い印象です。
もちろん、それも正しい使い方の一つです。しかし、「定型的で量が多い作業」に限って言えば、もう一段先が待っています。Human-In-The-Loop では人間の確認作業がボトルネックになります。検証方法と明確な完了基準を与え、ループを回して、寝る。Human-On-The-Loop の世界では人間がボトルネックになることはなくなります。
設計判断が必要なタスクや、完了条件を自動化できないタスクは人間と AI の協業。しかし、条件が揃う場面では、AI に完全に任せきってみる。これが新しい時間の使い方です。
寝ている間に終わる仕事は、寝ている間に終わらせておきましょう。
それでは、おやすみなさい。。。 zzz...
おまけ: AIに任せて本当に良かったこと(真のボトルネックの発見)
ちなみに、Jest → Vitest へ移行したブランチは、今現在マージをしていません。
Vitest に移行する理由の一つとしてあげていたテスト実行速度について、CI 環境でのテスト実行時間が改善どころか、むしろ一部悪化してしまったためです。
これは現在のパッケージ管理含む他エコシステムとの相性や、Redis / jsDom への依存といった別要因での重さがテストの大多数を占めていたことが原因でした。これがわかったことだけでもとても大きな収穫で、まずはこのボトルネックから解消していこうと思います。
もしもこのタスクを AI ではなく人力でやっていたら…人間が必死こいて移行した後、何の成果も得られませんでした!!むしろ悪化です!では悲しすぎますね。
テストライブラリの移行よりも、単体テストのスコープや戦略を見直す。こっちのほうが根本解決へと繋がるということが、リアルな体験を元に認識できた良い機会でした。
AI 駆動開発の関連記事
問い合わせ先
株式会社ライトカフェ / 株式会社ライトカフェクリエイションへの案件のご依頼・ご相談は、以下までご連絡ください。
- Mail: info@lightcafe.co.jp
We are hiring!
株式会社ライトカフェ / 株式会社ライトカフェクリエイションは、エンジニアを積極採用中です!
詳細は以下をご覧ください。
※その他メディア:noteでは、会社の魅力や雰囲気などを発信しています。















