ソフトウェア開発におけるコードレビューは品質保証の要です。しかし、レビューの質はレビュアーの専門知識と集中力に大きく依存し、人間のレビューでは見落としが避けられません。
この課題に対して、Linuxカーネル開発コミュニティから生まれたのがSashikoです。
本記事では、Sashikoの仕組みを詳しく解説し、それをJavaScript/TypeScriptライブラリのレビュー向けにカスタマイズしたSashiko JSについて紹介します。
Sashikoとは何か?
Sashiko(刺し子)は、Google社員のRoman Gushchin氏が開発したAIを用いたバグ発見システムです。特にLinuxカーネルのパッチをAIで自動レビューします。名前の由来は日本の伝統的な補修刺繍技法で、「布の弱い部分を補強する」という意味が、コードの脆弱な部分を見つけ出すという使命に重ねられています。
Sashikoはオープンソースプロジェクトとして公開されており、実際にLKML(Linux Kernel Mailing List)に投稿されるすべてのパッチを自動的にレビューしています。SashikoのREADMEによると、
Sashiko is not perfect, but in our measurements the quality of reviews is high: in our tests sashiko was able to find 53.6% (with Gemini 3.1 Pro) of bugs based on unfiltered last 1000 upstream commits with Fixed: tags. In some sense, it's already above the human level given that 100% of these bugs made it through human-driven code reviews and were accepted to the main tree.
とあり、直近の問題1000件のうち53%を自動的に検出することができたとのこと。またSashikoが発見した問題の100%は人間によって見過ごされていたもののようです。
Sashikoの有用性はどこにあるのか?
さらにREADMEを読み進めていくなかで、ふと疑問に思いました。そもそも「AIでコードレビューするなら、Claude CodeやChatGPTにdiffを貼り付ければいいのでは?」と。しかし、Sashikoはレビューのための複雑なアプローチをRustのコードで実現しているようでした。
単純なLLMレビューについて考える
例えばClaude Codeに「このdiffをレビューして」と依頼した場合、いくつかの問題があります。
- ワンショットで全観点をカバーしようとする
- diffだけでは呼び出し元・呼び出し先がわからない = コードの文脈が不足している
- 偽陽性が多い
- CopilotレビューやCodeRabbitやDevin Reviewなどなどでありがちな芯を食わない指摘
Sashikoの強み
上記の単純LLMレビューの問題点に対し、Sashikoは以下のようなアプローチで解決を試みているようです。
| 観点 | 単純なLLMレビュー | Sashiko |
|---|---|---|
| 分析の深さ | 1回のプロンプト | 9段階の専門家視点 |
| コード文脈 | diffのみ | ツールで能動的にコードベースを探索 |
| 偽陽性 | 多い | 専用ステージで排除・検証 |
| スケーラビリティ | 手動実行 | サーバー型で自動化・並行処理 |
| カスタマイズ | プロンプト手書き | ドメイン別プロンプトレジストリ(後述) |
なかでもSashikoの他と一線を画したレビュー結果に寄与している要因は以下の3点なのではないかと考えています。
- Function Callingによるツール提供 = コンテキストを得るための手段
- 9段階レビュープロトコル = 分析の構造化
- 偽陽性の排除の仕組み
以降のセクションでは、この3点にフォーカスしながらSashikoの仕組みを見ていきたいと思います。
Sashikoのアーキテクチャ概観
Sashikoの本質的な価値はツール提供・9段階プロトコル・偽陽性排除にありますが、それらを支えるインフラとしてのアーキテクチャも興味深いので簡単に触れておきます。以下は、Sashikoの簡単な構成図です。
graph LR
subgraph Input["入力"]
CLI["sashiko-cli<br/><small>submit HEAD</small>"]
NNTP["Ingestor<br/><small>NNTP / Git</small>"]
end
subgraph Pipeline["メッセージ駆動パイプライン"]
direction LR
raw_tx["raw_tx<br/><small>mpscチャネル</small>"]
Parser["Parser<br/><small>spawn_blocking</small>"]
parsed_tx["parsed_tx<br/><small>mpscチャネル</small>"]
DBWorker["DB Worker<br/><small>バッチ書き込み</small>"]
end
DB[("SQLite<br/><small>libsql</small>")]
subgraph Review["レビュー"]
Reviewer["Reviewer<br/><small>10秒ポーリング</small>"]
Worktree["Git Worktree"]
AI["AI Worker<br/><small>9 Stages</small>"]
end
LLM["Gemini / Claude"]
CLI --> raw_tx
NNTP --> raw_tx
raw_tx --> Parser --> parsed_tx --> DBWorker --> DB
DB --> Reviewer --> Worktree --> AI --> LLM
style Pipeline fill:#e8f4fd,stroke:#4a9eda
style Review fill:#fff3cd,stroke:#ffc107
全体はRust製の非同期サーバーで、注目すべきはメッセージ駆動のパイプライン設計です。パッチの取り込みからレビュー完了まで、各段階がTokioのmpscチャネルで疎結合に繋がっています。
具体的には、raw_txチャネルに投入された生データが、spawn_blockingで別スレッド実行されるParserで解析され、parsed_txチャネル経由でDB Workerに渡されます。DB Workerは50件単位のバッチでトランザクション書き込みを行い、Reviewer Serviceが10秒間隔でPendingなパッチセットをポーリングしてレビューを起動します。
この設計により、パッチの取り込み・解析・レビューが互いにブロックせず独立して動きます。LLMのAPI呼び出しが遅くても取り込みが止まることはありません。大量のパッチが一度に来てもチャネルがバッファとして機能します。Linuxカーネルのメーリングリストという大量のトラフィックを捌くために必要な設計であり、Sashikoが単なるスクリプトではなく本格的なシステムとして作られていることがわかります。
ではここから、Sashikoの本質的な3つのコンセプトを順に見ていきます。
ツールの提供
SashikoはAIが自律的にソースコードの解析を行うために必要なツールを提供しています。
read_files: ソースコードの読み込みgit_blame: 変更履歴の追跡git_log/git_show: コミット履歴の調査search_file_content: 正規表現によるコード検索find_files: ファイルパターン検索
これにより単にdiffだけが最初のコンテキストとして与えられたとしても、AIが能動的に足りないコンテキストを補完することができるようになります。
これらのツールはtool.rsのget_declarations()でツールの名前・説明・パラメータをJSON形式で定義します。これをGemini/Claude APIのtoolsパラメータとして送ります。AIはそのtoolから「xxxを呼びたい」とJSONで返答します。するとtools.rsのcall()がそのJSON要求を受け取り、Rust側でtoolを実行する。その実行結果をAIへ返すことで、AIが次の判断を行う...という流れになっています。
9段階レビュープロトコル
Sashikoはレビューを9つのステージに分割して実行します。簡単な全体の流れは以下の通りです。
flowchart LR
P0["ガイド選別"]
S17["Stage 1-7<br/><small>7つの専門家が<br/>独立して分析</small>"]
S8["Stage 8<br/><small>偽陽性排除<br/>+ 重大度判定</small>"]
S9["Stage 9<br/><small>レポート生成</small>"]
P0 --> S17 --> S8 --> S9
S17 -.->|"懸念なし"| SKIP["早期終了"]
S8 -.->|"所見なし"| SKIP
style S17 fill:#e8f4fd,stroke:#4a9eda
style S8 fill:#fce4ec,stroke:#e91e63
style P0 fill:#fff3cd,stroke:#ffc107
style S9 fill:#d4edda,stroke:#28a745
このStageのうち、最初に挙げた3大ポイントの残り二つ...多段階の分析がStage1-7で、偽陽性排除がStage8で行われます。これらについて少し詳しく見てみます。
多段階の分析
1回のプロンプトでざっくり「全部見て」と指示すると、AIは広く浅く見て終わりがちです。そこでSashikoはこれを7つの独立した専門家の視点に分割します。
| Stage | 専門家の役割 | 何を探すか |
|---|---|---|
| 1 | アーキテクト | API設計の欠陥、後方互換性の破壊 |
| 2 | 実装レビュアー | 要件の実装漏れ、副作用、契約違反 |
| 3 | 制御フロー分析者 | エラーパスの抜け、NULL参照、例外処理 |
| 4 | リソース管理者 | メモリリーク、リソース未解放、ライフサイクル |
| 5 | 並行処理の専門家 | デッドロック、レースコンディション |
| 6 | セキュリティ監査員 | 脆弱性、入力検証不備、権限の問題 |
| 7 | ドメイン専門家 | 領域固有の深掘り(カーネルならハードウェア操作等) |
各ステージはそれぞれ独立したAIセッションとして実行されます。つまりStage 2はStage 1の出力を知りません。前のステージの結論に引きずられるバイアスを排除し、各視点が独立して問題を発見できるようにしています。
偽陽性排除
Stage1-7で7つの専門家がそれぞれ懸念事項を報告しますが、そのまま出力すれば大量の的外れな指摘が混ざります。CopilotレビューやCodeRabbitで「芯を食わない指摘」が多い原因は、まさにこのフィルタリングの欠如です。Stage8はすべての懸念事項を集約した上で、以下のようなルールで厳密なフィルタリングを行います。
- 重複排除
- 複数ステージが同じ問題を異なる角度から報告した場合、統合して1つにします。
- 偽陽性排除
- 専用の
false-positive-guide.mdに基づいて、よくある誤検知パターンを除外します。例えば「防御的プログラミングを問題として報告する」「フレームワークが保証していることを再検証する」といったパターンです。
- 専用の
- 具体的証拠の要求
- Stage8では「このコードパスで、この条件が成立するとき、この問題が具体的に発生する」という証拠がない懸念事項はすべて却下されます。
- 重大度の判定
- 生き残った所見に対してCritical / High / Medium / Lowの4段階で重大度を付与します。
最後にこれらの内容を人間が見やすい形のレポートとして出力し、レビューを終了します。
SashikoをJS/TS用にカスタマイズする
ここまで見てきた内容を踏まえると、Sashikoの本質的な価値は以下の2点にあると考えられます。
- AIが自律的にレビューに必要な情報を収集できるツールが提供されている
- いくつかの異なる視点で情報を収集し、最後にそれらを統合/ノイズを除去する
つまりSashikoをLinuxカーネル以外のレビューに使う場合でも、元の構造を大きく変える必要はありません。基本的に必要なことは、「独立した専門家の視点」をLinux向けではなく、レビュー対象に応じたものに変えてあげることです*1。
そこで今回は表題のとおり、SashikoをJS/TS用にカスタマイズしてみることにします。かつ、ちょうどValibotにPRを出していたところだったので、そのPRのコミット内容を分析してもらうことにしました。
カスタマイズの基本方針
Sashikoのコードベースを直接フォークし、JavaScript/TypeScript向けに適応させました。基本的に変更したのは以下の2点です。
- 各ステージの「何を見るか」をJS/TS向けに書き換え
third_party/prompts/javascript/にJS/TSとValibot向けのプロンプトを作成- これが分析時に読み込まれる
- プロンプトをファイルベースにリファクタリング
- 再コンパイル不要でカスタマイズ可能にするべく、分析対象のコードベースへのパスをCLI引数で渡せるようにした
- 分析対象に応じてカスタムプロンプトを参照させられるように。今回の場合、
third_party/prompts/javascriptを指定。
もう少し詳しい修正対象は以下の通りです。
| ファイル | 変更内容 |
|---|---|
settings.rs |
prompts_dir設定フィールドを追加 |
worker/prompts.rs |
ステージプロンプトをファイルから動的に読み込む処理を追加 |
bin/review.rs |
--prompts、--repoのCLI引数を追加 |
reviewer.rs |
設定値からプロンプトディレクトリを参照するように変更 |
Cargo.toml |
パッケージ名をsashiko-jsにリネーム |
Settings.toml |
JS/TS向けのデフォルト設定に変更 |
これにより、別のライブラリ固有のガイドを追加するには、third_party/prompts/javascript/subsystem/にMarkdownファイルを追加し、subsystem.mdの索引を更新するだけでOKとなっています。作成したカスタマイズは以下に置いています。
実際にSashiko JSでValibotへのPRをレビューしてみる
では早速レビューをしてみます。今回はgemini-2.5-proでレビューしてもらうことにしました。
ビルド -> cargo runするとサーバーが起動します。http://127.0.0.1:8080 でダッシュボードにアクセスできます。アクセスのまえに、いくつかレビュー対象を投げておきます。以下のようにCLIを実行します。
# 最新コミットをレビュー cargo run --manifest-path Cargo.toml --bin sashiko-cli -- submit HEAD # 特定のコミットをレビュー cargo run --manifest-path Cargo.toml --bin sashiko-cli -- submit ec8f9d71ab20f1eedfd88c67ca20737ab0eb8613 # コミット範囲をレビュー cargo run --manifest-path Cargo.toml --bin sashiko-cli -- submit HEAD~5..HEAD
Webダッシュボードにアクセスすると、レビュー一覧が状態と共に確認することができます。


