Skip to main content

/moai clean

更新 2026-08-20 9分で読めます GitHub で編集 ↗

デッドコードの識別および安全な除去コマンドです。静的分析と使用グラフ分析を通じて 未使用コードを見つけ、安全に除去 します。

情報
一行要約: /moai clean は「コードダイエットツール」です。使っていない関数、変数、import、ファイルを 自動的に見つけて安全に削除 します。
情報
スラッシュコマンド: Claude Code で /moai:clean と入力すると、このコマンドをすぐに実行できます。/moai だけ入力すると、利用可能なすべてのサブコマンド一覧が表示されます。

概要

プロジェクトが成長すると、もう使っていないコードが溜まっていきます。未使用の import、呼び出されない関数、参照されない型などがコードベースを複雑にします。/moai clean はこうしたデッドコードを静的分析で見つけ出し、テスト検証を経て安全に除去します。

ハーネスエンジニアリングの観点では、このコマンドは ガベージコレクション の役割です。死んだコードは人間にとってだけの負担ではなくエージェントにとっても負担です — エージェントが読むコード 1 行 1 行がコンテキスト (トークン) なので、デッドコードの除去はコード衛生であると同時にコンテキストダイエット、すなわちトークノミクスです。

使い方

bash
# 基本的な使い方
> /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

–type フラグのオプション

タイプ説明
functions呼び出されない関数/メソッド
imports参照されない import 文
types使われない型定義
variables宣言後に使われない変数
filesどこからも import されないファイル

–dry フラグ

実際のコードを修正せず、どの項目がデッドコードに分類されるかを事前に確認します:

bash
> /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 注記まで一緒に取り除き、行き場を失った注記が残らないようにします。

ステップ 1: 静的分析スキャン

プロジェクト言語を project marker で自動検出し、各言語の標準的なデッドコード分析ツールで候補を検出します。16 の対応言語を同等に扱い (go, python, typescript, javascript, rust, java, kotlin, csharp, ruby, php, elixir, cpp, scala, r, flutter, swift)、インストールされていないツールは自動的にスキップします。認識できる言語マーカーのないプロジェクトは静かに通過します。以下は代表例であり、特定の言語を優遇するものではありません:

言語 (例)分析ツール (例)検査対象
Gogo vet, staticcheck, deadcode未使用の変数、関数、型
Pythonvulture, autoflakeデッドコード、未使用 import
TypeScript/JavaScriptts-prune, ESLint no-unused-vars未使用 export、変数
Rustcargo clippy, cargo udepsデッドコード警告、未使用の依存性

残りの 12 言語(java, kotlin, csharp, ruby, php, elixir, cpp, scala, r, flutter, swift など)も、それぞれの標準ツールチェーンで同じようにスキャンされます。

スキャンカテゴリ:

  • 未使用 import: 参照がない import 文
  • 未使用変数: 宣言されたが読まれない変数
  • 未使用関数: 定義されたが呼び出されない関数
  • 未使用型: 使用場所がない型定義
  • 未使用ファイル: どこからも import しないファイル
  • デッド依存性: インストールされたが import されないパッケージ

ステップ 2: 使用グラフ分析

静的分析結果を検証するために使用グラフを構築します:

  • 各候補についてコードベース全体で参照を検索
  • 間接使用の確認 (インターフェース、リフレクション、動的ディスパッチ)
  • テスト専用使用の確認 (テストのみで使用、プロダクションコードで未使用)
  • 条件付きコンパイルの確認 (ビルドタグ、環境ベースの import)

ステップ 3: 分類

分類説明除去の安全度
確実なデッドコードコードベースのどこからも参照なし安全
テスト専用テストファイルのみで使用されるおおむね安全
可能性のあるデッドコード低い信頼度 (動的使用の可能性)注意が必要
誤検出実際に使用中 (リフレクション、プラグインなど)除去不可

ステップ 4: 安全な除去

依存性グラフの逆順で除去します (リーフノードから先に):

  • 関連するコードをグループで除去 (関数 + 非公開ヘルパー)
  • 影響を受ける import を更新
  • すべての export が除去された空ファイルを整理
  • @MX:ANCHOR タグがあるコードは明示的な承認なしに除去しない

ステップ 5: テスト検証

