Claude Codeの/simplifyで差分を4つのエージェントが並列にクリーンアップする — /code-reviewはその後に実行する
Claude Codeの/simplifyスキルは、4つのエージェントで差分を並列にレビューして修正を適用します。そのあと/code-reviewで、修正後のコードにバグがないかを確認します。

目次
はじめに
Claude Codeに同梱されているスキル/simplifyを、私は何週間も使っていましたが、それが何をしているのかは知りませんでした。知っていたのは、/code-reviewという双子のようなスキルがあり、2つを組み合わせて使うよう勧める人が多いということだけです。2つのスキルはよく似て見えましたが、どう役割を分けているのかは説明できませんでした。
/simplifyはクリーンアップ専用のレビューです。4つのエージェントが差分を並列に読み、それぞれが1つの観点を担当します。観点は再利用、簡素化、効率、そして抽象度(変更が適切な層にあるか)です。修正はそのままワーキングツリーに書き込まれ、適用する修正を事前に一覧から選ぶ機会はありません。
/simplifyは正しさに関するバグを一切探さないので、/code-reviewはその後に、/simplifyが残したコードに対して実行します。このブログの実際のコミットで両方を実行し、それぞれが何を見つけるかを確かめました。
/simplifyが実行する内容
/simplifyはバンドルスキルです。Claude Codeに組み込まれたプロンプトで、モデルが自分のツールを使ってレビューと修正をどう進めるかを指示します。コマンドリファレンスでは、次のように説明されています(拙訳)。
変更されたコードをクリーンアップの観点でレビューし、修正を適用します。4つのレビューエージェントが並列に動き、既存ヘルパーの再利用、簡素化、効率、変更が適切な抽象度にあるかを確認します。正しさに関するバグは探しません。バグを見つけるには
/code-reviewを使ってください。
読み込まれるプロンプトは3つのフェーズで進みます。
- 差分を集める。upstreamブランチに対する
git diffに、コミット前の変更を加えたものです。引数でパスやプルリクエストを渡した場合はそれが対象になります。 - レビューする。4つのエージェントが同時に起動し、それぞれがステップ1で集めた差分と、担当する観点を受け取ります。
- 適用する。同じ行を指す指摘は1つにまとめられ、そのうえで1件ずつワーキングツリー上で修正されます。
各エージェントは、プロンプトからそれぞれ1つの担当を与えられます。
| エージェント | プロンプトが探すよう指示している内容 | 後述の実行での例 |
|---|---|---|
| 再利用 | コードベースにすでにあるヘルパーを、新しいコードが作り直していないか。共有モジュールや近くのファイルを検索して確認する | scripts/indexnow.tsでもnew URL(SITE)を作っているが、解析済みの値をエクスポートしている場所はなく、新しいコードから読み込めるものはない |
| 簡素化 | 冗長な状態や導出できる状態、少しだけ違うコピー&ペースト、深いネスト、消し忘れたデッドコード | resolveMarkが組み立てたオブジェクトを、唯一の呼び出し側がすぐに分解していた |
| 効率 | 繰り返される計算やI/O、独立しているのに順番に実行される処理、頻繁に通る経路に追加された処理 | luminance(DARK_BACKGROUND)がすべてのページのすべてのアイコンで計算し直されており、モジュール読み込み時に1回計算すれば済む |
| 抽象度 | 根本原因が1つ深い層にあるのに表面で症状を直していないか、共有コードに特殊ケースを積み重ねていないか | ブログの旧ホスト名が、site.tsではなくマークの表に直書きされていた |
適用フェーズを担うのは4つのレビュー担当ではなくメインのエージェントで、指摘を見送ってよい条件が書かれています。プロンプトから引用します(拙訳)。
修正が意図した動作を変える指摘、レビュー対象の差分から大きく外れた変更が必要な指摘、誤検知と判断した指摘は見送ってください。反論はせず、見送ったことを記録してください。
バグを探すのは、同じくバンドルスキルである/code-reviewの役割です。
/simplify | /code-review | |
|---|---|---|
| 探すもの | 再利用、簡素化、効率、抽象度 | 正しさに関するバグ。モデルとeffortレベルによってはクリーンアップも |
| ファイルの編集 | 修正を常に適用する | --fixを渡さない限り報告のみ |
| 実行形態 | 4つのレビューエージェントが並列 | 専用のコンテキストウィンドウを持つバックグラウンドのサブエージェント |
| 引数 | パス、またはプルリクエストの番号かURL | low〜maxまたはultraのeffortレベル、--fix、--comment、--max-findings、プルリクエスト・ブランチ・パス |
その3月の記事は、Rubyの静的解析・フォーマットツールであるRuboCopの作者、Bozhidar Batsov氏によるものです。同氏は/simplifyを「最もよく使うスキル」と呼び、「大きめのリファクタリングの直後や、AIが生成したコードをまとめて受け入れた直後」に実行しています(引用は拙訳)。
実際の差分で/simplifyを実行する
私が選んだのは、すでに本番公開済みの差分です。rehype-link-icons.tsは、リンクの横にブランドマークを描くこのブログのrehypeプラグイン(HTMLの構文木を加工するプラグイン)で、選んだ差分はそこに4つの新しいマークを追加したものでした。Qiita、Zenn、DevelopersIOの3つと、このブログへのリンクに付けるこのブログ自身の印(判子)です。
過去のコミットを別のワークツリーにコミット前の変更として再適用し、/simplifyが本来のコードや作業中の変更に触れずに自由に編集できるようにしました。
git worktree add --detach ../simplify-trial <commit>^git -C ../simplify-trial cherry-pick -n <commit>そのワークツリーの中で、Claude Code 2.1.310を使って次を実行しました。
/simplify src/lib/rehype-link-icons.ts4つのエージェントが返した指摘は9件で、/simplifyはそのうち3件を適用しました。
| エージェント | 指摘 | 適用 |
|---|---|---|
| 再利用 | 0 | 0 |
| 簡素化 | 3 | 2 |
| 効率 | 0 | 0 |
| 抽象度 | 6 | 1 |
再利用と効率が0なのは、この2つのエージェントが報告したのが前の表の例のような所見だけで、今回の差分で直すべき点はなかったからです。
適用された3つの修正
最も大きな修正は、上の表の簡素化の例にあたるMarkSymbol型の削除でした。この型の役割は、idフィールドをresolveMarkから唯一の呼び出し側に渡すことだけでした。その呼び出し側であるスプライト(すべてのマークをまとめた非表示の<svg>)を組み立てるコードは、戻り値を受け取った瞬間に分解していました。
function resolveMark(key: MarkKey): MarkSymbol { if (isLocal(key)) return { id: symbolId(key), ...LOCAL_MARKS[key]() }; return { id: symbolId(key), viewBox: "0 0 24 24", children: [markPath(key)] };}// …children: [...used].map((key) => { const { id, viewBox, children } = resolveMark(key); return element("symbol", { id, viewBox }, children);}),/simplifyはresolveMarkを、<symbol>ノードそのものを返すsymbol()に置き換え、MarkSymbol型はなくなりました。
function symbol(key: MarkKey): HastNode { const { viewBox, children } = isLocal(key) ? LOCAL_MARKS[key]() : { viewBox: "0 0 24 24", children: [markPath(key)] }; return element("symbol", { id: symbolId(key), viewBox }, children);}// …children: [...used].map(symbol),残りの2つは小さな修正です。
- faviconの読み取り方:プラグインは印の形状をfaviconから読み取っています。これまで
<svg>タグだけ別の行で読み、<circle>・<g>・<path>は1つの.mapで読んでいました。今は4つとも同じ.mapで読み取り、結果は変わりません。 - 旧ホスト名:ブログの旧アドレス
oharu-tech-blog.vercel.appがマークの表に直書きされていましたが、サイトのアドレスはsite.tsに置くべきものです。上の表の抽象度の例がこれです。今はsite.tsのLEGACY_HOSTSに移り、アドレスが変わってもsite.tsだけを直せば済みます。
見送られた6つの指摘
/simplifyが見送った6件の指摘と、その理由です。
| 指摘の提案 | 見送った理由 |
|---|---|
| 自前で描いたマーク(DevelopersIOと印)にもコントラストのチェックを通す | 動作が変わる:ダークモードでこの2つのマークの色が変わる |
リンクをパースしてから分類し、./other/のようなリンクにも印を付ける | 動作が変わる:今はアイコンのないリンクに印が付くようになる |
各アイコンの外側の<svg>から24×24のviewBoxを外す | 動作が変わる:アイコンの表示サイズが変わる可能性がある |
public/favicon.svgを正規表現で解析する代わりに、ブランドのジェネレーターから印の形状をモジュールとして出力させる | 差分の外側に及ぶ:変更先はfaviconを生成する別のスクリプトになる |
新しいelement()ヘルパーを、以前からあるノードビルダーでも使う | 差分の外側に及ぶ:今回のコミットが触れていないコードを変更することになる |
isLocalの分岐を、形の揃った1つのマークオブジェクトに置き換える | 一部は対応済み:symbol()への変更で、この分岐が出てくる場所の1つはすでに消えている |
/simplifyは、自分が編集したコードを実行しません。そこでClaude Codeが、3つの修正でページ上の表示が何も変わっていないことを別途確認しました。6種類のリンク(GitHub、ルート相対、旧ホスト、DevelopersIO、Zenn、脚注)を修正前と修正後のプラグインにそれぞれ通したところ、出力は完全に一致しました。
/simplifyが残したコードに/code-reviewを実行する
/simplifyが編集したrehype-link-icons.tsとsite.tsの2ファイルに/code-reviewを実行すると、指摘は10件でした。
そのうち9件は、本番公開されたときのコミットにすでにあったものです。この9件のうち3件はそのまま再現できます。
| 入力 | プラグインの動作 | 理由 |
|---|---|---|
href="/\github.com/x" | GitHubのマークを描く | ルート相対の判定は//を除外するが/\は除外せず、URLのパースではバックスラッシュがスラッシュとして読まれる |
href="http://constructor/" | TypeError: key.slice is not a functionを投げ、ビルド全体が失敗する | マークの表がプレーンなオブジェクトなので、ホスト名からObject.prototype.constructorが引ける |
DevelopersIOの#cbd31eのセグメント | ライトテーマの白背景に対するコントラスト比が1.63:1で、WCAGが求める3:1を下回る | 自前で描いたマークはコントラストのチェックを通らない |
抽象度のエージェントもmarkForにあるルート相対判定の正規表現を読んでいましたが、指摘したのは判定を置く層が不適切だという点だけでした。この正規表現が不正なhrefを通してしまうかどうかは正しさの問題で、このエージェントの担当外です。そのため、バックスラッシュのケースは/code-reviewまで見つかりませんでした。
/simplifyと/code-reviewはいつ実行するか
/simplifyを先に、/code-reviewを最後に実行します。/simplifyはワーキングツリーのコードを直接書き換え、レビューが見るのは実行した時点のコードだけです。順番を逆にすると、/simplifyによる変更はレビューされないままコミットされます。
Batsov氏の3月の記事で紹介されているワークフローは逆の順番で、「変更を加え、/reviewで問題を見つけ、指摘をすべて直してから/simplifyで整える」(拙訳)という流れです。
まとめ
/simplifyは差分を4つのエージェントに並列に渡し、再利用、簡素化、効率、抽象度の観点で修正を適用します。動作を変える修正や差分の外側に及ぶ修正は見送ります。バグは一切探さず、編集したコードを実行することもありません。
/code-reviewはその後に、/simplifyが残したコードに対して実行します。すでに本番公開したコミットでこの2つを試すなら、git cherry-pick -nでそのコミットを別のワークツリーに再現し、そこで実行してください。

