6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

マルチタスクが苦手なので、Slack の返信と PR レビューを Claude Code に定時で下ごしらえさせている

6
Last updated at Posted at 2026-10-30

はじめに

作ったきっかけ

自分はシングルスレッドな人間で、マルチタスクが大の苦手です。

  • Slack の返信に、業務の時間のかなりの部分を取られている
  • メンションがたくさん来ると、あとで返そうと思ったものを忘れてしまう

そこで、「返し忘れを拾う」「返信の下書きを先に作っておく」「レビューや仕様の確認は決まった時間にまとめて済ませておく」を Claude Code に任せることにしました。自分は、決まった時間に結果を見て、直して送るだけにしています。

やっていること

Mac の launchd から Claude Code をヘッドレス(claude -p)で定時実行し、次のジョブを自動で回しています。

ジョブ いつ やること 書き込み先
PR レビュー 平日 9:00 レビュー待ち PR をマルチエージェントでレビューし、Slack で決まった仕様とのずれも見る Slack のレビュー用チャンネル・ローカルの md
仕様ずれチェック 毎週月曜 10:00 1 週間分の Slack の仕様の話と、仕様書・main の実装を突き合わせる。main に入った差分のセキュリティレビューも 自分用チャンネル
未返信の拾い出し 毎日 8:45 直近 3 日の自分宛てメンション・DM のうち、まだ返していない依頼・質問を一覧にする 自分用チャンネル
Slack 返信の下書き 平日 10〜19 時の毎正時 自分宛てのメンション・DM の返信例を、元のスレッドに下書きとして置く 元のスレッドの下書き・自分用チャンネル

Claude Code のクラウド定期実行(routine)を使わず launchd にしたのは、状態ファイル・Slack の Webhook・自作スキル・gh の認証・macOS の通知と、手元の Mac にあるものに頼っているためです。

全体の構成

launchd(時刻で起動)
  └─ zsh -lc "claude -p '/<スキル名> を実行して' --allowedTools ..."
        └─ Claude Code が ~/.claude/skills/<スキル名>/SKILL.md の手順を実行
              ├─ gh(GitHub の読み取りだけ)
              ├─ Slack MCP(読み取り・投稿)
              └─ ローカルの状態ファイル(重複を防ぐ)

やることは Skill(SKILL.md)に書き、launchd 側は「このスキルを実行して」と 1 行頼むだけにしています。手順を変えたいときは SKILL.md を直せば済みます。

1. PR レビュー

launchd の設定

~/Library/LaunchAgents/com.example.pr-review.plist
<key>ProgramArguments</key>
<array>
    <string>/bin/zsh</string>
    <string>-lc</string>
    <string>cd ~/src/<repo> && ~/.local/bin/claude -p "/pr-review-loop を実行して" --allowedTools "Bash(gh pr list:*)" "Bash(gh pr view:*)" "Bash(gh pr diff:*)" "Bash(date:*)" "Bash(mkdir:*)" "Bash(terminal-notifier:*)" "Bash(osascript:*)" "Read" "Write" "Grep" "Glob" "mcp__claude_ai_Slack"</string>
</array>
<key>StartCalendarInterval</key>
<array>
    <dict><key>Weekday</key><integer>1</integer><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer></dict>
    <!-- 火〜金も同じ -->
</array>

--allowedTools で、GitHub は gh pr list / view / diff の読み取りだけを許可しています。gh pr review や gh pr comment は許可していないので、無人で動いても PR に勝手にコメントは付きません。

スキルの手順(要約)

  1. gh pr list でオープン PR を取り、draft と approve 済みを除く
  2. 状態ファイル(state.json、{"PR番号": "レビュー済みの head SHA"})と比べ、前回から head SHA が変わっていない PR は飛ばす
  3. PR ごとにマルチエージェントのレビューコマンドを実行する。使っているのは Claude Code のプラグインのコマンドで、6 つのエージェント(品質・コメント・テスト・握りつぶしたエラー・型設計・簡素化)が並列にレビューし、確信度 80 以上の指摘だけを採る
  4. 汎用の観点に、プロジェクト固有の観点を上乗せする(API を変えたのに仕様書の差分がない、層の分け方の規約に違反している、など)
  5. Slack で決まった仕様と照合する(下で説明)
  6. 結果をローカルの PR-<番号>-<日付>.md に全文で保存し、Slack には PR ごとに親メッセージ 1 通と、指摘はそのスレッドに投稿する
  7. state.json を更新する

