diff --git a/.claude/skills/setup/SKILL.md b/.claude/skills/setup/SKILL.md index 59b16ee..ce60a18 100644 --- a/.claude/skills/setup/SKILL.md +++ b/.claude/skills/setup/SKILL.md @@ -11,20 +11,21 @@ ## 基本ルール -- 各フェーズの成果物をユーザーが承認してから次のフェーズに進むこと +- 各フェーズの成果物をユーザーが承認し,コミット済みであること(未コミットの場合は,そのまま進んでよいかのユーザーの了承)を確認してから次のフェーズに進むこと(後述「立ち上げ中の Git 運用」) - ユーザーが「今日はここまで」と言った場合,CLAUDE.md の進捗(最新 1 行)と `docs/PROGRESS.md`(追記)を更新して中断する - ドキュメントの書式・命名は `.claude/rules/markdown-style.md`・`.claude/rules/docs-naming.md` に従って作成する(該当ファイル編集時に自動ロードされる) -- 成果物のドラフトを提示し,ユーザーの修正指示を反映してからファイルに書き出す +- 成果物は**最初から保存先にファイルとして書き出してから**レビューを受ける.チャットには成果物の全文を出さず,「書き出したファイルの一覧」と「判断してほしい点・Claude が決めた点」だけを短く示す(ユーザーはエディタでファイルを読む) +- ユーザーの修正指示はファイルに直接反映する(差分はユーザーが `git diff` で追える).修正内容はチャットに要点だけ報告し,全文を再掲しない - フォルダは成果物を実際に書き出すときにのみ作成する.空のカテゴリフォルダを先回りで作らない ## 立ち上げ中の Git 運用 (Git During Setup) -立ち上げ作業は専用ブランチ `chore/project-setup` の上で行い,**各フェーズの成果物を書き出してユーザーが承認したら,その場でコミットする**(フェーズごとに 1 コミット).手順・コミットメッセージの対応表は本スキルの `reference.md`(`.claude/skills/setup/reference.md`)「フェーズごとのコミット」に従う. +立ち上げ作業は専用ブランチ `chore/project-setup` の上で行う.**コミットは本スキルでは行わず,各フェーズの成果物をユーザーが確認したうえでユーザー自身が `/commit` で行う**(CLAUDE.md「Git 運用」の「`/commit` 自発実行禁止」どおり).フェーズごとのコミットメッセージ例は本スキルの `reference.md`(`.claude/skills/setup/reference.md`)「フェーズごとのコミット」にあり,ユーザーに案内してよい. -- 本スキルは CLAUDE.md「Git 運用」の「`/commit` 自発実行禁止」に対する**ユーザー承認済みの例外**である(`/auto-refactor`・`/auto-audit` と同格).例外が認められるのは `chore/project-setup` ブランチへのコミットに限る -- **`git push`・PR 作成・マージ・`main` への直接コミットは一切行わない**.`main` への取り込みは全フェーズ完了後にユーザーが `/commit push`(または `/commit merge`)で行う -- ブランチは最初のコミットを作る直前に `main` から作成する.既に `chore/project-setup` にいる場合(再開時)はそのまま使い続ける -- コミット履歴がそのままフェーズの進捗になるため,中断・再開しても「どこまで終わったか」が git から辿れる(`CLAUDE.md` の進捗欄・`docs/PROGRESS.md` の更新はそのフェーズのコミットに含める) +- ブランチ `chore/project-setup` の作成は本スキルが行ってよい.最初にファイルを書き換える前(前提確認での CLAUDE.md 書き換えを含む)に `main` から作成する.既に `chore/project-setup` にいる場合(再開時)はそのまま使い続ける(手順は `reference.md`「フェーズごとのコミット」) +- **`git commit`・`git push`・PR 作成・マージは行わない**.`main` への取り込みは全フェーズ完了後にユーザーが `/commit push`(または `/commit merge`)で行う +- 次のフェーズに進む前に `git status --porcelain` で作業ツリーがクリーン(そのフェーズの成果物がコミット済み)であることを確認する.未コミットの変更が残っている場合は,コミットしてから進むか,未コミットのまま次へ進むかをユーザーに確認する(勝手に進まない) +- フェーズごとにコミットしてもらうことで,中断・再開しても「どこまで終わったか」が git 履歴から辿れる(`CLAUDE.md` の進捗欄・`docs/PROGRESS.md` の更新はそのフェーズのコミットに含めてもらう) ## 前提確認 (Pre-check) @@ -35,7 +36,7 @@ - CLAUDE.md の以下を書き換える: - 1 行目の `# プロジェクト名` → `# {確定したプロジェクト名}` - 3 行目の `` → 概要テキスト -3. CLAUDE.md の「開発進捗」と `docs/PROGRESS.md` を確認し,どのフェーズから再開するか判断する +3. CLAUDE.md の「開発進捗」と `docs/PROGRESS.md` を確認し,どのフェーズから再開するか判断する(再開時は `git status --porcelain` で前回の未コミットの変更が残っていないかも確認し,残っていればユーザーに `/commit` するか確認する) 4. 初回の場合はフェーズ 1 から開始する ## 開発モードの選択 (Development Mode) @@ -84,17 +85,31 @@ 1. GUIDE_01 の該当フェーズを参照し,目的・成果物・役割分担を確認する 2. ユーザーとの対話で情報を収集する -3. 成果物のドラフトを作成し,ユーザーに提示する -4. 承認を得てから GUIDE_01 に記載された保存先に書き出す -5. 書き出した成果物をコミットする(前述「立ち上げ中の Git 運用」・`reference.md`「フェーズごとのコミット」.push・PR は行わない) +3. 成果物を GUIDE_01 に記載された保存先に直接書き出し,書き出したファイルの一覧と要確認点をユーザーに示す(全文はチャットに出さない) +4. ユーザーの修正指示をファイルに反映し,承認を得る +5. ユーザーに `/commit` でのコミットを案内する(前述「立ち上げ中の Git 運用」・`reference.md`「フェーズごとのコミット」のメッセージ例を添える) +6. 作業ツリーがクリーンになったことを確認してから次のフェーズに進む(未コミットのまま進むかはユーザーに確認する) ### 台詞テンプレート -「**フェーズ {N}({フェーズ名})のドラフトです.** +「**フェーズ {N}({フェーズ名})の成果物を書き出しました.** エディタで確認してください. -{ドラフト内容} +書き出したファイル: -修正点があれば指示してください.OKであれば {保存先} に保存し,`chore/project-setup` にコミットして次のフェーズに進みます.」 +- {ファイルパス}({新規作成 / 更新}: {1 行の説明}) + +判断してほしい点: + +- {ユーザーの判断が必要な点.無ければ「なし」} + +Claude が決めた点: + +- {ユーザーに確認せず Claude が仮に決めた点と理由} + +修正点があれば指示してください(ファイルを直接修正します.差分は `git diff` で確認できます). +OK であれば `/commit` でコミットしてください(メッセージ例: `{reference.md の対応表のメッセージ例}`).コミットを確認してから次のフェーズに進みます.」 + +修正を反映したときは,直したファイルと変更点の要点だけを示し,同様に `/commit` を案内する. ### フォルダ作成の注意 @@ -105,12 +120,13 @@ 外部サービスの設定(アカウント作成,コンソール操作等)はユーザー自身が行う.手順書に記載するが,AI が実行しないこと. **例外**として,`gh` CLI で操作できる GitHub リポジトリ設定は AI が実行する. 手順書を書き出した後は,それ以外の手順を実際に実行して環境を構築する(後述「環境構築の実行」.ツール導入は都度承認を得る). +このフェーズは「ファイル作成」と「構築の実行」が混ざるため,**構築を実行し,その結果(実際に使ったコマンド・バージョン・躓き)を手順書ファイルに反映してから**,ファイル一覧と要確認点を示してレビューを受ける. ### GitHub リポジトリのセキュリティ設定 (GitHub Repository Security Settings) Dependabot alerts("Vulnerabilities")と Dependabot security updates はリポジトリごとに既定で OFF のため,モード(solo / team)に関わらず AI が `gh api` で有効化する.コマンド・検証・トラブル対応は本スキルの `reference.md`(`.claude/skills/setup/reference.md`)「GitHub リポジトリのセキュリティ設定」に従う. -- `ENV_03_管理者用環境構築手順.md` のドラフトには,GitHub リポジトリ作成の直後の手順として `reference.md` の有効化・検証コマンドを必ず転記する(`/setup` 後にリポジトリを作った場合に管理者が単体で実行できるようにするため) +- `ENV_03_管理者用環境構築手順.md` には,GitHub リポジトリ作成の直後の手順として `reference.md` の有効化・検証コマンドを必ず転記する(`/setup` 後にリポジトリを作った場合に管理者が単体で実行できるようにするため) - ENV_03 を書き出したら,その場で `reference.md` の手順を 1 度実行する.リモート未作成で実行できなければ Phase 7 で再試行する ### 依存バージョン更新の設定 (Dependabot Version Updates) @@ -118,7 +134,7 @@ 上記の脆弱性検出とは別に,依存パッケージを定期的に最新化する PR を Dependabot に作らせるため,フェーズ 3 で `.github/dependabot.yml` を**ユーザーに選択を聞かずに必ず生成する**(`.gitignore` 等と同じ「設定ファイルの生成」の一部として扱う). - フェーズ 2 で確定した技術スタック(`ENV_01_技術スタック.md`)から対象エコシステムを決め,`reference.md`「依存バージョン更新の設定」の対応表と雛形に従って生成する -- 生成内容(対象エコシステム・更新頻度・グループ化)は他の成果物と同様にドラフトとしてユーザーに提示し,承認を得てから書き出す(「作るかどうか」は聞かず,「内容」だけを確認する) +- 生成内容(対象エコシステム・更新頻度・グループ化)は他の成果物と同様にファイルに書き出してから,要確認点として示してユーザーの承認を得る(「作るかどうか」は聞かず,「内容」だけを確認する) - マニフェストがまだ存在しない場合(立ち上げ時点でコードが無い)でも,スタックが確定していれば生成してよい.Dependabot はマニフェストが置かれた時点から動き始める ### 環境構築の実行 (Executing the Environment Setup) @@ -128,7 +144,7 @@ - リポジトリ内で完結する操作(プロジェクト初期化・依存インストール・設定ファイル生成・ビルドや起動の疎通確認・`gh` でのリポジトリ設定)はそのまま実行する - ツール導入(SDK・ランタイム・CLI のインストール,`docker build`,dev container の起動)は**実行するコマンドを提示して承認を得てから**実行する.OS・パッケージマネージャ・バージョン・入る場所(システム全体かプロジェクト内か)を明示する - 外部サービスのコンソール操作・アカウント作成・対話ログイン(`gh auth login` 等)・クレデンシャルの発行はユーザーに依頼する(`! gh auth login` のように `!` を付けてその場で実行できることを案内する) -- 実行して分かった手順書の誤り・不足・OS 依存の差異は `ENV_02`/`ENV_03` に反映してからコミットする.解決できなかった手順は「※ 未検証」と明記して残す +- 実行して分かった手順書の誤り・不足・OS 依存の差異は `ENV_02`/`ENV_03` に反映してからユーザーのレビューを受ける.解決できなかった手順は「※ 未検証」と明記して残す - 確定した起動・テスト・lint・ビルドのコマンドは `ENV_04_開発コマンド.md` に書き出す(GUIDE_01「環境構築」) - 生成物(`node_modules/`・ビルド出力等)を作る前に `.gitignore` を整備する @@ -147,8 +163,8 @@ 「作る」を選んだ場合: 1. `.claude/skills/verify/profile-template.md` を `.claude/verify-profile.md` にコピーする -2. 雛形の各節を,確定した技術スタック・開発コマンドに合わせてドラフトし,他の成果物と同様にユーザーの承認を得てから書き出す.埋められない項目(ランナー未整備のため実行コマンドが未定等)は空欄にせず「未定(ランナー整備後に記入)」と明記する - - 「検証対象の環境」は**ローカルのみ**でドラフトする.staging 等を許可するかは Claude が判断せずユーザーに確認し,許可する場合だけ「いじっても影響が無い」と判断した根拠・資格情報の受け渡し方法・テストデータの後始末をユーザーから聞いて記入する(本番は許可しない) +2. 雛形の各節を,確定した技術スタック・開発コマンドに合わせてファイル上で埋め,他の成果物と同様に要確認点を示してユーザーの承認を得る.埋められない項目(ランナー未整備のため実行コマンドが未定等)は空欄にせず「未定(ランナー整備後に記入)」と明記する + - 「検証対象の環境」は**ローカルのみ**で記入する.staging 等を許可するかは Claude が判断せずユーザーに確認し,許可する場合だけ「いじっても影響が無い」と判断した根拠・資格情報の受け渡し方法・テストデータの後始末をユーザーから聞いて記入する(本番は許可しない) 3. 検証結果の出力先を `.gitignore` に追記する 4. ランナーは雛形の「実行基盤の要件」を満たすようプロジェクト側で実装する必要がある旨を伝える(この場では実装しない.必要なら立ち上げ後に `/implement` で作る) @@ -166,7 +182,7 @@ 2. 作成した全ドキュメントの一覧を表示する 3. 最初の実装ステップを確認する 4. **モードに関わらず**,「GitHub リポジトリのセキュリティ設定」(前述)を実行する(Phase 3 で有効化済みなら検証コマンドだけで確認する.リモートがまだ無ければ,リポジトリ作成後に ENV_03 のコマンドを実行するようユーザーに案内する) -5. CLAUDE.md の最終更新・進捗の更新を `chore/project-setup` にコミットする(前述「立ち上げ中の Git 運用」).`main` への取り込みは行わず,ユーザーに `/commit push`(または `/commit merge`)を案内する +5. CLAUDE.md の最終更新・進捗の更新をユーザーに確認してもらい,`/commit` でのコミットを案内する(前述「立ち上げ中の Git 運用」).その後の `main` への取り込みも本スキルでは行わず,ユーザーに `/commit push`(または `/commit merge`)を案内する(最終更新のコミットと取り込みを 1 回の `/commit push` 等でまとめて行ってよい) 6. **team モードの場合**は,AI に実施できない「管理者の初期設定」(GUIDE_03「管理者の初期設定」)をユーザーに案内する: - GitHub リポジトリ作成・メンバー招待 - Issue テンプレートの用意 @@ -183,7 +199,7 @@ GitHub リポジトリのセキュリティ設定(Dependabot alerts / security updates): {有効化済み / リポジトリ未作成のため未実施(ENV_03 のコマンドで有効化してください)} 依存バージョン更新(`.github/dependabot.yml`): {対象エコシステム一覧} を {更新頻度} で監視 Dependabot が作る PR・alert は `/deps-update` で処理できます(安全な更新は自動マージ,メジャー更新等は分析付きで報告). -立ち上げの成果物は `chore/project-setup` に {N} コミットで積んであります.`main` への取り込みは `/commit push`(PR 作成まで)または `/commit merge`(マージまで)で行ってください. +立ち上げの成果物は `chore/project-setup` ブランチにあります(CLAUDE.md の最終更新は未コミットです.内容を確認してください).コミットと `main` への取り込みは `/commit push`(PR 作成まで)または `/commit merge`(マージまで)で行ってください. 環境構築: {実行した手順の要点 / ユーザーに依頼した手順 / 未検証のまま残した手順} 最初の実装ステップは `{ステップ名}` です.`/implement {タスク}` で開始できます. {team の場合: 「チーム運用の管理者初期設定(GitHub repo・CI 等)は GUIDE_03 を参照してユーザー側で実施してください.」}」 @@ -193,11 +209,15 @@ ユーザーが中断を希望した場合: 1. 現在のフェーズと状態を CLAUDE.md の「開発進捗」(最新 1 行に上書き)と `docs/PROGRESS.md`(末尾に追記)に記録する -2. ここまでの成果物と進捗の更新を `chore/project-setup` にコミットする(未コミットの差分を残さない.push・PR は行わない) +2. 本スキルではコミットしない.未コミットの成果物と進捗の更新があれば,書き出したファイルの一覧を示し,ユーザーに `/commit` でのコミットを案内する(コミットせずに中断してもよいが,その場合は未コミットの変更が残っていることを伝える) 3. 次回 `/setup` 実行時に続きから再開できるようにする -「**進捗を保存しました.** +「**進捗を記録しました.** 現在の状態: フェーズ {N}({フェーズ名})まで完了 -`chore/project-setup` にコミット済みです(未コミットの変更はありません). +未コミットのファイル: + +- {ファイルパス}(無ければ「なし」) + +未コミットのファイルがある場合は,`chore/project-setup` で `/commit` を実行してコミットしておくことを推奨します(メッセージ例: `{メッセージ例}`). 次回 `/setup` を実行すると,同じブランチでフェーズ {N+1} から再開します.」 diff --git a/.claude/skills/setup/reference.md b/.claude/skills/setup/reference.md index 116934f..a4cdccd 100644 --- a/.claude/skills/setup/reference.md +++ b/.claude/skills/setup/reference.md @@ -1,6 +1,6 @@ # setup リファレンス (Setup Reference) -`/setup`(`SKILL.md`)から参照される実行手順集(`gh` CLI で行うリポジトリ設定,`.github/dependabot.yml` の生成規則,フェーズごとのコミット,環境構築の実行).`/setup` の途中で AI が実行するほか,`/setup` 完了後にリポジトリを作成した場合などに管理者(人間)が単体で実行する runbook としても使う. +`/setup`(`SKILL.md`)から参照される実行手順集(`gh` CLI で行うリポジトリ設定,`.github/dependabot.yml` の生成規則,フェーズごとのコミットの案内,環境構築の実行).`/setup` の途中で AI が実行するほか,`/setup` 完了後にリポジトリを作成した場合などに管理者(人間)が単体で実行する runbook としても使う. ## GitHub リポジトリのセキュリティ設定 (GitHub Repository Security Settings) @@ -52,7 +52,7 @@ ## 依存バージョン更新の設定 (Dependabot Version Updates) -`.github/dependabot.yml` を置くと,Dependabot が依存パッケージの新バージョンを定期的に検出して更新 PR を作る(脆弱性の有無に関係なく).`/setup` のフェーズ 3 で,技術スタック(`ENV_01_技術スタック.md`)に合わせて**必ず生成する**(作るかどうかはユーザーに聞かない.内容だけドラフトとして確認する).PR のノイズを抑えるため,週 1 回・マイナー/パッチをまとめる・同時オープン数を絞る,を既定とする. +`.github/dependabot.yml` を置くと,Dependabot が依存パッケージの新バージョンを定期的に検出して更新 PR を作る(脆弱性の有無に関係なく).`/setup` のフェーズ 3 で,技術スタック(`ENV_01_技術スタック.md`)に合わせて**必ず生成する**(作るかどうかはユーザーに聞かない.書き出したファイルで内容だけ確認してもらう).PR のノイズを抑えるため,週 1 回・マイナー/パッチをまとめる・同時オープン数を絞る,を既定とする. ### エコシステム対応表 (Ecosystem Mapping) @@ -124,28 +124,26 @@ ## フェーズごとのコミット (Per-phase Commit) -`/setup` は立ち上げ専用ブランチ `chore/project-setup` の上で,各フェーズの成果物を書き出してユーザーが承認したタイミングごとにコミットする.`git push`・PR 作成・マージ・`main` への直接コミットは行わない(CLAUDE.md「Git 運用」の例外が認められるのはこのブランチへのコミットに限る). +立ち上げは専用ブランチ `chore/project-setup` の上で行い,各フェーズの成果物をユーザーがエディタで確認した後,**ユーザー自身が `/commit` でコミットする**(フェーズごとに 1 コミットを推奨).`/setup` はブランチの作成と,コミットの案内(メッセージ例の提示)・コミット済みの確認だけを行い,`git commit`・`git push`・PR 作成・マージは行わない. ### 手順 (Procedure) -1. 最初のコミットの直前にブランチを用意する(2 回目以降のフェーズは作成済みのブランチをそのまま使う): +1. `/setup` が最初にファイルを書き換える前にブランチを用意する(再開時は作成済みのブランチをそのまま使う): ```bash git branch --show-current # chore/project-setup なら,そのまま使う git switch -c chore/project-setup # main にいる場合のみ作成する ``` - - コミットが 1 つも無い(`git log` が失敗する)場合は,先に最初のコミットを作ってからブランチを切る(コミットが無いとブランチを作れないため) -2. そのフェーズで書き出したファイルだけをステージングする(`.env` やクレデンシャル・生成物はステージングしない.`.gitignore` の整備を先に済ませる) -3. `.claude/rules/git-conventions.md` の書式(`[タグ] 内容`・日本語・末尾の句点なし)でコミットする + - コミットが 1 つも無い(`git log` が失敗する)場合はブランチを作れないため,ユーザーに最初のコミットを依頼してからブランチを切る +2. `/setup` はフェーズの成果物を書き出してレビューを受けた後,下表のメッセージ例を添えてユーザーに `/commit` を案内する(`.env` やクレデンシャル・生成物がコミット対象に入らないよう,`.gitignore` の整備を先に済ませる) +3. ユーザーが `/commit` を実行する(書式は `.claude/rules/git-conventions.md`: `[タグ] 内容`・日本語・末尾の句点なし) +4. `/setup` は次のフェーズに進む前に作業ツリーがクリーンか確認する.未コミットの変更が残っていれば,コミットしてから進むか,そのまま進むかをユーザーに確認する ```bash - git add docs/03_PLAN/PLAN_01_要件定義書.md - git commit -m "[add] 要件定義書を作成" + git status --porcelain # 何も出力されなければクリーン ``` -4. コミットした旨(ブランチ・メッセージ)を次フェーズの案内と一緒に 1 行で報告する - ### フェーズとコミットの対応 (Commit per Phase) | フェーズ | 主な対象 | コミットメッセージ例 | @@ -159,13 +157,13 @@ | 6 開発計画 | `docs/03_PLAN/PLAN_02_開発ステップ.md` | `[add] 開発ステップを策定` | | 7 実装開始 | `CLAUDE.md`(最終更新),`docs/PROGRESS.md` | `[update] CLAUDE.md を立ち上げ完了状態に更新` | -- フェーズ 3 は「手順書・設定ファイルの作成」と「実際の構築(+手順書の修正)」で差分の性質が違うため,2 コミット以上に分けてよい(例: `[add] 環境構築手順と設定ファイルを整備` → `[update] 実際の構築結果を環境構築手順に反映`) -- 進捗(`CLAUDE.md` の進捗欄・`docs/PROGRESS.md`)を更新した場合は,そのフェーズのコミットに含める -- 承認を得た成果物がまだ無いフェーズ(対話だけで終わった)ではコミットしない(空コミットを作らない) +- フェーズ 3 は構築を実行し,その結果を手順書に反映してからレビューを受けるため,通常は 1 コミットでよい.ユーザーが分けたい場合は分けてよい(例: `[add] 環境構築手順と設定ファイルを整備` → `[update] 実際の構築結果を環境構築手順に反映`) +- 進捗(`CLAUDE.md` の進捗欄・`docs/PROGRESS.md`)を更新した場合は,そのフェーズのコミットに含めるよう案内する +- 承認を得た成果物がまだ無いフェーズ(対話だけで終わった)ではコミットを案内しない(空コミットを作らない) ### 取り込み (Merging into main) -全フェーズ完了後,ユーザーが `/commit push`(PR 作成まで)または `/commit merge`(マージまで)で `main` に取り込む.`/setup` からは案内のみを行う. +全フェーズ完了後,ユーザーが `/commit push`(PR 作成まで)または `/commit merge`(マージまで)で `main` に取り込む(フェーズ 7 の最終更新が未コミットなら,そのコミットもまとめて行われる).`/setup` からは案内のみを行う. ## 環境構築の実行 (Executing the Environment Setup) diff --git a/.claude/tests/test_setup_flow.py b/.claude/tests/test_setup_flow.py index b27e197..75c09e7 100644 --- a/.claude/tests/test_setup_flow.py +++ b/.claude/tests/test_setup_flow.py @@ -1,12 +1,19 @@ -"""/setup のフェーズごとのコミットと環境構築の実行のテスト. +"""/setup の「書き出してからレビュー」・コミットの人間への委譲・環境構築の実行のテスト. 実行(リポジトリルートで): python -B -m unittest discover -s .claude/tests -v -仕様の正本(ユーザーが承認した追加仕様): - 1. `/setup` は各フェーズが終わるたびに,専用ブランチ `chore/project-setup` へコミットする - (push・PR 作成・マージ・`main` への直接コミットはしない.取り込みは完了後に人間が `/commit` で行う) - 2. フェーズ 3 で環境構築の手順書ができた時点で,その手順に従って実際に環境を構築する +仕様の正本(Issue #47 および直前の承認済み仕様): + 1. `/setup` は各フェーズの成果物を最初から保存先ファイルに書き出し,チャットには + 「書き出したファイル一覧」と「判断してほしい点・Claude が決めた点」だけを示す(全文を出さない). + 修正指示はファイルに直接反映する + 2. `/setup` はフェーズごとの自動コミットをしない.コミットは人間が `/commit` で行う + (`chore/project-setup` ブランチの作成は `/setup` がしてよい.push・PR・マージもしない) + 3. 次のフェーズへは作業ツリーがクリーンなことを確認してから進む.未コミットのまま進むかは人間に確認する + 4. `/setup` は `/commit` 自発実行禁止の例外ではない(CLAUDE.md・GUIDE_02 の例外リストに無い. + 無人運転ループ `/auto-refactor`・`/auto-audit` の例外は残る) + 5. フェーズ 3 で環境構築の手順書ができた時点で,その手順に従って実際に環境を構築し, + 結果を手順書に反映してからレビューを受ける (リポジトリ内で完結する操作はそのまま実行/ツール導入は都度承認/外部サービス操作はユーザー) 対象は実行コードではなく指示書(Markdown)であるため,各テストは「仕様が要求する性質が, @@ -62,53 +69,162 @@ return "\n".join(lines[start:]) -class TestSetupSkillCommitsEachPhase(unittest.TestCase): - """仕様 1: フェーズごとのコミットが `/setup` の手順に組み込まれていること.""" +def numbered_steps(body: str) -> list[str]: + """節の直下(最初の下位見出しより前)にある番号付き手順を返す.""" + steps = [] + for line in body.splitlines(): + if HEADING_RE.match(line): + break + if re.match(r"^\d+\. ", line): + steps.append(line) + return steps + + +class TestSetupSkillWritesFilesBeforeReview(unittest.TestCase): + """仕様 1: 成果物を最初からファイルに書き出し,チャットには一覧と要確認点だけを示すこと.""" @classmethod def setUpClass(cls): cls.text = read(SETUP_SKILL) + cls.rules = section(cls.text, "基本ルール") - def test_has_git_section_with_dedicated_branch(self): - body = section(self.text, "立ち上げ中の Git 運用") - self.assertIn(SETUP_BRANCH, body) - self.assertIn("フェーズ", body) + def test_basic_rules_write_to_file_first(self): + self.assertRegex(self.rules, r"最初から.*書き出") + self.assertIn("レビュー", self.rules) - def test_states_no_push_pr_merge(self): - body = section(self.text, "立ち上げ中の Git 運用") - for word in ("push", "PR", "マージ"): + def test_basic_rules_forbid_full_text_in_chat(self): + self.assertRegex(self.rules, r"全文を出さ(ない|ず)") + self.assertIn("書き出したファイルの一覧", self.rules) + self.assertIn("判断してほしい点", self.rules) + self.assertIn("Claude が決めた点", self.rules) + + def test_basic_rules_apply_fixes_to_file_directly(self): + self.assertIn("ファイルに直接反映", self.rules) + + def test_no_longer_drafts_in_chat_before_writing(self): + # 旧仕様「ドラフトを提示し,修正を反映してからファイルに書き出す」が残っていないこと + self.assertNotRegex(self.text, r"ドラフトを提示") + self.assertNotIn("反映してからファイルに書き出す", self.text) + + def test_phase_loop_writes_file_before_user_review(self): + steps = numbered_steps(section(self.text, "フェーズ 1〜6")) + write_idx = next((i for i, s in enumerate(steps) if "書き出" in s), None) + review_idx = next((i for i, s in enumerate(steps) if "修正指示" in s), None) + self.assertIsNotNone(write_idx, f"書き出しのステップが無い: {steps}") + self.assertIsNotNone(review_idx, f"修正指示のステップが無い: {steps}") + self.assertLess(write_idx, review_idx, "書き出しがレビュー(修正指示)より後になっている") + self.assertRegex(steps[write_idx], r"全文.*出さない") + self.assertIn("ファイルに反映", steps[review_idx]) + + def test_dialogue_template_lists_files_and_points(self): + body = section(self.text, "台詞テンプレート") + for word in ("書き出したファイル", "判断してほしい点", "Claude が決めた点", "git diff"): with self.subTest(word=word): self.assertIn(word, body) - self.assertIn("/commit push", body) - def test_declares_exception_to_commit_prohibition(self): - body = section(self.text, "立ち上げ中の Git 運用") - self.assertIn("例外", body) + +class TestSetupSkillLeavesCommitToHuman(unittest.TestCase): + """仕様 2〜4: `/setup` は自動コミットせず,人間の `/commit` を案内し,クリーン確認をすること.""" + + @classmethod + def setUpClass(cls): + cls.text = read(SETUP_SKILL) + cls.git = section(cls.text, "立ち上げ中の Git 運用") + + def test_has_git_section_with_dedicated_branch(self): + self.assertIn(SETUP_BRANCH, self.git) + self.assertIn("フェーズ", self.git) + + def test_may_create_setup_branch(self): + lines = [line for line in self.git.splitlines() if SETUP_BRANCH in line and "作成" in line] + self.assertTrue(lines, "ブランチ作成を /setup が行ってよい旨が無い") + + def test_states_no_commit_push_pr_merge(self): + lines = [line for line in self.git.splitlines() if "行わない" in line] + self.assertTrue(lines, "行わない操作の明記が無い") + joined = "\n".join(lines) + for word in ("git commit", "push", "PR", "マージ"): + with self.subTest(word=word): + self.assertIn(word, joined) + self.assertIn("/commit push", self.git) + + def test_commit_is_done_by_user_via_commit_skill(self): + self.assertRegex(self.git, r"ユーザー(自身)?が\s*`/commit`") + + def test_does_not_declare_exception_to_commit_prohibition(self): + self.assertNotIn("例外", self.git) + self.assertNotIn("自律コミット", self.text) + self.assertNotIn("自動コミット", self.text) + + def test_never_instructs_git_commit_command(self): + self.assertNotIn("git commit -m", self.text) + self.assertNotIn("git add", self.text) + + def test_checks_clean_worktree_before_next_phase(self): + self.assertIn("git status --porcelain", self.git) + self.assertIn("クリーン", self.git) + + def test_asks_user_when_uncommitted_changes_remain(self): + lines = [line for line in self.git.splitlines() if "未コミット" in line] + self.assertTrue(lines, "未コミットの場合の扱いが無い") + self.assertIn("ユーザーに確認", lines[0]) + + def test_phase_loop_guides_commit_then_checks_clean(self): + steps = numbered_steps(section(self.text, "フェーズ 1〜6")) + commit_idx = next((i for i, s in enumerate(steps) if "`/commit`" in s), None) + clean_idx = next((i for i, s in enumerate(steps) if "クリーン" in s), None) + self.assertIsNotNone(commit_idx, f"/commit を案内するステップが無い: {steps}") + self.assertIsNotNone(clean_idx, f"クリーン確認のステップが無い: {steps}") + self.assertIn("案内", steps[commit_idx]) + self.assertLess(commit_idx, clean_idx) + self.assertIn("ユーザーに確認", steps[clean_idx]) + self.assertEqual(clean_idx, len(steps) - 1, "クリーン確認が次フェーズへ進む直前のステップでない") + + def test_dialogue_template_guides_commit_with_message_example(self): + body = section(self.text, "台詞テンプレート") self.assertIn("`/commit`", body) + self.assertIn("メッセージ例", body) - def test_phase_loop_includes_commit_step(self): - body = section(self.text, "フェーズ 1〜6") - steps = [line for line in body.splitlines() if re.match(r"^\d+\. ", line)] - self.assertTrue(steps, "フェーズの手順が箇条書きで見つからない") - self.assertTrue( - any("コミット" in s for s in steps), - f"フェーズの手順にコミットのステップが無い: {steps}", - ) - - def test_phase7_commits_and_hands_merge_to_user(self): + def test_phase7_guides_commit_and_hands_merge_to_user(self): body = section(self.text, "フェーズ 7") - self.assertIn("コミット", body) + self.assertIn("`/commit`", body) self.assertIn(SETUP_BRANCH, body) self.assertRegex(body, r"/commit (push|merge)") + self.assertIn("本スキルでは行わず", body) - def test_interruption_commits_before_stopping(self): + def test_interruption_guides_commit_without_committing(self): body = section(self.text, "中断時の処理") - self.assertIn("コミット", body) + self.assertIn("本スキルではコミットしない", body) + self.assertIn("`/commit`", body) self.assertIn(SETUP_BRANCH, body) + self.assertIn("未コミット", body) + + def test_resume_checks_uncommitted_changes(self): + body = section(self.text, "前提確認") + self.assertIn("git status --porcelain", body) + self.assertIn("/commit", body) + + +class TestSetupPhase3ReviewsAfterExecution(unittest.TestCase): + """仕様 5: フェーズ 3 は構築を実行し,結果を手順書に反映してからレビューを受けること.""" + + def test_phase3_note_orders_execute_reflect_review(self): + body = section(read(SETUP_SKILL), "フェーズ 3(環境構築)の注意") + i_exec = body.find("構築を実行") + i_reflect = body.find("反映", i_exec) + i_review = body.find("レビュー", i_reflect) + self.assertNotEqual(i_exec, -1, "構築を実行する旨が無い") + self.assertNotEqual(i_reflect, -1, "実行後に手順書へ反映する旨が無い") + self.assertNotEqual(i_review, -1, "反映後にレビューを受ける旨が無い") + + def test_reference_phase3_single_commit_after_reflection(self): + body = section(read(SETUP_REFERENCE), "フェーズごとのコミット") + line = next((l for l in body.splitlines() if l.startswith("- フェーズ 3")), "") + self.assertIn("反映してからレビュー", line) class TestSetupReferenceDescribesCommitProcedure(unittest.TestCase): - """仕様 1: 実行手順(ブランチの作り方・フェーズ対応表)が reference.md にあること.""" + """仕様 2・3: ブランチの作り方・コミットの案内・クリーン確認・フェーズ対応表が reference.md にあること.""" @classmethod def setUpClass(cls): @@ -119,10 +235,23 @@ self.assertIn(f"git switch -c {SETUP_BRANCH}", self.body) self.assertIn("git branch --show-current", self.body) - def test_shows_commit_command_following_git_conventions(self): - self.assertIn("git commit -m", self.body) + def test_guides_user_commit_following_git_conventions(self): + self.assertIn("`/commit`", self.body) + self.assertRegex(self.body, r"ユーザー(自身)?が\s*`/commit`") self.assertIn(".claude/rules/git-conventions.md", self.body) + def test_no_git_commit_command_for_setup_to_run(self): + self.assertNotIn("git commit -m", self.body) + self.assertNotIn("git add", self.body) + self.assertRegex(self.body, r"`git commit`[^\n]*行わない") + + def test_shows_clean_check_command(self): + self.assertIn("git status --porcelain", self.body) + self.assertIn("ユーザーに確認", self.body) + + def test_does_not_claim_exception(self): + self.assertNotIn("例外", self.body) + def test_commit_table_covers_every_phase(self): rows = [line for line in self.body.splitlines() if line.startswith("| ")] table = "\n".join(rows) @@ -147,7 +276,7 @@ class TestSetupExecutesEnvironmentSetup(unittest.TestCase): - """仕様 2: 手順書の作成後に実際の環境構築を行うことが定義されていること.""" + """仕様 5: 手順書の作成後に実際の環境構築を行うことが定義されていること.""" @classmethod def setUpClass(cls): @@ -199,7 +328,7 @@ class TestDocumentationIsConsistent(unittest.TestCase): - """GUIDE・CLAUDE.md・README が同じ 2 つの仕様を述べていること.""" + """GUIDE・CLAUDE.md・README が同じ仕様を述べていること.""" def test_guide_01_has_git_during_setup_section(self): body = section(read(GUIDE_01), "立ち上げ中の Git 運用") @@ -213,21 +342,58 @@ self.assertIn("都度承認", body) self.assertIn(".claude/skills/setup/reference.md", body) - def test_guide_02_lists_setup_as_commit_exception(self): + def test_guide_01_git_section_leaves_commit_to_human(self): + body = section(read(GUIDE_01), "立ち上げ中の Git 運用") + self.assertRegex(body, r"人間が\s*`/commit`") + self.assertNotIn("例外", body) + self.assertIn("クリーン", body) + self.assertRegex(body, r"最初から.*書き出") + self.assertIn("判断してほしい点", body) + self.assertIn("Claude が決めた点", body) + + def test_guide_02_does_not_list_setup_as_commit_exception(self): body = section(read(GUIDE_02), "コミットルール") lines = [line for line in body.splitlines() if "`/setup`" in line] - self.assertTrue(lines, "GUIDE_02 のコミットルールに /setup の例外が無い") - self.assertIn(SETUP_BRANCH, lines[0]) + self.assertFalse(lines, f"GUIDE_02 のコミットルールに /setup の例外が残っている: {lines}") + self.assertNotIn("例外(プロジェクト立ち上げ)", body) + self.assertNotIn(SETUP_BRANCH, body) - def test_claude_md_lists_setup_in_commit_exceptions(self): + def test_guide_02_keeps_unattended_loop_exceptions(self): + body = section(read(GUIDE_02), "コミットルール") + self.assertIn("例外(無人運転)", body) + self.assertIn("`/auto-refactor`", body) + self.assertIn("`/auto-audit`", body) + + def _claude_md_exception_block(self) -> list[str]: + lines = read(CLAUDE_MD).splitlines() + start = next(i for i, l in enumerate(lines) if l.lstrip().startswith("- **例外**:")) + block = [lines[start]] + for line in lines[start + 1:]: + if line.startswith(" - "): + block.append(line) + else: + break + return block + + def test_claude_md_does_not_list_setup_in_commit_exceptions(self): + block = self._claude_md_exception_block() + self.assertFalse([l for l in block if "/setup" in l], f"例外リストに /setup が残っている: {block}") + self.assertNotIn("プロジェクト立ち上げ", "\n".join(block)) text = read(CLAUDE_MD) - lines = [line for line in text.splitlines() if "`/setup`" in line and SETUP_BRANCH in line] - self.assertTrue(lines, "CLAUDE.md の自律コミット例外に /setup が無い") + self.assertNotIn(SETUP_BRANCH, text) - def test_readme_mentions_both_behaviours(self): + def test_claude_md_keeps_unattended_loop_exceptions(self): + block = "\n".join(self._claude_md_exception_block()) + self.assertIn("`/auto-refactor`", block) + self.assertIn("`/auto-audit`", block) + + def test_readme_mentions_new_behaviours(self): line = next(line for line in read(README_MD).splitlines() if line.startswith("- `/setup")) self.assertIn(SETUP_BRANCH, line) self.assertRegex(line, r"構築まで行う|実際に構築") + self.assertIn("書き出", line) + self.assertRegex(line, r"人間が\s*`/commit`") + self.assertNotRegex(line, r"ブランチへコミット") if __name__ == "__main__": diff --git a/CLAUDE.md b/CLAUDE.md index 68cde5b..407a723 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,8 +16,7 @@ - ブランチ名・コミットメッセージの書式は `.claude/rules/git-conventions.md` に従う(常時ロードされる) - コミットは `/commit` を使用する(push・PR 作成は `/commit push`,マージ・プルまで行う場合は `/commit merge`) - **`/commit` はユーザーが明示的に指示した時のみ実行する.Claude が自発的に `/commit` や `git commit` を呼んではならない**(`/implement` 完了後も,案内するだけで自分ではコミットしない.`/commit` skill は `disable-model-invocation` によりユーザー起動限定として強制されている) - - **例外**: 以下(プロジェクト立ち上げと無人運転ループ)はユーザー承認済みの例外として専用ブランチに自律コミットする.いずれも push・PR・マージ・`main` への操作はしない(取り込みは人間が `/commit push` 等で行う) - - `/setup`(プロジェクト立ち上げ)→ `chore/project-setup` 専用ブランチ(フェーズごとに 1 コミット) + - **例外**: 以下(無人運転ループ)はユーザー承認済みの例外として専用ブランチに自律コミットする.いずれも push・PR・マージ・`main` への操作はしない(取り込みは人間が `/commit push` 等で行う) - `/auto-refactor`(リファクタ/ドキュメント整理ループ)→ `refactor/` 専用ブランチ - `/auto-audit`(バグ/脆弱性の巡回監査ループ)→ `fix/` 専用ブランチ - **例外(`main` へのマージ)**: `/deps-update` は,Dependabot が作成した依存更新 PR に限り,ゲート(メジャー更新でない・競合なし・CI 緑またはローカル検証緑)を満たすものを `gh pr merge` で `main` に取り込む(ユーザーが明示的に起動した時のみ.メジャー更新・CI 赤・PR が付かない alert は報告して人間が判断する) diff --git a/README.md b/README.md index 37e683d..ef82b6a 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ ## 主なスラッシュコマンド -- `/setup ` — GUIDE_01 に従いプロジェクト立ち上げを対話的に進行(solo/team を選択.環境構築は手順書を書いた後に実際に構築まで行う.フェーズごとに `chore/project-setup` ブランチへコミット.GitHub リポジトリの Dependabot alerts / security updates を `gh api` で有効化し,`.github/dependabot.yml` も生成) +- `/setup ` — GUIDE_01 に従いプロジェクト立ち上げを対話的に進行(solo/team を選択.環境構築は手順書を書いた後に実際に構築まで行う.成果物はファイルに書き出してからレビューを受け,コミットは人間が `/commit` で行う.ブランチは `chore/project-setup`.GitHub リポジトリの Dependabot alerts / security updates を `gh api` で有効化し,`.github/dependabot.yml` も生成) - `/implement <タスク>` — 実装パイプライン(コーディング →(任意の検証)→ テスト → リファクタリング) - `/verify [観点]` — ローカル環境(およびプロファイルが許可した検証用環境)で動作とエッジケースを Claude に確認させ,人間が確認すべき範囲を絞る(検証プロファイル `.claude/verify-profile.md` を用意したプロジェクトのみ.雛形は `.claude/skills/verify/profile-template.md`.人間の動作確認は無くならない) - `/commit` / `/commit push` / `/commit merge` — コミット作成(`push` でプッシュと PR 作成まで,`merge` でマージ・プルまで) diff --git "a/docs/01_GUIDE/GUIDE_01_\343\203\227\343\203\255\343\202\270\343\202\247\343\202\257\343\203\210\347\253\213\343\201\241\344\270\212\343\201\222\343\203\225\343\203\255\343\203\274.md" "b/docs/01_GUIDE/GUIDE_01_\343\203\227\343\203\255\343\202\270\343\202\247\343\202\257\343\203\210\347\253\213\343\201\241\344\270\212\343\201\222\343\203\225\343\203\255\343\203\274.md" index 574cdde..8714f68 100644 --- "a/docs/01_GUIDE/GUIDE_01_\343\203\227\343\203\255\343\202\270\343\202\247\343\202\257\343\203\210\347\253\213\343\201\241\344\270\212\343\201\222\343\203\225\343\203\255\343\203\274.md" +++ "b/docs/01_GUIDE/GUIDE_01_\343\203\227\343\203\255\343\202\270\343\202\247\343\202\257\343\203\210\347\253\213\343\201\241\344\270\212\343\201\222\343\203\225\343\203\255\343\203\274.md" @@ -32,11 +32,12 @@ ## 立ち上げ中の Git 運用 (Git During Setup) -立ち上げ作業は専用ブランチ `chore/project-setup` の上で行い,**各フェーズの成果物が確定(ユーザーが承認)した時点でコミットする**(フェーズごとに 1 コミット).`/setup` が Git 規約(`.claude/rules/git-conventions.md`)の書式でコミットまで行い,`git push`・PR 作成・マージ・`main` への直接コミットは行わない.手順とフェーズごとのコミットメッセージ例は `.claude/skills/setup/reference.md`「フェーズごとのコミット」にある. +立ち上げ作業は専用ブランチ `chore/project-setup` の上で行う(ブランチの作成は `/setup` が行う).`/setup` は各フェーズの成果物を**最初から保存先のファイルとして書き出し**,チャットには書き出したファイルの一覧と要確認点(判断してほしい点・Claude が決めた点)だけを示す.人間はエディタでファイルを読んで修正点をチャットで伝え,`/setup` はファイルを直接直す(差分は `git diff` で追える). -- 狙いは,立ち上げの成果物をフェーズ単位でレビュー・巻き戻しできる形にし,中断・再開しても「どこまで終わったか」が git 履歴から辿れるようにすること +- **コミットは人間が `/commit` で行う**(フェーズごとに 1 コミットを推奨).`/setup` はコミット・push・PR 作成・マージを行わず,コミットメッセージ例の提示(`.claude/skills/setup/reference.md`「フェーズごとのコミット」)とコミット済みの確認だけを行う +- `/setup` は次のフェーズに進む前に作業ツリーがクリーン(コミット済み)であることを確認し,未コミットのまま進むかは人間に確認する +- 狙いは,書き出された最終形を人間がエディタで確認してからコミットできるようにし,フェーズ単位でレビュー・巻き戻しでき,中断・再開しても「どこまで終わったか」が git 履歴から辿れるようにすること - 全フェーズ完了後,`main` への取り込みはユーザーが `/commit push`(PR 作成まで)または `/commit merge`(マージまで)で行う -- これは CLAUDE.md「Git 運用」の「`/commit` 自発実行禁止」に対するユーザー承認済みの例外(`/auto-refactor`・`/auto-audit` と同格)であり,`chore/project-setup` ブランチへのコミットに限る ## 方針決定 (Direction) @@ -64,7 +65,7 @@ - Python 3.7 以上と `bash` — `.claude/settings.json` のフック(リポジトリ外アクセス制限・通知)の実行に使用.フックは `bash .claude/hooks/run_python.sh` 経由で起動し,`python3` → `python` → `py` の順に実際に起動できるものを使う(いずれか 1 つで起動できればよい.Windows では Git for Windows 付属の `bash` を使う).※ Python が見つからないとアクセス制限フックが Read・Write・Edit・Glob・Grep・Bash を**すべてブロックする**(通知フックは何もせず素通りする) - **基本方針**: 環境の再現性を重視し,手順書だけに頼らず構築を自動化・コード化できる方法を優先する(例: Docker,Dev Containers,Windows Sandbox,IaC ツール等). - **人間が決めること**: 開発マシンの選定,クラウドサービスのアカウント作成,環境構築方法の選択 -- **実際の構築まで行う**: 手順書を書いて終わりにせず,`/setup` がその手順に従って実際に環境を構築し,実行して分かった誤り・前提の抜けを手順書に反映する(未検証の手順書は誤りを含みやすく,最初に詰まるのがその場のユーザーになるため).区分は次の 3 つ(詳細は `.claude/skills/setup/reference.md`「環境構築の実行」) +- **実際の構築まで行う**: 手順書を書いて終わりにせず,`/setup` がその手順に従って実際に環境を構築し,実行して分かった誤り・前提の抜けを手順書に反映してから人間のレビューを受ける(未検証の手順書は誤りを含みやすく,最初に詰まるのがその場のユーザーになるため).区分は次の 3 つ(詳細は `.claude/skills/setup/reference.md`「環境構築の実行」) - リポジトリ内で完結する操作(プロジェクト初期化・依存インストール・設定ファイル生成・ビルドや起動の疎通確認・`gh` でのリポジトリ設定)はそのまま実行する - ツール導入(SDK・ランタイム・CLI のインストール,`docker build`,dev container の起動)は実行するコマンド・バージョン・入る場所を提示して**都度承認を得てから**実行する - 外部サービスのコンソール操作・アカウント作成・対話ログイン(`gh auth login` 等)・クレデンシャルの発行はユーザーが行う diff --git "a/docs/01_GUIDE/GUIDE_02_\343\202\250\343\203\274\343\202\270\343\202\247\343\203\263\343\203\210\351\201\213\347\224\250\343\203\253\343\203\274\343\203\253.md" "b/docs/01_GUIDE/GUIDE_02_\343\202\250\343\203\274\343\202\270\343\202\247\343\203\263\343\203\210\351\201\213\347\224\250\343\203\253\343\203\274\343\203\253.md" index 04fef34..9fb0d5d 100644 --- "a/docs/01_GUIDE/GUIDE_02_\343\202\250\343\203\274\343\202\270\343\202\247\343\203\263\343\203\210\351\201\213\347\224\250\343\203\253\343\203\274\343\203\253.md" +++ "b/docs/01_GUIDE/GUIDE_02_\343\202\250\343\203\274\343\202\270\343\202\247\343\203\263\343\203\210\351\201\213\347\224\250\343\203\253\343\203\274\343\203\253.md" @@ -55,8 +55,6 @@ ※ リファクタリングとテストは実装と一体の成果物として,まとめてコミットする.必要に応じて分割コミットも可. -※ **例外(プロジェクト立ち上げ)**: `/setup` は立ち上げ中,各フェーズの成果物が確定した時点で `chore/project-setup` ブランチに自律コミットする(GUIDE_01「立ち上げ中の Git 運用」).push・PR・マージは行わず,`main` への取り込みは完了後に人間が `/commit push` 等で行う. - ※ **例外(無人運転)**: 以下のループは CLAUDE.md の「`/commit` 自発実行禁止」ルールに対するユーザー承認済みの例外として,専用ブランチに自律コミットする.いずれも push・PR・マージ・`main` への操作は行わず,取り込み可否は人間が判断する. - `/auto-refactor`(リファクタ/ドキュメント整理ループ)→ `refactor/` 専用ブランチ