setup
テンプレートから作ったリポジトリの立ち上げを、1コマンドで進める。GitHub の設定を変え、ファイルを消すので、人間が `/setup` と打ったときだけ動く。
SKILL.md.claude/skills/setup/SKILL.md
GitHub/setup
立ち上げの手順の正はこの Skill である。
この Skill で使う語
/setupの変更:各手順が書き換えるパス(docs/adr/・docs/project-context/project-claude.md・docs/project-context/core-parts.md・docs/project-context/issue-destinations.md・scripts/auto-programmer/config.mjs)のうち、git status --porcelain -- docs/adr/ docs/project-context/project-claude.md docs/project-context/core-parts.md docs/project-context/issue-destinations.md scripts/auto-programmer/config.mjsに出るもの。前回の/setupが書き換えて、まだコミットしていない変更も含む(途中で止まって流し直しても、取りこぼさないため)立ち上げの Issue:
/setupの変更をリポジトリへ入れる Issue。タイトルに目印の語「立ち上げの準備をリポジトリへ入れる」を含む。次で探すgh issue list --state all --limit 100 --search '立ち上げの準備をリポジトリへ入れる in:title' --json number,title,state --jq '.[] | select(.title | contains("立ち上げの準備をリポジトリへ入れる"))'手作業の Issue:人間の手作業が済まなかったときに起票する Issue。タイトルに「/setup の手作業:<手順の見出し>」を含む(例:「/setup の手作業:リポジトリ設定を入れる」)。次で探す
gh issue list --state open --label ready-for-human --limit 100 --search '"/setup の手作業" in:title' --json number,title --jq '.[] | select(.title | contains("/setup の手作業:<手順の見出し>"))'Bedrock 切り替えの Issue:Claude の認証方式に Bedrock を選んだときに起票する Issue。タイトルに目印の語「pr-ai-triage を Bedrock 認証に切り替える」を含む。次で探す
gh issue list --state open --limit 100 --search 'pr-ai-triage を Bedrock 認証に切り替える in:title' --json number,title --jq '.[] | select(.title | contains("pr-ai-triage を Bedrock 認証に切り替える"))'
すべての手順に効く決まり
- 済んだ手順は飛ばす:各手順は、まず済んでいるかを確かめ、済んでいれば飛ばす。途中で止まっても、もう一度
/setupを流せば続きから進む(例外は「ボードを作る」で、作りかけのボードを消してから流し直す)。何度流しても同じ結果になるスクリプトを流す手順(「ラベルを作る」「リポジトリ設定を入れる」)は、確かめをスクリプトに任せる - 人間の手作業は、済まなければ Issue にして進む:人間にしかできない作業は、何をするかを案内し、
AskUserQuestionで済ませたかを聞く。済ませたなら確かめ直して次へ進む。その場で済まなければ、手作業の Issue を/quick-issueで起票し、次の手順へ進む。ラベルはready-for-humanにし、人間のタスクの頭に「(人間)」と書く。同じ手順の手作業の Issue が open で残っていれば、起票し直さない。例外は次の2つで、どちらも Issue にせずに止める- 「ラベルを作る」が済むまでの手作業が済まなかった:gh かラベルが無く、Issue を起票できない
- テンプレート本体のリポジトリで流された:手作業として聞かずに止める(続けると、本体の ADR や設定を消す)
- 変更は、立ち上げの Issue の PR で入れる:手順が書き換えたファイルは、その場でコミットしない。最後に「立ち上げの Issue を起票する」と「ブランチでコミットして push する」が、まとめてリポジトリへ入れる
手順
上から順に進める。
前提を確かめる
gh が使えるかと、どのリポジトリで流されたかを確かめる。テンプレート本体の場所は
scripts/sync-template.shのTEMPLATE_URLから引く。template=$(sed -n "s/^readonly TEMPLATE_URL='\(.*\)'$/\1/p" scripts/sync-template.sh) && { test -n "$template" || { echo 'scripts/sync-template.sh から TEMPLATE_URL を引けない' >&2; false; }; } && origin=$(git remote get-url origin) && gh repo view "$template" --json nameWithOwner --jq .nameWithOwner && gh repo view "$origin" --json nameWithOwner --jq .nameWithOwner- 失敗した:gh が無い・未認証・origin が無い・
TEMPLATE_URLを引けない、のどれか。エラーを見せ、人間の手作業として扱う(gh を入れる・gh auth loginする・自分のリポジトリを origin に足す・scripts/sync-template.shのreadonly TEMPLATE_URL='…'の行をテンプレートの形に戻す)。認証はgh auth statusで確かめない(どれか1つのホストのトークンが切れているだけで失敗する) - 2行が同じ:テンプレート本体のリポジトリである。何もせずに止め、自分のリポジトリを作って origin をそこへ向けてから流し直すよう案内する
- 失敗した:gh が無い・未認証・origin が無い・
node_modulesが無ければnpm ciを流す。「テンプレートの ADR を消す」のnpm run gen:adr-indexと、コミット時の git hook が prettier を使う
ラベルを作る
./scripts/setup-labels.sh を流す。
失敗したら、エラーを見せ、人間の手作業として扱う。
リポジトリ設定を入れる
./scripts/setup-repo-settings.sh を流す。最初の push で PR が作られ、CI が動くための設定を入れる。
終了コードが 1 なら、「失敗した」と表示された段を人間の手作業として扱う(管理者権限・組織の設定・プランの制約など、AI には直せない原因のため)。直し方は各段のエラーに添えてある。確かめ直すときは、スクリプトを流し直す。
ボードを作る
GitHub Projects のボードを API で作る。Auto-Programmer が拾う Ready と、レビュー待ちの In Review が、新しいボードの Status には無いためである。持ち主はリポジトリの持ち主、名前はリポジトリ名にする。組織が持つリポジトリでも同じステップを流す。失敗したら、末尾の扱いに従う。
projectスコープ(ボードを読み書きする権限)を確かめる。失敗してエラーにscopesを含む文が出たら、スコープ不足である。! gh auth refresh -s projectを案内し、人間の手作業として扱う(「すべての手順に効く決まり」)。それ以外のエラーは、エラーを見せて人間の手作業として扱う。済まなければ、この節の残りを飛ばす。gh api graphql -f query='{viewer{projectsV2(first:1){totalCount}}}'済んでいれば、この節の残りを飛ばす。済んでいるとは、
config.mjsのrepositoryが origin のリポジトリで、board.owner・board.numberのボードが引け、その Status に、ステップ4で入れる選択肢が全部あることである。origin=$(gh repo view "$(git remote get-url origin)" --json nameWithOwner --jq .nameWithOwner) && node -e "import('./scripts/auto-programmer/config.mjs').then(({config})=>{if(config.repository!==process.argv[1])process.exit(1);console.log(config.board.owner,config.board.number)})" "$origin"repositoryが違えば何も出ず、終了コード 1 で終わる(テンプレートから作った直後はこうなる)。<owner> <番号>が出たら、Status の選択肢を見る。gh project field-list <番号> --owner <owner> --format json --jq '.fields[] | select(.name=="Status") | [.options[].name] | join(",")'Todo,Ready,In progress,In Review,Doneが出たら、済んでいる- 作りたてのボードの
Todo,In Progress,Doneのように足りなければ、済んでいない(In Progressは P が大文字で、In progressとは別の表記である) Could not resolve to a ProjectV2 with the number <番号>のエラーで終わったら、ボードが引けないので、済んでいない
ボードを作る。
repositoryIdを渡すので、作成と同時にリポジトリへ紐づく。出力の<ボードID> <番号>を以降で使う。repo=$(gh repo view "$(git remote get-url origin)" --json nameWithOwner --jq .nameWithOwner) && ids=$(gh api graphql -f query='query($o:String!,$n:String!){repository(owner:$o,name:$n){id owner{id}}}' -f o="${repo%/*}" -f n="${repo#*/}" --jq '.data.repository | "\(.owner.id) \(.id)"') && gh api graphql -f query='mutation($o:ID!,$r:ID!,$t:String!){createProjectV2(input:{ownerId:$o,repositoryId:$r,title:$t}){projectV2{id number}}}' -f o="${ids% *}" -f r="${ids#* }" -f t="${repo#*/}" --jq '.data.createProjectV2.projectV2 | "\(.id) \(.number)"'Status の選択肢を
Todo・Ready・In progress・In Review・Doneにする(表記は issue-policy「ボードの Status の意味」と同じ)。updateProjectV2Fieldは渡した値で選択肢を上書きするので、残す選択肢にはidを渡す。まず Status のフィールド ID と選択肢の ID を引く。gh api graphql -f query='query($p:ID!){node(id:$p){... on ProjectV2{fields(first:30){nodes{... on ProjectV2SingleSelectField{id name options{id name}}}}}}}' -f p=<ボードID> --jq '.data.node.fields.nodes[] | select(.name=="Status")'Todo・In Progress・Doneのidを、次の<…の id>に入れて流す(In ProgressはIn progressへ改名される)。gh api graphql -f query='mutation($f:ID!){updateProjectV2Field(input:{fieldId:$f,singleSelectOptions:[{id:"<Todo の id>",name:"Todo",color:GREEN,description:"ボードに積まれただけ"},{name:"Ready",color:BLUE,description:"着手してよい"},{id:"<In Progress の id>",name:"In progress",color:YELLOW,description:"着手した"},{name:"In Review",color:ORANGE,description:"PR が出た"},{id:"<Done の id>",name:"Done",color:PURPLE,description:"完了した"}]}){projectV2Field{... on ProjectV2SingleSelectField{options{id name}}}}}' -f f=<Status のフィールド ID>表ビューを整える。新しいボードには表形式のビュー(
View 1)が1つあるので、名前をBacklogにし、フィルタを-status:Done、列を Title・Status・Labels・Assignees にする。visibleFieldIdsはconfigurationの中に置く。まずビューの ID と、4つのフィールドの ID を引く。gh api graphql -f query='query($p:ID!){node(id:$p){... on ProjectV2{views(first:5){nodes{id name}} fields(first:30){nodes{... on ProjectV2FieldCommon{id name}}}}}}' -f p=<ボードID>gh api graphql -f query='mutation($v:ID!){updateProjectV2View(input:{viewId:$v,name:"Backlog",layout:TABLE_LAYOUT,filter:"-status:Done",configuration:{visibleFieldIds:["<Title の id>","<Status の id>","<Labels の id>","<Assignees の id>"]}}){projectV2View{name filter}}}' -f v=<ビューの ID>API で設定できない Workflows と階層表示を、画面で案内する。ボードの URL は
https://github.com/users/<owner>/projects/<番号>(組織ならorgs)。AskUserQuestionで済ませたかを聞く。- Workflows の「Auto-add to project」を有効にする(対象はこのリポジトリ)。新しいボードには無く、無いと Issue がボードに載らない
- Workflows の「Pull request linked to issue」の移し先を
In Reviewにする。有効にはなっているが、移し先は既定のままで、API では変えられず読めもしない - 表ビュー(
Backlog)で、sub-issue の階層表示を有効にする。API で設定も確認もできない
済んだと答えたら、Workflows が有効かだけ API で確かめる。移し先と階層表示は確かめられないので、答えを信じる。
gh api graphql -f query='query($p:ID!){node(id:$p){... on ProjectV2{workflows(first:20){nodes{name enabled}}}}}' -f p=<ボードID> --jq '.data.node.workflows.nodes[] | select(.name=="Auto-add to project" or .name=="Pull request linked to issue")'両方が
"enabled":trueで出れば済んでいる。作りたてのボードでは{"enabled":true,"name":"Pull request linked to issue"}の1行だけが出る。「Auto-add to project」の行が出ないか"enabled":falseなら、済んでいない。
ステップ3〜5の API が失敗したら、エラーを見せ、人間の手作業として扱う。作りかけのボードを残すと、流し直しで2つ目のボードができるので、gh project delete <番号> --owner <owner> で消すよう案内する。消したと答えたら、ステップ3からやり直す。済まなければ、この節の残りと「config.mjs にボードを書く」を飛ばす。
config.mjs にボードを書く
「ボードを作る」を飛ばしたか、そのステップ3〜5が失敗して済まなかったなら、これも飛ばす。
scripts/auto-programmer/config.mjs を書き換える。
repository(ファイル先頭の定数):origin のowner/repoboard.owner:作ったボードの持ち主board.number:作ったボードの番号board.statusFieldName・todoStatusName・readyStatusName・inProgressStatusName:ボードの Status のフィールド名と、ステップ4で入れた「積まれただけ」「着手してよい」「着手した」の選択肢の表記。すでに同じなら触らない
書き換えたら、「ボードを作る」ステップ2の2本のコマンドを流して確かめる。<owner> <番号> が出て、Status が全部揃っていれば終わり。出なければ、config.mjs の書き換えを見直す。
Claude の認証方式を決める
pr-ai-triage.yml は、シークレット CLAUDE_CODE_OAUTH_TOKEN で Claude を呼ぶ。無いと pr-ai-triage が落ち、PR が auto-merge されない。Bedrock のプロジェクトは、このトークンを使わない。
次のどちらかなら飛ばす。
gh secret listにCLAUDE_CODE_OAUTH_TOKENがある- Bedrock 切り替えの Issue が open である
飛ばさないなら、AskUserQuestion で方式を聞く(選択肢は「Claude サブスクリプションの OAuth トークン」「Bedrock」。最初を既定にする)。
OAuth:次を案内する。トークンの値は会話に貼らせない。人間が自分で登録する
claude setup-tokenでトークンを発行する- Settings → Secrets and variables → Actions で、シークレット
CLAUDE_CODE_OAUTH_TOKENに登録する
済ませたかを
AskUserQuestionで聞き、済んだならgh secret listに名前があるかだけを確かめる。無い、または済ませていないなら、手作業の Issue(見出しは「Claude の認証方式を決める」)を起票して次へ進むBedrock:その場では
pr-ai-triage.ymlを切り替えない。立ち上げ時はinfra/が空で、GitHub Actions から AWS に入るための IAM ロールがまだ無いため。代わりに Bedrock 切り替えの Issue を/quick-issueで起票して次へ進む。Issue には次を書く- タイトル:Bedrock 切り替えの Issue の目印の語「pr-ai-triage を Bedrock 認証に切り替える」を含める
- 理由:
pr-ai-triage.ymlはCLAUDE_CODE_OAUTH_TOKENで Claude を呼ぶ。Bedrock のプロジェクトはこのトークンを使わず、シークレットが無いとpr-ai-triageが落ちて PR が auto-merge されない - 対応方針:
pr-ai-triage.ymlを Bedrock 認証に切り替える。.github/はテンプレート同期の対象外なので、書き換えても戻らない - ブロッカー:先に
infra/で、GitHub Actions から AWS に入るための IAM ロールを作る
project-context の3ファイルを書く
docs/project-context/ の project-claude.md・core-parts.md・issue-destinations.md には、テンプレート本体の内容が入っている。残すと、AI が自分のプロジェクトをテンプレート本体だと思い込み、/link-root-issue はテンプレートのルート(構築・改善)を自分のプロジェクトに作る。3ファイルを書く機会は立ち上げのときしかないので、人間に聞いて、その場で書く。
3ファイルのどれにもテンプレート本体の説明が残っていなければ、済みとして飛ばす。テンプレート本体の説明とは、次をいう。書くときは、これらも消す。
project-claude.mdの「(テンプレート本体の記述。」で始まる段落core-parts.md・issue-destinations.mdの注記にある「下の表はテンプレート本体のもの」の文core-parts.md・issue-destinations.mdの、テンプレート本体の表の行
3ファイルごとに、AskUserQuestion で次を聞いて書く。
project-claude.md:何を作るシステムか(一文)と、いまのフェーズ(立ち上げ段階など)。「このシステムは何か」と「現在のプロジェクトのフェーズ・状況」に書くissue-destinations.md:新規開発ガイドを使うか。使うなら、表の代わりに「issue-policy の標準のルートを使う」と書く。使わないなら、ルートと振り分け条件を聞いて表に書くcore-parts.md:コア部分(壊れると全体が回らなくなる部分)が決まっていれば表に書く。まだなら表を空にする
答えられない項目は、空にして進む。Issue にはしない。「すべての手順に効く決まり」の「人間の手作業は、済まなければ Issue にして進む」は、この手順には当てない。質問への答えは人間の手作業ではなく、空でもハーネスは止まらないためである(core-parts.md には、空でも ADR の判定ができると書いてある)。
「立ち上げの Issue を起票する」は、この手順で書いた issue-destinations.md を前提にする(起票のとき /link-root-issue が読むため)。
glossary.md はこの手順で書かない。
テンプレートの ADR を消す
テンプレートの ADR(docs/adr/ の NNN-*.md)を消し、一覧を作り直す。残すと、テンプレートのハーネスについての ADR が、自分のプロジェクトの一覧に混ざり続ける(docs/adr/ はテンプレート同期の対象外なので、一度消せば戻らない)。
次のどちらかなら飛ばす。
- close 済みの立ち上げの Issue がある:テンプレートの ADR は、その Issue の PR で消えている。いま
docs/adr/にある ADR は、自分のプロジェクトが書いたものである docs/adr/にNNN-*.mdが無い
飛ばさないなら、消すファイルを表示しながら消し、一覧を作り直す。adr-template.md と adr-index.md は消さない。
find docs/adr -maxdepth 1 -name '[0-9][0-9][0-9]-*.md' -print -delete && npm run gen:adr-index
立ち上げの Issue を起票する
立ち上げの Issue を探し、次で分ける。
- open のものがある:それを使う
- open のものが無く、
/setupの変更がある:/quick-issueで起票する。ラベルとルート Issue への紐付けは/quick-issueの決まりに従う - open のものが無く、
/setupの変更も無い:リポジトリへ入れる変更が無い。この手順と「ブランチでコミットして push する」を飛ばす
起票する Issue には次を書く。
- タイトル:立ち上げの Issue の目印の語を含める
- 対応方針:
/setupの変更を、ブランチと PR でリポジトリへ入れる - タスク一覧:
/setupの変更の内容を1つずつ並べ、済んだものにチェックを入れる - ラベル:
ai-fixable。/setupの変更にテンプレートの ADR の削除があるなら、「不可逆・外部に出る」に当たるのでissue:decidedを重ね、人間の発言には「/setup」と書く - 実装フロー(使用するSkill):該当なし(
/setupが直接編集した)
ブランチでコミットして push する
立ち上げの Issue の番号を <番号> とする。
立ち上げのブランチ
chore/issue-<番号>に移る。ローカルにあればgit switch chore/issue-<番号>で移る。無ければ、デフォルトブランチの最新から作る。デフォルトブランチ名は、origin を名指しして GitHub から引く(upstream など別の remote と取り違えない)。シェル変数は Bash ツールの呼び出しをまたいで残らないので、1回で実行する。base=$(gh repo view "$(git remote get-url origin)" --json defaultBranchRef --jq .defaultBranchRef.name) && git fetch origin "$base" && git switch -c chore/issue-<番号> --no-track "origin/$base"git が「Your local changes ... would be overwritten」で断ったら、人間の未コミットの変更と重なっている。メッセージを見せ、人間の手作業(コミットか stash で片付ける)として扱う。済まなければ、この手順の残りを飛ばす
/setupの変更だけをgit add <パス>でステージし、/git-commit stageでコミットする。ワーキングツリー全体はステージしない(人間の作業中の変更を混ぜないため)。/setupの変更が無ければ(前回の/setupでコミット済みなど)飛ばすpush の前に、デフォルトブランチの最新を取り込む。
npm run gen:adr-indexで差分が出たら、git add docs/adr/adr-index.mdして/git-commit stageでコミットするbase=$(gh repo view "$(git remote get-url origin)" --json defaultBranchRef --jq .defaultBranchRef.name) && git fetch origin "$base" && git merge --no-edit "origin/$base" && npm run gen:adr-indexgit push -u origin HEADで push し、/pr-body <番号>を流す。/pr-bodyが「PR が現れない」で止まったら、PR を作るpipeline.ymlの実行を引き、落ちたジョブのログを見る。gh run list --workflow pipeline.yml --branch chore/issue-<番号> --limit 1 --json databaseId,url --jq '.[] | "\(.databaseId) \(.url)"' gh run view <run ID> --log-failedcreate-pull-requestジョブがGitHub Actions is not permitted to create or approve pull requestsで落ちた:Actions に PR の作成が許されていない。人間の手作業として扱う(Settings → Actions → General の Workflow permissions で、Actions に PR の作成と承認を許す。組織所有なら組織の設定も)。確かめ直すときは、./scripts/setup-repo-settings.shを流し、gh run rerun <run ID> --failedで落ちたジョブを流し直してから、/pr-body <番号>をもう一度流す- ほかの原因:エラーと実行の URL を報告に載せ、「次にやることを案内する」へ進む
次にやることを案内する
次を人間に伝える。
- 新規に立ち上げるなら、新規開発ガイド に従い、要件定義から始める
- 要件定義書(
docs/requirements.md)と設計書(docs/design/)は、空から書く - 実装は
app/・infra/に書く。どちらも空なので、samples/の参照実装を手本にして写す(samples/自体は書き換えない)
あわせて、手順ごとの結果(済ませた/済んでいたので飛ばした/Issue にした番号)を報告する。PR を作ったなら、その URL も添える。