mcpField
C
cli-design

cli-design

github.com/yahyabedirhan開発247 回インストール6 日前に更新
リポジトリ

cli-design について

コマンドラインインターフェースの設計、説明、監査、再設計を支援するスキルです。要件から進化までを一貫した手順で整理し、人、スクリプト、CI、エージェント向けの予測可能な契約を重視します。

主な機能

  1. 017段階の CLI 提案フレームワーク
  2. 02コマンドツリーと動詞の規則
  3. 03引数、フラグ、入力の規則
  4. 04出力、エラー、終了コードの指針
  5. 05ヘルプ構成と探索性の指針
  6. 06契約の進化と監査の実践

活用シーン

  1. 01新しい CLI コマンドモデルの作成
  2. 02既存 CLI の不統一の監査
  3. 03名前変更を追跡したコマンド再設計
  4. 04フラグとサブコマンドの選択

インストール

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

$npx skills add https://github.com/yahyabedirhan/skills --skill cli-design

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

同梱ファイルreferences/conventions.md

詳細

CLI 設計

コマンドラインインターフェースは、ターミナルを使う人、スクリプト、CI ジョブ、エージェントなど、それを呼び出すすべての人との契約です。コマンド名、フラグ、出力形式、終了コード、環境変数はすべてその契約の一部であり、公開されたその日から、どこかのスクリプトが依存します。優れた CLI は予測しやすいものです。あるコマンドを覚えた人なら次のコマンドも推測でき、ヘルプだけで使い方がわかります。

設計、説明、監査、再設計のいずれを行うセッションでも、デリバリーフレームワークを通じて設計を作成し、提示してください。そうすれば、ユーザーはいつも同じ場所に同じものを見つけられます。セッションの目的はユーザーが決め、回答の構成方法はフレームワークが決めます。設計にユーザーが合意したらそこで終了してください。実装は後で行います。

繰り返し起こる問題は一貫性の崩れです。各コマンドをそれぞれのやり方で追加していくと、同じ動詞が3つの意味を持ち、同じ概念に3つの名前が付き、ヘルプ、ドキュメント、コードにそれぞれ異なる一覧が載るようになります。名詞、動詞、フラグ名、出力とエラーの規約について一度ルールを決め、そのルールからすべてのコマンドと、読者に表示するすべての一覧を導き出すことで、これを防ぎましょう。

コマンドの背後にあるコードを、モジュール、クラス、フォルダーのレベルで設計するには、/low-level-design を使用してください。ネットワーク API には、/system-design を使用してください。

手順

  1. セッションの目的を1行で言い換えます。 依頼とそのコンテキストから目的を読み取り、読み違いでやり取りが1回無駄にならないようにします。新しい CLI や新しいコマンドの設計、既存の CLI の説明や監査、その再設計、または1つの問いへの判断のいずれかです。
    • CLI があるプロジェクト内で、指示がない状態で呼び出された場合: その CLI を説明し、監査します。
    • 目的が不明確な場合: 新しい設計、既存の CLI の監査、または変更のどれを望んでいるかを尋ねます。CLI が存在するかどうかも確認します。
  2. 以下の提供フレームワークを段階ごとに進めます。 ある段階でフラグ、終了コード、環境変数、設定、またはヘルプの構成を扱う際は、conventions.md を読みます。
  3. すべての段階を提示し、ユーザーの合意を得るまで修正します。
  4. ユーザーが希望する場所に設計を残します。

