mcpField
C
cli-ops

cli-ops

github.com/0xdarkmatter開発7836 回インストール2 週間前に更新
リポジトリ

cli-ops について

AI アシスタントや上級ユーザーが組み合わせて使うコマンドラインツールの開発者向け設計ガイドです。予測可能な JSON 出力、一貫したエラー処理、組み合わせやすいコマンドを扱います。

主な機能

  1. 01コマンド構成と命名規則
  2. 02JSON 出力とストリーム分離の規則
  3. 03終了コードとエラー形式
  4. 04ヘルプと使用例の要件
  5. 05認証・フィルタリング・ページネーションのパターン

活用シーン

  1. 01スクリプトで解析しやすい出力の設計
  2. 02サブコマンド間のフラグ統一
  3. 03エラー種別に応じた自動処理の分岐
  4. 04認証コマンドと認証情報保存の計画

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/0xdarkmatter/claude-mods --skill cli-ops

インストール後、Claude Code で/cli-opsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
.gitkeep
references/
implementation.md
json-schemas.md
scripts/
.gitkeep

詳細

エージェント型ワークフローの CLI パターン

AI アシスタントやパワーユーザーが連結、解析でき、信頼して使える CLI ツールを構築するためのパターンです。

哲学

エージェント型ワークフロー向けに CLI を構築します。対象は、コマンドを連結し、出力をプログラムで解析し、予測可能な動作を期待する AI アシスタントやパワーユーザーです。

基本原則
原則意味重要な理由
自己説明的--help の内容が充実しており、常に最新であるLLM が外部ドキュメントなしで機能を見つけられます
予測可能すべてのコマンドで同じパターンを使う一度覚えれば、どこでも使えます
組み合わせ可能Unix の哲学に基づき、1つのことを適切に行うツールを自然に連結できます
解析可能常に --json を利用でき、常に有効な JSON を返す解析のための小細工なしで、機械から利用できます
デフォルトでは静か要求されない限り、データのみを出力し、装飾を加えない予期しない出力によってスクリプトが壊れるのを防ぎます
迅速に失敗する無効な入力は直ちにエラーにするサイレントな失敗や部分的な結果を防ぎます
設計原則
  1. stdout は神聖です - データのみを出力します。進捗、ログ、装飾は一切出力しません。
  2. stderr は人間向けです - プログレスバー、色、テーブル、警告はここに出力します。
  3. 終了コードには意味があります - スクリプトは失敗の種類に応じて処理を分岐できます。
  4. ヘルプには例を含めます - 理解するための最短経路です。
  5. JSON の形は予測可能です - すべてのコマンドで同じ構造を使います。

コマンドアーキテクチャ

構造パターン
<tool> [global-options] <resource> <action> [options] [arguments]

すべての CLI は次の階層に従います。

<tool>
├── --version, --help              # Global flags
├── auth                           # Authentication (if required)
│   ├── login
│   ├── status
│   └── logout
└── <resource>                     # Domain resources (plural nouns)
    ├── list                       # Get many
    ├── get <id>                   # Get one by ID
    ├── create                     # Make new (if supported)
    ├── update <id>                # Modify existing (if supported)
    ├── delete <id>                # Remove (if supported)
    └── <custom-action>            # Domain-specific verbs
命名規則
要素規則有効な例無効な例
ツール名小文字、2~12文字mytool、datactlMyTool、my-tool-cli
リソース複数形の名詞、小文字invoices、usersInvoice、user
アクション動詞、小文字list、get、synclisting、getter
ロングフラグケバブケース--dry-run、--output-format--dryRun、--output_format
ショートフラグ1文字-n、-q、-v-num、-quiet
標準的なリソースアクション
アクションHTTP 相当戻り値冪等性
listGET /resources配列あり
get <id>GET /resources/:idオブジェクトあり
createPOST /resources作成されたオブジェクトなし
update <id>PATCH /resources/:id更新されたオブジェクトあり
delete <id>DELETE /resources/:id確認あり
searchGET /resources?q=配列あり

フラグとオプション

必須フラグ

すべてのコマンドは、次をサポートしなければなりません。

