はじめに
Codex TUI では、スラッシュ(/
)で始まる入力によって設定変更や状況確認を即座に行うことができます。本記事では、現在実装されているスラッシュコマンドとカスタムプロンプト機能をソースコードの参照箇所とともに詳しく解説します。
コマンド一覧は
codex-rs/tui/src/slash_command.rs
のSlashCommand
列挙体に定義されています。ポップアップの表示順もこの列挙体の順番に従います(コメントに “DO NOT ALPHA-SORT!” とある通り)。
1. スラッシュコマンド一覧
コマンド | 概要 (description() 参照) |
主な処理/実装箇所 | タスク実行中の可否 (available_during_task ) |
備考 |
---|---|---|---|---|
/model |
モデルと Reasoning Effort を選択 |
chatwidget.rs:1097-1120 の open_model_popup() 。選択結果は Op::OverrideTurnContext ・UpdateModel ・PersistModelSelection を送信。 |
❌ | モデル候補は codex-rs/tui/src/model_presets.rs 。認証モードに応じて選択肢が変化。 |
/approvals |
承認ポリシーとサンドボックス権限を切替 |
chatwidget.rs:1113-1115 の open_approvals_popup() 。 |
❌ |
AskForApproval と SandboxPolicy を UI から変更し、次のターンで適用。 |
/review |
現在の変更をレビュー |
chatwidget.rs:1107-1110 の open_review_popup() 。 |
❌ |
codex-rs/tui/src/review_popup.rs でレビュー対象を選択し、Codex にチェックを依頼。 |
/new |
会話中に新しいチャットを開始 |
chatwidget.rs:1087-1089 で AppEvent::NewSession を発火。 |
❌ | 現在の会話を終えて新しいセッションを開始。履歴は ~/.codex/sessions/ に保存。 |
/init |
AGENTS.md を生成 |
chatwidget.rs:1091-1094 で prompt_for_init_command.md のテンプレートを送信。 |
❌ | カスタム手順を Codex に伝える起点。初回プロジェクトの導入に最適。 |
/compact |
会話履歴を要約してコンテキストを節約 |
chatwidget.rs:1096-1100 の Op::Compact 。 |
❌ | 長時間のセッションでトークン消費を抑える。 |
/undo |
直近のスナップショットを復元 |
chatwidget.rs:1127-1130 → undo_last_snapshot() → restore_ghost_commit() 。 |
❌ |
BETA_FEATURE 環境変数が必要。Git リポジトリでのみ有効。 |
/diff |
Git diff(未追跡含む)を表示 |
chatwidget.rs:1131-1139 の非同期タスクで get_git_diff() を実行。 |
✅ | 出力は履歴に挿入され、長い diff は pager 表示。 |
/mention |
@ を挿入してファイル参照補助 |
chatwidget.rs:1143-1145 の insert_str("@") 。 |
✅ | ファイル検索 (@ ) と組み合わせて特定ファイルを提示。 |
/status |
セッション設定・トークン使用量を表示 |
chatwidget.rs:1147-1152 → status::new_status_output() 。 |
✅ | サンドボックス範囲、承認ポリシー、トークン数、レートリミット情報をまとめて確認。 |
/mcp |
登録済み MCP ツールの一覧 |
chatwidget.rs:1151-1170 → add_mcp_output() 。MCP 未設定時は history_cell::empty_mcp_output() 。 |
✅ | MCP 連携の確認やデバッグに活用。 |
/logout |
Codex からログアウト |
chatwidget.rs:1119-1123 。codex_core::auth::logout() 成功後に AppEvent::ExitRequest で終了。 |
❌ | ログアウト後は再起動・再ログインが必要。 |
/quit |
Codex を終了 |
chatwidget.rs:1117-1119 の AppEvent::ExitRequest 。 |
✅ | Ctrl+C よりクリーンな終了手段。 |
/test-approval |
(デバッグ用)承認ダイアログのテスト |
chatwidget.rs:1153-1176 (debug_assertions ビルドのみ)。 |
✅ | 通常ビルドでは無効。承認 UI の開発検証に使用。 |
2. 実装の流れと具体例
-
列挙体で定義:
codex-rs/tui/src/slash_command.rs
のSlashCommand
にコマンド名・説明・タスク実行中の可否を定義。 -
ポップアップに登録:
CommandPopup::new()
(codex-rs/tui/src/bottom_pane/command_popup.rs
)がbuilt_in_slash_commands()
を呼び出し、コマンド一覧とカスタムプロンプトを並べて候補リストを構築。 -
入力補完:入力欄が
/
で始まるとCommandPopup::on_composer_text_change()
がファジーマッチで候補を絞り込みます。 -
実行:
ChatWidget::handle_slash_command()
(codex-rs/tui/src/chatwidget.rs:1080
付近)でSlashCommand
の各変種に対応した処理を発動。
実装例:/model
// chatwidget.rs(抜粋)
SlashCommand::Model => {
self.open_model_popup();
}
fn open_model_popup(&mut self) {
let presets: Vec<ModelPreset> = builtin_model_presets(auth_mode);
let mut items: Vec<SelectionItem> = Vec::new();
for preset in presets {
// …中略… モデル切替の AppEvent を送信
let actions: Vec<SelectionAction> = vec![Box::new(move |tx| {
tx.send(AppEvent::CodexOp(Op::OverrideTurnContext {
model: Some(model_slug.clone()),
effort: Some(effort),
// …
}));
tx.send(AppEvent::UpdateModel(model_slug.clone()));
tx.send(AppEvent::PersistModelSelection { model: model_slug.clone(), effort });
})];
items.push(SelectionItem { name, description, is_current, actions });
}
self.bottom_pane.show_selection_popup(items);
}
実装例:/mcp
SlashCommand::Mcp => {
self.add_mcp_output();
}
pub(crate) fn add_mcp_output(&mut self) {
if self.config.mcp_servers.is_empty() {
self.add_to_history(history_cell::empty_mcp_output());
} else {
self.submit_op(Op::ListMcpTools);
}
}
実装例:/diff
SlashCommand::Diff => {
self.add_diff_in_progress();
let tx = self.app_event_tx.clone();
tokio::spawn(async move {
let text = match get_git_diff().await {
Ok((is_git_repo, diff_text)) => {
if is_git_repo { diff_text } else { "`/diff` — _not inside a git repository_".to_string() }
}
Err(e) => format!("Failed to compute diff: {e}"),
};
tx.send(AppEvent::DiffResult(text));
});
}
3. カスタムプロンプトをスラッシュコマンドとして使う
ビルトインコマンドに加えて、prompts/<name>.md
のようなファイルを配置するとカスタムプロンプトが /prompts:<name>
として呼び出せます。
3.1 構成
- Codex は
~/.codex/prompts/
と、作業ディレクトリのprompts/
サブフォルダを探索します。 - 各ファイルは Markdown やプレーンテキストで、冒頭に簡単なメタ情報をコメントとして書くことも可能(必須ではありません)。
- 読み込まれたファイルは
codex-rs/protocol/src/custom_prompts.rs
のCustomPrompt
構造体で表されます。pub struct CustomPrompt { pub name: String, pub path: PathBuf, pub content: String, pub description: Option<String>, pub argument_hint: Option<String>, }
- コマンドポップアップは
built_in_slash_commands()
とカスタムプロンプトをマージし、prompts:name
の形式で表示します。 - ビルトインと同名のプロンプトは無視される(
command_popup.rs
のprompt_name_collision_with_builtin_is_ignored
テスト参照)。
3.2 例:prompts/test-plan.md
# 自動テスト計画の出力テンプレート
以下の情報を箇条書きでまとめてください:
- 追加した / 修正した機能
- 単体テストでチェックすべき項目
- 手動テスト(UI/CLI)の観点
このファイルを prompts/test-plan.md
に置くと、TUI で /prompts:test-plan
と入力するだけでテンプレートを送信できます。複数のプロジェクトで共有したい場合は ~/.codex/prompts/
に配置しておくと便利です。
3.3 引数付きプロンプト
argument_hint
を設定すると、プロンプトが引数を取ることを UI に示せます。たとえば以下の JSON メタ情報付きテンプレートを prompts/refactor.json
として用意すると:
{
"name": "refactor",
"description": "既存コードをリファクタリングする際の指示",
"argument_hint": "ファイルパスや関数名を入力してください"
}
---
対象コード:
Codex は argument_hint
の内容をポップアップに表示し、ユーザーに入力を促します。フォーマットは content
部分に続けて Markdown を記述するだけで OK です(上記のように JSON メタ情報+---
区切りを使うとわかりやすい)。
3.4 ベストプラクティス
-
命名規則:
prompts:<name>
は/init
などビルトインと重複しないように命名。ユニークな接頭辞を付けると検索しやすい。 -
説明文:
description
を書いておくとポップアップで用途が一目でわかる。JSON メタ情報を使うか、冒頭にコメントを残すなどの方法があります。 -
引数ヒント:
argument_hint
を設定すると、複数のカスタムプロンプトを運用する際に入力ミスが減ります。 -
共有:チームで共通テンプレートを使う場合はリポジトリ内に
prompts/
フォルダを置き、README に運用ルールを記載すると良いでしょう。
4. ユースケースと使いどころ
-
セッション管理:
/new
や/status
を活用すると、複数の課題を順に処理する際に作業状況を把握しやすくなります。 -
権限調整:
/approvals
で権限を緩和しすぎないよう制御しつつ、必要な場面で一時的に解除。/diff
→/review
で変更点の確認とリスク洗い出しをセットで実施。 -
MCP 連携確認:
/mcp
を使って登録済みツールが認識されているかチェック。/status
と組み合わせるとワークスペース範囲とトークン使用量も把握可能。 -
カスタムワークフロー:
/prompts:<name>
を利用してプロジェクトごとの定型プロンプトを即座に展開。ドキュメント作成やテスト計画の定着に役立ちます。
5. まとめ
- スラッシュコマンドは TUI 操作を効率化するショートカット。列挙体(
slash_command.rs
)とhandle_slash_command
の分岐を押さえることで挙動が把握できます。 -
/model
・/approvals
・/status
・/diff
などは日常的に活躍。ベータ機能の/undo
を試す際はBETA_FEATURE=1
を設定。 - カスタムプロンプトを
/prompts:<name>
形式で呼び出し、チーム独自のテンプレートを簡単に利用可能。description や argument_hint を活用すると UI も使いやすくなる。
今後のシリーズ記事では、コマンド実装を拡張する方法や独自のカスタムコマンドを追加する手順についても取り上げる予定です。