🤖

Claude Code で ChakraUI から CSS Modules 移行を自動化できるか実験してみた

に公開

はじめに

UIライブラリの移行、めんどくさいですよね。
コンポーネントひとつひとつ書き換えて、スタイル確認して……

そこで Claude Code に移行作業を任せられないか実験してみました。
結論は、完全に手放しは難しいがまぁまぁいける。

この記事では Claude Code と agent-browser を活用して、Chakra UI → CSS Modules の移行を自動化した実験について紹介します。

使用したツール

Claude Code

Anthropic の CLI ツール。ターミナルから Claude にコーディングを任せられます。
.claude/ に設定ファイルを置いて、移行作業に特化した振る舞いをさせました。

agent-browser

https://agent-browser.dev/

AI エージェントからブラウザを操作する CLI ツール。
Playwright ベースで、スクリーンショット取得などができます。

CDP Mode が特に便利。既存の Chrome に接続できるので、ログイン済みセッションを使い回せます。

agent-browser --cdp 9222 open "http://localhost:3000/dashboard"
agent-browser --cdp 9222 screenshot "dashboard.png" --full

gh

皆さんご存知だと思いますが、GitHub issue や PR の参照、作成をコマンドから行えるツールです。

https://github.com/cli/cli#installation

移行計画

方針