フラグショート動作出力
--help-h例を含むヘルプを表示ヘルプテキストを stdout に出力し、終了コード 0
--json機械可読形式で出力JSON を stdout に出力

ルートコマンドは、さらに次をサポートしなければなりません。

フラグショート動作出力
--version-Vバージョンを表示<tool> <version> を stdout に出力し、終了コード 0
推奨フラグ
フラグショート型用途デフォルト
--quiet-qbool必須ではない stderr 出力を抑制false
--verbose-vbool詳細度を上げるfalse
--dry-runbool実行せずに結果をプレビューfalse
--limit-nint返す結果の最大数20
--output-opath出力をファイルに書き込むstdout
--format-fenum出力形式コマンドによる
フラグの動作規則
  1. ブールフラグに値は不要です:--json。--json=true ではありません。
  2. ショートフラグは連結できます:-vq は -v -q と同じです。
  3. 未知のフラグはエラーにします:黙って無視してはいけません。
  4. フラグの繰り返し:最後の値を使用します(適切でない場合はエラーにします)。

出力仕様

ストリームの分離

最も重要なルールです。

ストリーム内容タイミング
stdoutデータのみ常に
stderrその他すべて対話モード

stdout に出力されるもの:

  • --json が設定されている場合の JSON
  • 対話モードでの最小限のテキスト出力
  • それ以外は何も出力しません。例外はありません。

stderr に出力されるもの:

  • 進行状況インジケーター(スピナー、バー)
  • 状態メッセージ(「取得中…」、「完了」)
  • 警告
  • リッチな書式のテーブル
  • 色と装飾
  • デバッグ情報(--verbose)
対話モードの検出
import sys

def is_interactive() -> bool:
    """True if connected to a terminal, not piped."""
    return sys.stdout.isatty() and sys.stderr.isatty()
コンテキストstdout.isatty()動作
ターミナルTrueリッチな出力を stderr に、概要を stdout に出力
パイプ接続(| jq)False最小限の出力/JSON を stdout に出力
リダイレクト(> file)False最小限の出力を stdout に出力
--json フラグ任意JSON を stdout に出力し、stderr のノイズを抑制
JSON 出力スキーマ

JSON 応答パターンの詳細は、references/json-schemas.md を参照してください。

主な規約:

  • リスト応答:{"data": [...], "meta": {...}}
  • 単一項目:{"data": {...}}
  • エラー:{"error": {"code": "...", "message": "..."}}
  • ISO 8601 形式の日付、10 進数形式の金額、文字列形式の ID

終了コード

スクリプトで利用できる、意味のある終了コードです。

コード名前意味発生条件
0SUCCESS操作が完了しましたすべて正常に動作した場合
1ERROR一般/不明なエラー予期しない失敗
2AUTH_REQUIRED認証されていませんトークンがない、または期限切れ
3NOT_FOUNDリソースが見つかりませんID が存在しない
4VALIDATION入力が無効です引数が不正、または検証に失敗
5FORBIDDENアクセスが拒否されました認証済みだが認可されていない
6RATE_LIMITEDリクエストが多すぎますAPI によるスロットリング
7CONFLICT状態の競合同時変更、重複
使用方法
# Script can branch on exit code
mytool items get item-001 --json
case $? in
  0) echo "Success" ;;
  2) echo "Need to authenticate" && mytool auth login ;;
  3) echo "Item not found" ;;
  *) echo "Error occurred" ;;
esac
実装
# Constants
EXIT_SUCCESS = 0
EXIT_ERROR = 1
EXIT_AUTH_REQUIRED = 2
EXIT_NOT_FOUND = 3
EXIT_VALIDATION = 4
EXIT_FORBIDDEN = 5
EXIT_RATE_LIMITED = 6
EXIT_CONFLICT = 7

# Usage
raise typer.Exit(EXIT_NOT_FOUND)

エラー処理

エラー出力形式

--json を指定した場合、エラーは構造化 JSON として stdout に出力され、stderr にもメッセージが出力されます。

stderr:

Error: Item not found

