1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code の --from-pr で「PRの続き」から再開する:gh + launchd で朝のレビュー待ちPRを即再開する実装

1
Posted at

はじめに:PRを開くたびに「前回の文脈」を説明し直していた

当社(合同会社ジョインクラス)は社員ゼロで、launchd の定期ジョブ17個と Claude Code で業務の大半を回しています。開発もほぼ Claude Code 経由で、PR は Claude に作らせることが多いです。

困っていたのは 翌朝のレビュー対応 でした。レビューコメントが付いたPRを直そうとすると、新しいセッションで「このPRは何のためで、どこまでやって、なぜこの設計にしたか」を毎回説明し直す必要がありました。説明が雑だと、AIが前日に却下した案を平気で再提案してきます。

これを解決するのが claude --from-pr です。本記事では、

  1. --from-pr の基本と、効く条件・効かない条件
  2. 当社の実スクリプト(GitHub監視ジョブ)をベースにした「レビュー待ちPRを朝に一覧化し、再開コマンドまで出す」実装
  3. ハマりどころと検証方法

をまとめます。

--from-pr とは

--from-pr は、GitHub の PR に紐づいた Claude Code セッションを再開する オプションです。

# PR番号で再開
claude --from-pr 123

# PR URL でも可
claude --from-pr https://github.com/JOINCLASS/ai-ceo-framework/pull/123

ポイントは「紐づいた」の部分です。Claude Code のセッション内で gh pr create を実行してPRを作ると、そのセッションがPRとリンクされます。--from-pr はそのリンクをたどって、PRを作ったときの会話履歴ごと 復元します。

状況 --from-pr の挙動
Claude Code セッション内で gh pr create したPR 作成時のセッションが再開される
人間がブラウザで作ったPR 紐づくセッションがないので再開できない
別マシンで作ったPR セッションはローカル保存のため、そのマシン以外では再開できない

つまり 「PRはClaude Codeの中で作る」を運用ルールにしておくこと が前提です。

Step 1:PR作成をClaude Code内に寄せる

当社では CLAUDE.md に以下を書いています(抜粋)。

## Git運用
- PRは必ずこのセッション内で `gh pr create` を使って作成する(--from-pr で再開するため)
- PR本文に「設計判断」と「却下した案」を必ず書く
- git push --force は禁止

「却下した案」をPR本文に残すのは、--from-pr で会話は戻っても、長い会話の後半では古い判断が埋もれやすいためです。PR本文は人間のレビュアーにも効くので一石二鳥です。

git push --force 禁止は、過去にAIが force push してブランチを消した事故の再発防止です。--from-pr で再開したセッションが「履歴をきれいにしましょう」と rebase + force push を提案してくることがあるので、ここは明示しておくのが安全です。

Step 2:朝にレビュー待ちPRを一覧化する(実スクリプトベース)

当社には毎朝8:00に走る auto-github-monitor.sh があり、gh api でStar/Fork/Issueの増減を取ってSlackに投げています。この骨格(gh + jq + 前回状態との比較 + Slack通知)をそのまま流用して、変更要求が付いた自分のPRを拾い、再開コマンド付きで通知する ジョブを足しました。

#!/bin/bash
# レビュー対応待ちPRを一覧化し、--from-pr の再開コマンドをSlackに通知
# launchd: com.joinclass.auto-pr-resume(毎日8:05 JST)
set -uo pipefail

export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
export HOME="/Users/kyoagun"

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
LOG_FILE="$PROJECT_ROOT/.company/scripts/logs/auto-pr-resume.log"
REPO="JOINCLASS/ai-ceo-framework"

notify_slack() {
  local msg="$1"
  if [ -n "${SLACK_WEBHOOK_URL:-}" ]; then
    curl -sf -X POST "$SLACK_WEBHOOK_URL" \
      -H 'Content-Type: application/json' \
      -d "$(jq -n --arg text "$msg" '{text: $text}')" \
      >/dev/null 2>&1 || true
  fi
}

echo "$(date): === PR再開チェック開始 ===" >> "$LOG_FILE"

