mcpField
S
swain-teardown

swain-teardown

github.com/cristoslcエージェントワークフロー236 回インストール25 週間前に更新
リポジトリ

swain-teardown について

swain-teardownは、セッション終了時にリポジトリとワークツリーを確認し、未完了の完了手順を補い、引き継ぎとクリーンアップを調整するスキルです。未コミット変更、未マージブランチ、ワークツリー削除に安全確認を設けています。

主な機能

  1. 01孤立したワークツリーを確認
  2. 02未コミット変更を提示
  3. 03不足している完了手順を実行
  4. 04チケット同期を促す
  5. 05セッション引き継ぎ要約を作成

活用シーン

  1. 01セッション終了前にリポジトリ状態を確認
  2. 02セッションのブックマークがないワークツリーを検出
  3. 03引き継ぎ前にテストや振り返りを補完

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cristoslc/swain --skill swain-teardown

インストール後、Claude Code で/swain-teardownを入力して読み込まれたか確認します。

詳細

セッションの終了処理

セッションを終了するための単一のエントリーポイントです。ダイジェスト、ふりかえり、マージ、クリーンアップ、クローズ、コミットのシャットダウンシーケンス全体を実行します。以前の swain-session close ハンドラーを置き換えます(ADR-023)。

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
bash "$REPO_ROOT/.agents/bin/swain-session-check.sh" 2>/dev/null

session-chain が渡されておらず、JSON 出力の "status" が "active" 以外の場合は、オペレーターに「終了処理を行うアクティブなセッションはありません。」と伝えます。コード 0 で正常終了します。


このスキルの内容

セッションの終了前に、セッションの終了処理で一連の衛生チェックを実行します。

  1. 孤立したワークツリーの検出 — 対応するセッションブックマークがないワークツリーを見つけます(SPEC-233:安全チェックを伴う対処が可能)
  2. Git のダーティ状態チェック — オペレーターが離れる前に、未コミットの変更を明らかにします
  3. 完了パイプラインのチェック — BDD、スモークテスト、ふりかえりが実行されたことを確認し、未実施の手順を実行します(SPEC-258)
  4. チケット同期の確認 — 実施内容とチケットが一致しているか、オペレーターに確認を促します(SPEC-234:セッションがない場合は状態の低下を記録します)
  5. 引き継ぎの概要 — セッションの概要を SESSION-ROADMAP.md に追記します

ふりかえりについて: SPEC レベルのふりかえりは、現在、完了パイプラインの一部として実行されます(ステップ 3/swain-do ステップ 2d)。EPIC レベルのふりかえりは、swain-session の close ハンドラーによって実行されます。終了処理では、パイプラインのふりかえりステップが実施されなかった場合に限り、補完としてふりかえりを実行します。


ステップ 0 — 現在のロックファイルの要求を解除する(SPEC-247)

現在のセッションがアクティブなロックファイルのあるワークツリーで実行されている場合は、その要求を解除します。これを最初に実行することで、後続の孤立ワークツリー検出で現在のワークツリーがアクティブとして誤って検出されるのを防ぎます。

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
LOCKFILE_SCRIPT="$REPO_ROOT/.agents/bin/swain-lockfile.sh"
GIT_COMMON=$(git rev-parse --git-common-dir 2>/dev/null)
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)

if [ "$GIT_COMMON" != "$GIT_DIR" ] && [ -f "$LOCKFILE_SCRIPT" ]; then
  BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
  bash "$LOCKFILE_SCRIPT" release "$BRANCH" 2>/dev/null || true
fi

ステップ 1 — 孤立ワークツリーのチェック(SPEC-233、SPEC-247)

このステップでは、session.json の worktrees 配列からワークツリーのブックマークを読み取り、ロックファイルの状態と照合します(SPEC-247)。孤立ワークツリーは、安全チェックを行ったうえで、オペレーターの確認後に削除する候補として提示されます。このステップは --session-chain の有無にかかわらず、必ず実行されます。

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SESSION_FILE="$REPO_ROOT/.agents/session.json"
LOCKFILE_SCRIPT="$REPO_ROOT/.agents/bin/swain-lockfile.sh"

