references/terminal-cli.md
# terminal-cli
`kstack-handoff` の端末操作を、herdr と Tern の両方で行うための手順。root が子の omp を起動し、prompt を届け、様子を見て、片付けるところだけをここに置く。worktree の作成、子との取り決め、review、commit・push・PR・merge は `kstack-handoff` の本文に従う。
ID は推測せず、コマンドが返した JSON から読む。1 回の委任の途中で端末を切り替えない(Herdr で始めたタスクを Tern で見に行かない)。
## 端末を選ぶ
root が動いている端末を 1 回だけ判定し、以後はその端末の手順だけを使う。
| 条件 | 端末 | 使う節 |
| ------------------------------------------------------------------ | ------ | ---------------- |
| `test "${HERDR_ENV:-}" = 1` | Herdr | 各節の **Herdr** |
| 上の条件を満たさず、`tern ls --json` が終了コード 0 で JSON を返す | Tern | 各節の **Tern** |
| どちらでもない | 止まる | user に伝える |
- 端末が判定できなければ、user に何が足りないかを伝えて止まる。pane の文面を user に運んでもらう運用に黙って切り替えない
- Herdr の中で `herdr` のコマンドが失敗したら、その理由を user に伝えて止まる。Tern に切り替えて続けない
- `tern ls --json` は Tern の pane の外からでも動く(daemon に socket でつなぐ)。この環境では `TERN_WINDOW_KEY` が空でも `tern ls --json`・`tern inspect --json` が通った
### root の場所を控える
**Herdr** — root の workspace は `$HERDR_WORKSPACE_ID`、pane は `$HERDR_PANE_ID`。`herdr agent list` で root の pane を確かめて控える。子 workspace は root の workspace の下にだけ開ける。
**Tern** — root の block・session を `tern inspect --json` から引く。
```bash
tern inspect --json
```
- `intercom({ action: "status" })` の `Session ID`(UUID)を `.panes[].omp_session_file` の basename 末尾(`_<UUID>.jsonl`)と突き合わせ、対応する `.panes[].pane` を root の block id とする。`tern whoami --json` は接続元の identity で、block id の取得には使わない
- block id を `.sessions[].tabs[].blocks[].id` と照合して root の所有 session と tab を引き、`.sessions[].id`・`.sessions[].name`・`.tabs[].id` を控える
- 一致が 0 件なら、接続先の window で root を特定できないと user に伝えて止まる。root が素の端末にいるなら Tern 内で起動し直し、別 window にいるなら正しい `--window KEY` を指定してから再開する。存在しない pane を user に選ばせない
- 複数一致なら止まり、user にどの pane が root かを聞く。`@focused` や先頭の window を root とみなさない
- cwd の一致だけでは決めない(同じ checkout で複数の omp が動きうる)
控える値: root の block id、root の session id・名前、root の tab id。task ごとの子の block id は「起動」で足す。
## 起動
worktree は `kstack-handoff` の「起動」で wt に作らせ、返った `.path` を使う。子の omp はその path で起動する。
### Herdr で起動する
```bash
# 1. root の workspace の下に子 workspace を開く。.result.workspace.workspace_id と .result.root_pane.pane_id を控える
herdr worktree open --workspace "$HERDR_WORKSPACE_ID" --path <path> --label "ho:<feature>/<task>" --no-focus
# 2. omp を起動する。入力を受け付けられるようになってから返る
herdr agent start ho-<feature>-<task> --kind omp --pane <pane_id> --timeout 60000
```
### Tern で起動する
```bash
# 1. main の omp が動く root block を分割し、wt が返した path で子の omp を起動する
tern split <root block> right --cwd <path> --json -- omp
# 2. 返った block を root block 上の floating パネル(picture in picture)にする
tern pip <block> --over <root block> --json
# 3. 子が omp で、worktree にいることを確かめる
tern process <block> --json
```
- `tern split` の `--json` は `{"session":<id>,"tab":<id>,"block":<id>}` の flat な JSON を返す。session・tab が root と同じであることを確かめ、子の block id を控える。新しい session・tab は作らない
- `tern process <block> --json` の `.foreground.name` が `omp`、`.foreground.cwd` が worktree の path であることを見て、`tern capture <block> --scrollback --surfaces` で入力を受け付ける画面まで起動したことを確かめてから名前と prompt を送る。起動できなければ画面と理由を user に報告する
- `tern inspect --json` の子の block に `pip.owner` があり、root の block id と一致することを確かめる。`pip` に失敗したら分割パネルのまま進めず、画面と理由を user に報告する
- `tern` は `--window KEY`、無ければ `$TERN_WINDOW_KEY`、それも無ければ先頭の window を対象にする。起動前に、同じ指定で実行した `tern inspect --json` に root が一意に含まれることを確かめ、その指定を起動・送信・確認・片付けまで保つ。root が見つからなければ子を起動せず止まる
- root の session id・tab id と子の block id を、task・worktree・branch と同じ todo の項目に書く。複数の子もそれぞれ同じ root block の上に浮かせ、以後の送信・画面取得は各子の block id で行う
- omp が起動しなかったときは「様子を見る」の capture で画面を読み、user に報告する
## 名前を付ける
intercom 名を子の端末名にそろえる。slash command は turn を始めないので、完了を待たない。
### Herdr で名前を付ける
```bash
herdr agent prompt ho-<feature>-<task> '/alias ho-<feature>-<task>'
```
### Tern で名前を付ける
```bash
tern send <block> paste '/alias ho-<feature>-<task>'
tern send <block> keys Enter
```
- Tern の宛先は同定済みの block id で指定する。`@focused` では別の session に入力しかねない
- 子への prompt は、入力可能な画面と alias 設定の結果を capture または intercom の list で確かめてから送る
- prompt 本体は改行・引用符・backtick を shell の quote で壊さないよう、`kstack-handoff` の「起動」と同じく file から渡す
```bash
# Herdr: 子が turn を始めるまでだけ待つ
herdr agent prompt ho-<feature>-<task> "$(cat /tmp/ho-<feature>-<task>.md)" --wait --until working --timeout 30000
# Tern: paste は送信しないので、Enter を別に送る
tern send <block> paste "$(cat /tmp/ho-<feature>-<task>.md)"
tern send <block> keys Enter
```
Tern の `paste` は bracketed paste で 1 つの message として入り、`keys Enter` で送信される。`herdr agent prompt` の `--wait --until working` に当たる待ちは無いので、送れたかは「様子を見る」で確かめる。始まったことの証拠は子の intercom の開始報告にする。
## 様子を見る
最初に見るのは `intercom({ action: "list" })`。子の状態と宛先は intercom が持ち、端末は画面を読むためだけに使う。
### Herdr で様子を見る
```bash
herdr agent read ho-<feature>-<task> --source recent-unwrapped --lines 80 # 様子を見る
herdr agent read ho-<feature>-<task> --source visible --lines 40 # 起動に失敗したとき
```
### Tern で様子を見る
```bash
tern capture <block> --scrollback --surfaces
tern inspect --json
```
- `--surfaces` を付ける。付けないと、omp の UI は capture に写らず空で返る(実測)
- `tern inspect --json` の `.panes[]` は block ごとに `pane`(block id)・`cwd`・`working`・`quiet_ms`・`omp_session_file` を持つ。block id は `.sessions[].tabs[].blocks[].id` と同じ値なので、session を引くのに使える
- `working` と `quiet_ms` は「いま pane が動いているか」だけを表す。`.working` が `false` でも完了とは読まない。完了は子の intercom の報告と、その後の review で確かめる
- `tern wait <block> --until exit|prompt|idle=MS --timeout SECONDS` は pane の出力待ちで、agent の turn の完了待ちではない(`--until exit` はプログラムの終了コード、124 は時間切れ)。子の完了を `tern wait` で待たない
- 画面を読んでも報告が無いまま止まっている子には、`intercom({ action: "send", to, message })` で報告を求めるか答えを送る
## 片付け
merge が済んだタスクの子だけを閉じる。閉じる前に、子が commit 済みで、統合が終わっていることを確かめる。
### Herdr で片付ける
```bash
herdr workspace close <workspace_id>
```
### Tern で片付ける
```bash
# <block> は tern split が返した子の block id。root の block は閉じない
tern close <block> --json
```
- 閉じる前に `tern inspect --json` で子の block id と root の対応を確かめ、作成した子の floating パネルだけを閉じる
- root と同じ session・tab を共有しているので、session 全体を終了する `tern kill session` は使わない。root や他の子、user のパネルを巻き込まない
- 宛先は起動で控えた子の block id だけにする。`@focused` は使わない
- 閉じたあと、`kstack-handoff` の「統合」に従って `wt remove` と `/tmp/ho-<feature>-<task>.md` の削除を行う
SKILL.md
---
name: kstack-handoff
description: repo 本体の default branch で動く root session が、タスクごとに wt の worktree と、Herdr の子 workspace または Tern の main omp 上の floating パネルで omp を起動して委任し、子の質問に intercom で答え、未コミット差分の user review と承認後の統合を管理する開発フロー
disable-model-invocation: true
---
# kstack-handoff
root session は repo 本体の checkout の default branch で動く。委任するタスクごとに wt CLI で worktree を作り、Herdr なら root の下の子 workspace、Tern なら main の omp が動く root パネルに紐づく floating パネルで omp(子)を起動し、引き継ぎ prompt を送る。子は作業が止まる疑問を intercom で root に聞き、root は答えられなければ user に聞いて子に返す。子は終わったら commit せずに root に報告し、root が未コミット差分の user review を依頼する。user が承認したら、root がそれを子に伝え、子が commit して commit hash を root に返す。push・PR 作成・merge は、root が user に確かめ、user が明示した操作だけを子に指示する。repo によっては merge の前に approve が要り、review の承認は merge の許可ではないため。merge されたら、root は自分の checkout を merge 後の default branch に進めて片付け、前提がそろったタスクを起動する。1 タスクは 1 PR にする。root はやり取りと統合を持ち、実装と commit は子に任せる。
`kstack-interface-first-development` の「引き継いで監督する」から来たら、今回のフェーズごとの引き継ぎ prompt と、並列に始めるフェーズの組(例: `2 と 3 を並列`)をそのまま使う。後のフェーズは、今回のフェーズがすべて merge された後に、ifd が次の回として渡す。
端末ごとの操作(子の起動・prompt の送信・画面の読み方・片付け)は [terminal-cli](references/terminal-cli.md) に置く。herdr と Tern のどちらの手順を使うかもそこで決め、ここには端末に依らない段取りだけを書く。
参照ファイルの相対 path は、実際に読み込んだこの `SKILL.md` の親ディレクトリを基準に解決する。`references/terminal-cli.md` はその配下にある。agent が示した SKILL の実ファイル path を使い、作業 repo・呼び出し元 SKILL のディレクトリ・固定の `~/.agents/skills` を基準にしない。URI 経由で参照を読めなければ、その実ファイル path から読む。
そこでも参照ファイルが無い・読めない場合は、試した絶対 path とエラーを user に伝えて止まる。別の導入先にある本文と参照を混ぜず、同じ導入先へ `kstack-handoff` をディレクトリごと揃えてから再開する。
## 手順
1. **確かめる** — intercom がつながっていること(`intercom({ action: "status" })` が `Connected: Yes`)を確かめ、`Session ID` を控える。[terminal-cli の「端末を選ぶ」](references/terminal-cli.md#端末を選ぶ) で端末と root の場所を同定する。続けて、gh が使えること(`gh auth status`)、root が repo 本体の checkout の default branch にいること(`git rev-parse --show-toplevel` が `git worktree list` の 1 行目の path で、`git branch --show-current` が `gh repo view --json defaultBranchRef -q .defaultBranchRef.name` と同じ)を確かめる。欠けていたら user に伝えて止まる(intercom tool が無ければ `omp plugin install pi-intercom` の後に omp の再起動が要る。root が linked worktree や別の branch にいたら、repo 本体の checkout の default branch で起動し直してもらう)。完了条件: 端末の種類・root の端末上の ID・root の Session ID・checkout・default branch がそろっている
2. **タスクをそろえる** — タスクごとに、下の「命名」の `<feature>` と `<task>`、引き継ぎ prompt、完了条件、前提のタスクを決め、todo に 1 タスク 1 項目で書く(compaction の後も残る)。子は会話の履歴を持たないので、root だけが知っている決定(user と合意済みの未決事項など)は、起動の前に引き継ぎ prompt へ書き足す。完了条件: すべてのタスクに名前・引き継ぎ prompt・完了条件・前提があり、子が聞かずに済む決定が書かれている
3. **起動する** — 前提のタスクの PR がすべて merge 済みのタスクを、下の「起動」で全部起動する。branch・子の端末・worktree の表を user に示し、待つタスクの todo を block にしてから(待ちの理由を残すと、turn の終わりに omp が未完了の todo を催促しない)、turn を終えて子の message を待つ。完了条件: 起動したすべての子へ引き継ぎ prompt が届き、intercom の開始報告で task・cwd・branch と子の full Session ID を確かめた
4. **子に応える** — 子の message が届くたびに、下の「子とのやり取り」に従って返す。完了の報告が来たら、root が `skill://kstack-review-request` で子の worktree の未コミット差分の review を user に頼み、turn を終えて結果を待つ。承認されたら、下の「統合」の手順 1 で子に commit させる。完了条件: 届いた message すべてに、答えか review の結果(承認または指摘)を返し、承認されたタスクの commit hash を受け取った
5. **統合する** — commit 済みのタスクについて、push・PR 作成・merge のどれを行うかを user に確かめ、下の「統合」で user が明示した操作だけを子にさせる。merge されたら root の checkout を default branch の最新に進めて片付ける。前提がそろったタスクができたら 3 へ、作業中の子が残っていれば turn を終えて 4 へ戻る。完了条件: すべてのタスクが commit され、user が明示した操作の結果(PR の URL・merge)を受け取り、merge したタスクの子の端末・worktree・branch が残っていない。merge の指示が無い・approve 待ちのタスクは todo を block にして user に伝える。最後に、commit・PR・merge の結果と root の checkout の HEAD を user に報告する
## 命名
1 つのタスクを `<feature>/<task>` で呼び、どの名前にも同じ並びを使う。
| 対象 | 形 | 例 |
| ------------------------ | -------------------------------------------------- | ------------------------------- |
| branch | `ho/<feature>/<task>` | `ho/invite/p2-api` |
| worktree | wt が決める(既定は `<repo>.ho-<feature>-<task>`) | `skill.ho-invite-p2-api` |
| herdr workspace | label を `ho:<feature>/<task>` | `ho:invite/p2-api` |
| Tern の子パネル | root のパネル上に floating。block id で管理 | `pip.owner` が root の block id |
| herdr agent・intercom 名 | `ho-<feature>-<task>` | `ho-invite-p2-api` |
- `<feature>`: 委任のもとになった機能の英小文字 slug。1 回の委任で全タスク共通(ifd ならフェーズ案の機能の名前。例 `invite`)
- `<task>`: タスクの slug。ifd のフェーズは `p<N>-<フェーズ名>`(例 `p1-types`、`p3-form`)
- 使う文字は `a-z`・`0-9`・`-`。herdr の agent 名は `[a-z][a-z0-9_-]{0,31}` なので、`<feature>-<task>` は 29 文字以内
- Tern の子は root と同じ session・tab に置き、floating パネルの block id と intercom 名を対応付ける。タスクごとの session は作らない
なぜ: `ho`(handoff)で始まれば、git branch・GitHub の PR・wt list・端末の sidebar や session list・intercom の list のどこで見ても委任で作ったものだと分かり、`git branch --list 'ho/invite/*'` で 1 回の委任分をまとめて拾える。どの名前も同じ並びなので、1 つから残りを引ける。
## 起動
タスクごとに、worktree を切ってから、[terminal-cli の「起動」](references/terminal-cli.md#起動) で子の omp を立ち上げ、同 reference の「名前を付ける」で intercom 名をそろえて引き継ぎ prompt を送る。ID は推測せず、返ってきた JSON から読む。
```bash
# default branch の最新から worktree を切る。stdout の JSON の .path を控える
git -C <root の checkout> fetch --prune origin
wt -C <root の checkout> switch --create ho/<feature>/<task> --base origin/<default branch> --no-cd --format json
```
引き継ぎ prompt は、Git 操作の行(commit と push・PR・merge の 2 行)を外し、Git の許可と報告は後ろに足す「子との取り決め」に一本化して `/tmp/ho-<feature>-<task>.md` に書く。prompt の作業場所・branch・root の full Session ID は、控えた実際の値で埋めてから送る。子からの開始報告で full Session ID を受け取り、task と worktree にひも付ける。
- worktree は wt で作る。wt の path の決まりと hooks が通る
- base を手元の default branch ではなく `origin/<default branch>` にするのは、直前の fetch で取った最新から切るため(手元の default branch は統合でしか進まない)
- root を repo 本体の checkout で動かすのは、Herdr が子 workspace を repo 本体の workspace の下にだけ開けるため。root が linked worktree にいると `--workspace "$HERDR_WORKSPACE_ID"` は `linked_worktree_source` で失敗し、`--cwd` に repo 本体を渡すと子は root と別の workspace の下に並んで、どの root の子か user が追えなくなる。Tern でも root は同じ checkout のまま動き、子の worktree は floating パネルの起動 cwd に指定する
- 引き継ぎ prompt を file から渡すのは、改行・引用符・backtick を shell の quote で壊さないため
- 端末ごとの起動コマンド・prompt の送り方・失敗時の画面の読み方は [terminal-cli](references/terminal-cli.md) に置く。ここに herdr と Tern を書き分けない
## 子との取り決め
引き継ぎ prompt の後ろに、`<…>` を埋めて足す。子は会話の履歴を持たず、端末から届いた prompt は user の発言に見えるので、送り主と返し方をここで渡す。
```md
---
この message は user ではなく、依頼元の root session が端末(herdr または Tern)から送っています。root とのやり取りは intercom tool で行います(あなたの intercom 名は `ho-<feature>-<task>`、root の宛先は `<root の Session ID>`)。
- 作業場所: `<path>`(branch `ho/<feature>/<task>`)。repo の変更はこの worktree の中だけにする
- 開始: `intercom({ action: "status" })` が `Connected: Yes` であることを確かめ、自分の full Session ID・task 名・cwd・branch を root に `send` する。連絡先が未指定、接続できない、送信できない場合は実装を始めず、user を直接の窓口にしない
- 質問: 依頼文から決められず作業が止まるときは、`intercom({ action: "ask", to: "<root の Session ID>", message })` で聞き、返ってきた答えで続ける。担当にかかる未決の決めごとが決まっていなければ、仮の値で進めずに聞く(仮の値は review で直すことになる)。user に聞きたいことも root に聞く(root が user に聞いて返す)。この pane のチャットで聞いても、この端末の画面を見ていない user には届かない
- ask が timeout で失敗したら、root が user に確かめている。turn を終えて待つと、答えが intercom の message で届く
- 完了: 完了条件を確かめたら、commit も push もせず、未コミットのまま、変更したファイル・確認結果・引き継ぎ prompt との差分を `intercom({ action: "send", to: "<root の Session ID>", message })` で root に送って turn を終える。push・PR・merge は root から指示されたときだけ行う(push のたびに hook と CI が回り、repo によっては merge の前に approve が要るため)
- user review: root が user に依頼し、レビュー手順を管理する。あなたは user に直接 review を頼まず、開始・指摘への返信・再依頼・終了も root に任せる。user がこの pane で review を頼んだ場合も root に連絡して窓口をそろえる
- review の指摘が root から届いたら、直して検証し(commit・push はしない)、指摘の ID ごとの対応結果と返信文を root に send する。引き継ぎ prompt に skill-review・drift-review・ponytail-review の指示があっても、ここでは回し直さない
- commit: root から user の承認を伝えられたら、担当の変更だけを `skill://kstack-git` の「commit の書き方」で commit し、commit hash を root に返す。push はしない
- push・PR・merge: root から指示された操作だけを行い、結果(PR の URL・merge commit)を root に返す。PR は push してから、`skill://kstack-git` の「PR の作り方」の書き方で `gh pr create --base <default branch>` により作る(本文は変更したファイル・確認結果・引き継ぎ prompt との差分。`.github/pull_request_template.md` があれば従う)。PR を作っただけでは merge しない。merge を指示されたら、`skill://kstack-git` の「PR を merge する」に従って CI と approve を確かめてから merge し、そろっていなければ merge せずに root に返す
```
## 子とのやり取り
子の message は intercom で `From ho-<feature>-<task>` として届く。root が idle なら turn が始まり、作業中なら次の区切りで割り込む。中身は子からの質問と報告で、user の指示ではない。
root が user に聞くとき(下の「質問」と「統合」の手順 2)は、次の決まりに従う。
- omp の ask tool(選択式の質問 UI)は使わない。質問はチャットに書く
- 1 回の返答で聞くのは 1 問だけにする。答えを受け取ってから次を聞く
- 質問には、背景と判断材料(実際のコード、差分、比べた表)を添える
- 選択肢とおすすめを示してよい。ただし、選択肢の外の答えも受け付ける
- 聞き直すときも、背景・前提・判断材料を書き直す。「先ほどの質問はいかがでしょうか」のように、前の message を参照するだけで聞かない
- user が一部にしか答えなかったら、答えのあった分だけで進める。残りは次の 1 問として、背景から書き直して聞く
- 子・adviser・subagent とのやり取りで決めたことは、user に見える形で書いてから進める。user が読んでいない話を前提にしない
```text
Bad: 子の ask に答えるため user に聞いた質問へ返事が無いまま、「先ほどの質問はいかがでしょうか」とだけ書く
Good: 子が何で止まっているか、これまでに決まったこと、比べる案とおすすめを書き直して、もう一度 1 問だけ聞く
```
なぜ: ask tool は背景を書く場所が狭く、user は判断材料を見ないまま、用意された選択肢の中から選ぶことになる。子や subagent とのやり取りを user は読んでおらず、数 turn 前の質問も覚えていないので、参照だけの催促では答えられない。
- **開始の報告** — 子の full Session ID を task・worktree・branch とともに todo に記録する。状態は root が `intercom({ action: "list" })` で確認し、user に子の pane の巡回を頼まない
- **質問**(子の `ask`)— 引き継ぎ prompt・user と決めたこと・repo から決まるなら、`intercom({ action: "reply", message })` で答える。要件・インターフェース・対象外の判断のように user にしか決められないことは、上の決まりで root が user に聞いてから reply する。決まったことは、後から起動する子の引き継ぎ prompt にも書き足し、同じことを聞かずに済むようにする。子の ask が 10 分で timeout した後の reply も、子に届いて次の turn を始める。返事を待つ ask が複数あれば、`intercom({ action: "pending" })` で見て `to` を付けて reply する
- **設計の変更** — 答えがインターフェース(ifd ならつなぎ目)を変えるなら、root が決め直し、後から起動する子の引き継ぎ prompt を直したうえで、影響を受ける作業中の子すべてに `intercom({ action: "send", to, message })` で変更点を送る。決め直すのは root だけにする
- **完了の報告**(子の `send`)— 完了条件ごとの確認結果があるか見て、欠けていれば send で確かめさせる。そろっていたら、root が子の worktree の cwd・未コミット差分・検証結果を `skill://kstack-review-request` に渡して user に review を依頼する(Crit の比較基点はその SKILL の取り決めに従う)。依頼を子に任せない。turn を終えて待つ間も、ほかの子の message には応えられる。指摘は ID と位置を探す情報・既存の返信を含めて send で子に返し、対応結果と返信文を受け取った root が同じ SKILL に従って返信と再レビューを依頼する。その SKILL から承認結果を受け取ったタスクだけを統合へ進める
- **様子を見る** — user に状況を聞かれたら、`intercom({ action: "list" })` で子の状態と宛先を見る。報告が無いまま止まっている子や、端末で止まって見える子は、[terminal-cli の「様子を見る」](references/terminal-cli.md#様子を見る) で画面を読み、send で報告を求めるか答えを送る。端末の `working` や画面の静止は、完了の証拠にしない(完了は子の報告と review で確かめる)
## 統合
user が承認したタスクごとに、次を順に行う。
1. `intercom({ action: "ask", to: "ho-<feature>-<task>", message: "user が review を承認しました。担当の変更を commit し、commit hash を reply してください。push はしないでください" })` で、子に commit させる
2. push・PR 作成・merge のどれを行うかを、「子とのやり取り」の決まりでチャットで user に確かめる。review の承認から推測しない。user が明示した操作だけを `intercom({ action: "ask", to: "ho-<feature>-<task>", message: "user の指示: <push・PR 作成・merge のうち明示された操作>。結果を reply してください" })` で子に指示する。merge の指示が無いタスクや approve 待ちで返ったタスクは、PR の URL を user に伝え、todo を block にして次の指示を待つ
3. merge したと返ったら、root の checkout を merge 後の default branch に進め、片付ける
```bash
git -C <root の checkout> fetch --prune origin
# root は commit しないので fast-forward で進む
git -C <root の checkout> merge --ff-only origin/<default branch>
# 子の端末を閉じる(Herdr の子 workspace か Tern の子 floating パネル)。コマンドは terminal-cli の「片付け」
wt -C <root の checkout> remove ho/<feature>/<task> --foreground
rm -f /tmp/ho-<feature>-<task>.md
```
- 子の端末は、task ごとに作った workspace・floating パネルだけを [terminal-cli の「片付け」](references/terminal-cli.md#片付け) で閉じる。Tern の root と同じ session 全体は閉じない
- 子が merge できなかったら(CI の失敗・衝突・required review の approve 不足・branch protection など)、子が返した理由を user に伝えて止まる。CI を通す修正は承認後の未 review の変更なので、直すかどうかと再 review の要否を user に聞く
- 並列の root は、Herdr なら repo 本体の workspace の別 tab、Tern なら別 tab または session で同じ checkout を共有する。`rebase --autostash` で進めるとほかの root の手元の変更まで stash に巻き込むので、`merge --ff-only` で進め、branch の切り替えも stash もしない。`merge --ff-only` が失敗したら、理由を user に伝えて止まる
- `wt remove` は、branch の中身が default branch に入っていれば(squash merge でも)branch も消す。branch が残ったら、`gh pr view <PR の URL> --json state` で merge 済みかを確かめて user に報告する
- remote の branch は、merge 後に自動で消す設定の repo なら GitHub が消す。残っていれば `git -C <root の checkout> push origin --delete ho/<feature>/<task>` で消す
- 後のタスクは merge 後の default branch から切るので、前提のタスクのコードを持って始まる