Chakra UI のコンポーネントを src/components/ui/* に CSS Modules で再実装し、段階的に置き換えていく方式を採用しました。
車輪の再発明に見えますが、目的は Chakra UI の破壊的変更から逃げることです。自前実装に置き換えておけば、次のUIライブラリ(もしくは独自コンポーネントなど)を選定する時間を稼げます。

# docs/migration-plan.md より

1. src/components/ui の数だけ Issue を作る
2. 既存の src/components/* はそのまま使う
3. 置き換えた components/ui を使って src/components/* を置き換える
4. 置き換えた components/ui を使って src/pages/* を置き換える

使用中の Chakra UI コンポーネント

まず現状分析。Claude Code に grep させて使用回数を集計。

使用回数 コンポーネント
34 Box
29 Text
26 VStack / HStack
20 Button
18 Badge
16 Avatar
14 FormControl
... (計50種類以上)

Phase 構成

36個の Issue を4つの Phase に分割しました。

Phase 1: src/components/ui 作成(17 Issue)

# タイトル コンポーネント
1 レイアウト系 Box, Flex, VStack, HStack, Stack, Center, SimpleGrid, Wrap
2 テキスト系 Text, Heading
3 ボタン系 Button, IconButton, CloseButton
... ... ...
17 Hooks useDisclosure, useToast, useColorModeValue

Phase 2: src/components/* 置き換え(6 Issue)

# タイトル
18 src/components/common 置き換え
19 src/components/data 置き換え
... ...

Phase 3: src/pages/* 置き換え(12 Issue)

# タイトル
24 pages/login 置き換え
25 pages/index 置き換え
... ...

Phase 4: 完了(1 Issue)

# タイトル
36 Chakra UI 削除・最終確認

.claude/ の構成

.claude/
├── commands/
│   └── migrate.md
├── rules/
│   └── migration.md         # ブランチ運用、スクショ必須ルール
├── skills/
│   ├── screenshot/SKILL.md  # /screenshot <before|after> <path>
│   ├── compare/SKILL.md     # /compare <issue-number>
│   ├── create-component/SKILL.md
│   ├── migrate-page/SKILL.md
│   ├── create-branch/SKILL.md
│   ├── create-pr/SKILL.md
│   ├── create-todo/SKILL.md
│   └── create-compare-page/SKILL.md
└── todos/                   # サブエージェント用TODOファイル
    ├── issue-171-worker.md
    └── issue-171-reviewer.md

サブエージェント活用が肝

最大のポイント:メインエージェントは司令塔に徹し、実作業は3つのサブエージェントに委任します。
一つのエージェントで作業するとコンテキストが溜まったときにおかしい動作をすることが多いです。

  • main ブランチで作業する
  • 意味のない機能を作る(空の function やまったく関係のない処理など)
  • agent-brower でスクショを撮るという命令を無視して Playwright を install しようとする
  • component の見た目の指摘をすると修正できていても無限に修正しようとしたり別の問題を直そうとする

サブエージェントは効率化も目的の一つですが、個人的にはメインエージェントにコンテキストを溜めさせないように使っています。

# docs/migration-work.md より

main agent は 3 つの sub agent を作成する。

1. researcher: 調査agent
2. worker: 作業agent
3. reviewer: 確認agent

Phase 1 の作業フロー

1. <main> userから指示されたissue-numberを取得
2. <main> 作業ブランチ作成(issue-<number>)
3. <main> subagentを作成(researcher)
4. <researcher> 対象コンポーネントの使われ方を調べる
5. <researcher> worker用のTODOを作成
6. <researcher> reviewer用のTODOを作成
7. <main> researcherを終了させる
8. <main> worker subagentを作成
9. <worker> workerのTODOを消化
10. <main> workerを終了させる
11. <main> reviewer subagentを作成
12. <reviewer> コードの確認
13. <reviewer> スクリーンショットの確認
14. <reviewer> 問題があれば修正
15. <main> reviewerを終了させる
16. <main> push & PRを作成

TODOファイルでサブエージェント間の引き継ぎ

サブエージェント間の情報共有は .claude/todos/ 内のファイルで行います。

researcher が作成する worker TODO

# .claude/todos/issue-171-worker.md

対象コンポーネント: Box, Flex, VStack, HStack, Stack, Center, SimpleGrid, Wrap, WrapItem

## 使用箇所一覧

### Box(55箇所)
- src/pages/profile.tsx
- src/pages/settings.tsx
- src/components/layout/Layout.tsx
...

## 使用されているprops

### Box
| prop | 使用例 |
|------|--------|
| p | p={8}, p={6}, p={4} |
| bg | bg="white", bg="gray.50" |
| borderRadius | borderRadius="lg", borderRadius="md" |
...

## タスク

1. [pending] src/components/ui/Box.tsx を作成
2. [pending] src/components/ui/Box.module.css を作成
...

researcher が使用箇所と必要な props を洗い出し、worker はそれを見て実装するだけ。
コンテキストの引き継ぎが明確になり、サブエージェントが迷いにくくなります。

実装上の注意点も TODO に含める

## 実装上の注意点

### レスポンシブ対応
- SimpleGridのcolumnsはレスポンシブオブジェクト(base, md, lg)をサポートする必要がある
- HStack/VStackのflexWrapもレスポンシブオブジェクトをサポートする必要がある

### motion対応
- framer-motionのmotion()でラップされるケースがある(MotionBox = motion(Box))
- 新コンポーネントもmotion()でラップ可能にする必要がある

skills/ の実装例

/screenshot

---
name: screenshot
description: agent-browserでスクリーンショットを取得する
argument-hint: "<before|after> <path>"
user-invocable: true
---

# スクリーンショット取得

## 引数

- $0: before または after
- $1: ページパス(例: /compare/Button)

## コマンド

agent-browser --cdp 9222 open "http://localhost:3000/$1"
agent-browser --cdp 9222 screenshot "screenshots/issue-<number>/$1-$0.png" --full

/create-component

---
name: create-component
description: 共通UIコンポーネントを作成する
argument-hint: "<ComponentName>"
user-invocable: true
---

# $ARGUMENTS コンポーネントの作成

## 作成ファイル

- src/components/ui/$ARGUMENTS.tsx
- src/components/ui/$ARGUMENTS.module.css

## 手順

1. Chakra UIの$ARGUMENTSコンポーネントのAPI仕様を確認
2. src/components/ui/$ARGUMENTS.tsx を作成
3. src/components/ui/$ARGUMENTS.module.css を作成
4. src/components/ui/index.ts にexport追加
5. npm run build でエラーがないことを確認

/migrate-page

---
name: migrate-page
description: 指定したページを共通UIコンポーネントを使って移行する
argument-hint: "<page-path>"
user-invocable: true
---

# $ARGUMENTS ページの移行

## 手順

1. 対象ページのChakra UIインポートを特定
2. @chakra-ui/react → @/components/ui に置き換え
3. 型エラーがあれば修正
4. npm run build でエラーがないことを確認

rules/ でガードレール

ブランチ運用

# .claude/rules/migration.md

## ブランチ運用

- 親ブランチは `migration` を使用する(mainではない)
- 作業ブランチは `issue-<number>` 形式で作成
- PRは `migration` ブランチに向けて作成

git checkout migration
git pull
git checkout -b issue-<number>

Before/After 必須ルール

## Before/After必須

移行作業(Phase 2, 3, 4)では、Before/Afterのスクリーンショット取得を必ず行う。

### 手順

1. 作業開始前にBeforeスクリーンショットを取得
2. 作業完了後にAfterスクリーンショットを取得
3. Before/Afterを比較して差異がないことを確認
4. 差異がある場合は修正

## 違反した場合

スクリーンショットを取得せずに作業を進めた場合、その作業は無効とする。

この「無効とする」という強い表現がポイント。Claude Code はルールに従おうとするので、スクショ忘れを防げ……られないときも多いです。
Claude Code が言うにはこのようにする方がいいらしいです。
でも君忘れるやん

認証が必要なアプリでのスクショ

Firebase Auth が必要なアプリなので、普通にスクショを撮ってもログイン画面しか映りません。

解決策: CDP Mode で認証済みChromeに接続。

# 人間がやる: デバッグポート付きでChrome起動 → ログイン
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
  --remote-debugging-port=9222 \
  --user-data-dir=/tmp/chrome-debug-profile &
# Claude Code がやる: 認証済みChromeでスクショ
agent-browser --cdp 9222 screenshot "profile-before.png" --full

Phase ごとのワークフロー比較

Phase 1: コンポーネント作成

3つのサブエージェント(researcher → worker → reviewer)を使う最も複雑なフロー。

  • researcher: 使用箇所と props を調査、TODO 作成
  • worker: コンポーネント実装
  • reviewer: コードレビュー、比較ページでの動作確認

このようなスクショを取得します。

Claude Code のスクショの取得忘れが非常に多く、commands, rules, skills に徹底するように指示しました。
それでも取得しないケースもあり、都度指摘するほうがいいかもしれません。

font size や color の間違いも多かったです。
それでも取得したスクショで確認して指摘するだけですので、自分で移行作業することに比べるとかなり楽できてますね。

Phase 2, 3: 置き換え

2つのサブエージェント(worker → reviewer)で十分。

  • worker: インポートパス変更
  • reviewer: ビルド確認、スクショ比較

Phase 4: 削除

サブエージェント不要。メインエージェントが直接実行。

1. 全ページのBeforeスクリーンショット取得
2. Chakra UI関連パッケージを削除
3. _app.tsxからChakraProvider削除
4. npm run build 確認
5. 全ページのAfterスクリーンショット取得
6. Before/After比較

おわりに

Claude Code + agent-browser + サブエージェント活用で、UIライブラリ移行をかなり自動化できました。

特に効果的だったのは:

  • サブエージェントによる分業 - researcher/worker/reviewer の役割分担
  • TODOファイルでの引き継ぎ - コンテキストを明示的に渡す
  • ルールによるガードレール - スクショ必須、ブランチ運用の強制

並列化

Phase 1 がある程度すすんだところで並列化を試してみました。

Phase1のissue(#181~#187)をgit worktreeとsub agentを使って並列で作業してほしい

「通知されます」とか「待ちます」とか Claude Code が言ってきますが信じてはいけません。
通知されないです。ちょいちょい突かないと終わってても何も言ってきません。
突いても「コンポーネントファイルは全て作成済みです!比較ページとPR作成の状況を確認します。」とか調子のいいこと言われますので、深呼吸して対応しましょう。
Bash の権限がうまく渡せていないのか gh や agent-browser のコマンドが失敗していましたので main agent から実行しました。

同時に見なくてはいけない範囲が多くなる分人間の確認作業がかなり大変でした。
Claude の見た目の確認の精度が上がれば良いやり方を検討できそうですね。

他にも node_modules がうまく install できてなかったり、どの作業をしているのかわからなくなったりと自分では並列化は扱いきれず諦めました。

MEMO:

✅ PR #217〜#223 を全て閉じた
✅ worktree 7つを全て解除
✅ ローカル・リモートブランチを削除
✅ 実行中のagentを停止
並列worktree方式は、各worktreeでnode_modulesが必要になる問題がありました。別のアプローチを検討した方が良さそうです。

まとめ

  1. サブエージェントでコンテキスト分離 - 調査・実装・レビューを分けることで、各エージェントの責務が明確に
  2. TODOファイルで引き継ぎ - サブエージェント間の情報共有を明示的に
  3. rules/ で強制ルール - 「違反した場合は無効」のような強い表現が効く(やるとはいってない)
  4. skills/ でワークフロー定型化 - 毎回同じ指示を書かなくて済む
  5. agent-browser でスクショ比較 - 見た目の変化を人間がチェックしやすいようにする

このやり方に行き着くまで結構試行錯誤してます。
よかったら repo にある docs/**/*.md をみてください〜〜
Star もよろしくおねがいします!

ドクターメイト

Discussion