Repository navigation
v0.25.0
[0.25.0] - 2026-08-19
Highlight: 公開面(LP・README・チュートリアル・concept)を Vibe Engineering の軸へ据え替えた回(Epic #1807、子 Issue 10 件)。あわせて収録基盤
demo-videoが worktree ID の path 由来化に追従できておらず実収録が必ず失敗する状態を復旧し、さらにfake-agent.shが承認フレームを自動応答してしまいwaitが「起きていない作業」にCompletedを返す欠陥を修正した。これを直さないまま撮っていたら、全デモが「検証を通ったことになっている」だけの映像になっていた。製品側では実行契約と検証結果を Web UI に露出し(#1816)、codex 起動ダイアログへの Auto-Yes 誤応答(#1829)と CI のハング放置(#1830)を塞いだ。
Added
-
feat(demo-video): 新シーン・code card・静止画生成を追加する (#1810):
contract-verify(tmux pane を収録し、send --contract→wait --verifyのGATE/RESULT/ 終了コードを実ゲートの実 exit code のまま映す)・attention-badge・review-screen・slash-palette・install-skillの 5 シーン、絵コンテのtype: code(ファイルを組版する静止カード。sourceは絵コンテのディレクトリ配下に閉じることを解決後のパスで検証)、および LP / README 用の静止画 5 点を同じ隔離環境から機械生成するstills.ts(バイト予算はゲートで、収まらなければ書かずに落ちる) -
feat(ui): 実行契約と検証結果を Web UI に露出する (#1816)
- worktree 詳細ヘッダに状態チップを追加。 task 行を持つ worktree に限り、直近 task の
title・TaskStatus・直近検証ランのRESULTを表示する。判定の理由(不合格ゲートの ID
一覧まで)をaria-labelとtitleの両方に出すため、ポインタでもスクリーンリーダーでも
ペインを開かずに読める(docs/design/discoverability-principle.md実装規約 1) - Activity Bar に「Verification」ペインを追加(スマホは Tools タブの「検証」サブタブ)。
上段=現在の契約(title / goal 冒頭 /scope.allow/verify.gates/autoYes.mode)、
中段=検証ラン一覧+「再検証」、下段=選択ランのゲート表(gate id / PASS・FAIL・TIMEOUT・SKIP /
exit code / duration / logTail 末尾 40 行=CLI のMAX_PRINTED_LOG_TAIL_LINESと同値)。
契約が無い worktree にはcommandmate send --contractと Skillcmate-task-contractを案内する
空状態文を出す - 新しい API は 1 つも追加していない。 #1542 / #1543 / #1545 で既に在った
GET /api/worktrees/:id/tasks、GET|POST /verify、GET /verify/runs[/:runId]の配線のみ - 独自のポーリングタイマーを増やしていない。 worktree 詳細が既に回している 2s/5s の
ポーリング末尾でpollTickを上げ、useWorktreeVerificationがそれに相乗りする
(通常は 15s スロットル、runningラン中はティックごと)。ヘッダチップと Verification ペインは
同じフックの 1 インスタンスを共有するので、2 面同時表示でも要求は倍にならない - en の
RESULT/GATE語彙はdocs/design/verification-config.md§3.4 に合わせた
(passed/failed/not_started、PASS/FAIL/TIMEOUT/SKIP)。
tests/unit/i18n/verification-keys-1816.test.ts が en/ja のキー等価と語彙一致を固定する docs/design/discoverability-principle.mdの「運用者が読む層」に Web UI を追加し、
実装規約に「新しい判定は CLI と Web UI の両方に出す」を追加
- worktree 詳細ヘッダに状態チップを追加。 task 行を持つ worktree に限り、直近 task の
Changed
- ci: 全ワークフローの全ジョブに
timeout-minutesを設定する (#1830): GitHub Actions の既定タイムアウトは 360 分(6 時間)で、ci-pr.yml(11 ジョブ)/pages.yml/publish.ymlにはtimeout-minutesが 1 つも無かった。2026-08-19 に develop の run32218070769でE2E TestsがInstall Playwright browserのまま 88 分ハングし、手動キャンセル →gh run rerun --failedで 6 分 47 秒で success(CDN 由来の一過性)。値は直近 12 ランの成功ジョブの実測(median / max)からmax × 2・最低 10 分で決め、根拠は各ジョブのコメントに残した(E2E 6.2m/16.2m → 30、Unit Tests 12.3m/13.2m → 30、他は 10)。publish.ymlは実測 median 14.3m / max 16.0m(n=10)が存在したため Issue 記載の 20 分ではなく 30 分とした。あわせて、自前で外部からバイトを取得するステップ(npm ci/npx playwright install/apt-get install/npm install/npm audit/npm publish)にステップ単位のtimeout-minutesを付け、タイムアウト時に「どのステップで詰まったか」がログから読めるようにした。tests/unit/guards/workflow-timeouts.test.tsが、ジョブの付け漏れ・360 分以上の無意味な値・ジョブ上限以上の死んだステップ上限・未設定のインストールステップを赤にする
Documentation
-
docs(tutorial): 契約 → 検証ループを体験する構成へ改稿し、GIF 8 本を v0.24 の UI で撮り直す (#1813): ja / en のチュートリアルを Fork → 登録 → Skill 導入 → ゲートを赤で確認(exit 20) → 契約を渡して判定(exit 0)→ 2 契約を並列 → 証跡 の 8 ステップへ改稿し、各ステップに「エンジニアならここで何を気にするか」を 1 行添えた。旧 §1.5 の誤記(「Skill は同じ場所へ入れ直せない」= #1243 / #1244 以降は誤り、install 先が 1 ディレクトリ)を、更新フロー・
.agents/skillsと.claude/skillsの 2 ディレクトリ・再起動が要る理由に置き換えた。GIF は 8 本 × ja / en を隔離環境で撮り直し(旧 5 本 × 2 は削除)、絵コンテをdocs/images/tutorial/storyboards/01…08-*.yamlに差し替えた。demo-video スキルにはverify-redとevidenceの 2 シーン(cli-scene.sh --mode)を追加している。掲載する出力はすべて実機の実測値で、commandmate verify <id>(ゲート無指定)が work-evidence で exit 21 を返すこと、wait --verifyは開いている契約に対してのみ契約ゲートで判定することも本文に明記した -
LP(
website/)を Vibe Engineering 軸の v2 へ作り替え (#1812): 文言はdocs/design/public-messaging.mdからコピーし(hero H1・定義文・4 カード・With / Without 7 行・キャプション・footer タグライン)、独自に言い換えていない。hero の静止画はループ図の inline SVG(要求 → CommandMate → Coding Agent → 検証された成果物、色はすべて CSS 変数で light / dark 追従、role="img"+aria-label)へ差し替え、ダッシュボード静止画は Gallery 先頭へ移した(og:image は引き続き同ファイル。SVG は social preview に描画されないため)。契約 → 実行 → 検証の 4 拍を実物のコード片(Kewton/commandmate-tutorialのverify.yaml/tasks/fix-shout.yaml、GATE/RESULT/exit 0)で見せる#loop節を新設。競合 4 製品名の比較表(#comparison)は#with-withoutへ置換し、ナビも差し替えた。デモはdocs/images/features/のcm-11/cm-03/cm-01/cm-12の en 版を byte-for-byte コピーした 4 本に入れ替え(cmpで確認、旧 3 本は削除)、Track A のセットアップ質問を実装どおり 5 項目(CM_BROWSE_ROOTSを含む)に、チュートリアル導線を 15 分・fork してから・契約 → 検証へ直した。ガードはwebsite/**からの禁止語一掃・定義文の逐語一致・#with-without7 行・byte-for-byte・hero SVG の色がすべて CSS 変数であること、を追加した -
README のデモ GIF 2 本を隔離環境の素材へ差し替え、旧
demo-*.mp4を削除 (#1815):docs/images/demo-desktop.gifはcm-11-contract-verify.en.mp4の 0〜18 秒(title カード → 契約 YAML →verify.yaml→ 実ゲートのGATE3 行・RESULT passed・0。outro の URL カードは README では冗長なので落とした)、docs/images/demo-mobile.gifはcm-03-never-miss-waiting.en.mp4のrespond-from-mobile(14〜18 秒)を 1280x800 の合成から 520x800 に切り抜いたもの。切り抜き幅はスマホ枠(実測 x=455..824 の 370px)ではなくテロップ帯の文字幅で決めた — 枠幅で切ると "Answer from your phone." が途中で切れ、帯の全幅(x=343..935 の 594px)で切るとスマホが 187px まで縮んで画面の字が読めなくなる(3 案を出力解像度のまま描画して比較した)。生成は.claude/skills/video-to-gif/scripts/to-gif.shに現行バイト数をそのまま予算として渡し(desktop 1,929,059 / mobile 4,230,486)、両方とも rung 1(600px / 300px・10fps・256 色)で収まった: desktop 909,922 バイト(現行の 47%)・mobile 180,521 バイト(同 4%)、どちらも GIF89a。旧素材に映っていた私有情報(私有リポジトリ名 6 件・LAN IP192.168.11.6:3001・旧製品名)は隔離環境の seed(cmdemo-app/wt-dark-mode/feature/demo-dark-mode)に置き換わっている。確認は代表フレームの目視だけで止めず、出荷される GIF から全 220 フレーム(desktop 180 / mobile 40)を復号して tesseract で OCR し、私有リポジトリ名・個人パス(/Users/)・プライベート IP・旧製品名・ポート番号のパターンに 1 件もヒットしないことを実測した。未参照のまま残っていた旧demo-desktop.mp4(22,674,969 バイト)/demo-mobile.mp4(47,195,161 バイト)は削除し、git ls-files docs/images | grep demo-を GIF 2 本だけにした。README(EN / JA)のaltは "CommandMate Desktop Demo" のような何も説明しない文字列をやめ、docs/design/public-messaging.md§5 / §6 の確定語彙に合わせて映像の内容を書いた -
特徴デモ 12 本を新シーンで撮り直し、product-highlights を Vibe Engineering 軸へ更新 (#1811): 絵コンテ 12 本(
cm-11-contract-verify/cm-12-install-skillを新設)を書き直し、48 ファイル(12 × ja/en × gif/mp4)を隔離環境から一度に撮り直した。旧 10 本は同一 4 シーンの使い回しで、cm-01とcm-08の 9 秒地点が SSIM 0.970(ほぼ同一フレーム)だったのに対し、新しい 5 本(cm-01/cm-03/cm-09/cm-11/cm-12)は代表フレームの総当たり SSIM が最大 0.828・最小 0.080 まで離れている。cm-11は tmux ペインを収録し、実ゲートのGATE work-evidence / scope / unit PASS・RESULT passed・0をそのまま映す。product-highlights(ja / en)は "control plane" を除いてdocs/design/public-messaging.mdの定義文と 4 段の梯子に差し替え、11・12 を先頭に置いた 12 見出し構成(ja / en 一致)にし、「デモが映している範囲」を実際のシーン構成へ更新した -
cm-11(contract-verify)のテロップ帯が GATE 行に重なっていたのを直し、ja / en を再収録 (#1811): 端末シーンのペインを 32 行から 26 行に下げ、
cli-scene.shがsend --contractと 1 回目のwaitの機械可読な stdout(task id ・ プロンプト JSON、合わせて 8 行)をファイルへ逃がすようにした(バナーはリダイレクトごと表示するので、ペインは実行していないコマンドを映さない)。帯の位置(telop.htmlのmargin-bottom: 7.5%)は他の 11 本のレイアウトを動かさないよう据え置き。あわせて 黙って切り詰められたテイクが合成を通ってしまう穴を塞いだ:respond後の同期プローブが「生成中」だけを待っていたため、カセットが先に完走した回はプローブが 90 回空振りしてペインを収録途中で殺し、Response sent.で終わる映像がそのまま cut になっていた(実測: ja 版のテイクが 138 秒・GATE ブロックなし)。プローブは「プロンプトに留まっている / 生成中 / 応答なしで静止」の 3 状態を返すようにし、静止は capture キャッシュ(5s)を跨ぐ 6 回連続で受理する。recordTerminalSceneは最終フレームにRESULT passedが無ければテイクを失敗させる -
README(EN / JA)の hero・Key Features・ワークフロー節・比較表を Vibe Engineering 軸へ整合 (#1814): hero を
docs/design/public-messaging.mdの H1 +定義文に差し替え、Key Features 先頭に Task Contract / Verification Gates / Evidence & Metrics / Skills Catalog / 入力待ち通知の 5 行を追加し、Multi-Agent 行を 7 CLI(CLI_TOOL_IDS実数)へ更新した。「Optional Workflow Layer」は## Vibe Engineering workflowへ昇格して "optional, not required" を削除し、公式 Catalog Skill とsend --contract→wait --verifyの最小コマンド列で説明する構成に変えた(.claude/commands表はこのリポジトリ限定である旨を明記して 1 行リンクへ縮退)。競合 4 製品名の比較表は With / Without CommandMate 表に置換。ガードtests/unit/docs/public-messaging.test.tsの対象に両 README を追加した -
Mission / Vision を
docs/concept.md/docs/en/concept.mdに正本化し、公開面の文言表docs/design/public-messaging.mdを新設 (#1808): hero・定義文・4 カード・With / Without 表・デモのキャプションとテロップ・チュートリアル導入文・footer タグライン・禁止語リストを ja / en 両方で確定した。軸語 "Vibe Engineering" の一次情報(Simon Willison, 2025-10-07)を実際に確認し出典として記録。禁止語リストはガードテストtests/unit/docs/public-messaging.test.tsの配列と一致していることを固定している -
docs(en): verify / task / skills / hooks の英語ドキュメントを JA と同構成に整備 (#1817) —
docs/en/user-guide/cli-operations-guide.mdにsync/verify/task(実行契約・gateDefinitions・無人実行テンプレート)/ 読むモード /instances/ マルチセッション /skill/report metricsの各節を追加し、docs/en/user-guide/skills.mdとdocs/en/user-guide/agent-event-hooks.mdを新規作成。ENcommands-guide.mdに「このリポジトリ限定」の明記と全 27 コマンド表を追加し、tests/unit/docs/ja-en-heading-parity.test.tsが 4 対の ja/en で##見出し数の一致を固定する
Removed
- refactor(review): 未使用の
ReviewCard.tsxと 8 tests を削除する (#1824):src/components/review/ReviewCard.tsx(91 行)は#600(ed612bcf)で/reviewがReviewTabへ移行した時点から呼び出し元がゼロで、tests/unit/ReviewCard.test.tsxの 8 tests は出荷 UI を何も保証しないまま緑を出し続けていた(実際 #1810 のreview-screenシーンはこの testid を同期点に据えて起票され、収録が空振りした)。ReviewCard固有の 4 挙動(?pane=terminal付きリンク /nextAction行 / 行ごとのReviewStatusバッジ / インライン返信のchildrenスロット)はReviewTabの現行 UI で代替済みか、統合すると出荷中の UX 変更になるため取り込まない。どこも読まなくなったreview.status.doneを en / ja のlocales/*/review.jsonとtests/unit/i18n/review-keys.test.tsのRUNTIME_KEYSから外し、i18n ガードが「実際に解決されるキー」だけを固定する状態へ戻した
Fixed
-
fix(codex): Auto-Yes が codex の起動ダイアログを勝手に確定してセッションが hooks レビュー画面で固着する (#1829): Auto-Yes は既定ルールで「既定の選択肢=option 1」を送るため、codex の
Hooks need reviewに1. Review hooks、update 通知に1. Update nowを撃っていた。前者は #1760 の3(trust せず継続)を無効化してt/escしか出口の無いレビュー画面へ、後者は #890 が防いでいたnpm install -g @openai/codex(=codex プロセス死)へ繋がる。これらの画面の応答はCodexTool.waitForReadyの担当だが、waitForReady はstartSession中しか見張らず Auto-Yes ポーラーはセッションと無関係に 2s で回り続けるため、先に見た方が勝つレースになっていた(起動後にダイアログが再出現した実セッション 2 本が固着)。修正は 3 点。(1) auto-answer 層のみで抑止 —getCodexLifecycleDialog(detection/cli-patterns.ts)が非 null の間、ポーラーは何も送らない。検出層は無変更で、detectPromptはこれまで通り画面をプロンプトとして報告する(検出層で潰すと人間にも提示されなくなる)。抑止はcapture --jsonのautoYes.lastSuppression(reason: agent-launch-dialog)に出る。(2) 固着からの復帰 —waitForReadyが hooks 画面2/3 を検出したらEscapeを最大 4 回まで送って上位へ戻す(t=trust は送らない)。(3) 誤表示の解消 — 画面2/3 は選択肢も confirm フッタも thinking マーカーも持たずrunning既定に落ちていたので、STATUS_REASON.CODEX_HOOKS_REVIEWとしてwaitingを返し NavigationButtons を出す。fixture は codex-cli 0.148.0 の実キャプチャ(3 画面)へ更新した -
fix(demo-video): worktree ID の path 由来化に追従し、収録パイプラインを復旧する (#1809)
demo-videoスキルは #1621 / #1644(v0.20.0)以降、実収録が必ずタイムアウトしていた。
worktree ID が<repo>-<branch>からsanitize(basename(path))(deriveWorktreeId)に
変わったのに、harness 側が旧規則の ID を定数で持っていたため。サーバが探す tmux セッション名は
mcbd-claude-wt-dark-modeなのに harness は別名のセッションを作り、isSessionRunningが
永久に false のまま全シーンが個別のタイムアウトで死んでいた(警告も出ない)- ID を定数で持つのをやめ、
env-up.shが seed ディレクトリから導出してstate.envに書く。
CM_DEMO_PRIMARY_WORKTREE_ID/CM_DEMO_WORKTREE_ID/CM_DEMO_LOGIN_WORKTREE_ID/
CM_DEMO_UNSYNCED_WORKTREE_IDと、それぞれの*_PATH。record-scenes.tsの
DEFAULT_WORKTREE_ID/UNSYNCED_WORKTREE_IDは削除し、引数・環境変数・state.envの
いずれも与えなければブラウザを開く前に停止する(黙って旧値に落ちない) - 二重の安全策: 録画開始前とシーンごとの
prepareで/api/worktreesのpathと
CM_DEMO_WORKTREE_PATHを突き合わせ、同じディレクトリが別 ID で登録されていたら
その場で ID と path の両方を出して落ちる。ID はパス単位で初回登録時に凍結されるため、
待っても直らない条件をタイムアウトまで待たない - 後片付けは記録駆動にした。
fake-agent.sh --record-toが作成したセッション名を
$CM_DEMO_SESSIONS_FILEに追記し、env-down.shはその記録とstate.envの ID から組んだ
mcbd-<tool>-<id>[-<suffix>]だけを kill する。旧実装のgrep -- '-cmdemo-app-'は
新 ID のmcbd-claude-wt-dark-modeに一致せず、偽エージェントを取り残していた - 依存チェックに
claudeを追加。POST /api/worktrees/[id]/sendは
cliTool.isInstalled()(実体はwhich claude)が false だと 503 を返すため、未導入だと
依存チェックではなく録画の途中でテイクが死ぬ。欠けていれば導入方法を出して収録前に止まる - テストは製品の規則を固定する形に置き換えた。旧テストは stale な定数どうしを突き合わせて
いたので #1621 を素通りしていた。deriveWorktreeIdを import して seed ディレクトリ名から
ID を導き、env-scripts.test.tsはtmuxスタブを介して「kill する名前」を実測する
(実 tmux は触らない) - 隔離環境(
HOME差し替え・ポート 3466・$HOME/.commandmate-demo)で
demo-video.sh --locale enを通しで完走させ、尺検証ゲートの通過を確認済み