stdout:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Item not found",
    "details": {
      "item_id": "bad-id"
    }
  }
}
エラーコード
コード終了コード意味
AUTH_REQUIRED2最初に認証が必要です
TOKEN_EXPIRED2トークンの更新が必要です
FORBIDDEN5権限が不足しています
NOT_FOUND3リソースが存在しません
VALIDATION_ERROR4入力が無効です
INVALID_ARGUMENT4引数の値が不正です
MISSING_ARGUMENT4必須の引数がありません
RATE_LIMITED6リクエストが多すぎます
CONFLICT7状態の競合
ALREADY_EXISTS7リソースが重複しています
INTERNAL_ERROR1予期しないエラー
API_ERROR1上流 API でエラーが発生しました
NETWORK_ERROR1接続に失敗しました
実装パターン
def _error(
    message: str,
    code: str = "ERROR",
    exit_code: int = EXIT_ERROR,
    details: dict = None,
    as_json: bool = False,
):
    """Output error and exit."""
    error_obj = {"error": {"code": code, "message": message}}
    if details:
        error_obj["error"]["details"] = details

    if as_json:
        print(json.dumps(error_obj, indent=2))

    # Always print human message to stderr
    console.print(f"[red]Error:[/red] {message}")
    raise typer.Exit(exit_code)

ヘルプシステム

ヘルプの要件

すべての --help 出力には、必ず次の内容を含めてください。

  1. 簡単な説明(1 行)
  2. 使用構文
  3. 説明付きのオプション
  4. 例(機能を知るうえで重要)
ヘルプ形式のテンプレート
<one-line description>

Usage: <tool> <resource> <action> [OPTIONS] [ARGS]

Arguments:
  <arg>          Description of positional argument

Options:
  -s, --status TEXT    Filter by status
  -n, --limit INTEGER  Max results [default: 20]
  --json               Output as JSON
  -h, --help           Show this help

Examples:
  <tool> <resource> <action>
  <tool> <resource> <action> --status active
  <tool> <resource> <action> --json | jq '.[0]'
例は重要です

例には、次の内容を示してください。

  1. 基本的な使用方法 - 最も簡単な実行方法
  2. 一般的なフィルター - 最もよく使われるオプション
  3. JSON のパイプ接続 - jq と連携する方法
  4. 実際のシナリオ - 実際のユースケース

認証

認証コマンド

認証が必要なツールには、必ず次の機能を実装してください。

<tool> auth login      # Interactive authentication
<tool> auth status     # Check current state
<tool> auth logout     # Clear credentials
認証情報の保存優先順位

推奨: 最大限のセキュリティを確保するため、フォールバック付きの OS キーリングを使用します。

  1. 環境変数(CI/CD、テスト)

    • MYTOOL_API_TOKEN など
    • 最優先で、ほかのすべてのソースを上書きします
  2. OS キーリング(プライマリストレージ — 安全)

    • Windows:Credential Manager
    • macOS:Keychain
    • Linux:Secret Service(GNOME Keyring、KWallet)
    • 保存時に暗号化され、ユーザーごとに分離されます
  3. .env ファイル(開発時のフォールバック)

    • 現在のディレクトリにプレーンテキストで保存します
    • ローカル開発に便利です
    • .gitignore に含める必要があります

依存関係:

dependencies = [
    "keyring>=24.0.0",      # OS keyring access
    "python-dotenv>=1.0.0", # .env file support
]

シンプルな代替案: ~/.config/<tool>/ に設定ファイルのみを配置します

  • 機密性の高い認証情報を必要としないツールに適しています
  • OS キーリングが複雑さを増しすぎる場合にも適しています

認証情報の保存方法の完全な実装については、references/implementation.md を参照してください。

未認証時の動作

認証が必要にもかかわらず、認証情報がない場合:

$ mytool items list
Error: Not authenticated. Run: mytool auth login
# exit code: 2
$ mytool items list --json
# stderr: Error: Not authenticated. Run: mytool auth login
{"error": {"code": "AUTH_REQUIRED", "message": "Not authenticated. Run: mytool auth login"}}
# exit code: 2

データ規約

日付の処理

入力(柔軟): ユーザーの利便性のため、複数の形式を受け付けます