目的によって、段階の進め方が決まります。以下のケースはよくある例ですが、すべてを網羅しているわけではありません。1つのセッションで複数のケースを組み合わせたり、別のケースに移ったりすることもあります。

  • 新しいものを設計する場合: ユーザーの要件に基づき、すべての段階を通して完全な初稿を作成します。
  • 既存の CLI を説明または監査する場合: 現状のまま各段階を進めます。
    • 証拠に基づいて各段階を作成します。トップレベルのヘルプと各グループのヘルプを実行し、コマンド定義とディスパッチコードを読み、CLI を呼び出すドキュメント、スクリプト、スキルも読みます。主張ごとに、根拠となるファイルまたはコマンドを引用します。
    • 動作から読み取った要件には 推定 と明記します。主な呼び出し元が誰か、名前が選ばれた理由など、証拠からは分からないことには 不明 と明記し、推測で埋めずに尋ねます。
    • 監査で判明した件数を記録します。グループごとのコマンド数、動詞とそれぞれの意味、同じ内容を手作業で列挙している箇所を数えます。形容詞よりも数字のほうが、ずれを明確に示せます。
    • 弱点は、最後の検証リストに照らした観察事項として記録し、変更案は提示しません。このセッションでは CLI を現状のままにするためです。
  • 既存の CLI を再設計する場合: まず CLI を説明し、その説明が正しいことについてユーザーの合意を得ます。その後、同じ段階を通して、問題に必要な変更だけを加えて再設計します。名前を変更するすべてのコマンドについて、違反するルールとともに変更前/変更後の行として示し、既存の呼び出し元が古い名前に依存しているため、進化の段階でも変更を反映します。
  • 「これはフラグにするべきか、それともサブコマンドにするべきか」のように、1つの問いを判断する場合: 関連する設計部分、その背景にある要件、トレードオフを含む選択肢、および推奨案を示して回答します。

設計対象の CLI がよく知られたツールに似ている場合は、記憶に頼る前に、そのツールのヘルプと末尾に挙げられたガイドを調べます。呼び出し元にとって役立つパターンを取り入れ、省いたパターンとその理由を明記します。

提供フレームワーク

Requirements → Command model → Inputs → Output and errors → Help → Implementation → Evolution

各段階は前の段階を土台にします。コマンドモデルは要件から生まれ、入出力がモデル内の各コマンドの内容を明確にし、ヘルプはそれらすべてから生成され、実装では一元管理され、進化の段階では次の変更に照らして設計全体を検証します。現在の段階の成果物に必要なものがすべて揃ったら、次の段階に進みます。後の段階で不足が明らかになった場合は、前の段階に戻ります。

要件

次の5つのテーマについて検討します。

  • 呼び出し元: CLI を実行するのは誰ですか。ターミナルを使う人、スクリプト、CI、エージェントなどです。各ジョブの主な呼び出し元を明記してください。人向けのコマンドとスクリプト向けのコマンドでは、トレードオフが異なります。
  • ジョブ: 各呼び出し元は何をするために使いますか。「呼び出し元は〜できる必要がある」という形式で記述してください。対象範囲のリストは短く保ちます。各ジョブは1つまたは数個のコマンドになります。
  • 役割: コマンドの効果に基づく種類です。読み取り専用、データの変更、実行中のサービスやアプリへの操作、イベントの待機、管理などがあります。確認、ロック、認証情報が必要になるなど、それぞれの役割には固有のルールがあります。
  • ランタイム: 各コマンドの実行に必要なものです。何も必要ない、ローカルファイル、実行中のデーモンやアプリ、ネットワークなどがあります。どのコマンドがオフラインで動作するかを明記してください。確認対象のサービスを必要とするステータス確認では、そのサービスの停止を報告できないためです。
  • 対象外: CLI が対応しないことです。たとえば、対話型インターフェース、プラグインシステム、Windows のサポートなどがあります。対象外を明確にすることで、誰からも求められていないコマンドがコマンドツリーに増えるのを防げます。

短い番号付きリストとして示します。

コマンドモデル

ジョブをコマンドツリーに変換します。

  • 名詞: ジョブの対象となるオブジェクトを表します。プロジェクトの用語集、UI、ドキュメントですでに使われている言葉を使います。独自のコマンドを持つ名詞はグループにし、名詞に関する情報はグループではなくオプションまたは出力フィールドにします。
  • 階層: アカウント › プロジェクト › 環境のように、名詞を包含関係のツリーとして表し、グループもそれに沿わせます。noun verb の順にします。こちらのほうが一般的で、ヘルプでも関連するコマンドがまとまるためです。
  • 動詞: 1つの意味を持つ、単一の固定語彙を使い、対応する動詞があるすべての名詞で同じように使用します。create と new、get と show などの同義語の組から1つを選び、どこでも統一してください。印刷と表示は分けます。データを印刷する動詞は常に印刷し、ウィンドウやピッカーには専用の動詞を使います。既定の語彙は conventions.md にあります。
  • 深さ: 最大2階層とし、tool <noun> <verb> の形式にします。複合アクションには、第3階層を設けず、ハイフンでつないだ動詞(send-text など)を使います。
  • トップレベル: 呼び出し元が毎回実行する少数のコマンドと help のみを置きます。それ以外はすべてグループに入れます。長いフラットな一覧では、重要なコマンドが埋もれてしまうためです。
  • 対象の指定: コマンドが操作対象のオブジェクトを指定する方法を1つに決めます。必須の語句(tool project get <id>)、名前付きオプション(--project <id>)、またはオプションで上書きできる現在の既定値(設定済みのコンテキストや作業ディレクトリなど)のいずれかです。すべてのコマンドで同じルールを適用してください。