Slack の決定と照合する

仕様の細かい決定は、仕様書より先に Slack のスレッドで決まることがよくあります。PR がその決定どおりかを、レビューのときに確かめさせています。

  1. PR のタイトル・本文・ブランチ名から、課題キー・PR 番号・機能を表す語を拾う
  2. それを手がかりに、開発用のチャンネルに絞って直近 60 日の Slack を検索する
  3. ヒットしたスレッドを読み、「〜にする」「〜はしない」といった決定だけ抜き出す。後から変わっていれば最新の発言を採る
  4. 決定と PR の差分を比べ、ずれていそうなものは差分とファイルを読み直して確かめる
  5. ずれは Slack のリンク付きで出す。どちらが正しいかは決めさせない(判断はプロダクトオーナーに回す)

Slack への投稿は、こういう形にしています。

:mag: **#123 PR タイトル**
@author · 🔴2 🟡3 ⚪1 💬1
<PR URL>

💬 は Slack の決定とのずれの件数です。スレッドには Critical と Important、Slack とのずれだけを 1 行ずつ(file.ts:42 の形で)書き、Advisory は件数とローカルのファイル名だけにしています。理由や修正案はローカルの md にだけ書き、Slack は読み流せる量にしています。

2. 未返信の拾い出し(毎朝)

朝 8:45 に、直近 3 日の自分宛てメンションと DM から「まだ返していないもの」を拾い、一覧を自分用チャンネルに 1 通で送ります。

  1. Slack MCP の検索で、自分宛てメンションと DM / グループ DM を取る(自分の投稿・bot の投稿は除く)
  2. 1 件ずつスレッドを読み、次をすべて満たすものだけ残す
    • そのメッセージより後に、自分の投稿がない
    • 自分のリアクションが付いていない
    • 依頼・質問・確認依頼・判断待ちである(挨拶・お礼・共有だけのものは除く)
  3. 古い順に、要件を 1 行に言い換えて並べる。2 日以上前のものには ⏳ を付ける
@自分 Slack 見逃し 10/28(2 件)

• <permalink|#チャンネル名> 送信者(10/27 16:18): ○○をチェックしてほしい

「返したかどうか」を検索の結果だけで決めず、スレッドを読んで判断させているのがポイントです。DM で別に返していたものは対応済みとして外します。ルールに書いていない「スレッドで他の人が対応済み」のものを、理由を添えて外したこともありました。

3. Slack 返信の下書き(毎正時)

  1. Slack MCP の検索で、直近 24 時間の自分宛てメンションと DM を取る
  2. スレッドを読み、自分が返信・リアクション済みのもの、挨拶・お礼だけのものを除く
  3. 1〜3 文の返信例を作る。口調は、同じ会話の自分の過去の投稿に合わせる。事実が分からない箇所は [要確認: 〜] と残し、推測で埋めない
  4. 返信例を、元のスレッドの入力欄に下書きとして置く(Slack MCP の slack_send_message_draft)
  5. 自分用チャンネルに「どこに下書きを置いたか」を 1 通で通知する
@自分 Slack 返信の下書き 10:00(2 件) リンク先の入力欄に下書きがあります。直して送ってください

• <permalink|#チャンネル名> 送信者(9:12): 要件を 1 行 📝
• <permalink|DM 相手> 送信者(9:40): 要件を 1 行 📝(要確認あり)

通知のリンクを開くと、入力欄に返信例が入った状態になっています。いつもの入力欄で直して、自分で送信します。送信は Claude にはさせていません。

同じスレッドに下書きが既にあるなどで置けなかったときは、通知に返信例の全文を載せ、手でコピーして送ります。

通知は Slack の Incoming Webhook(bot)から送っています。自分のアカウントで投稿すると、自分へのメンションでも通知が鳴らないためです。

最初は「✅ で自動送信」にしていた

最初の版は、通知に ✅ を付けると、5 分ごとのジョブが元のスレッドに自分の名前で送る仕組みでした。二重送信を防ぐ記録や、手で返信済みなら送らない判定も入れていました。