# Build a list of bookmarked worktree paths from session.json
bookmarked_wts=$(jq -r '(.worktrees // [])[] | .path' "$SESSION_FILE" 2>/dev/null)

orphan_candidates=()
orphan_results=()
ready_candidates=()

# Get all physical worktrees
git worktree list --porcelain 2>/dev/null | grep "^worktree " | while read -r line; do
  wt_path="${line#worktree }"
  wt_branch="$(git -C "$wt_path" rev-parse --abbrev-ref HEAD 2>/dev/null)"

  # Skip trunk (protected)
  if [ "$wt_path" = "$REPO_ROOT" ]; then
    echo "protected: $wt_path (trunk)"
    continue
  fi

  # Check lockfile state (SPEC-247)
  if [ -f "$LOCKFILE_SCRIPT" ]; then
    lock_branch="${wt_branch##*/}"  # strip refs/heads/ prefix
    lockfile="$REPO_ROOT/.agents/worktrees/${lock_branch}.lock"
    if [ -f "$lockfile" ]; then
      # Check if ready_for_cleanup — safe to remove without confirmation
      if grep -q 'ready_for_cleanup=true' "$lockfile" 2>/dev/null; then
        echo "ready: $wt_path ($wt_branch) — marked ready_for_cleanup"
        ready_candidates+=("$wt_path|$wt_branch|$lockfile")
        continue
      fi
      # Check if actively claimed by another session
      if ! bash "$LOCKFILE_SCRIPT" is-stale "$lock_branch" >/dev/null 2>&1; then
        echo "claimed: $wt_path ($wt_branch) — active lockfile, skip"
        continue
      fi
    fi
  fi

  # Check if bookmarked in session.json
  is_orphan=true
  reason=""
  if echo "$bookmarked_wts" | grep -qF "$wt_path"; then
    is_orphan=false
    echo "linked: $wt_path ($wt_branch)"
  fi

  if [ "$is_orphan" = true ]; then
    # Safety checks per SPEC-233 AC1-AC3
    if [ "$wt_path" = "$(pwd)" ]; then
      reason="current directory"
    elif [ -n "$(git -C "$wt_path" status --porcelain 2>/dev/null)" ]; then
      reason="uncommitted changes"
    elif ! git merge-base --is-ancestor "$wt_branch" trunk 2>/dev/null; then
      reason="branch not fully merged"
    else
      reason="safe to remove"
      orphan_candidates+=("$wt_path|$wt_branch")
    fi
    echo "orphan: $wt_path ($wt_branch) — $reason"
    orphan_results+=("$wt_path|$wt_branch|$reason")
  fi
done

孤立ワークツリーが見つかった場合は、「次のワークツリーにはアクティブなセッションブックマークがありません。削除を検討してください。」と表示します。

ready_for_cleanup のワークツリーを自動削除する(SPEC-247)

ready_for_cleanup とマークされたワークツリーはマージとプッシュが完了しているため、オペレーターの確認なしで安全に削除できます。最初に session.json をアーカイブします(SPEC-248)。

ARCHIVE_SCRIPT="$REPO_ROOT/.agents/bin/swain-session-archive.sh"
for candidate in "${ready_candidates[@]}"; do
  IFS='|' read -r wt_path wt_branch lockfile <<< "$candidate"

  # Archive session.json before deletion
  if [ -f "$ARCHIVE_SCRIPT" ]; then
    bash "$ARCHIVE_SCRIPT" save "$wt_path" 2>/dev/null || true
  fi

  if git worktree remove "$wt_path" 2>/dev/null; then
    rm -f "$lockfile"  # Clean up lockfile (SPEC-247 AC3)
    bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" worktree remove "$wt_path" 2>/dev/null || true
    echo "Auto-removed (ready_for_cleanup): $wt_path"
  fi
