behave について
behaveは、CLIの動作をテストケースとして記録し、元のツールや別の実装に対して再実行します。移植、リファクタリング、比較を行う開発者向けで、仕様はレビューやCIに利用できます。
主な機能
- 01ヘルプやmanページからケースを生成
- 02標準出力、標準エラー、終了コードを記録
- 03別の実装に対してケースを再実行
- 04ドキュメント記載のフラグ網羅率を測定
- 05出力を正規化し不安定なケースを検出
- 06CI向けJUnitレポートを出力
活用シーン
- 01CLIの書き換え版の互換性確認
- 02リファクタリングや更新後の回帰検出
- 032つのコマンドライン実装の比較
- 04フラグのテスト状況を追跡しCIで報告
MCP 対応
MCPサーバーは、コマンド実行、動作仕様の生成と追加、ケース一覧表示、記録済みの動作との実装比較を行うツールを提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
behave
あらゆる CLI の動作を記録します。書き換え後も同じように動作することを証明します。
behave はコマンドラインツールをブラックボックスとして扱います。--help(および man ページ)を読み取り、数百件のテストケース(すべてのフラグ、フラグの組み合わせ、標準入力のエッジケース、ファイル引数、不正な値、存在しないファイル)を生成し、ツールの実際の動作(標準出力、標準エラー、終了コード)を記録して、別の実装に対してそのケースを再実行します。

