Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Claude Code の /goal コマンドの話

Claude Code の /goal コマンドの話

Claude Code の /goal コマンドを使って実装を自律的に自走。裏テック無尽で使うデモの実装をやらせてみました。

Avatar for numa08

numa08

July 24, 2026

More Decks by numa08

Other Decks in Technology

Transcript

  1. /goal は「終わりの条件」を渡すコマンド 完了条件を書いて渡すと、満たすまでターンをまたいで回り続ける ▸ 毎ターン後、軽量モデルが「条件は満たされたか」だけを判定 → 未達なら次のターンを自 動で開始 ▸ Claude

    Code v2.1.139 から。 /goal で状況確認、 /goal clear で中断 ▸ /goal all tests pass and the lint step is clean = 人間が「まだ終わってないよ」と言い続ける役から降りられる。 逆に言うと、終わりの条件を書けない仕事には使えない。 2
  2. やったこと:ブラウザアプリを1本 Vite + TypeScript の Web アプリ。ドメインロジック + UI +

    e2e まで一式 ▸ 02:00 受入テストを「赤」のまま凍結し、 /goal を起動 → 03:15 一通り緑 ▸ この 1時間15分、プロンプトは1回も打っていない 全体の流れ ▸ 外部仕様の調査 → 仕様を対話で作る(SPEC.md) → 受入テストを赤で凍結 → /goal → 緑になる まで自走 自走したのは最後の矢印1本だけ。手間は太字の2つにほぼ全部かかっている。 今日はそっちの話をします。 3
  3. 実際に打った条件文 /goal SPEC.md の全受入基準(AC-1〜AC-32)に対応するテストが pnpm test で exit 0、 lint・型チェックがクリーン、Playwright

    で AC-24 の起動〜メイン画面描画が通ること。 SPEC.md と test/ 以外の既存テストは変更しない。Non-Goals に記載の項目には着手しない。 3行。仕様本文は1文字も貼っていない。 AC-1〜AC-32 ・ Non-Goals という単語で、全部 SPEC.md に外だししている。 4
  4. この3行には4つ仕掛けがある 1. 判定をコマンドの終了コードに寄せた — pnpm test で exit 0、lint・型チェックがクリーン 2.

    範囲を数えられる形にした — 「全部」ではなく AC-1〜AC-32 3. 触っていい場所を閉じた — SPEC.md と test/ 以外の既存テストは変更しない 4. やらないことを名指しした — Non-Goals に記載の項目には着手しない この3行が短く書けるかどうかは、SPEC.md 側が全部引き受けられているかで決まる。 ここから、その SPEC.md をどう作ったかの話。 5
  5. ① 章立てを固定し、非目標を必ず埋める 固定した章立て 実際に切った非目標(9項目) 1. 目的 / 背景 ▸ 本物の

    FT8 信号のデコード / WSJT-X との 2. ユーザーストーリー 相互運用 3. 受入基準 ▸ 6文字コールサイン対応 4. 制約 5. 非目標 ▸ 名前衝突の自動回避(その場で手動修正) 6. 未解決の疑問 漏れの最大の発生源は「書いてある要件」ではなく暗黙 ▸ SNR 算出・グリッドロケータ交換・バン の前提。 ド切替 だから空欄を許さない章を先に決める。 非目標は /goal の柵になる。 書いておかないと、親切心でスコープを広げに行く。 6
  6. ② 受入基準は EARS 記法で書く 「いつ〜したとき、システムは〜しなければならない」の定型に落とす。 AC-2 もし 入力された名前が大文字英数字ちょうど3文字でなければ、 システムは 確定を拒否し理由を表示しなければならない。

    この一文が、そのまま1本の受入テストに写せるのがミソ ▸ 逆に EARS で書けない要件は「まだ曖昧=漏れ」 として検出できる ▸ 時間に関する要件には、必ず数値の許容誤差を書く(例:スロット境界から ±500ms 以 内) ▸ 7
  7. ③ 一気に書かせず、2〜3問ずつ引き出す 私が話した箇条書きに対して、返ってきた質問(抜粋) ▸ 「時刻同期(15秒スロット)は目標ですか、非目標ですか」 ▸ 「7台が同じ部屋で同時に鳴ったら? サブバンド分離を狙うのか、ターン制にするのか」 ▸ 「複数応答の順序基準を1つ決めてください(先着

    / 辞書順 / 周波数の低い順)」 ▸ 「3回リトライは、自分の CQ 側ですか、他局への応答側ですか」 全部「決めないと受入テストが書けない」項目。 逆に言うと、テストが書けるかどうかを基準に聞くべきことが決まる。 8
  8. 実装前に出た穴 ① メッセージが器に入らない 私の案:「名前は3文字か4文字。衝突するので誕生月を足す」(例: TF07 ) 律速は完了時の <相手> DE <自分>

    73 " DE "=4文字 " 73"=3文字 → 固定7文字。13-7=6 → 名前は 3+3 が天井 ABC DE DEF 73 = ちょうど13文字 OK ABCD DE EFGH 73 = 15文字 NG 4文字案はここで破綻。名前は3文字固定へ。この1つの決定が AC-2 / AC-6 / AC-12 / 非目標 に波及し、 新しい受入基準(全送信メッセージ13文字以内)が1本増えた。 9
  9. ④ 書いた仕様を、4つの視点で敵対的に読ませる 視点 実装者 QA PM セキュリティ 見るもの そもそも実現できるか テストに落とせるか

    目的と合っているか リスクはないか 指摘には critical / important / minor の重大度をつけ、critical が残っている間は次に進ま ない。 「自分の宿題を採点させるな」を、実装だけでなく仕様の段階にも効かせる。 10
  10. 実装前に出た穴 ② 時刻同期が critical 実装者視点「端末時計は数秒ずれる。15秒スロットには致命的」 ▸ QA視点「AC-7 は許容誤差が未定義でテストに落とせない」 ▸ →

    「スロット境界から ±500ms 以内に送信開始」と数値を入れて、はじめて合否判定で きる基準になった ▸ PM視点も刺さった。「1 QSO = 4スロット×15秒 = 60秒。7人なら21ペア。10分で回るのか」 → 成功条件を「参加者の半数以上が最低1回交信」と数値で握り直した。 11
  11. ⑤ AC とテストを1対1で結び、3層に仕分ける 受入基準に ID を振り、受入テストにも同じ ID を付ける。ID が片方にしかない=漏れ ▸

    32本を 自動 / 治具が要る / 手動 の3層に仕分けた ▸ 判定役はログしか読まない。だから条件になれるのは「自動」の層だけ ▸ 実機の音響結合やマイク許可ダイアログは、当日の手動チェックリストへ ▸ テストを書く作業自体は /goal に乗せない — 実装役に採点基準を書かせると甘くなる 人がテストを書く → 凍結(コミット) → そこで初めて /goal ▸ 12
  12. しくじり① 1文字で条件は死ぬ - /goal ... 対応するテストが npm test で exit

    0、... + /goal ... 対応するテストが pnpm test で exit 0、... このリポジトリに npm test は存在しない ▸ 判定役はツールを叩かない。Claude の出力を読んで判定するだけ ▸ つまり、存在しないコマンドを条件にすると誰も気づかないまま話が進む ▸ 13
  13. しくじり② レビューは当てていた 時刻同期は、critical として指摘されていた ▸ 選択肢は3つ出ていた — (a) サーバの Date

    ヘッダで補正 / (b) 外部の時刻API / (c) 端末時計 そのまま ▸ 私は (c) を選んだ。「time.is へのリンクを貼っておけば十分」と思って ▸ 実機2台で 1.7秒ズレ。デコード不成立でデモが成立しない 落としたのはレビューではなく、人間の判断のほう 人間が切り分け → OQ-5 を改訂して (a) へ → 受入基準を2本追加 → もう一度 /goal ▸ 14
  14. 自走ループの内側と外側 工程 実装(受入テストを緑にする) 受入テストの実装 仕様(SPEC.md)の決定 実機で初めて分かる問題 自走できたか ◎ 自走できた ◦

    おおむね自走 △ 人が主導 ✗ 人が必要 理由 pnpm test の終了コードで決定論的に判定できる ただし「自動化できる範囲」の見極めは人が判断 何を作る / 作らないかは人が決める 動かして初めて分かる。ループの外側の出来事 15