done
安全な孤立ワークツリーをオペレーターに確認する

reason="safe to remove" の孤立ワークツリーのみを削除候補として提示します。安全な孤立ワークツリーごとに、次の操作を行います。

removed_worktrees=()
for candidate in "${orphan_candidates[@]}"; do
  wt_path="${candidate%%|*}"
  wt_branch="${candidate##*|}"

  echo "> Remove orphan worktree $wt_path ($wt_branch)? [y/N]"
  read -r response
  if [ "$response" = "y" ] || [ "$response" = "Y" ]; then
    # Archive session.json before deletion (SPEC-248)
    if [ -f "$ARCHIVE_SCRIPT" ]; then
      bash "$ARCHIVE_SCRIPT" save "$wt_path" 2>/dev/null || true
    fi
    if git worktree remove "$wt_path" 2>/dev/null; then
      removed_worktrees+=("$wt_path|$wt_branch")
      # Clean up lockfile if present (SPEC-247 AC3)
      lock_branch="${wt_branch##*/}"
      rm -f "$REPO_ROOT/.agents/worktrees/${lock_branch}.lock" 2>/dev/null || true
      # Clear the bookmark from session.json
      bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" worktree remove "$wt_path"
      echo "Removed: $wt_path"
    else
      echo "ERROR: Failed to remove $wt_path — skipping bookmark cleanup"
    fi
  fi
done
安全規則(SPEC-233 AC1-AC3、AC7)
  • 現在のディレクトリ: 削除候補として提示しません。reason="current directory" としてフラグを設定します。
  • 未コミットの変更: 削除候補として提示しません。reason="uncommitted changes" としてフラグを設定します。
  • 未マージのブランチ: 削除候補として提示しません。reason="branch not fully merged" としてフラグを設定します。
  • トランク: 削除候補として提示しません。必ず protected: <repo_root> (trunk) と表示します。
  • 確認が必須: 必ずオペレーターに確認します。自動削除はしません。

ステップ 2 — Git のダーティ状態チェック

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"

cd "$REPO_ROOT"
git_status=$(git status --porcelain 2>/dev/null)

if [ -n "$git_status" ]; then
  echo "WARN: Dirty git working tree — uncommitted changes detected."
  echo "Changes:"
  echo "$git_status" | head -20
else
  echo "OK: Working tree is clean."
fi

確認結果と、実行可能な推奨事項を報告します。


ステップ 3 — 完了パイプラインのチェック(SPEC-258)

チケット同期に進む前に、このワークツリーで完了した作業について、完了パイプラインが実行されたことを確認します。未実施のステップがあれば、ここで実行します。

3a — パイプラインの状態を検出する
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
STATE_FILE="$REPO_ROOT/.agents/completion-state.json"
SWAIN_TEST="$REPO_ROOT/.agents/bin/swain-test.sh"

completion-state.json が存在する場合: 内容を読み取り、未完了のステップを確認します。

PENDING_STEPS=$(jq -r '.steps | to_entries[] | select(.value.status == "pending" or .value.status == "failed") | .key' "$STATE_FILE" 2>/dev/null)
SPEC_ID=$(jq -r '.spec_id // empty' "$STATE_FILE" 2>/dev/null)
  • PENDING_STEPS が空の場合 → すべてのステップが成功したか、スキップされています。「完了パイプライン:すべてのステップが完了しました。」と表示して続行します。
  • PENDING_STEPS が空でない場合 → 対応が必要なステップを表示して実行します(3b を参照)。

completion-state.json が存在しない場合: ワークツリーに完了済みタスクがあるか確認します。