コマンドツリー、動詞の表、対象の指定ルールを使ってモデルを示します。

入力

各コマンドの引数、フラグ、その他の入力をすべて明記します。

  • 単語とフラグ: 単語とは、コピーするファイルのように、自然な順序で指定する必須の入力です。それ以外はすべて名前付きフラグにします。フラグは後から追加しても呼び出し元との互換性を損なわず、スクリプトでも読みやすいためです。コマンドに種類の異なる入力が2つ必要な場合は、2つ目をフラグとして指定し、呼び出し元が誤って順序を入れ替えないようにします。
  • フラグ名: すべてのフラグにケバブケースの長い名前を使い、特に一般的な少数のフラグに限り、短い1文字の名前を使います。標準的な意味には標準の名前(--help、--version、--json、--quiet、--force、--dry-run)を使います。同じフラグは、どのコマンドでも同じ意味にします。
  • すべてのコマンドで使う出力形式、詳細度、対象コンテキストなどのグローバルフラグは、1か所で解析します。
  • その他の入力元: 引数が - の場合の標準入力、環境変数、設定ファイルです。フラグから組み込みのデフォルト値まで、優先順位を統一します。
  • 対話: 標準入力が端末の場合にのみプロンプトを表示し、各プロンプトに回答するフラグを用意して、スクリプトやエージェントが応答待ちで停止しないようにします。破壊的な操作は確認を求め、--force または --yes で確認を省略できるようにします。元に戻しにくい操作には --dry-run を用意します。
  • シークレット: シークレットはファイル、標準入力、または環境変数から取得します。フラグには指定しません。フラグはシェルの履歴やプロセス一覧に残るためです。
  • オプションの終端: -- でオプションを終端します。これにより、ハイフンで始まるテキストも単語として扱えます。

各コマンドについて、単語、フラグ、値のプレースホルダーを含む使用例を1行ずつ示します。

出力とエラー

各コマンドが出力する内容と、エラー時の動作を決めます。

  • ストリーム: パイプで渡せるよう、データは標準出力に出力します。進行状況、警告、エラーは標準エラーに出力します。
  • 人間向け出力とJSON出力: デフォルトの出力は人間向けとし、簡潔で読みやすくします。データを出力する各コマンドで --json を指定した場合は、安定した文書化済みの形式を出力します。JSONの形式は契約の一部として扱い、通常の出力は改善のために変更できるようにします。
  • 端末: 色、スピナー、プログレスバーは、ストリームが端末の場合にのみ使用します。また、NO_COLOR、TERM=dumb、--no-color の場合は色を無効にします。約100ミリ秒以内に何かを出力し、少しでも時間がかかる処理では進行状況を表示して、コマンドが停止したように見えないようにします。
  • エラー: 何が問題だったかと次に何をすべきかを1行で示し、対処に使うコマンドやフラグを明記します。最も重要な情報は、目に留まりやすい文末に置きます。デバッグ用のトレースは、要求された場合にのみ出力します。
  • 終了コード: 成功時は0、失敗時は0以外のコード、使用方法が誤っている場合は専用のコードを返します。CLIが使用するすべてのコードを文書化します。タイムアウトや「該当なし」のように、呼び出し元が失敗とは異なる扱いをする場合に限り、コードを追加します。
  • 堅牢性: 処理を始める前に入力を検証し、すべてのネットワーク呼び出しと待機にタイムアウトを設定します。可能な場合は再実行しても安全にし、Ctrl-C では速やかに終了します。

