Gemini API×RSS×launchdで朝夕2回のAI日報を全自動生成するMac一次情報リサーチ術
作成日:
更新日:

Gemini API×RSS×launchdで朝夕2回のAI日報を全自動生成するMac一次情報リサーチ術


🔧 論旨

毎朝スマホを開いて SNS やまとめサイトを眺めていると、誰かのポジショントークや感情的な二次情報ばかりが目に入り、肝心の「世界で実際にどんな論文・特許・法律・予算が動いたのか」という一次情報になかなか辿り着けません。かといって海外の科学誌や公的機関のサイトを毎日手動で巡回するのは時間がいくらあっても足りません。

結論からお伝えすると、情報収集の質と時間を劇的に変える最適解は、「信頼できる一次情報の RSS フィードを Node.js で直接集め、Gemini API と macOS の launchd で毎日朝・夕 2 回、自分専用の分析レポートをローカルへ全自動生成する仕組み」 を組むことです。本記事では、スリープ復帰時の通信エラー対策からビルド破壊を防ぐ JSON 構造化出力まで、実稼働コードをベースに解説します。

🔧 合わせて読みたい深まる関連情報
🔧 対象となる方
  • SNS のノイズや扇情的なまとめ記事に疲れており、海外論文・特許・公的機関の一次情報だけを毎朝スッキリ把握したい 方

  • Gemini API と Node.js を使い、自分のブログや研究テーマに直結する「下書き(たたき台)」まで自動で用意させたい 方

  • Mac の launchd で定期スクリプトを組んだものの、スリープ復帰直後のネットワーク切断エラーや nvm のパス問題でつまずいた 方

SNSの二次情報疲れを断つ自分専用AI朝刊・夕刊

世の中の AI ニュース要約サービスや Web 上の定期タスク機能は便利ですが、情報源が一般的なニュースサイトに偏っていたり、要約結果がチャット画面の中に閉じ込められていたりするのが難点です。ローカルの Mac 上で RSS 巡回と Gemini API を直結させると、自由度と資産性が桁違いに高まります。

比較項目手動での SNS・ニュース巡回クラウド AI の定型スケジュール機能RSS × Gemini API × launchd(本方式)
情報源の純度煽りや感想・二次情報が混ざりやすい検索エンジンの上位記事に引っ張られる自分が厳選した論文・公的機関 RSS 100%
保存先と検索性流れて消える(あとから探せない)各 AI サービスの画面内に分散する手元の Markdown フォルダ&SQLite に永久蓄積
次工程への直結ゼロから自分で構成を考えて書くコピペして書式を手直しする手間が発生そのまま公開昇格できる MDX 下書きまで自動生成
スリープ時の挙動—クラウド側で実行されるMac を開いた瞬間に launchd が自動補完実行
質問するおじさん

朝起きてコーヒーを淹れとる間に、世界中の最新の論文や法改正が日本語のレポートになって手元のフォルダに届いとるわけじゃな。記者の感想文を全部カットして「数字と事実と出典 URL だけ出せ」と指示できるのが最高じゃわい。

解説ナビゲーター

まさに「自分専用の調査室」を Mac の中に持つ感覚ですね!しかも出力先を Astro サイトの非公開フォルダ(hidden: true)にしておけば、AI エディタからも即座に全文検索して執筆の根拠データとして使えるんです。


一次情報RSS×Gemini API自動生成の全体像

論文・特許・法制を直結する12系統RSS設計

どんなに優秀な AI モデルを使っても、入力する材料(ゴミデータ)が悪ければ出力も薄っぺらくなります。そこで巡回対象の RSS リストには、ゴシップや一般コラムを含まない「科学論文・知財・国際機関・技術コミュニティ」を中心に 12 系統を登録し、直近 24 時間以内に公開された記事だけを抽出しています。

毎日朝・夕2回稼働する一次情報リサーチ&下書き自動生成パイプライン
Step 1
12系統RSS巡回

Nature、arXiv、IPWatchdog、EU議会、IMF、国内行政動向などから最新記事を収集します。

Step 2
戦略日報の生成

Gemini APIで記者の主観を排除し、統計・予算額・法案の一次事実のみを出典付きでレポート化します。

Step 3
JSON構造化抽出

記事化すべき重大テーマがあれば、JSONスキーマ指定で各章のパーツを抽出します。

Step 4
内部資料へ保存

公開ディレクトリを汚さず、hidden: true 付きのMD/MDXとして内部資料フォルダへ安全保管します。

APIのレート制限と混雑を避けるため、1段目と2段目の間に10秒のインターバルを挟んでいます

モデル呼び出し部(generateWithArgonOnly)では、下位モデルや旧世代モデルへ安易に自動フォールバックさせると分析の鋭さが落ちたり引退済みモデルへのリクエストで無駄なエラーを招いたりするため、使用するモデルは最上位の gemini-4-argon 一択に完全固定 しています。スリープ復帰直後のネットワーク瞬断(fetch failed)や一時的な API 混雑(HTTP 429 / 503 エラー)が起きた場合も、他モデルへ妥協切り替えせず DNS 疎通の再確認と指数バックオフ待機(12 秒 → 25 秒 → 45 秒)を挟んで gemini-4-argon 単体で粘り強く再試行する安全網を組んでいます。

MDX構文破壊を防ぐJSON構造化テンプレート合成

この自動生成システムを運用する中で一番の学びになったのが、「AI に直接 .mdx ファイル全文をフリーテキスト出力させてはいけない」 という教訓です。

Astro の MDX コンパイラは構文に非常に厳格です。AI に Markdown や MDX を丸ごと書かせると、YAML フロントマターの references 内にコロン(:)が混ざってパースエラーになったり、見出しに勝手な番号や ** が入って目次ルールから外れたりする事故が一定の確率で起きます。

AIによる下書き生成の失敗パターンと鉄壁の構造化パターン
設計の分岐点
構文エラー多発
NG:MDX全文をAIに直接書かせる
  • YAMLフロントマター内の引用符抜けやコロン混入でビルドが停止する
  • 見出しの文字数上限(30文字)や禁止記号のルールを時々破る
  • コンポーネントの import パスや閉じタグを書き間違えるリスクがある
ビルド破壊ゼロ
OK:JSONで受け取り関数で流し込む
  • responseMimeType: “application/json” で各章の本文テキストだけを受け取る
  • フロントマターは JSON.stringify() で100%安全にエスケープする
  • 見出しは sanitizeHeadingSuffix() で記号除去と文字数切り詰めを機械保証する

具体的には、以下のように AI からは純粋な JSON オブジェクトのみを受け取り、JavaScript 側のテンプレート関数で安全な MDX へ組み立てています。

// 見出しサフィックスから禁止記号を除去し、文字数上限以内に収める機械ガード
function sanitizeHeadingSuffix(rawSuffix, fallbackText, prefixLength = 3, maxTotalLength = 30) {
  let s = String(rawSuffix || "")
    .replace(/\r?\n/g, " ")
    .replace(/\*\*/g, "")
    .replace(/<\/?[a-zA-Z][^>]*>/g, "")
    .replace(/\{[A-Za-z0-9_$.]+\}/g, "")
    .replace(/^(?:\d+[\.\))\s::]|[①-⑳]|■|◆|●|▼|▶)+/, "")
    .trim();
  if (!s) s = fallbackText;
  const maxChars = Math.max(8, maxTotalLength - prefixLength);
  const chars = [...s];
  return chars.length > maxChars ? chars.slice(0, maxChars).join("") : s;
}

// Gemini API 呼び出し時は JSON MIME タイプを指定して構造化データのみを受け取る
const rawResp = await ai.models.generateContent({
  model: "gemini-4-argon",
  contents: prompt,
  config: {
    responseMimeType: "application/json",
    thinkingConfig: { thinkingLevel: "high" },
  },
});

この「AI には中身の論理と文章だけを考えさせ、器(構文・フロントマター・タグ)は決定論的なコードで組む」という役割分担にして以降、ビルドエラーは完全にゼロになりました。


Macのlaunchdで毎日2回安定稼働させる急所

スリープ復帰直後のDNS失敗を防ぐ60秒待機処理

定期実行のスケジューラには、昔ながらの cron ではなく macOS 標準の launchd(~/Library/LaunchAgents/*.plist) を使います。最大の理由は、夜間や外出中に Mac をスリープさせていても、スリープから復帰した瞬間に「寝ている間に逃したスケジュール分」を自動で補完実行してくれる からです。

ただし、ここに Mac 特有の有名な落とし穴があります。Mac の画面を開いてスリープから復帰した直後の数秒間は、まだ Wi-Fi や有線 LAN の再確立が終わっておらず、launchd が即座に Node.js スクリプトを走らせると ENOTFOUND(DNS 名前解決エラー)で即死してしまう のです。

質問するおばさん

「手動でコマンドを打つとちゃんと動くのに、朝 Mac を開いたときの自動実行だけ毎回エラーログが出ている!」という現象の正体はそれだったのね!

解説ナビゲーター

大正解です!スクリプトの冒頭に、Google API サーバーの名前解決が通るまで 3 秒おきに最大 60 秒間じっと待つ waitForNetwork() を 1 つ挟むだけで、スリープ復帰直後の失敗がピタッとなくなりますよ。

import dns from "node:dns/promises";

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// スリープ復帰直後のWi-Fi/LANリンク確立を最大60秒待機するガード
async function waitForNetwork(maxRetries = 20, intervalMs = 3000) {
  for (let i = 1; i <= maxRetries; i++) {
    try {
      await dns.lookup("generativelanguage.googleapis.com");
      return true;
    } catch {
      console.log(`[Network] 接続待機中... (${i}/${maxRetries})`);
      await sleep(intervalMs);
    }
  }
  return false;
}

3時間クールダウンとnvm絶対パス指定の鉄則

さらに毎日気持ちよく動かし続けるために、以下の 3 つの工夫を .plist とスクリプトの双方に入れています。

🔧 ⚙️ launchd定期実行で失敗しない3つの実践ノウハウ
  1. 実行時刻は「00分ちょうど」を避けて朝 06:17・夕方 18:23 に散らす : 世界中のボットやバッチ処理が集中する毎時 00分 や 30分 は、RSS 配信元サーバーも Gemini API も一時的な混雑(503 エラー)を起こしやすくなります。中途半端な分(17分 や 23分)にずらすだけで成功率がぐっと安定します。

  2. 3 時間の重複実行クールダウンを入れる : 朝と夕方の両方とも逃していた場合やプロセス再読み込み時に、数秒差で連続実行されて API 枠を無駄遣いしないよう、出力先ファイルの更新時刻(mtimeMs)を確認し、「直近 3 時間以内に生成済みならスキップする(手動強制実行は --force)」 というガードを入れています。

  3. nvm 環境の Node パスと .env は必ず絶対パスで明示する : launchd はターミナルの .zshrc を読み込まないため、node とだけ書くと「コマンドが見つかりません」になります。which node で調べたフルパスを ProgramArguments に記述し、スクリプト側でも path.join(__dirname, '../.env') で環境変数を確実にロードします。

実際に使用している LaunchAgent 設定ファイル(パスは汎用表記)は以下の通りです。朝刊で海外の深夜動向をキャッチし、夕刊で国内の最新発表を上書き更新する 1 日 2 回体制が最もリズムよく機能しています。

<?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.example.daily-ai-news</string>

    <key>ProgramArguments</key>
    <array>
        <string>/Users/yourname/.nvm/versions/node/v24.20.0/bin/node</string>
        <string>/Users/yourname/Desktop/my-blog/scripts/generate_daily_ai_news.js</string>
    </array>

    <key>WorkingDirectory</key>
    <string>/Users/yourname/Desktop/my-blog</string>

    <key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Hour</key>
            <integer>6</integer>
            <key>Minute</key>
            <integer>17</integer>
        </dict>
        <dict>
            <key>Hour</key>
            <integer>18</integer>
            <key>Minute</key>
            <integer>23</integer>
        </dict>
    </array>

    <key>StandardOutPath</key>
    <string>/tmp/daily-ai-news.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/daily-ai-news.err.log</string>
    <key>ProcessType</key>
    <string>Background</string>
</dict>
</plist>
ノルウェージャンフォレストキャット

みんなが押し寄せる 00 分を避けて 6 時 17 分にこっそり新聞を取りに行くなんて、賢い早起き猫のワザでちね!


まとめ:情報の受け手から一次情報の分析者へ変わる

毎日流れてくる大量のニュースを自分の目と指で追いかけ続けるのは限界がありますが、集める場所(一次情報 RSS)と分析の軸(プロンプト)さえ自分で設計してしまえば、AI は 365 日休まず働く優秀な専属リサーチャーになってくれます。まずはあなたの関心分野の RSS を 5〜10 個選び、毎朝 1 枚の Markdown 日報が自動で届く心地よさ を体験してみてください。

🔧 ✅ 本システムで幸せになる人・向かない人
  • 導入して幸せになる人 : 専門分野の最新論文・法改正・技術トレンドを出典付きで漏れなく把握し、ブログ執筆や研究開発のネタ帳を自動で育てたい Mac ユーザーの方

  • 別の選択肢が向く人 : API キーの発行やターミナル設定を行わず、スマホアプリの手軽なニュース通知だけで十分な方

ご自身の Mac とブログ・ノート環境(Astro、Obsidian、Notion 用 Markdown など)に合わせてこの自動日報システムを構築したい方は、以下のプロンプトをコピーして AI エディタへ渡してみてください。

🔧 🤖 自分の環境に合わせてAIに構築させるコピペ用プロンプト

※launchd のパス解決や API レート制限・JSON スキーマ設計をミスなく一発で組ませるため、必ず 『Gemini 4 Argon』(または同等以上の最上位推論モデル)を選択して実行してください。

以下の記事の設計にもとづき、私の Mac 環境に「一次情報 RSS × Gemini API × launchd による朝・夕2回の自動リサーチ日報システム」を構築してください。
参照URL: https://lab.chihouzakki.com/blog/review/gemini-api-rss-launchd-daily-research-automation/

【作業ルール(厳守)】
1. まず私の Mac の node 実行ファイルの絶対パス(which node)、保存したいフォルダ構成、.env の有無を確認し、実装計画と巡回したい RSS ジャンルの案を提示して私の合意を得てください。
2. スクリプトには必ず ①スリープ復帰直後のDNS待機処理(waitForNetwork)、②短時間の重複実行を防ぐクールダウン判定、③API使用モデルを gemini-4-argon 一択に固定した上での通信瞬断・混雑時の指数バックオフ再試行(下位モデルへのフォールバック禁止)、④構文エラーを防ぐ JSON 構造化出力(Structured Outputs)を組み込んでください。
3. API キーは絶対にコードへ直書きせず .env(.gitignore 対象確認必須)から読み込む設計とし、テスト実行(--force)で正常出力を確認してから launchd 登録手順を案内してください。

ノイズだらけのタイムラインから卒業して、澄み切った一次情報で 1 日を始める習慣を手に入れましょう!

朝の光が差し込む部屋で遠くを凛々しく見つめるノルウェージャンフォレストキャット

▲ 朝起きたときにはもう、世界の動きが1枚のレポートに整理されています