除去後にテストスイート全体を実行して回帰を検証します。テストが失敗した場合、その除去をロールバックして「誤検出」に分類します。「消したけど大丈夫そう」ではなくテスト通過という証拠で安全を判定します。

ステップ 6: 報告書

text
デッドコード除去報告書

除去済み: 15 項目 (287 行)
  - src/utils/helper.go: UnusedFunction (15 行)
  - src/models/old.go: ファイル全体削除 (120 行)

維持 (誤検出): 2 項目
  - src/api/handler.go: DynamicHandler (リフレクション使用)

テスト結果: PASS (すべてのテスト通過)

コードベースの削減:
  - ファイル除去: 3 個
  - 行の除去: 287 行
  - 依存性の除去: 1 個

エージェント委任チェーン

/moai cleanAgent(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、直接)

よくある質問

Q: デッドコードを誤って除去したらどうなりますか?

Git で元に戻せます。MoAI は依存性の逆順で除去してテストを実行するので、問題が起きれば自動的にロールバックします。

Q: --aggressive はいつ使いますか?

呼び出し元が 1 個でその呼び出し元もデッドコードの場合を含めたいときに使います。大規模なリファクタリング後の整理に有用です。

Q: リフレクションで使われるコードも除去されますか?

--safe-only モードでは「確実なデッドコード」のみ除去します。リフレクションや動的ディスパッチで使われるコードは「誤検出」に分類され保存されます。

もうひとつの表面 — moai clean --home (ホームディレクトリ整理)

情報
同じ名前のターミナル CLI moai clean --home は、上記の /moai clean(プロジェクトのデッドコード)とは対象が異なります — こちらは ~/.moai ホームディレクトリを整理します。スラッシュコマンドではなく、デッドコード分析も行いません。

~/.moai にはセッション状態、キャッシュ、ログ、古いプロファイルが溜まっていきます。moai clean --home はこのうち許可リスト(allowlist)に載っている整理対象ディレクトリだけを整理します — リストにないものは問わずに残します。~/.claude には決して触れません。

bash
# 整理対話 — デフォルトは dry-run(報告だけで消さない)
$ moai clean --home

# 実際に削除 — ガードされた force
$ moai clean --home --force
  • dry-run がデフォルトです。削除したい場合は --force を明示的に付ける必要があり、それも許可リストの内側でのみ動作します。
  • 削除前にどれだけ占用しているかは、moai doctorHome Disk Usage 診断が先に知らせます — 勧告(advisory)性質のチェックで、しきい値はコンパイル済みの既定値に従います。
  • ~/.moai の場所自体を変えたい場合は、MOAI_HOME 環境変数でホームルートを再指定できます(空でない絶対パスのみ有効、空値は未設定と同じで相対パスは無視)。ただしこの変数を読むのは Go バイナリだけで、シェルフックは従いません

許可リスト 4 カテゴリ

カテゴリ対象条件
debugclaude-profiles/<プロファイル>/debug/ の項目保持期間を経過
releasesreleases/ のリリースバイナリ(+ 対になる .sha256)現行バージョンと残りのうち最新 3 個を除いたもの。version.jsonLATEST は候補にならない
logsルート logs/ のファイル保持期間を経過
backupsbackups/removed-* ディレクトリ保持期間を経過

リストにないものはスキャナからそもそも見えません。そして保護対象(config/state/projects/worktrees/mcp/bin/search/studio/plugins/launch.yamlpreferences.yamlcredentials で始まるすべてのファイル)は許可リストの内側でも勝ちます — 古い backups/removed-* の中にそうしたファイルが一つでもあれば、そのディレクトリは丸ごとスキップされます。~/.claude--force を付けても読まれません。

state.home_retention_days

保持期間は HOME ティアのファイル ~/.moai/config/sections/state.yaml からのみ読まれます。プロジェクトの state.retention_days とは別のキー・別のティアです — ホームは一つなのにプロジェクトは複数あるため、プロジェクトごとに異なる期間で同じホームを整理してしまうのを防ぎます。

動作
キーなし / ファイルなし既定値の 30 日
正の整数その日数より古い項目だけが候補
0整理無効 — 候補が出ません

全体の話は ホームディレクトリ衛生 にあります。

関連ドキュメント