各コマンドまたはコマンドグループについて、出力内容、--json の形式、拒否される操作とその終了コードを表にまとめます。

ヘルプ

ヘルプを、ユーザーにもエージェントにも CLI を学ぶための主要なインターフェースとして設計します。

  • **3 つのレベル:**トップレベルのヘルプ(tool --help)は 1 画面に収め、グループのヘルプ(tool <group> --help、またはグループ名だけ)には各コマンドの完全な使用方法を記載し、コマンドのヘルプ(tool <group> <verb> --help)には使用方法、説明、すべてのフラグ、例を記載します。レイアウトはconventions.mdにあります。
  • **概要:**各コマンドにつき 1 行で、動詞から始め、コードがどのように処理するかではなく、コマンドで何ができるかを述べます。同じ概要を、表示される場所すべてで使います。
  • 例は、読者の多くがコピーして調整するため、コマンドのヘルプの先頭に配置します。
  • **誤った使い方:**誤った使い方をした場合は、コマンドの使用方法とヘルプへの案内を表示し、マニュアル全体は表示しません。入力ミスのあるコマンドには最も近い候補を提示し、呼び出し元に実行を委ねます。
  • **見つけやすさ:**トップレベルのヘルプで、完全なドキュメントの場所を示します。エージェントが呼び出し元になる場合は、help --json やスキーマコマンドなど、機械可読なコマンド一覧を用意し、トップレベルのヘルプから 1 回案内します。
  • 一般的なシェル向けの補完を、同じコマンド定義から生成します。

トップレベルのヘルプ、1 つのグループのヘルプ、1 つのコマンドのヘルプをモックアップで示します。

実装

CLI がコード内で契約を維持する方法を設計します。その言語のエコシステムで標準となっている引数解析ライブラリを使い、足りない部分だけを実装します。

  • **データとしてのコマンドテーブルを 1 つ用意:**各コマンドの名前、グループ、使用方法、概要、説明、例、フラグ、対象、役割を 1 か所にまとめます。パーサー、ヘルプ、補完、ドキュメント、機械可読な一覧は、すべてこのテーブルを参照します。
  • **引数から終了コードまでの経路を 1 つにする:**グローバルフラグを解析し、コマンドを特定して、その入力を解析し、実行し、出力して終了します。すべてのコマンドがこの経路を通るため、各コマンドで規約を繰り返し記述せずに適用できます。
  • **一覧を二重に書かない:**フラグを受け付けるコマンドなど、読者が目にする一覧はすべてテーブルから生成します。ヘルプやドキュメントに手作業で一覧を書くと、コードと食い違っていきます。
  • **グループごとにファイルを 1 つ用意し、グループ名を付ける:**グループに変更を加えるときは、1 つのファイルを開けば済むようにします。
  • 契約テストで設計を維持します。ヘルプ内のすべての例が解析できること、エラーメッセージ、ドキュメント、スクリプトで名前が挙がるすべてのコマンドが存在すること、ヘルプが保存済みのスナップショットと一致すること、各コマンドの--json出力がドキュメントに記載された形式と一致することを確認します。

フォルダーツリーと各ファイルの責務、コマンドテーブルのフィールド、引数から終了コードまでを追ったコマンド 1 つの例、そして拒否例 1 つを示します。

進化

今後起こりそうな変更に照らして設計をテストし、契約をどう変更するか決めます。

  • **まずは追加:**コマンド、フラグ、JSON フィールドは、変更するのではなく追加します。新しいフラグなら、指定しない利用者の動作を変えずに挙動を変えられます。
  • **名前の変更:**一定期間、古い名前を非表示のエイリアスとして残し、新しい名前を示す警告を標準エラーに出します。すべてのエイリアスを名前付きで列挙し、完全一致のみで判定します。すべてを受け付けるコマンドは、捕捉する単語を含む将来のコマンドをすべて妨げ、前方一致は同じ接頭辞を持つ将来のコマンドをすべて妨げます。
  • **破壊的変更:**リリース前に CLI で告知し、現在の使い方を変更する方法を示したうえで、呼び出し元が確認できるバージョン変更とともにリリースします。
  • バージョン管理:--versionでバージョンを表示し、CLI を呼び出すドキュメント、補完、エージェント向けの指示は、すべて同じリリースに含めます。