export PATH="$REPO_ROOT/.agents/bin:$PATH"
CLOSED_COUNT=$(ticket-query '.status == "closed"' 2>/dev/null | wc -l | tr -d ' ')
  • CLOSED_COUNT > 0 の場合 → 作業は行われましたが、パイプラインは開始されていません。すべてのステップを pending に設定して状態ファイルを作成し、実行します。
    # Try to find the SPEC ID from the plan epic
    EPIC_ID=$(ticket-query '.type == "epic"' 2>/dev/null | head -1 | jq -r '.id // empty')
    SPEC_ID=$(tk show "$EPIC_ID" 2>/dev/null | grep -i 'external_ref' | awk '{print $NF}')
    mkdir -p "$REPO_ROOT/.agents"
    jq -n --arg spec "${SPEC_ID:-unknown}" --arg branch "$(git branch --show-current)" \
      '{spec_id: $spec, branch: $branch, pipeline_started: (now | todate), steps: {bdd_tests: {status: "pending", timestamp: null, detail: null}, smoke_test: {status: "pending", timestamp: null, detail: null}, retro: {status: "pending", timestamp: null, detail: null}}}' \
      > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
    
  • CLOSED_COUNT == 0 の場合 → 完了した作業はありません。このステップを何も表示せずにスキップします。
3b — 不足しているステップを実行する

パイプラインの順序(bdd_tests → smoke_test → retro)に沿って、各ステップの状態を確認します。passed または skipped のステップはスキップします。pending または failed のステップを実行します。

bdd_tests:

BDD_STATUS=$(jq -r '.steps.bdd_tests.status' "$STATE_FILE")

BDD_STATUS が pending または failed の場合:

  • swain-test.sh が存在する場合:

    BDD_OUTPUT=$(bash "$SWAIN_TEST" --artifacts "$SPEC_ID" 2>&1)
    BDD_EXIT=$?
    
    • 終了コード 0 → 出力の先頭 5 行を詳細として passed に更新します。
    • 0 以外 → 末尾 10 行を詳細として failed に更新します。次のように尋ねます:"BDD failed. retry, skip, or abort?"
      • retry → このステップを再実行します
      • skip → 詳細を "operator skipped during teardown" として skipped に設定します
      • abort → ティアダウン全体を停止し、同期に進みません
  • swain-test.sh が存在しない場合: 詳細を "swain-test.sh not available" として skipped に設定します。警告を表示します。

すべての状態書き込みには、DESIGN-018 のアトミックな jq 更新パターンを使用します:

jq --arg step "$STEP" --arg status "$STATUS" --arg detail "$DETAIL" \
  '.steps[$step].status = $status | .steps[$step].timestamp = (now | todate) | .steps[$step].detail = $detail' \
  "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"

smoke_test:

pending または failed の場合:

  • swain-test.sh が存在する場合: swain-test の出力から ## SMOKE セクションを抽出し、オペレーターに提示します。次のように尋ねます:"Did the smoke test pass? (yes / no / skip)"

    • yes → 詳細を "operator confirmed during teardown" として passed に設定します
    • no → failed に設定します。次のように尋ねます:"retry, skip, or abort?"
    • skip → 詳細を "operator skipped during teardown" として skipped に設定します
  • swain-test.sh が存在しない場合: 詳細を "swain-test.sh not available" として skipped に設定します。

retro:

pending または failed の場合:

Skill ツールを使用して swain-retro を呼び出します:

Skill ツールを使用します:swain-retro を次の args で呼び出します:"Teardown catch-up — run retro for before sync."

  • 成功時 → 詳細を "retro captured during teardown" として passed に設定します
  • 失敗時 → 次のように尋ねます:"Retro failed. retry or abort?"(retro はスキップできません)
3c — 強制バイパス

オペレーターが --force を付けてティアダウンを呼び出した場合(呼び出し引数に "force" または "--force" が含まれていることで判定):

# Mark all pending steps as skipped
for step in bdd_tests smoke_test retro; do
  STEP_STATUS=$(jq -r ".steps.$step.status" "$STATE_FILE")
  if [ "$STEP_STATUS" = "pending" ] || [ "$STEP_STATUS" = "failed" ]; then
    jq --arg step "$step" \
      '.steps[$step].status = "skipped" | .steps[$step].timestamp = (now | todate) | .steps[$step].detail = "operator forced bypass"' \
      "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
  fi