ただ、返信例を直したいときは「通知のスレッドに直した文を書いてから ✅」と手間がかかります。しかも ✅ が無くても 5 分ごとに Claude Code が丸ごと起動していて、空振りでも 1 回あたり数十万トークン(ほとんどはキャッシュの読み込み)を使っていました。

下書きを元のスレッドに置く形に変えたことで、5 分ごとのジョブは要らなくなり、直すのもいつもの入力欄で済むようになりました。

4. 仕様ずれチェック(毎週月曜 10:00)

PR レビューが「マージ前の PR と Slack」を比べるのに対し、こちらは「マージ後の main と Slack」を比べます。最初は平日毎日にしていましたが、今は週 1 回にしています。

  1. 開発用のチャンネルの、前回の実行以降の投稿とスレッドを読み、仕様の話だけ抜き出す
  2. 発言ごとに、仕様書と実装を grep して、それぞれ何と言っているかを確かめる
  3. ずれの候補(Slack と仕様書、Slack と実装、仕様書と実装)ごとにサブエージェントを 1 体起動し、実ファイルを読んで「本当にずれているか、別の PR で解消済みでないか」を判定させる。実在したものだけ残す
  4. 前回から main に入った差分を、セキュリティレビュー用のエージェントに見せる。CRITICAL / HIGH の指摘は別のエージェントに実コードで確かめさせ、実在したものだけ残す
  5. 自分用チャンネルに 1 通で報告する。0 件でも「なし」と送る
@自分 仕様ずれチェック 11/2

*仕様ずれ* なし
*セキュリティ*(`<前回のSHA>..<mainのSHA>`)なし

調べるのは専用に作った worktree(main を detached で checkout)です。普段作業しているリポジトリには触りません。

候補を出すエージェントと、実在を確かめるエージェントを分けているのは、それっぽいだけの指摘を減らすためです。

無人で回すときに気をつけたこと

--allowedTools は最小にする

claude -p は対話できないので、許可されていない操作は実行できずに止まります。逆に言えば、許可した操作しかできません。ジョブごとに必要なコマンドだけを書いています。

run.sh(抜粋)
claude -p "$prompt" --allowedTools "Bash(date:*)" "Bash($dir/post.sh:*)" "Edit($out)" "${extra[@]}" "mcp__claude_ai_Slack"

ファイルの書き込みも、Edit(<状態ファイルのパス>) のようにファイル単位で絞っています。

状態はファイルに持つ

claude -p は実行ごとに記憶がありません。「どの PR をどの SHA でレビューしたか」「どの通知を送ったか」はファイルに書き、次の実行で読ませています。古い行は 24 時間で消しています。

スリープ明けに備える

launchd の StartCalendarInterval は、Mac がスリープ中に時刻が来ると、起きたときに 1 回だけ実行します(man launchd.plist)。cron と違い、朝 Mac を開いたときに 9:00 の分が走ります。

一方、スリープから戻った直後はネットワークがつながっていないことがあるので、実行スクリプトで 3 回まで再試行しています。

run.sh(抜粋)
for i in $tries; do
  if (cd ~ && $claude -p "$prompt" --allowedTools ...); then
    exit 0
  fi
  (( i < ${#tries} )) && sleep 60
done

launchd は「平日の毎正時」を 1 行で書けない

StartCalendarInterval は cron のような範囲指定ができないので、「平日 10〜19 時の毎正時」は「曜日・時・分」の組(plist の <dict>)を、曜日 5 × 時刻 10 で 50 個並べています。

定時のジョブは Sonnet で動かす

claude -p は、指定しなければ普段使いのモデルで動きます。Slack のジョブは --model sonnet を付けて、軽めのモデルで回すようにしました。

run.sh(抜粋)
claude -p "$prompt" --model sonnet --allowedTools ...

まとめ

  • 手順は Skill に書き、launchd からは claude -p "/<スキル名> を実行して" と 1 行頼むだけにする
  • 無人で動かすぶん、--allowedTools で書き込み先を絞る。GitHub は読み取りだけにして、結果は Slack に集める
  • 仕様は Slack で決まることが多いので、PR と main の両方を Slack と突き合わせる。どちらが正しいかは人が決める
  • 自分の名前で送るものは、Claude に送らせない。元のスレッドに下書きを置き、人が直して送る。分からない事実は 要確認 のまま残す
  • 始めたばかりなので、使いながら直している。頻繁に起動するジョブは、空振りのコストも見ておく

参考

6
1
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
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?