想定される変更を「変更 → 変更する箇所」の表で示します。テーブル内の新しいコマンド 1 つだけで対応できる変更は吸収できます。同じ編集を複数のファイルで繰り返す必要がある変更には、分離点が必要です。

まずはデフォルトから

各選択肢はデフォルトから始めてください。呼び出し側は他の CLI でのこうした想定を持っており、デフォルトから外れるたびに調べる手間が発生するためです。名前のある要件がある場合に限ってデフォルトから変更し、その要件を明示してください。

  • コマンドの形式: 2 階層で 名詞 動詞。
  • フラグ: 標準の名前を使用します。
  • 出力: データを出力するすべてのコマンドで --json を使用します。データは標準出力に、メッセージは標準エラー出力に出力します。
  • 終了コード: 成功は 0、失敗は 1、誤った使い方は 2 です。
  • プロンプト: ターミナル以外では表示しません。
  • ヘルプ: 1 つのコマンドテーブルから生成します。

検証

設計が完成したら、または既存の CLI を監査する際は、以下のすべてを確認してください。

  1. ヘルプだけで、各作業を実行できます。
  2. 動詞はツリー全体でそれぞれ 1 つの意味を持ち、各概念には 1 つの名前が付いています。
  3. すべての名詞に、プロジェクトで既に使われている言葉を使用しています。
  4. ツリーは最大 2 階層で、最上位には日常的に使うコマンドだけがあります。
  5. 同じフラグはどのコマンドでも同じ意味を持ち、標準的な意味には標準の名前を使用しています。
  6. データを出力するすべてのコマンドで --json を使え、データとメッセージは異なるストリームに出力されます。
  7. すべてのエラーで次に何をすべきかを示し、すべての終了コードが文書化されています。
  8. ターミナルがない場合にプロンプトを表示したり、処理が停止したりせず、待機処理にはすべてタイムアウトが設定されています。
  9. ヘルプとドキュメントにあるリストはすべて、コマンドテーブルから生成されています。
  10. すべての例がテストされており、エラー、ドキュメント、スクリプトで名前が挙がるコマンドはすべて存在します。
  11. 名前を変更する際は必ずエイリアスを残し、破壊的変更はリリース前に告知します。

ユーザーとの作業

/show-me を読み込み、各段階を視覚的に提示してください。コマンドツリーはツリー形式、動詞と名前の変更はテーブル形式、ヘルプはモックアップ、トレースしたコマンドは呼び出しツリーで示します。文章は選択の理由を説明する場合にのみ使ってください。

  • 設計の現行版を 1 つ保ち、最初からやり直すのではなく、それを改訂します。
  • 各改訂の冒頭で、変更した理由と内容を、変更対象のツリー、テーブル、またはヘルプの変更前/変更後の diff で示し、その変更が影響するすべての段階に反映します。
  • ユーザーが決定した事項は、ユーザーが再検討しない限り変更しません。
  • 妥当な選択肢が複数ある場合は、選択肢に番号を付けて横並びにし、それぞれのコストを示します。推奨案を最初に提示してください。
  • コード、ドキュメント、ユーザーの以前の回答で判断できないことだけを、1 回に 1 つずつ質問します。それ以外は自分で判断し、判断した内容を伝えてください。

設計を調整している間は、リポジトリの規約に従い、プロジェクトのスクラッチ用または一時フォルダーにドラフトとして保存します。規約がない場合は、保存先を尋ねてください。説明は会話内に残してもかまいません。ユーザーが設計に同意し、保存を希望したら、プロジェクトのドキュメントに書き込みます。その際、設計ドキュメントを新たに追加するのではなく、既存の設計ドキュメントを更新します。

参考資料

参考資料内容
conventions.mdデフォルトの動詞の語彙、標準のフラグ名、終了コード、環境変数、設定の優先順位、および 3 つのヘルプ階層のレイアウト

出典:Command Line Interface Guidelines および POSIX Utility Conventions。

コメント