/moai clean
デッドコードの識別および安全な除去コマンドです。静的分析と使用グラフ分析を通じて 未使用コードを見つけ、安全に除去 します。
情報一行要約:/moai cleanは「コードダイエットツール」です。使っていない関数、変数、import、ファイルを 自動的に見つけて安全に削除 します。
情報スラッシュコマンド: Claude Code で/moai:cleanと入力すると、このコマンドをすぐに実行できます。/moaiだけ入力すると、利用可能なすべてのサブコマンド一覧が表示されます。
プロジェクトが成長すると、もう使っていないコードが溜まっていきます。未使用の import、呼び出されない関数、参照されない型などがコードベースを複雑にします。/moai clean はこうしたデッドコードを静的分析で見つけ出し、テスト検証を経て安全に除去します。
ハーネスエンジニアリングの観点では、このコマンドは ガベージコレクション の役割です。死んだコードは人間にとってだけの負担ではなくエージェントにとっても負担です — エージェントが読むコード 1 行 1 行がコンテキスト (トークン) なので、デッドコードの除去はコード衛生であると同時にコンテキストダイエット、すなわちトークノミクスです。
# 基本的な使い方
> /moai clean
# プレビュー (修正せず確認のみ)
> /moai clean --dry
# 安全な項目のみ除去
> /moai clean --safe-only
# 特定のファイル/ディレクトリのみ分析
> /moai clean --file src/auth/
# 特定のコードタイプのみ分析
> /moai clean --type functions| フラグ | 説明 | 例 |
|---|---|---|
--dry (または --dry-run) | 除去せず分析結果のみ表示 | /moai clean --dry |
--safe-only | 確実なデッドコードのみ除去 (不確実な項目はスキップ) | /moai clean --safe-only |
--file PATH | 特定のファイルまたはディレクトリのみ分析 | /moai clean --file src/utils/ |
--type TYPE | 特定のコードタイプのみ分析 | /moai clean --type imports |
--aggressive | 使用の少ないコードも含める (1 個の呼び出し元がデッドコードの場合) | /moai clean --aggressive |
| タイプ | 説明 |
|---|---|
functions | 呼び出されない関数/メソッド |
imports | 参照されない import 文 |
types | 使われない型定義 |
variables | 宣言後に使われない変数 |
files | どこからも import されないファイル |
実際のコードを修正せず、どの項目がデッドコードに分類されるかを事前に確認します:
> /moai clean --dryこのオプションは除去前に分析結果を検討したいときに有用です。
/moai clean は 7 ステップで実行されます。
flowchart TD
Start["/moai clean 実行"] --> Phase1["ステップ 1: 静的分析スキャン"]
Phase1 --> Phase2["ステップ 2: 使用グラフ分析と分類"]
Phase2 --> Classify{"分類結果"}
Classify --> Dead["確実なデッドコード"]
Classify --> TestOnly["テスト専用"]
Classify --> Likely["可能性のあるデッドコード"]
Classify --> False["誤検出 (実際に使用中)"]
Dead --> Phase3{"ステップ 3: 除去計画の承認
(AskUserQuestion / --dry?)"}
Phase3 -->|--dry または却下| Report["分析結果を表示して終了"]
Phase3 -->|承認| Phase4["ステップ 4: 安全な除去"]
Phase4 --> Phase5["ステップ 5: テスト検証"]
Phase5 --> Pass{"テスト通過?"}
Pass -->|いいえ| Rollback["ロールバック後に再試行"]
Pass -->|はい| Phase6["ステップ 6: MX タグ整理"]
Rollback --> Phase6
Phase6 --> Phase7["ステップ 7: 報告書"]ステップ 3 の除去計画承認は、オーケストレーターが AskUserQuestion で削除対象の一覧を示して承認を受けるヒューマンゲートです。ステップ 6 の MX タグ整理では、消したコードに付いていた @MX 注記まで一緒に取り除き、行き場を失った注記が残らないようにします。
プロジェクト言語を project marker で自動検出し、各言語の標準的なデッドコード分析ツールで候補を検出します。16 の対応言語を同等に扱い (go, python, typescript, javascript, rust, java, kotlin, csharp, ruby, php, elixir, cpp, scala, r, flutter, swift)、インストールされていないツールは自動的にスキップします。認識できる言語マーカーのないプロジェクトは静かに通過します。以下は代表例であり、特定の言語を優遇するものではありません:
| 言語 (例) | 分析ツール (例) | 検査対象 |
|---|---|---|
| Go | go vet, staticcheck, deadcode | 未使用の変数、関数、型 |
| Python | vulture, autoflake | デッドコード、未使用 import |
| TypeScript/JavaScript | ts-prune, ESLint no-unused-vars | 未使用 export、変数 |
| Rust | cargo clippy, cargo udeps | デッドコード警告、未使用の依存性 |
残りの 12 言語(java, kotlin, csharp, ruby, php, elixir, cpp, scala, r, flutter, swift など)も、それぞれの標準ツールチェーンで同じようにスキャンされます。
スキャンカテゴリ:
- 未使用 import: 参照がない import 文
- 未使用変数: 宣言されたが読まれない変数
- 未使用関数: 定義されたが呼び出されない関数
- 未使用型: 使用場所がない型定義
- 未使用ファイル: どこからも import しないファイル
- デッド依存性: インストールされたが import されないパッケージ
静的分析結果を検証するために使用グラフを構築します:
- 各候補についてコードベース全体で参照を検索
- 間接使用の確認 (インターフェース、リフレクション、動的ディスパッチ)
- テスト専用使用の確認 (テストのみで使用、プロダクションコードで未使用)
- 条件付きコンパイルの確認 (ビルドタグ、環境ベースの import)
| 分類 | 説明 | 除去の安全度 |
|---|---|---|
| 確実なデッドコード | コードベースのどこからも参照なし | 安全 |
| テスト専用 | テストファイルのみで使用される | おおむね安全 |
| 可能性のあるデッドコード | 低い信頼度 (動的使用の可能性) | 注意が必要 |
| 誤検出 | 実際に使用中 (リフレクション、プラグインなど) | 除去不可 |
依存性グラフの逆順で除去します (リーフノードから先に):
- 関連するコードをグループで除去 (関数 + 非公開ヘルパー)
- 影響を受ける import を更新
- すべての export が除去された空ファイルを整理
@MX:ANCHORタグがあるコードは明示的な承認なしに除去しない
除去後にテストスイート全体を実行して回帰を検証します。テストが失敗した場合、その除去をロールバックして「誤検出」に分類します。「消したけど大丈夫そう」ではなくテスト通過という証拠で安全を判定します。
デッドコード除去報告書
除去済み: 15 項目 (287 行)
- src/utils/helper.go: UnusedFunction (15 行)
- src/models/old.go: ファイル全体削除 (120 行)
維持 (誤検出): 2 項目
- src/api/handler.go: DynamicHandler (リフレクション使用)
テスト結果: PASS (すべてのテスト通過)
コードベースの削減:
- ファイル除去: 3 個
- 行の除去: 287 行
- 依存性の除去: 1 個/moai clean は Agent(general-purpose) リファクタリングスペシャリストのスポーン 2 回で実行されます (専用の named エージェントではなく、リファクタリングホワイトリスト + ANALYZE-PRESERVE-IMPROVE 指針がスポーン時点で注入される汎用エージェント)。ステップ 1・2 は 1 つの結合スポーン、ステップ 4・5 はもう 1 つの結合スポーン、ステップ 6 はオーケストレーター直接 (スポーンなし) です。
flowchart TD
User["ユーザーリクエスト"] --> MoAI["MoAI オーケストレーター"]
MoAI --> Refactor1["Agent(general-purpose) リファクタリングスペシャリスト
静的分析 + 使用グラフ (結合スポーン 1)"]
Refactor1 --> MoAI2["MoAI オーケストレーター
ユーザー承認"]
MoAI2 --> Refactor2["Agent(general-purpose) リファクタリングスペシャリスト
安全な除去 + テスト検証 (結合スポーン 2)"]
Refactor2 --> MoAI3["MoAI オーケストレーター
@MX タグ整理 (直接)"]
MoAI3 --> Complete["完了"]| エージェント | 役割 | 主な作業 |
|---|---|---|
| Agent(general-purpose) リファクタリングスペシャリスト (スポーン 1) | 分析 | 静的分析 + 使用グラフ (ステップ 1・2 結合) |
| Agent(general-purpose) リファクタリングスペシャリスト (スポーン 2) | 除去および検証 | 安全な除去 + テストスイート実行・回帰確認 (ステップ 4・5 結合) |
| MoAI オーケストレーター | 調整 | ユーザー承認、@MX タグ整理 (ステップ 6、直接) |
Git で元に戻せます。MoAI は依存性の逆順で除去してテストを実行するので、問題が起きれば自動的にロールバックします。
呼び出し元が 1 個でその呼び出し元もデッドコードの場合を含めたいときに使います。大規模なリファクタリング後の整理に有用です。
--safe-only モードでは「確実なデッドコード」のみ除去します。リフレクションや動的ディスパッチで使われるコードは「誤検出」に分類され保存されます。
情報同じ名前のターミナル CLImoai clean --homeは、上記の/moai clean(プロジェクトのデッドコード)とは対象が異なります — こちらは~/.moaiホームディレクトリを整理します。スラッシュコマンドではなく、デッドコード分析も行いません。
~/.moai にはセッション状態、キャッシュ、ログ、古いプロファイルが溜まっていきます。moai clean --home はこのうち許可リスト(allowlist)に載っている整理対象ディレクトリだけを整理します — リストにないものは問わずに残します。~/.claude には決して触れません。
# 整理対話 — デフォルトは dry-run(報告だけで消さない)
$ moai clean --home
# 実際に削除 — ガードされた force
$ moai clean --home --force- dry-run がデフォルトです。削除したい場合は
--forceを明示的に付ける必要があり、それも許可リストの内側でのみ動作します。 - 削除前にどれだけ占用しているかは、
moai doctorの Home Disk Usage 診断が先に知らせます — 勧告(advisory)性質のチェックで、しきい値はコンパイル済みの既定値に従います。 ~/.moaiの場所自体を変えたい場合は、MOAI_HOME環境変数でホームルートを再指定できます(空でない絶対パスのみ有効、空値は未設定と同じで相対パスは無視)。ただしこの変数を読むのは Go バイナリだけで、シェルフックは従いません。
| カテゴリ | 対象 | 条件 |
|---|---|---|
debug | claude-profiles/<プロファイル>/debug/ の項目 | 保持期間を経過 |
releases | releases/ のリリースバイナリ(+ 対になる .sha256) | 現行バージョンと残りのうち最新 3 個を除いたもの。version.json・LATEST は候補にならない |
logs | ルート logs/ のファイル | 保持期間を経過 |
backups | backups/removed-* ディレクトリ | 保持期間を経過 |
リストにないものはスキャナからそもそも見えません。そして保護対象(config/・state/・projects/・worktrees/・mcp/・bin/・search/・studio/・plugins/、launch.yaml・preferences.yaml、credentials で始まるすべてのファイル)は許可リストの内側でも勝ちます — 古い backups/removed-* の中にそうしたファイルが一つでもあれば、そのディレクトリは丸ごとスキップされます。~/.claude は --force を付けても読まれません。
保持期間は HOME ティアのファイル ~/.moai/config/sections/state.yaml からのみ読まれます。プロジェクトの state.retention_days とは別のキー・別のティアです — ホームは一つなのにプロジェクトは複数あるため、プロジェクトごとに異なる期間で同じホームを整理してしまうのを防ぎます。
| 値 | 動作 |
|---|---|
| キーなし / ファイルなし | 既定値の 30 日 |
| 正の整数 | その日数より古い項目だけが候補 |
0 | 整理無効 — 候補が出ません |
全体の話は ホームディレクトリ衛生 にあります。