done

次のように表示します:"Force bypass — all pending pipeline steps marked as skipped." ステップ 4 に進みます。

3d — パイプラインゲート

すべてのステップを実行またはスキップした後、次を確認します:

REMAINING=$(jq -r '.steps | to_entries[] | select(.value.status == "pending" or .value.status == "failed") | .key' "$STATE_FILE")
  • 空の場合 → ステップ 4 に進みます
  • 空でない場合 → ティアダウンはブロックされています。残っているステップを表示して停止します。

ステップ 4 — チケット同期の確認(SPEC-234 AC3、ステップ 3 から番号を変更)

このステップは必ず実行します。アクティブなセッションがない場合は、状態が不完全であることを記録します:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
session_check=$(bash "$REPO_ROOT/.agents/bin/swain-session-check.sh" 2>/dev/null)
session_status=$(echo "$session_check" | jq -r '.status // "none"')

session_status が "active" でない場合:

  • --session-chain が渡されている場合は、そのまま続行します(呼び出し元がすでに確認済みです)。
  • それ以外の場合は、オペレーターに次のように伝えます:"No active session. Run /swain-init to start one, or proceed with cleanup only?" 続行する場合は、ステップ 1~2(ダイジェスト/retro。セッション状態が必要です)をスキップし、ステップ 3(マージ)に進みます。

ステップ 1 — セッションダイジェスト

セッションがまだアクティブなうちに、セッションダイジェストを生成します。

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
SESSION_ID="$(jq -r '.session_id // empty' "$REPO_ROOT/.agents/session-state.json" 2>/dev/null)"

if [ -n "$SESSION_ID" ]; then
  bash "$REPO_ROOT/.agents/bin/swain-session-digest.sh" \
    --session-id "$SESSION_ID" \
    --output "$REPO_ROOT/.agents/session-log.jsonl" 2>/dev/null
fi

ダイジェストスクリプトが見つからないか、実行に失敗した場合は、警告を記録して続行します。ダイジェストは有用ですが、必須ではありません。


ステップ 2 — Retro(セッションはアクティブのまま)

重要: retro の実行時には、セッション状態を読み取れるよう、セッションがまだアクティブである必要があります。このステップの前にセッションを閉じないでください。

swain-retro を呼び出します:

Skill("swain-retro", "Session is closing. Run retro to capture learnings before session state is cleared.")

swain-retro が利用できない場合は、"Retro skill not found — skipping" を記録して続行します。スキルが見つからないことを理由に、シャットダウンシーケンスを失敗させてはいけません。


ステップ 3 — ワークツリーのブランチをマージする

trunk を除く各アクティブなワークツリーについて、そのブランチを trunk にマージするかどうかを確認します。これは以前のティアダウンで欠けていたステップです。これがなければブランチがマージされないため、ワークツリーを「安全に削除できる」状態にできません。

3.1 — ワークツリーを列挙する
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
TRUNK=$(bash "$REPO_ROOT/.agents/bin/swain-trunk.sh" 2>/dev/null || echo "trunk")

git worktree list --porcelain 2>/dev/null | grep "^worktree " | while read -r line; do
  wt_path="${line#worktree }"
  # Skip trunk
  [ "$wt_path" = "$REPO_ROOT" ] && continue
  wt_branch="$(git -C "$wt_path" rev-parse --abbrev-ref HEAD 2>/dev/null)"
  echo "$wt_path|$wt_branch"
done
3.2 — 各ワークツリーをトリアージする

各ワークツリーの状態を分類します。

状態条件アクション
すでにマージ済みgit merge-base --is-ancestor "$wt_branch" "$TRUNK"マージをスキップし、安全にクリーンアップできるものとしてマーク
クリーン、未マージ未コミットの変更がなく、ブランチが未マージマージを提案
変更ありgit -C "$wt_path" status --porcelain に出力があるオペレーターに警告し、先にコミットするよう提案
現在のディレクトリ"$wt_path" = "$(pwd)"先に ExitWorktree で退出する必要があります
3.3 — 未マージのブランチをマージする