# 自分が作者で、変更要求 or 未レビューのオープンPR
PRS=$(gh pr list --repo "$REPO" --author "@me" --state open \
  --json number,title,reviewDecision,url \
  --jq '.[] | select(.reviewDecision == "CHANGES_REQUESTED" or .reviewDecision == "REVIEW_REQUIRED")
        | "#\(.number) [\(.reviewDecision)] \(.title)\n  → claude --from-pr \(.number)"' \
  2>/dev/null || true)

if [ -z "$PRS" ]; then
  echo "$(date): 対応待ちPRなし" >> "$LOG_FILE"
  exit 0
fi

notify_slack "🔁 [レビュー対応待ちPR]\n${PRS}\n\n作業ディレクトリ: ${PROJECT_ROOT}"
echo "$(date): 通知送信" >> "$LOG_FILE"

Slackにはこう届きます。

🔁 [レビュー対応待ちPR]
#142 [CHANGES_REQUESTED] feat: 承認キューの期限切れ自動エスカレーション
  → claude --from-pr 142

朝はこの1行をコピペするだけで、前日の会話の続きからレビュー対応を始められます。

Step 3:launchd に登録する

macOS では cron がフルディスクアクセスの制約で全滅した経験があり、当社の定期ジョブは全て launchd です。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>com.joinclass.auto-pr-resume</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string>
    <string>/Users/kyoagun/workspace/one-ceo/.company/scripts/auto-pr-resume.sh</string>
  </array>
  <key>StartCalendarInterval</key>
  <dict><key>Hour</key><integer>8</integer><key>Minute</key><integer>5</integer></dict>
  <key>EnvironmentVariables</key>
  <dict><key>SLACK_WEBHOOK_URL</key><string>https://hooks.slack.com/services/XXX</string></dict>
</dict>
</plist>
cp com.joinclass.auto-pr-resume.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.joinclass.auto-pr-resume.plist
# 即時に1回動かして確認
launchctl start com.joinclass.auto-pr-resume
tail -n 5 /Users/kyoagun/workspace/one-ceo/.company/scripts/logs/auto-pr-resume.log

ハマりどころ

1. 作業ディレクトリが違うと再開できない

セッションはプロジェクト(ディレクトリ)単位で保存されます。PRを作ったリポジトリのルートで claude --from-pr を実行してください。Slack通知に PROJECT_ROOT を入れているのはこのためです。worktree で作業した場合は、その worktree のパスで実行します。

2. launchd では gh が見つからない / 認証されていない

launchd は対話シェルの PATH を引き継ぎません。スクリプト冒頭で PATH と HOME を明示しないと gh: command not found か未認証扱いになり、|| true で握りつぶされて「対応待ちPRなし」と誤判定します。ログが毎日「なし」なら、まず以下を疑ってください。

env -i HOME="$HOME" PATH="/opt/homebrew/bin:/usr/bin:/bin" gh auth status

3. 人間が作ったPRは再開できない

ブラウザでPRを作ると紐づくセッションがありません。その場合は通常どおり claude を起動し、「PR #142 のレビューコメントに対応して」と頼みます(gh pr view 142 --comments で読ませる)。

4. 再開後のセッションは古いブランチ状態を前提にしている

前日からmainが進んでいると、会話上の前提とコードが食い違います。再開直後に必ず次を実行させています。

git fetch origin && git status && gh pr view --comments

検証方法

  1. Claude Code 内で小さな変更を加え、gh pr create でPRを作る
  2. セッションを終了する
  3. GitHub上でそのPRに「Request changes」を付ける
  4. bash auto-pr-resume.sh を手動実行し、Slackに claude --from-pr <番号> が出ることを確認
  5. 出てきたコマンドを実行し、PR作成時の会話が残っていること(「さっき〇〇の案を却下した理由は?」と聞いて答えられるか)を確認

5の質問で正しく答えられれば、文脈ごと復元できています。

おわりに

導入して一番変わったのは、レビュー対応の「立ち上がり」です。以前は説明し直しに毎回10分ほどかかり、しかも説明が漏れると却下済みの案が再提案されていました。--from-pr + 朝の通知にしてからは、コマンドを1行貼るだけで続きから始められます。

一人会社では、人間の判断時間が一番希少なリソースです。AIに「前回の続き」を覚えさせておく仕組みは、地味ですが効きます。

PR作成・レビュー・再開までを含めた、AIを前提にした開発プロセス全体の設計は、書籍『AI駆動開発ライフサイクル(AI-DLC)の教科書』にまとめています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?