しばらく待っていると、レビュー状態がReviewedになりました。Critical: 2 · High: 1 · Medium: 1 · Low: 0 となっています。

実際に確認すると、やはり4つの指摘事項が記載されています。

Looking at the template literal types for cron fields,
CronFieldValueuses${string}in a few places. Could this allow non-numeric values to pass type checking, for example in a value like'*/abc'? SincebuildCronthen casts the result toCronExpressionwithout any runtime validation, I'm wondering if this might create a false sense of type safety.

I noticed that the
CronActionoutput type is the same as its input type here. Was it intentional not to narrow the output type to the brandedCronExpression? It seems like this could be a great opportunity to improve type safety for users of thecronaction, so they get the branded type after a successful validation.

I have a couple of questions about the validation logic in
_isCron. The regexCRON_FIELD_PATTERNseems like it might be a bit too permissive. For example, would it incorrectly accept an expression like'1/2-10', which isn't standard cron syntax? Also, the current implementation doesn't appear to check if the numbers in each field are within their valid ranges (e.g., minute 0-59, hour 0-23). Could this lead to invalid expressions like'99 99 * * *'being accepted?On another note, have we considered the performance implications of using
input.split(' ')on very large strings? It seems like it could be vulnerable to a denial-of-service issue if a malicious user provides a multi-megabyte string of spaces, which might cause excessive memory usage.
この4点はいずれもPRを作成した際には自分が認知していない指摘内容だったため、コードレビューを通過してしまう可能性がありました。
- うち1点目の指摘事項についてはPR内でCodeRabbitからも同様の指摘があり、対応済みの内容でした。
- 一方で残りの3点については、Copilot Review, CodeRabbitのいずれも検知できていない内容でした。
また今回のレビュー時にかかった費用は¥169.81でした。

まとめ
Sashikoは「AIにdiffを投げて感想を聞く」という素朴なアプローチとは一線を画す、構造化された多段階レビューシステムです。
- 9段階の専門家視点により、単一プロンプトでは見落とす問題を発見
- エージェント型のツール使用により、コードベース全体を能動的に調査
- 偽陽性排除の専用ステージにより、ノイズの少ない実用的なレビューを提供
GoogleのPrompt Engineeringに則った、AIによるコードレビューのまさにお手本となるようなアーキテクチャ/完成度となっていて、さすがGoogler...と感服しました。Sashikoのフレームワークをそのまま変わらず使うとした場合、ここからさらにレビューの精度を上げていくためには「third_party/promptsのクオリティをいかに上げるか?(=いいコンテキストを与えられるか)」となるため、やはり変わらず人間の専門性や発想力は重要だなと思いましたし、コンテキストエンジニアリングの時代は加速するのかなと思いました。
*1:例えば自社のアプリケーションを分析したいのであれば、チーム内の決まり事やドメイン知識などを与えてあげればよいことになる。