形式例解釈
ISO 日付2025-01-15正確な日付
ISO 日時2025-01-15T10:30:00Z正確な日時
相対today、yesterday、tomorrow現在/前日/翌日
相対last、this(文脈に応じて)前の期間/現在の期間

出力(厳密): 常に ISO 8601 形式で出力します

{
  "created_at": "2025-01-15T10:30:00Z",
  "due_date": "2025-02-15",
  "month": "2025-01"
}
金額
  • セントではなく、小数として保存します
  • 曖昧な場合は通貨を含めます
  • 書式設定はしません(JSON に「$」や「,」を含めません)
{
  "total": 1250.50,
  "currency": "USD"
}
ID
  • 常に文字列にします(数値の場合も同様)
  • ソースの形式をそのまま保持します
{
  "id": "abc_123",
  "legacy_id": "12345"
}
列挙型
  • JSON では UPPER_SNAKE_CASE を使用します
  • 入力では大文字と小文字を区別しません
# All equivalent
--status DRAFT
--status draft
--status Draft
{"status": "IN_PROGRESS"}

フィルタリングとページネーション

一般的なフィルターパターン
# By status
--status DRAFT
--status active,pending    # Multiple values

# By date range
--from 2025-01-01 --to 2025-01-31
--month 2025-01
--month last

# By related entity
--user "Alice"
--project "Project X"

# Text search
--search "keyword"
-q "keyword"

# Boolean filters
--archived
--no-archived
--include-deleted
ページネーション
# Limit results
--limit 50
-n 50

# Offset-based
--page 2
--offset 20

# Cursor-based
--cursor "eyJpZCI6MTIzfQ=="
--after "item_123"

実装

Typer を使った CLI のスケルトン、httpx を使ったクライアントパターン、エラー処理、認証フロー、テストパターンを含む Python 実装テンプレート一式については、references/implementation.md を参照してください。


避けるべきパターン

❌ 出力の混入
# BAD: Progress to stdout
$ bad-tool items list --json
Fetching items...
[{"id": "1"}]
Done!

# GOOD: Only JSON to stdout
$ good-tool items list --json
[{"id": "1"}]
❌ 対話型プロンプト
# BAD: Prompts in non-interactive context
$ bad-tool items create
Enter name: _

# GOOD: Fail fast with required flags
$ good-tool items create
Error: --name is required
❌ 一貫性のないフラグ
# BAD: Different flags for same concept
$ tool1 list -j
$ tool2 list --format=json

# GOOD: Same flags everywhere
$ tool1 list --json
$ tool2 list --json
❌ サイレントな失敗
# BAD: Success exit code on failure
$ bad-tool items delete bad-id
Item not found
$ echo $?
0

# GOOD: Semantic exit code
$ good-tool items delete bad-id
Error: Item not found: bad-id
$ echo $?
3

クイックリファレンス

必須チェックリスト
  • <tool> --version
  • 例を含む <tool> --help
  • <tool> <resource> list [--json]
  • <tool> <resource> get <id> [--json]
  • 意味のある終了コード(0、1、2、3、4、5、6、7)
  • エラーは stderr、データは stdout に出力
  • --json で有効な JSON を出力
  • ストリームの分離(stdout = データ、stderr = UI)
推奨される追加項目
  • 認証コマンド(auth login、auth status、auth logout)
  • 作成/更新/削除の操作
  • --quiet モードと --verbose モード
  • 変更を伴う操作に対する --dry-run
  • ページネーション(--limit、--page)
  • フィルタリング(ステータス、日付範囲、検索)
  • 自動テスト

フレームワークの選択

Typer(新しいツールに推奨):

  • 型ヒントによる自動バリデーション
  • ヘルプの自動生成機能を内蔵
  • 美しい出力を実現する Rich との統合
  • Click よりボイラープレートが少ない

Click(既存のツールでは許容):

  • Typer は Click を基盤として構築されています(100%互換)
  • 適切に構成された Click コードは移行する必要がありません
  • どちらも同じ出力規約に従う必要があります
# Typer (preferred)
import typer
from rich.console import Console

app = typer.Typer()
console = Console(stderr=True)  # UI to stderr

# Click (acceptable)
import click
from rich.console import Console

console = Console(stderr=True)  # Same pattern

コメント