Skip to content

Instantly share code, notes, and snippets.

@potix2
Created March 21, 2026 10:07
Show Gist options
  • Select an option

  • Save potix2/6044bd9d8b5fc724429583c32930bec0 to your computer and use it in GitHub Desktop.

Select an option

Save potix2/6044bd9d8b5fc724429583c32930bec0 to your computer and use it in GitHub Desktop.
# AIエージェントが使いやすいCLI設計条件 — 2026年版
## 背景:なぜ今CLIが再注目されているか
2025〜2026年にかけて、Claude Code・Codex CLI・Gemini CLIなどの**Agentic CLI**が爆発的に普及した。同時に「MCP (Model Context Protocol) サーバーを構築したが、結局よく設計されたCLIに置き換えた」というチームが続出している。Peter Steinberger(OpenClaw作者、2026年のGitHub最多貢献者)の「*mcp were a mistake. bash is better.*」という発言が象徴するように、**CLIこそがAIエージェントと世界をつなぐ本命インターフェース**という認識が定着しつつある。
以下、2026年時点で業界コンセンサスが形成されつつある設計条件を7つの柱で整理する。
-----
## 1. 構造化出力をデフォルトにする
**原則: すべてのコマンドで `--json` (または `--output json`) を保証する**
エージェントは人間向けの装飾テーブルやカラー出力をパースできない。
|観点 |Human DX |Agent DX |
|-------|------------|-------------------|
|デフォルト出力|整形テーブル |JSON / JSONL |
|カラー |ANSI色付き |`NO_COLOR=1` で無効化可能|
|プログレス表示|スピナー、プログレスバー|stderr へのイベントストリーム |
**具体的な条件:**
- JSON を stdout、メッセージ・ログを stderr に分離する
- フィールド名・型をコマンド間で一貫させる
- `--quiet` フラグでパイプ向けの裸出力を提供する
-----
## 2. 出力フォーマットをAPIコントラクトとして扱う
**原則: CLI出力はバージョン管理されたAPIサーフェスである**
Kubernetes が v1.18 で `--export` フラグを削除した際、Helmチャート・CI/CDパイプラインが大量に壊れた。Terraform は state ファイルに `version` フィールドを明示し、互換性を安全に管理している。
**具体的な条件:**
- JSON Schema や CUE でスキーマを定義し、CIで破壊的変更を検知する
- セマンティックバージョニング: 追加フィールドはマイナー、削除・変更はメジャーバンプ
- 出力スキーマのリグレッションテストをCI基盤に組み込む
- 破壊的変更が不可避な場合、ツール内にマイグレーションパスを組み込む
```yaml
# CIでの出力スキーマ検証の例
- run: mycli show --output json > show-output.json
- run: cue vet schema.cue show-output.json
```
-----
## 3. 非対話性を保証する(Escape Hatch の設計)
**原則: エージェントはプロンプトに答えられない。すべてのコマンドにマシンフレンドリーな迂回路を用意する**
AWS CLI v2 がデフォルトページャーを `less` に変更した際、数千のCIジョブがインタラクティブ入力待ちで停止した。
**3層の迂回路:**
|レイヤー |例 |用途 |
|-----|---------------------------------|---------------|
|明示フラグ|`--no-prompt`, `--yes`, `--force`|コマンド単位の制御 |
|環境変数 |`NO_COLOR=1`, `MYCLI_PROFILE=dev`|グローバルコンテキスト設定 |
|TTY検出|stdin が TTY でなければ自動で非対話モード |ヘッドレス環境のフォールバック|
**優先順位モデル:** `明示フラグ > 環境変数 > TTY自動検出`
-----
## 4. べき等性(Idempotency)と意味的Exit Codeの設計
**原則: 同じ操作を2回実行しても安全。状態変化はフォローアップコマンドで観測可能にする**
エージェントは人間と違い、コマンドをチェインし、並列実行し、失敗時にリトライする。しかもexit codeだけでなく、後続コマンドで結果を確認する傾向がある。
```bash
# 脆い: リトライで壊れる
$ myctl create namespace prod
Error: namespace "prod" already exists
# 堅牢: べき等
$ myctl ensure namespace prod
namespace "prod" already exists (no changes)
```
**Exit Code設計:**
|範囲 |意味 |
|-----|-----------------------------------|
|0 |成功 |
|1-2 |ユーザー修正可能なエラー |
|3-125|アプリケーション固有エラー(5 = already exists 等)|
**ポイント:**
- 宣言的コマンド(`ensure`, `apply`, `sync`)は命令的コマンド(`create`, `delete`)より本質的にエージェント安全
- べき等にできない操作は、コンフリクトを型付きエラーとして返す
- `kubectl apply` のモデルが良い参考
-----
## 5. `--help` をコントラクトとして設計する
**原則: エージェントが未知のCLIに遭遇したとき、最初に実行するのは `--help`**
helpテキストはエージェントにとって「ツール記述 + パラメータ仕様 + 使用ガイド」のすべてを兼ねる。
**良いhelpの条件:**
- 使い方(Usage)、全引数・フラグ、出力モード、exit code を網羅する
- 具体的な使用例(Examples)を含める
- 環境変数の一覧を「Environment」セクションに記載する
- バージョン間で安定させる(helpテキスト自体もコントラクト)
```bash
# Bad: エージェントは何もわからない
$ myctl deploy --help
Usage: myctl deploy [flags]
# Good: エージェントが自律的に学習できる
$ myctl deploy --help
Deploy a service to the target environment.
Usage: myctl deploy <service> [flags]
Flags:
--env string Target environment (staging|production) [required]
--dry-run Preview changes without applying
--output string Output format: json, table (default: table)
--timeout int Timeout in seconds (default: 300)
Exit Codes:
0 Success
1 Invalid arguments
5 Service already running (no changes)
Examples:
myctl deploy api --env staging --dry-run --output json
```
-----
## 6. フィードバックループを短くする
**原則: トークンはエージェントの通貨。無駄なトークン消費を避け、早期に正しいフィードバックを返す**
### 早期バリデーション(Dry Run / Validate)
```bash
ansible-playbook nginx.yml --syntax-check # 構文チェック
ansible-playbook nginx.yml --check --diff # 変更プレビュー
```
破壊的操作の前に `--dry-run` で安全確認できることが必須。`validate` と `run` を分離する設計が望ましい。
### 進捗レポーティング
長時間タスクは stderr にイベントストリームを出力する。エージェントは出力を読み、失敗を早期検知し、中断タイミングを推定できる。
### グレースフルターミネーション
`SIGTERM` を適切にハンドリングし、状態を一貫した形でクリーンアップする。エージェントがツールの一貫性を信頼できなければ、全体の信頼性が低下する。
-----
## 7. MCPとの共存戦略
**原則: まずCLIを堅牢に設計し、MCP はその上のディスカバリ層として位置づける**
2026年の実践的コンセンサスは「MCP vs CLI」ではなく「CLIをMCPでラップする」方向に収束しつつある。
**MCPが追加する価値:**
- 動的なケイパビリティディスカバリ(エージェントが実行時にツール機能を発見)
- 入力の事前バリデーション(スキーマベース)
- ベスポーク統合なしに、MCP対応の全エージェントから即座に利用可能
**実装順序:**
1. CLIのエスケープハッチ・構造化出力・exit codeを完成させる
1. bats-core 等でCLIのリグレッションテストを確立する
1. fastMCP 等のフレームワークでMCPサーバーをCLIのラッパーとして構築する
```json
{
"name": "deploy",
"description": "Deploy the application to a chosen environment",
"inputSchema": {
"type": "object",
"properties": {
"environment": { "type": "string", "enum": ["staging", "production"] },
"force": { "type": "boolean", "default": false }
},
"required": ["environment"]
}
}
```
-----
## チェックリスト
|# |条件 |状態|
|--|-------------------------------|--|
|1 |`--json` フラグで全コマンドが構造化出力可能 |☐ |
|2 |JSON は stdout、メッセージは stderr |☐ |
|3 |意味的 exit code(0/1だけでなく) |☐ |
|4 |べき等な操作(または明示的コンフリクトハンドリング) |☐ |
|5 |例付きの包括的 `--help` |☐ |
|6 |破壊的コマンドに `--dry-run` |☐ |
|7 |`--yes` / `--force` でプロンプトをバイパス|☐ |
|8 |`--quiet` でパイプ向け裸出力 |☐ |
|9 |コマンド間で一貫したフィールド名と型 |☐ |
|10|一貫した名詞-動詞階層(例: `noun verb`) |☐ |
|11|エラーコード付きのアクショナブルなエラーメッセージ |☐ |
|12|バッチ操作のサポート |☐ |
|13|TTY検出による非対話自動切替 |☐ |
|14|出力スキーマのCI検証 |☐ |
|15|MCP ディスカバリ対応 |☐ |
-----
## 2026年の新しい潮流
### CLI-Anything(2026年3月〜)
香港大学発のOSSプロジェクト。任意のGUIソフトウェアのソースコードを解析し、AIエージェントが使えるCLIを自動生成する。GIMP、Blender、LibreOffice等に対応。「今日のソフトウェアは人間向け。明日のユーザーはエージェント」というビジョンを体現。生成されるCLIはすべて上記の設計原則(デフォルトテーブル + `--json`、永続状態、undo/redo)に従う一貫した設計。
### テレメトリのエージェント対応
エージェントは人間と異なる利用パターンを示す(全機能を一度に採用、高速チェイン、並列実行)。テレメトリでエージェント起因のエラー率・タイムアウトを追跡し、デフォルト値や出力形式の改善に活かす流れ。`MYCLI_NO_TELEMETRY=1` によるオプトアウトは必須。
-----
## 参考ソース
- InfoQ「Keep the Terminal Relevant: Patterns for AI Agent Driven CLIs」(2025.8)
- DEV Community「Writing CLI Tools That AI Agents Actually Want to Use」(2026.2)
- nibzard「Designing CLI Tools for AI Agents」(2026.2)
- Medium「Why CLIs Beat MCP for AI Agents」(2026.3)
- CLI-Anything (GitHub, 2026.3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment