作業環境・自動化

起きたらDiscordに在庫レポートが来てた——Python+launchd朝イチ通知の作り方

起きたらDiscordに在庫レポートが来てた——Python+launchd朝イチ通知の作り方

この記事は約 6 分で読めます

📖 目次
  1. 📌 朝起きたら届いていたもの
  2. 📌 動いている環境
  3. 📌 その朝のエラー3連発
  4. 📌 通知が届くまでの仕組み
  5. 📌 件数が増えても中身は追いつかない
  6. 📌 問題が見えるだけで動ける

最終更新: 2026-04-28

4/19の朝、スマホを掴んだ瞬間にDiscordのバッジが光っていた。Bot通知だった。在庫の件数とエラーが一画面に収まっていて、PCを開く前に今日やることが全部わかった。これをどう組んだか、その途中で何が壊れたかを書く。


朝起きたら届いていたもの

こういう通知が来ていた。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
☀️ 04/19 (日) おはようございます
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 今すぐやること
📌 X承認待ちが12件あります → !xapprove で確認
📌 YouTubeの在庫が空です → /youtube-mbti で台本を生成
📌 エラーが発生しています → 下のエラー欄を確認

📦 コンテンツ在庫
🟢 ブルースカイ 39件
🟢 X(エックス) 22件 うち承認済み 12件、未承認 10件
🟢 note 41件
🟢 ブログ 17件
🔴 YouTube 0件

⚠️ 昨夜のエラー(1件)
• KDP:ブラウザ操作がタイムアウト → KDPのページを手動で確認推奨
━━━━━━━

PCを開かなくていい——それが一番の変化だった。以前はターミナルを立ち上げてファイルをgrepして、どのキューが何件かを目で追っていた。今はベッドの上でこれを読んで、今日どこから手を付けるか決めて起き上がる。

動いている環境

MacBook Pro M5 32GBで動かしている。Discord Bot本体は 01_Scripts/discord_bot/bot.py、Python 3.11。定時起動はlaunchdに任せていて、crontabは使っていない。コンテンツ生成側ではClaude Sonnet 4.6を呼んでいるが、通知スクリプト自体はAPIを一切叩かない。JSONを読んで件数を数えてDiscordに投げるだけ——それだけの処理にAPIコストをかけるのは無駄だと判断した。

その朝のエラー3連発

通知に出ていた問題が3つ重なっていた。X承認待ち12件、YouTube在庫ゼロ、KDPタイムアウト——三連発。

X側は !xapprove コマンドでDiscord上から承認・却下できる設計にしているが、前日の夕方から確認をサボっていたので積み上がっていた。12件は1日放置した結果で、経験上2日放置すると30件を余裕で超える。どこかで手動でドバっとさばく羽目になって、中身をちゃんと読まなくなる——というループにそろそろ気づいていた。

YouTubeだけゼロなのは生成コストの問題だ。台本1本あたりの処理時間がBSkyやXの5〜8倍かかる。他のキューは自動補充されていくのにYouTubeだけ /youtube-mbti スキルを手動で叩かないと増えない。ここはまだ自動化しきれていない——正直後回しにしている。

一番厄介だったのがKDPのタイムアウトだった。PlaywrightでKDPの出版フォームを操作しているが、前夜のどこかでブラウザが応答しなくなって処理が止まっていた。エラーログには TimeoutError: Locator.click: Timeout 30000ms exceeded が残っていて、セレクタ自体は正しい。KDP側のUIが重い時間帯に当たった可能性が高い。自動リトライは3回で打ち切る設計なので、それ以上は手動確認になる。

通知が届くまでの仕組み

Bot本体がやっていることは単純で、各キューのJSONファイルを読んで件数を数えて、24時間以内のエラーログを引っ張ってDiscordに投げる。以上。

# 各ストックファイルから件数を集計
bsky_count = len(load_queue("bsky_queue.json"))
x_count    = len(load_queue("x_queue.json"))
note_count = len(load_queue("note_queue.json"))
blog_count = len(load_queue("blog_queue.json"))
yt_count   = len(load_queue("youtube_queue.json"))

# エラーログを直近24時間分だけ拾う
recent_errors = get_recent_errors(hours=24)

定時起動はlaunchdのplistで毎朝7:00に設定している。crontabではなくlaunchdにしているのは、Macがスリープ中でもスリープ明け直後に遅延実行してくれるから。crontabだとスリープ中のジョブは黙って取りこぼす——これを知らずにcrontabで組んでいた時期は「なぜ朝に通知が来ない日があるのか」が全然わからなかった。

実装自体は1時間かからなかった。詰まったのはDiscordへの送信部分ではなく、launchdのplist書き方だった。StartCalendarInterval の辞書の記述が微妙にXMLの仕様と噛み合わなくて、最初の試行では全く起動しなかった。launchctl list | grep morning で確認すると登録はされているのに実行されていない——というよくわからない状態が続いた。原因はplistのインデントが壊れていたせいで、plutil -lint com.taito.morning_report.plist を実行したら一発でエラー箇所が出てきた。

件数が増えても中身は追いつかない

件数が増えることと使える在庫が増えることは、別の話だ——通知を毎朝見ていてようやく実感した。

その日の !xapprove で12件を確認したとき、中身を読んだら専門用語が詰まりすぎていた。「Claude Sonnet 4.6のtool_use実装でlatencyが〜」みたいな投稿が3本連続していて、これを見る人の9割はエンジニアではない。生成プロンプトには「一般向けに書く」と明示してあるのに、Ollama qwen2.5:3bが噛んだ部分は技術寄りになる傾向がある。ClaudeとOllamaを混在させているせいで文体が揺れる問題が残っている。

件数だけ追っていると中身の劣化に気づかない。承認ゲートがあるのに「承認済み」が12件積み上がっているということは、私がまとめてさばいていてちゃんと読んでいないということでもある。次に手を入れるのはプロンプトより承認フローの方かもしれない、と思い始めている。

問題が見えるだけで動ける

PCを立ち上げる前に優先度が決まる——それだけで朝の動き方が変わった。YouTubeが空、KDPがタイムアウト、Xに12件詰まっている。状況が見えているだけで、とりあえず何から手を付けるかが決まる。

ただ件数が増えても中身が追いつかない問題は残る。在庫が39件あっても文体がバラバラなら意味が薄い。次はOllama生成分の文体をClaude Sonnet 4.6で後処理して平滑化するか、承認フロー自体を見直すか——どちらかに手を入れる予定でいる。

一ノ瀬泰斗のアバター
一ノ瀬泰斗
AI自動化エンジニア / Python個人開発者

Claude Code × Ollama × launchd で SNS・ブログ・KDPを全自動化。実測データと失敗談を軸に、月5万円収益化のリアルな記録を発信中。

💬 自動化の相談・小規模受託も受付中:「launchd で毎朝 AI が動く仕組みを作りたい」「KDP の自動出版を組みたい」など、X (@taito_automate) の DM からお気軽にどうぞ。

✨ AUTHOR'S KDP BOOKS

かかる人向ケ、10分でわかるAI自動化入門

Claude Code / Ollama / launchd の実践テクニックをコンパクトにまとめたシリーズ。非エンジニアの会社員向けに書いてます。

Amazonで見る ›

✨ FOLLOW ME

AI自動化の実験・失敗・実測データを毎日発信中

𝕏 フォローする