次のような場合にご利用ください。
- ツールを Rust または Go に移植し、移植版に互換性があることを証明したい場合。
- CLI をリファクタリングまたはアップグレードし、数秒で回帰を検出できるようにしたい場合。
- 同じツールの 2 つの実装を比較したい場合。
ステータス:初期段階(v0.1)です。CLI と MCP サーバーは動作します。フィードバックをお待ちしています。
クイックスタート
Releases から Linux または macOS 用のバイナリをダウンロードするか、次のコマンドを実行してください。
go install github.com/emirmrkaljevic/behave/cmd/behave@latest
# 1. record how GNU sort behaves (writes ./behave-sort/)
behave probe sort
# 2. check that the recording is stable
behave run behave-sort
# 3. compare another implementation against it
behave diff behave-sort --impl ./target/release/sort --skip-tag meta
または、まずコミット済みのサンプルをお試しください。behave run examples/cut(GNU cut の 27 ケース)、behave run examples/paste(GNU paste の 18 ケース)、behave run examples/join(GNU join の 26 ケース)、behave run examples/nl(GNU nl の 26 ケース)、behave run examples/fold(GNU fold の 28 ケース)、または behave run examples/jq(jq 1.7 の 33 ケース)を実行してください。examples/ をご覧ください。
フィルター、パターン、フィールドリストなどの位置引数が必要なツールでは、サンプルを指定してください。
behave probe jq --arg . --arg '.a' --arg '.[]' --arg 'map(.+1)' --arg keys
behave diff behave-jq --impl gojq --ignore-stderr
出力例(抜粋):
✗ flag --output-delimiter, value -1, arg -f1 0135-flag-output-delimiter-value-1-arg-f1.yaml
$ cut --output-delimiter -1 -f1
exit:
exit: want 0, got 1
stdout:
- hello
flags with differences:
--output-delimiter 2/16 cases differ
flags fully compatible: 9 of 10
cut vs ./uu/cut: 172/175 passed, 3 failed, 0 skipped (differs in: exit 2, stdout 3) [0.1s]
初日に見つかったこと
このマシンで実際のツールに対して実行した結果です。生成したケースのみを対象とし、--help/--version は除外しています。
| 元の実装 | 候補 | ケース数 | 合格 | 主な差異 |
|---|---|---|---|---|
| GNU wc 9.7 | uutils wc 0.12.0 | 63 | 63 | なし |
| GNU head | uutils head | 51 | 51 | なし |
| GNU uniq | uutils uniq | 100 | 100 | なし |
| GNU tr | uutils tr | 63 | 63 | なし |
| GNU cut | uutils cut | 175 | 172 | --output-delimiter -1 が拒否される(- で始まる値) |
| GNU base64 | uutils base64 | 36 | 31 | 不正な入力に対する -d:GNU はデコード済みのバイトを出力しますが、uutils は何も出力しません |
| GNU sort | uutils sort | 290 | ~260† | 使用法エラーの終了コードが 2 ではなく 1;--debug の下線の幅;--check --merge |
| jq 1.7 | gojq 0.12.19 | 596 | 331* | 未サポートのフラグ(--seq、--ascii-output、…)、キーの順序、大きな数値の書式 |
* --ignore-stderr を指定した場合。ほぼすべてのケースでエラーメッセージの表現が異なります。
† 1〜2 件ほど変動します。入力が小さい場合、一部の --random-sort ケースは不安定な動作として検出されることもあれば、検出されないこともあります。
これらの多くはバグではなく、意図的な設計上の選択です。behave はそれらを可視化するだけです。 実際のバグもいくつか見つかり、現在は上流で修正されています。
- uutils
cut --output-delimiter -x(uutils/coreutils#15341、#15345 で修正) - uutils
sort --check --mergeがチェックを無視していた問題(uutils/coreutils#15380、#15381 で修正)
MCP サーバー
behave mcp は同じ機能を標準入出力経由で提供します。コーディングアシスタントは元のツールを調査し、作業しながら仕様を拡充して、変更のたびに移植版を検証できます。
{
"mcpServers": {
"behave": { "command": "behave", "args": ["mcp"] }
}
}
| ツール | 機能 |
|---|---|
behave_exec | 一時ディレクトリでコマンドを 1 回実行し、終了コード/標準出力/標準エラーを返します(調査用) |
behave_probe | --help から仕様を生成して記録します |
behave_add_case | ケースを追加し、元のツールの動作を記録します |
behave_list_cases | ケースを一覧表示します。タグ(flag:--sort、manual)で絞り込むこともできます |
behave_diff | 実装に対してケースを再実行し、差分とともに失敗したケースを返します |
仕様の形式
仕様は、コミットしてレビューできるディレクトリです。
behave-cut/
behave.yaml # command, timeout, normalizers
cases/
0001-help.yaml
0135-flag-output-delimiter-value-1-arg-f1.yaml
...
name: flag --output-delimiter, value -1, arg -f1
args: [--output-delimiter, "-1", -f1]
stdin: |
hello
tags: [flag-value, "flag:--output-delimiter"]
expect:
exit: 0
stdout: |
hello
stderr: ""
ケースでは env、files(新しい一時ディレクトリに作成)、および timeout_ms も設定できます。独自のケースは behave add behave-cut --stdin 'a,b' -- -d, -f2 で追加できます。
決定性が保たれる仕組み
- 各ケースは、固定された環境(
LC_ALL=C.UTF-8、TZ=UTC、NO_COLOR=1、HOME=一時ディレクトリ)で、新しい一時ディレクトリ内で実行されます - 各ケースを3回記録します。実行ごとに変化するものは
flakyとしてマークされ、スキップされます(例:sort --random-sort) - 比較の前に、正規化器がノイズを除去します:
ansi、workdir、cmd(jq:とgojq:の違い)、timestamp、hexaddr、duration、pidに加え、behave.yamlで独自の正規表現ルールも指定できます - タイムアウト時はプロセスグループ全体を強制終了します
コマンド
| コマンド | 動作 |
|---|---|
behave probe <cmd> | フラグを検出し、ケースを生成して記録します(--arg、--inputs text|json|both、--max、--skip-flag、--dry-run) |
behave record <spec> | オリジナルから期待値を再記録します |
behave add <spec> -- ARGS | 手書きのケースを1つ追加します |
behave run <spec> | オリジナルに対して再実行します |
behave diff <spec> --impl <bin> | 別の実装に対して再実行します(--ignore-stderr、--ignore-exit、--tag、--skip-tag、--json、--junit file、-v) |
behave coverage <spec> | ケースでテストされているドキュメント記載のフラグ(--help/man)を確認します(--min PCT、--all、--json) |
behave normalizers | 組み込みの正規化器を一覧表示します |
runとdiffは、いずれかのケースが失敗すると終了コード1を返すため、そのままCIに組み込めます。CIダッシュボード(GitHub Actions、Jenkinsなど)用にJUnit XMLレポートを書き出すには、--junit report.xmlを指定してください。
coverageでは、specでまだテストされていない項目を確認できます。手動で選んだcutの例:
$ behave coverage examples/cut
cut: 27 cases exercise 7 of 12 documented flags (58%)
not exercised (5): -n --zero-terminated --help --version -M
used but not in help: --no-such-flag
probeと同じ方法でフラグを読み取り、--long=value、曖昧さのない長いフラグのプレフィックス、短いフラグの連結(-sf1)を理解します。カバレッジが80%を下回った場合、--min 80を指定すると終了コード1を返します。
このリポジトリには、バイナリをビルドし、stdio上でbehave mcpを起動するマルチステージDockerfileが含まれています(DockerfileからビルドするGlamaやその他のMCPレジストリ向け)。
ロードマップ
- ヘルプテキストから、よりスマートに値を生成する機能(
WHEN can be: auto, always, never)
安全性
behaveは、指定されたバイナリのみを一時ディレクトリ内で実行します。作業ディレクトリの外部を変更するツール(パッケージマネージャーやrm -rf形式のツール)を、--skip-flagとサンドボックスなしでプローブしないでください。
リンク
- MCP Registry名:
io.github.emirmrkaljevic/behave
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。