kanzaki
v0.3.3
Published
LLM-powered semantic pre-commit linter. Define rules in Markdown, review diffs with AI.
Maintainers
Readme
Kanzaki
変更内容を、Markdownで書いたチェックリストに照らしてLLMがレビューするCLIツールです。既定では git diff --staged を起点にしますが、--working-tree / --range / --files で任意のレビュー範囲に切り替えられます。
概要
kanzaki check を実行すると、変更内容を .kanzaki/rules.md に書かれたルールと照合し、LLM(OpenAIまたはAnthropic)に判定させます。違反が見つかった場合、重要度に応じてコミットをブロックするか警告を出します。
チェック対象はコードに限りません。ドキュメント、リサーチノート、設定ファイルなど、テキストベースの差分であれば利用できます。ルールは自然言語で記述するため、フォーマッターや構文チェッカーでは検出できない「意味的な問題」を拾うことを目的としています。
ただし、LLMの判定は100%正確ではありません。誤判定を前提に、重要度を使い分けて運用することを推奨します。
しくみ
kanzaki check は次の手順で動作します。
- 起点の決定 — 既定は
git diff --staged。フラグで--working-tree(git diff HEAD)、--range <a..b>、--files <paths...>に切り替え可能。起点フラグ同士は排他です。 - 対象ファイルの取得 — 起点に応じて変更ファイル(または指定ファイル)の一覧を決定します。0件なら終了します。
- 認証情報のロード — CLIフラグ → 環境変数 →
~/.config/kanzaki/credentials.jsonの優先順位で解決します。 - ルール解析 —
.kanzaki/rules.mdから次の要素を抽出します。- [ ]で始まる行 → ルール(重要度・判定スコープ・テキスト)## ヘッダー (*.ts)の形式 → グループ名とファイルスコープ- それ以外のテキスト → LLMに渡す補足コンテキスト
- フォーマット検証 — ルールファイルの書式エラー(空ルール、重複、閉じ括弧忘れなど)を検出します。エラーが1件でもあればLLMを呼ばずに
exit(1)で中断します。詳細は ルールファイルのフォーマットチェック を参照してください。 - 差分とファイル内容の取得 — 起点に応じた diff と、対象ファイルの全文(バイナリや100KB超は除外)を取得します。
rangeの場合は終端リビジョンでの内容をgit showで読み、filesの場合は現在の作業ツリーから読みます。 - ルールのフィルタリング — 対象ファイルにマッチしないファイルスコープのルールを除外します。
@state(<glob>)で追加参照先が指定されていれば、git ls-filesからマッチするファイルを追加で読み込みます。ここで適用対象ルールが0件になった場合は警告を出してexit(0)します。 - プロンプト構築 — コンテキスト、起点情報、ルール一覧(判定スコープ付き)、diff(最大50KB)、ファイル全文(各最大20KB)を1つのプロンプトにまとめます。
- LLM呼び出し — OpenAIはJSON mode、AnthropicはテキストレスポンスからJSONを抽出します。各ルールについて
{ rule, passed, reason }が返されます。 - 結果出力 —
!errorルールが1件でも失敗した場合はexit(1)でコミットをブロックします。!warnのみの失敗なら警告を表示してexit(0)します。 - フィードバック書き出し(既定で有効) — 違反があれば
.kanzaki/reviews/<タイムスタンプ>.mdにコーディングエージェント向けの指示ファイルを出力します。不要な場合は--no-emit-feedbackで無効化できます。詳細は エージェント向けフィードバック出力 を参照してください。
pre-commitフック(Husky等)で実行することを想定していますが、手動実行でも同じように使えます。
インストール
npm install -g kanzakiNode.js 20.6以上が必要です。
セットアップ
1. 認証
認証方式は4種類あります。いずれの場合も認証方法の指定が必須です。
# APIキーを対話入力(入力は ****** でマスク表示)
kanzaki login --provider openai # OpenAIのAPIキー
kanzaki login --provider anthropic # AnthropicのAPIキー
# ChatGPT Plus/ProサブスクリプションでOAuthログイン
kanzaki login --use-chatgpt
# ローカルのClaude Code CLIをサブプロセスとして利用
kanzaki login --use-claude引数なしで kanzaki login を実行すると、上記の選択肢を案内するエラーメッセージが表示されます。
認証情報は ~/.config/kanzaki/credentials.json に保存されます。一度ログインすれば全プロジェクトで使えます。
--use-chatgpt について
OpenAI公式の Codex CLI と同じOAuthフロー(Authorization Code + PKCE)でChatGPTサブスクリプションに紐づくトークンを取得し、https://chatgpt.com/backend-api/codex/responses に対してレビューリクエストを送ります。ChatGPT Plus/Proの利用上限が適用されます。
--use-claude について
ローカルにインストールされた claude コマンドをサブプロセスとして起動する方式です。Claude Code CLI が既にログイン済みである必要があります。kanzakiは claude -p にプロンプトをstdin経由で渡し、標準出力をJSONとして解釈します。認証・セッション管理はすべてClaude CLI側が担当します。
2. プロジェクトの初期化
cd your-project
npx kanzaki init.kanzaki/rules.md のテンプレートが作成されます。
3. Gitフックへの組み込み(任意)
コミット時に自動実行したい場合は、Husky等で kanzaki check を pre-commit フックに登録します。
npm install --save-dev husky
npx husky init
echo "npx kanzaki check" > .husky/pre-commit手動実行でも利用できます。
4. ルールのカスタマイズ
.kanzaki/rules.md をプロジェクトに合わせて編集します(詳細は後述)。
ルールの書き方
.kanzaki/rules.md はMarkdownのチェックリスト形式です。
基本構文
# プロジェクトのレビュールール
## グループ名
- [ ] ルールの内容(デフォルトで !error 扱い)
- [ ] !error 明示的にエラーとして定義
- [ ] !warn 警告のみ(コミットはブロックしない)重要度
| 記法 | 動作 |
|------|------|
| !error(デフォルト) | 違反時に exit(1) でコミットをブロック |
| !warn | 警告表示のみ、コミットは続行 |
判定スコープ
各ルールは「差分だけを見る」か「ファイル現状も見る」かを選べます。タグはseverityの前後どちらにも書け、省略時は diff。
| 記法 | 動作 |
|------|------|
| (未指定/@diff) | この変更が新たに違反を持ち込んでいないかを判定。既存の違反はスルー |
| @state | 対象ファイルの現状に対して判定。既存の違反も違反として扱う |
| @state(<glob>, ...) | @state に加えて、変更されていない参照ファイルもコンテキストに含める(例: 用語集、スキーマ) |
## コード (*.ts, *.js)
- [ ] !error @state console.log が残っていないこと
- [ ] !warn @state(docs/glossary.md) 用語が glossary と一致していること@diffは既存コードの負債で毎回ブロックされないpre-commit用途に向いています@stateは「このファイルが現時点で規約を満たしているか」を問うような、静的解析に近い用途に向いていますfiles-only起点(--files)では全ルールが実質stateとして評価されます
補足コンテキスト
チェックリスト以外のテキスト(段落など)はLLMへの補足情報として送信されます。プロジェクトの前提や背景をここに書くことで、判定の精度が変わることがあります。
# レビュールール
このプロジェクトは医療機器の規制文書を管理しています。
すべての変更は FDA 21 CFR Part 11 に準拠する必要があります。
## コンプライアンス
- [ ] !error 規制要件への参照が正確であること
- [ ] !error 変更履歴が適切に記録されていることファイルスコープ
ヘッダー名に続けて括弧で glob パターンを書くと、そのグループのルールは該当ファイルに変更があった場合のみ適用されます。
## ドキュメント (*.md, *.txt)
- [ ] !error リンク切れがないこと
- [ ] !warn 見出しの階層構造が正しいこと
## コード (*.ts, *.js)
- [ ] !error console.log が本番コードに残っていないこと
- [ ] !error ハードコードされた秘密情報がないこと
## 全ファイル
- [ ] !warn TODO コメントが残っていないことパターン未指定のグループは全ファイルに適用されます。
glob の挙動について — Kanzaki は軽量な内製 glob を使っており、アンカーは「ファイル名または
/直後」です。そのため*.tsは任意の深さで.tsファイルにマッチし、src/*.tsはsrc/foo.tsだけでなくapp/src/foo.tsなどネストしたsrc/配下にもマッチします。厳密なルート相対マッチが必要な場合は、プロジェクトを分けるか**/src/*.tsのように明示してください。
ルール例
リサーチ・論文
調査レポートや論文のレビューで最も労力がかかるのは「主張と根拠の対応」「論理展開の妥当性」「用語の一貫性」の確認であり、これらは Markdown リンターや textlint では判定できません。Kanzakiは本文全体を読んで主張単位で根拠の有無を判定できるため、形式的なチェックより手前の「意味レベルのレビュー」を任せられます。
# リサーチレビュールール
再生可能エネルギーに関する調査レポート。
データに基づいた客観的な分析が求められる。
## 正確性
- [ ] !error 統計データには出典が明記されていること
- [ ] !error 事実誤認や誤解を招く主張がないこと
- [ ] !warn 数値の単位が明確に記載されていること
## 構成
- [ ] !error 各セクションに適切な見出しがあること
- [ ] !warn 論理的な流れが維持されていること
## 文体
- [ ] !warn 用語が文書全体で統一されていること
- [ ] !warn 受動態の過剰使用を避けていること各ルールがKanzakiに向いている理由:
- 正確性: 「統計に出典があるか」「単位が明記されているか」は、主張と近傍テキストを対応づける意味的な照合が必要。静的解析では「数字が出てきた」までしか分からない。
- 構成: 見出しの有無は Markdown 構文でも見えるが、「セクションの内容が見出しと整合しているか」「論理展開が破綻していないか」は内容理解が前提のため LLM 向き。
- 文体: 用語統一は辞書ベースの lint でも可能だが、表記揺れ(「再エネ」と「再生可能エネルギー」など)やドメイン特有の用法を柔軟に拾うには自然言語ルールの方がメンテコストが低い。
ソフトウェア開発
Kanzakiは、linterでは拾いづらい「複数ファイルにまたがる意味的な整合性」や「ドメインの前提に照らしたレビュー」に向いています。単一ファイル内の構文ルール(未使用変数、console.logの検出、秘密情報の漏洩など)は、LLMに判定させるよりESLintやgitleaks等の静的解析に任せたほうが速く正確です。
# コードレビュールール
Next.js + TypeScript の SaaS アプリケーション。
認証が必要な API ルートは `withAuth` ミドルウェアでラップする運用。
## API とドキュメントの整合
- [ ] !error 新規の API ルート (`app/api/**/route.ts`) が `withAuth` でラップされていること
- [ ] !error 公開 API のリクエスト/レスポンス型を変更したら `docs/api.md` が同じPRで更新されていること
- [ ] !warn 新しい環境変数を追加したら `.env.example` にも追加されていること
## PII 取り扱い (*.ts, *.tsx)
- [ ] !error ログ出力に `email`・`phone`・`address` を素のまま渡さないこと(`maskPii()` を経由する)
- [ ] !warn 新規のエラーログは、原因調査に必要な識別子(`tenantId`、`requestId`)を含むこと
## 用語統一 (*.ts, *.tsx, *.md)
- [ ] !warn @state(docs/glossary.md) コメント・ドキュメントで使う業務用語が `glossary.md` の定義と一致していること各ルールがKanzakiに向いている理由:
- API とドキュメントの整合: linterは単一ファイルしか見ないため、「型を変えたらドキュメントも更新」のようなファイル間の同期は判定できない。
- PII 取り扱い: 「素のまま渡さない」は文字列テンプレートや分割代入を含むためパターンマッチが困難。LLMなら文脈を読んで「マスキング関数を経由しているか」を判定できる。
- 用語統一:
@state(docs/glossary.md)で glossary を追加コンテキストとして読み込み、変更されていない外部定義との整合を取る。
プレゼン・レポート
プレゼン資料の品質は「主張 → 根拠 → 結論の整合」と「複数スライドをまたいだ一貫性」にかかっています。スペルチェッカーや構文チェックでは「このグラフにソースが書かれていない」「前四半期比較が欠けている」といった欠落は見つけられません。Kanzakiは本文を横断的に読むため、こうした欠落や不整合を内容レベルで拾えます。
# プレゼンレビュールール
Q4 決算報告プレゼンテーション。
経営陣向け、データドリブンな内容が求められる。
## 内容
- [ ] !error すべてのグラフ・チャートにデータソースが記載されていること
- [ ] !error 前四半期との比較データが含まれていること
- [ ] !warn 結論がデータに基づいていること
## スタイル
- [ ] !warn 箇条書きが簡潔であること
- [ ] !warn フォーマットが全スライドで統一されていること各ルールがKanzakiに向いている理由:
- 内容: 「データソースが書かれているか」「比較データが含まれているか」は、スライド全体を通読して欠けている要素を検出するタスク。構文チェッカーでは「何が書かれているか」までしか判定できない。
- スタイル: 「箇条書きが簡潔」「全スライドでフォーマット統一」は、厳密な文字数閾値ではなく相対的な違和感を拾う判定で、LLM のファジーな基準が向いている。
ルールファイルのフォーマットチェック
kanzaki check はLLMにプロンプトを送る前に、ルールファイルの書式を検証します。以下のいずれかが検出された場合、LLMを呼び出さずに exit(1) で中断します。
| 検出内容 | 例 |
|---------|----|
| ヘッダーの括弧不一致 | ## Security (*.ts (閉じ括弧なし) |
| 空の括弧 | ## Foo () |
| 空のチェックリスト項目 | - [ ] (本文なし) |
| タグのみで本文なし | - [ ] !warn / - [ ] @state |
| 不正なseverityタグ | - [ ] !err foo (!error / !warn のみ有効) |
| @state(...) の閉じ括弧忘れ | - [ ] @state(*.md foo |
| @state() の空括弧 | - [ ] @state() foo |
| 不正なチェックボックス形式 | * [ ] foo や - [x] foo |
| 同一グループ内の重複ルール | 同じグループに同一のルールテキストが2回以上 |
エラーは行番号とともに表示され、コミット前に気づけるようになっています。
また、次の2つのケースはエラーではなく警告として扱われ、LLMを呼ばずに exit(0) で終了します。
- ルールファイルに有効なルールが1件もない場合
- 変更ファイルにマッチするルールが1件もない場合(ファイルスコープでフィルタされた結果)
プロンプトの構造
Kanzakiは1回のレビューで システムプロンプト と ユーザープロンプト の2つをLLMに送信します。ユーザープロンプトは次の順序でブロックを組み立てます(各ブロックは該当データがある場合のみ出現)。
## Project Context # rules.md の自由記述テキスト(任意)
<コンテキスト本文>
## Review Source # 起点ラベル("staged" / "range:a..b" / "files" など)
Source: <label>
Mode: files-only (no diff) … # --files 指定時のみ
## Checklist Rules # ファイルスコープでフィルタ後のルール
### <グループ名> (applies to: *.ts, *.md)
- Rule #1 [severity=ERROR, scope=state, also_consult=docs/glossary.md]
text: コメント中の業務用語が glossary.md と一致していること
- Rule #2 [severity=WARNING, scope=diff]
text: …
## Changes (git diff) # 起点が staged/workingTree/range のとき
```diff
<差分本文 最大50,000文字>Full File Context # 対象ファイル+@state() の参照先
src/example.ts
<ファイル全文 各最大20,000文字>
**サイズ制限**:
| ブロック | 上限 | 超過時 |
|---------|------|--------|
| diff 全体 | 50,000文字 | 末尾を `... (truncated)` で切り詰め |
| ファイル1件あたり | 20,000文字 | 同上 |
| ファイル読み込み時 | 100,000文字 | そのファイルを丸ごと除外 |
バイナリファイル(`.png`, `.pdf`, `.lock` など拡張子ベース)は自動で除外されます。
**システムプロンプトに含まれる指示**:
- レビュアーとしての役割定義(コード・ドキュメント・論文など任意のドメインに対応)
- `scope=diff` と `scope=state` の解釈ルール(差分のみを見るか、現状全体を見るか)
- `also_consult=<glob>` の意味(追加参照ファイル)
- レスポンスJSONスキーマ(`{ results: [{ rule, passed, reason }], summary }`)
**確認と拡張**:
- `kanzaki check --verbose` は送信される内容のメタ情報(プロバイダー・モデル・ルール件数・対象ファイル・追加参照ファイル)を表示しますが、プロンプト全文はダンプしません。
- 生のプロンプト構築ロジックは [`src/core/reviewer.ts`](src/core/reviewer.ts) の `SYSTEM_PROMPT` 定数と `buildUserPrompt()` 関数にあります。挙動を完全に把握したい場合はこちらを参照してください。
---
## エージェント向けフィードバック出力
`kanzaki check` は違反内容をまとめたMarkdownを `.kanzaki/reviews/<タイムスタンプ>.md` に**既定で書き出します**。Claude Code や Cursor などのコーディングエージェントに「このファイルを読んで修正してください」と渡す用途を想定しています。書き出しを止めたい場合は `--no-emit-feedback` を付けてください。
ファイルには次の内容が含まれます。
- ヘッダー(生成日時、エラー数・警告数、変更ファイル一覧)
- エージェントへの指示文(違反を修正し、`git add` の上で再度 `kanzaki check` を実行する旨)
- 違反ごとのセクション(重要度タグ、ルールテキスト、グループ、適用スコープ、rules.mdの行番号、LLMが示した違反理由)
違反が0件のときはファイルを作成しません。`.kanzaki/reviews/` は `kanzaki init` が生成する `.kanzaki/.gitignore` によってGit管理対象外になります。
---
## コマンド一覧
| コマンド | 説明 |
|---------|------|
| `kanzaki init` | `.kanzaki/rules.md` テンプレートを作成 |
| `kanzaki check` | ステージ済みの変更をレビュー |
| `kanzaki login` | 認証情報を保存 |
| `kanzaki logout` | 保存済み認証情報を削除 |
| `kanzaki status` | 現在の認証状態を表示 |
### `kanzaki login` のオプション
| オプション | 説明 |
|-----------|------|
| `-p, --provider <名前>` | `openai` または `anthropic`(デフォルト: `openai`) |
| `--use-chatgpt` | OpenAIのOAuthフロー(ChatGPT Plus/Pro) |
| `--use-claude` | ローカルのClaude CLIをサブプロセスとして利用 |
### `kanzaki check` のオプション
| オプション | 説明 |
|-----------|------|
| `-p, --provider <名前>` | LLMプロバイダー(`openai` / `anthropic`) |
| `-m, --model <名前>` | 使用モデル |
| `-r, --rules <パス>` | ルールファイルのパス(デフォルト: `.kanzaki/rules.md`) |
| `--api-key <キー>` | APIキーを直接指定(`kanzaki login` の利用を推奨) |
| `--no-block` | エラーでも `exit(1)` せず、警告のみ |
| `-o, --emit-feedback` / `--no-emit-feedback` | 違反をまとめたmarkdownを `.kanzaki/reviews/` に書き出す(既定: 有効)。`--no-emit-feedback` で無効化 |
| `-v, --verbose` | 詳細出力 |
| `--working-tree` | ステージではなく作業ツリー(`git diff HEAD`)をレビュー |
| `--range <a..b>` | 任意のリビジョン範囲をレビュー(例: `HEAD~3..HEAD`) |
| `--files <paths...>` | 指定ファイルの現状をレビュー(diffなし、git管理外もOK) |
| `--all` | `git ls-files` で取れる**全追跡ファイル**をレビュー(diffなし、小さなリポジトリ向け) |
| `--max-bytes <n>` | LLMに送る合計バイト数の上限。超えたら実行前に `exit(1)`(デフォルト: `2000000`) |
`--working-tree` / `--range` / `--files` / `--all` は排他で、同時に指定するとエラーになります。いずれも指定しなければ既定の staged 起点です。
`--all` はドキュメント中心の小規模リポジトリなど、全体を1プロンプトに入れられるケース向けです。大きなリポジトリでは `--max-bytes` に引っかかって止まるため、`--range` や `--files` で範囲を絞るか、`--max-bytes` を上げてLLMのコンテキストウィンドウに収まる範囲で指定してください。`--max-bytes` の見積もりは、diff(最大50,000文字)と各ファイル内容(各最大20,000文字)のトランケート後の合計で計算されます。
---
## 環境変数
| 変数 | 説明 | デフォルト |
|------|------|-----------|
| `KANZAKI_API_KEY` | LLM APIキー | — |
| `KANZAKI_PROVIDER` | `openai` / `anthropic` | `openai` |
| `KANZAKI_MODEL` | モデル名 | `gpt-5.4`(OpenAI)/ `claude-opus-4-7`(Anthropic) |
| `KANZAKI_RULES_PATH` | ルールファイルのパス | `.kanzaki/rules.md` |
プロジェクトルートに `.env` があれば自動で読み込まれます。
---
## ライセンス
MIT