各「クリーン、未マージ」のワークツリーについて、オペレーターに確認します。

ワークツリー {path}(ブランチ {branch})には未マージの変更があります。次のオプションがあります。

  1. マージ — 今すぐブランチを {trunk} にマージする
  2. PR — ブランチをプッシュしてプルリクエストを作成する
  3. スキップ — ブランチをそのまま残す(ワークツリーは保持されます)

マージする場合:

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
TRUNK=$(bash "$REPO_ROOT/.agents/bin/swain-trunk.sh" 2>/dev/null || echo "trunk")

# Link safety — scan for worktree-specific path links before merging
DETECT_SCRIPT="$REPO_ROOT/.agents/bin/detect-worktree-links.sh"
RESOLVE_SCRIPT="$REPO_ROOT/.agents/bin/resolve-worktree-links.sh"
if [ -x "$DETECT_SCRIPT" ]; then
  MERGE_BASE=$(git -C "$wt_path" merge-base HEAD "origin/$TRUNK" 2>/dev/null || true)
  CHANGED_FILES=$([ -n "$MERGE_BASE" ] && git -C "$wt_path" diff --name-only "$MERGE_BASE" HEAD 2>/dev/null || true)
  if [ -n "$CHANGED_FILES" ]; then
    if ! echo "$CHANGED_FILES" | xargs "$DETECT_SCRIPT" --repo-root "$REPO_ROOT" > /dev/null 2>&1; then
      echo "[link-safety] Found suspicious links in $wt_branch. Resolving..."
      echo "$CHANGED_FILES" | xargs "$RESOLVE_SCRIPT" --repo-root "$REPO_ROOT" 2>/dev/null || true
    fi
  fi
fi

# Merge into trunk from the main worktree
cd "$REPO_ROOT"
git fetch origin 2>/dev/null
git merge "$wt_branch" --no-edit

マージで競合が発生した場合は、オペレーターに報告し、このワークツリーをスキップします。強制的に競合を解決してはいけません。

PR の場合:

cd "$wt_path"
git push -u origin "$wt_branch" 2>/dev/null
SUBJECT=$(git log -1 --pretty=format:'%s')
gh pr create --base "$TRUNK" --head "$wt_branch" --title "$SUBJECT" --body "Teardown PR — branch from session teardown."

PR の URL を報告します。

スキップする場合: ワークツリーを保持対象としてマークします。ステップ 4 では削除されません。

3.4 — 「現在のディレクトリ」のワークツリーを処理する

オペレーターが現在ワークツリー内にいる場合は、最後に処理します。他のすべてのワークツリーを処理した後:

  1. このブランチもマージするか確認します(3.3 と同じオプション)。
  2. マージまたは PR の場合は、未コミットの変更を先にコミットしてから、ExitWorktree を呼び出して trunk に戻ります。
  3. スキップする場合は、action: "keep" を指定して ExitWorktree を呼び出し、ブランチを保持します。

ステップ 4 — ワークツリーのクリーンアップ

マージ後、ブランチがマージ済みになったワークツリーをクリーンアップします。

4.1 — 再列挙してマージ状態を確認する
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
TRUNK=$(bash "$REPO_ROOT/.agents/bin/swain-trunk.sh" 2>/dev/null || echo "trunk")

git worktree list --porcelain 2>/dev/null | grep "^worktree " | while read -r line; do
  wt_path="${line#worktree }"
  [ "$wt_path" = "$REPO_ROOT" ] && continue
  wt_branch="$(git -C "$wt_path" rev-parse --abbrev-ref HEAD 2>/dev/null)"

  # Safety checks
  if [ "$wt_path" = "$(pwd)" ]; then
    echo "SKIP: $wt_path — current directory"
    continue
  fi
  if [ -n "$(git -C "$wt_path" status --porcelain 2>/dev/null)" ]; then
    echo "SKIP: $wt_path — uncommitted changes"
    continue
  fi
  if ! git merge-base --is-ancestor "$wt_branch" "$TRUNK" 2>/dev/null; then
    echo "SKIP: $wt_path — branch not merged"
    continue
  fi

  echo "SAFE: $wt_path|$wt_branch"
done
4.2 — 安全なワークツリーを削除する

SAFE な各ワークツリーについて、確認を求めずに削除します。ブランチはマージ済みで、未コミットの変更はなく、現在のディレクトリでもありません。オペレーターはステップ 3 ですでにマージを承認しています。

git worktree remove "$wt_path" 2>/dev/null && echo "Removed: $wt_path ($wt_branch)"
# Clear bookmark
bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" worktree remove "$wt_path" 2>/dev/null

削除に失敗した場合は報告し、続行します。

4.3 — 古いワークツリー参照を整理する
git worktree prune 2>/dev/null
bash "$REPO_ROOT/.agents/bin/swain-bookmark.sh" worktree prune 2>/dev/null

ステップ 5 — セッション状態を閉じる

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
WALKAWAY_NOTE="${WALKAWAY:-Session closed via teardown}"

bash "$REPO_ROOT/.agents/bin/swain-session-state.sh" close \
  --walkaway "$WALKAWAY_NOTE" \
  --session-roadmap "$(pwd)/SESSION-ROADMAP.md" 2>/dev/null

ウォークアウェイノートには、達成した内容をまとめます。セッションでの作業(マージ済みブランチ、完了したタスク、レトロの出力)から推測するか、オペレーターに一言でまとめてもらいます。


ステップ 6 — 引き継ぎをコミットする

終了処理中に変更されたセッション成果物をステージングしてコミットします。

REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"

# Stage session artifacts
git add SESSION-ROADMAP.md 2>/dev/null
git add docs/swain-retro/ 2>/dev/null
git add .agents/session-state.json 2>/dev/null
git add .agents/session-log.jsonl 2>/dev/null

# Check if there's anything to commit
# Resolve model name from the system prompt. When subagents ran under a
# different model, include one Co-Authored-By trailer per model (see
# AGENTS.md Model attribution).
if [ -n "$(git diff --cached --name-only 2>/dev/null)" ]; then
  git commit -m "chore: session teardown handoff

Co-Authored-By: <model-name-from-system-prompt> <noreply@unknown>"
fi

概要レポート

すべてのステップの完了後、概要を表示します。

=== Session Teardown Complete ===

Retro:          {fired / skipped / not available}
Branches:       {N merged, M PRs created, K preserved}
Worktrees:      {N removed, M preserved}
Session state:  closed
Handoff commit: {hash or "nothing to commit"}

重大なエラーが発生しない限り、コード 0 で終了します。


エラー処理

状況対応
アクティブなセッションがない(--session-chain を指定していない場合)クリーンアップのみのモード(ステップ 3~4)を提案し、ダイジェスト/レトロをスキップ
ダイジェストスクリプトが見つからない警告して続行
レトロスキルが見つからない警告して続行
マージ競合競合しているファイルを報告し、そのワークツリーをスキップ
ワークツリーの削除に失敗報告して続行
セッション状態スクリプトが見つからない警告して終了処理をスキップ
ステップ 6 でコミットするものがない「クリーン」と報告して終了
Git を利用できない致命的エラー — 続行できません

統合

swain-init からの呼び出し(意思決定予算)

セッション中に意思決定予算に達すると、swain-init は終了処理を呼び出せます。

Skill("swain-teardown", "Decision budget reached. Run teardown sequence.")
meta-router からの呼び出し

swain meta-router は、「done」、「wrap up」、「close session」、「teardown」をこのスキルにルーティングします。

単独での呼び出し

オペレーターはいつでも /swain-teardown を実行できます。アクティブなセッションがない場合は、クリーンアップのみのモードが提示されます。

コメント