AIとの対話で「RSS週次要約」ツールを作った:設計からlaunchdまで一気に形にした記録

RSSで収集した新規記事の要約を自動作成するプログラムを作成 バイブコーディング実例

以前、「確実に更新を確認したい情報源」からの情報をRSSで収集する記事を書きました。AIで収集してもらってもいいのですが、「この情報源から確実に」となると、やはりRSSの方が信頼できる、というのがキモでした。

RSSで更新を自動収集する:情報収集の「入口」を固定して探す時間を減らす(Feedly/Inoreader→Zotero/Notion)

一方で、RSSで入ってくる情報を全てチェックするのも結構面倒・・・。そこで、RSSから入ってきた新規の情報を、定期的に要約してまとめてくれるプログラムを作成することにしました。

RSSで収集した情報を自動で要約してもらう

「ObsidianのLocal RSSで00Inbox/RSSに保存されているRSSのmdを、毎週金曜AM9:00に、直近1週間分だけGeminiCLIで要約して、同じフォルダにObsidianリンク付きの要約mdを出したい。」

この記事では、そのツールを AI(Cursor)との対話だけで 設計から実装、launchdでの自動実行まで一気に形にした過程をまとめます。コードを書く前に「どうしたらいいか考えて、まだ実装はしないで」と頼んだところから始まり、確認事項への回答を経て実装、利用前のセットアップ、そして「plistの認証・launchdへの読み込み・動作確認までやって」と頼んで完了するまでを、そのままブログ用に再構成したものです。

Local RSS プラグインについて

今回のプログラムが対象にしているのは、Obsidian のコミュニティプラグイン「Local RSS」 が取得・保存した md ファイルです。

Local RSS は、RSS フィードを配信しているサイトの記事を、Obsidian の Vault 内にマークダウン(.md)としてローカル保存するプラグインです。Feedly や Inoreader のような専用リーダーではなく、Obsidian 内で「RSS の更新を md として溜める」ことができます。出力 先フォルダは設定可能で、各記事にはタイトル・公開日(publish_date)・著者・概要などのプロパティが frontmatter で付きます。Obsidian の Bases と組み合わせると、カードビューで一覧表示したり、公開日で並び替え・フィルタしたりすることもできます。

作成者・松濤 Vimmer 氏によるプラグインの紹介記事はこちらです。
RSSをローカル取得できるObsidianプラグインを開発しました!(note)

要点まとめ(先に結論)

RSS要約ツールでやりたいこと
  • やりたいことを「入力・処理・出力・スケジュール」に分解して設計メモにまとめ、確認したいこと(フォルダ名、日付の持ち方、launchdでGeminiCLIが動くか)を先に明文化した。
  • 実装はMacAutomator配下のプロジェクトフォルダ(RSSWeeklyDigest)に集約。Pythonで「publish_dateが直近7日」のmdを列挙→収集→GeminiCLI(標準入力+-p)で要約→要約mdを保存、までを一本のスクリプトにした。
  • 認証は「Login with Google」のキャッシュで十分で、APIキーは必須ではない。launchdから動かすときは PATH(node を通す)をplistに追加する必要があった。

PGP(Personal Growth & Productivity)としての位置づけ

PGPは、機微情報の線引きを前提に、知的労働を「続く形」に整えるブログです。
今回の話は、情報収集の出口(週次で何を読むか)を自動でまとめるところまで寄せた一例で、「RSSで入口を固定する」記事や「未読をAIで要点化する」記事の延長にあります。

ステップ1:設計だけ先にやる

バイブコーディングの3ステップ

最初の設計プロンプトと回答

最初に頼んだのは「実装はしないで、どうしたらいいか考えて教えて」でした。実際にCursorに投げたプロンプトは以下の通りです。最近感じるのは、いきなり実装するよりも、最初は設計プランだけを立てるようにした方が、設計時点でのエラーに気づきやすかったり、最終的にできるものの質が高い気がしています。

ObsidianのLocal RSSというコミュニティプラグインで現在いくつかのRSSからの情報を"00inbox/RSS"にmdファイルとして保存するようにしている。

このPCにインストールされているGeminiCLIを用いて、毎週金曜日のAM9:00に、直前一週間に更新されたRSS情報の要約を、該当するmdファイルへのObsidianリンクを添えて、"00Inbox/RSS"フォルダ内にmdファイルとして作成してほしい。

これを実現するにはどうしたらいいか考えて教えて。まだ実装はしないで。

“00Inbox”というのは、私のObsidianのVaultにあるフォルダで、とりあえずの情報保管庫になります。このフォルダ内に”RSS”というフォルダを作成し、Local RSSで指定しているサイトの新着記事をmdファイルとして取り込むように設定しています。

こういうプログラムを作成するときに大事なことは、「いわゆるプログラムで対応可能な作業」か、「AIに依頼すべき作業」かの分離と思っています。例えばこのプログラムでは、特定のフォルダの特定属性のファイルを参照することは、いわゆるプログラムで対応可能な作業になります。一方で各記事の要約をする作業はいわゆるプログラムでは不可能で、生成AIにしてもらう必要があります。その場合、「プログラムから呼び出せる生成AI」を自分のPCに準備しておき、それを使用するよう指示しておくのが良いでしょう。

そうこうしているうちに、Cursorが”00Inbox/RSS”にあるmdファイルの形式や、私のMacBookでのGemini CLIのインストール状況を確認し、このプログラムの実現方法について回答をくれます。

実現の流れ(5ステップ)

  1. 対象mdの特定
    直近1週間に更新された(mtime または Local RSS の日付).md を 00inbox/RSS(または 00Inbox/RSS)から列挙する。
  2. 内容の収集
    各mdの「ファイル名・タイトル・本文(または抜粋)」を1つのテキストにまとめる。Obsidianリンク用にファイル名を控えておく。
  3. GeminiCLIで要約
    そのテキストをパイプまたは -p / -f で渡し、
    「各項目を1〜2行で要約し、Obsidianのウィキリンク [[ファイル名]] を必ず付けてMarkdownで出力せよ」というプロンプトで要約させる。
    –markdown でMarkdown出力にする。
  4. 要約mdの保存
    標準出力を 00Inbox/RSS/RSS週次要約_YYYYMMDD.md のような名前で保存する(日付は実行日=金曜)。
  5. 金曜9:00の自動実行
    launchd で、上記1〜4を行うスクリプトを毎週金曜 9:00 に実行する。
    plist は ~/Library/LaunchAgents/ に置き、StartCalendarInterval で Weekday=5(金)、Hour=9、Minute=0 を指定する。

流れはいい感じですね。私の希望の要件を満たしてくれているように思います。

今回は要約にGeminiCLIを使用するよう指定しました。こういうプログラムを作成する際は、pythonで呼び出せるAIを利用するので、私の環境だとLM Studioに入れているOSSかGeminiCLIになります。今回は元々webから収集した公開情報の要約作成を行うので、学習に使われたり外部サーバーに送られても問題ないため、より高い精度と速度が期待できるGeminiCLIを要約用AIに選びました。

使う技術

  • 対象の絞り込み: ファイルの mtime(推奨)か、Local RSS が frontmatter に書く日付。
  • GeminiCLI: 非対話モード(パイプ or -p / -f)、–markdown で要約+リンク付きMarkdownを取得。
  • スケジュール: macOS の launchd(cron より推奨)。

mtime(modification time)はファイルを最後に更新した日時です。Local RSS で保存した md は取得したタイミングで更新されるため、この日付で「直近1週間」を判定できます。launchd は macOS 標準のスケジューラで、cron より推奨されており、指定した日時にジョブを実行できます。

実装前に確認したいこと

  • フォルダ名: 実際のVaultでは 00inbox/RSS か 00Inbox/RSS か(大文字小文字をスクリプトと揃える)。
  • Local RSSの保存形式: ファイル名の規則、日付が frontmatter のどのキー(またはファイル名)に入るか。
    → 「直近1週間」を mtime で取るか、frontmatter の日付で取るかを決める。
  • GeminiCLI: コマンド名(gemini かフルパスか)、launchd から実行したときに認証や環境変数が通るか。

実装せずに設計だけを依頼すると、こちらの指示プロンプトで曖昧だった点について実装前に確認してくれます。よく見ると確かにプロンプトでフォルダ名の大文字・小文字が一貫していませんでしたね。

注意点
1週間分をまとめて渡すと長くなりがちなので、件数上限(例: 50件)や本文の文字数上限を設けると安全。
Obsidianリンクは、要約も同じフォルダに出すなら [[ファイル名]] で足りることが多い(必要なら [[00inbox/RSS/ファイル名]] に変更可能)。

細やかな注意までありがたい限り。

Cursorからの確認事項に回答

設計を進めるため、Cursorからの確認事項に回答する以下のプロンプトを投げます。

確認したいことについて回答します。

- フォルダ名: 実際のVaultでは 00inbox/RSS か 00Inbox/RSS か(大文字小文字をスクリプトと揃える)。
⇨実際には00Inbox/RSSと大文字ですね。

- Local RSSの保存形式: ファイル名の規則、日付が frontmatter のどのキー(またはファイル名)に入るか。
→ 「直近1週間」を mtime で取るか、frontmatter の日付で取るかを決める。
⇨ファイル名は元のhtmlのタイトルのようです。mdファイルの"publish_date"というプロパティに日付がありますね。
直近一週間の決め方は任せます。

GeminiCLI: コマンド名(gemini かフルパスか)、launchd から実行したときに認証や環境変数が通るか。
⇨ターミナルからはgeminiで行けますが、launchdからはどうかがわかりません。確認して。

この辺りでも、自分で決定できることは決めてしまいますが、よくわからない、あるいはどちらでもいいことについては任せるような回答をします。すると、早速以下のように設計を修正してくれました。

設計メモに反映した内容

  1. フォルダ名
    00Inbox/RSS(大文字 I)に統一し、セクション0「確認済み事項」に追記しました。
  2. Local RSS の保存形式
    ファイル名: 元の HTML タイトル由来
    日付: frontmatter の publish_date
    「直近1週間」は publish_date で判定する方針にし、対象 md の特定(3.1)と実装順序案(6)をその前提で書き換えました。
  3. GeminiCLI と launchd
    確認結果を「3.3 GeminiCLI」「3.5 launchd」「4. launchd から GeminiCLI を動かすための確認結果」に反映しました。

こちらの指示に従いつつ、任せた部分は自分できちんと解決してくれたようです。

launchd から GeminiCLI を動かすための結論

  • PATH
    launchd はログインシェルの PATH を継承しないため、gemini だけでは見つかりません。
    この環境では gemini は [geminiのファイルパス] にあったので、スクリプト内ではこのフルパスで実行するように設計メモに書きました。
  • 認証
    ヘッドレスでは GEMINI_API_KEY が必須です(Google AI Studio で取得)。
    plist の EnvironmentVariables に GEMINI_API_KEY を入れる
    またはスクリプト先頭で source ~/.config/gemini-rss-digest.env のように読み込む
    plist にキーを書く場合は chmod 600 で plist を保護する旨も追記しました。
  • 動作確認
    実装後は launchctl startで手動実行し、標準出力・標準エラーをログファイルにリダイレクトして確認するとよい、とメモに書きました。

GeminiCLIのlaunchdからの実行について、調べて解決してくれたようですね。

設計メモの該当ファイルは
PGP/20260202_RSSワークフロー/20260202_RSS週次要約GeminiCLI設計メモ.md です。実装時は「0. 確認済み事項」と「4. launchd から GeminiCLI を動かすための確認結果」を参照してください。

ここで問題に気づきました。私はいつも作業自動化用のプログラムは、ObsidianのVault内にある“MacAutomator”というフォルダ内でプロジェクトフォルダを作成して実装しているのですが、設計メモを含むプロジェクトフォルダがこのブログ投稿作成用のフォルダ”PGP”に作られてしまっています。

この辺りのプログラム作成場所についてはCursorのrulesで定義しておいたつもりですが、ちょっと不思議な挙動ですね。まあこんなこともあります。ということで、Cursorに以下のように修正を指示し、プログラムのプロジェクトフォルダを移動させました。

設計メモの保存場所が今のままではまずいでしょう。MacAutomatorフォルダ内に、適切なプロジェクト名のフォルダを作成し、そちらに設計メモを移してください。また、ここから先の実装作業もそちらのプロジェクトフォルダで行いましょう。

すると、

  • プロジェクト名: RSSWeeklyDigest(MacAutomator/RSSWeeklyDigest/)
  • 中身: 設計メモ.md、README.md

とプロジェクトフォルダと必要ファイルを作成してくれました。

ステップ2:プログラムの実装

さて、そろそろ面倒になってきたので、実装してもらうことにしました。

実装して。

なんともそっけないプロンプトですが、ここまでで設計メモを作成しているので、これで十分だったりします。しばらくCursorがコーディングしてくれた後、

実装内容

  1. 追加・更新したファイル
    ファイル 説明
    config.json.example rss_folder(00Inbox/RSS の絶対パス)、gemini_cli_path、days_back(7)、max_items(50)、max_chars_per_item(1500)などのサンプル
    rss_weekly_digest.py メインスクリプト。対象 md の列挙(publish_date で直近 N 日)、収集、GeminiCLI 呼び出し、要約 md の保存
    com.rssweeklydigest.plist.example 毎週金曜 9:00 実行用の launchd plist(GEMINI_API_KEY は要編集)
    要件定義書.md 入力・出力・設定・launchd の要件
    README.md セットアップ・手動実行・launchd の手順を追記
    .gitignore config.json と *.log を除外
  2. スクリプトの動き
    config.json を読み、rss_folder などを取得
    rss_folder 内の .md を走査し、frontmatter の publish_date が直近 days_back 日(デフォルト 7 日)以内のものを列挙(RSS週次要約_ で始まるファイルは除外)
    各 md から「ファイル名(拡張子なし)・タイトル・本文抜粋」を集め、1 本のテキストにまとめる(1 件あたり最大 max_chars_per_item 文字、最大 max_items 件)
    そのテキストを一時ファイルに書き、GeminiCLI を -f と –markdown で呼び出し、要約+[[ファイル名]] 形式の Markdown を取得
    出力を 00Inbox/RSS/RSS週次要約_YYYYMMDD.md に保存
    対象が 0 件のときは GeminiCLI は呼ばず、ログだけ出して正常終了します。
  3. 動作確認
    config.json.example を config.json にコピーした状態で実行し、「直近7日間に publish_date のあった md がありません。終了します。」で正常終了することを確認しました(00Inbox/RSS に該当 md が無い想定)。

勝手にいろんなファイルを作ってくれていますが、これもCursorのrulesでプログラム作成時のルール(README・要件定義書の必須、設定はjsonで管理、gitから除外など)を元々指示しているため、こちらが何も言わなくてもやってくれています。こういう設定がAIエージェントを使う上ではとても大事だな、と最近感じています。

利用前にやること

  1. config.json を用意
    cp config.json.example config.json のあと、rss_folder を実際の 00Inbox/RSS の絶対パスに合わせて編集。
  2. 手動で 1 回実行
    export GEMINI_API_KEY=… を設定してから
    python rss_weekly_digest.py を実行し、要約 md が 00Inbox/RSS に出力されるか確認。
  3. launchd で金曜 9:00 に回す場合
    com.rssweeklydigest.plist.example を ~/Library/LaunchAgents/com.rssweeklydigest.plist にコピーし、YOUR_GEMINI_API_KEY を実際のキーに書き換え → launchctl load ~/Library/LaunchAgents/com.rssweeklydigest.plist で有効化。
    詳細は README.md と 要件定義書.md を参照してください。

利用前の設定について指示されました。が、AIに指示されたからといって愚直に自分でやる必要はありません。ここまでで設定を色々伝えているので、次のプロンプトで十分です。

利用前にすることを実施して。

すると、実際に上記の3つの手順をやってくれます。しばらくすると、実施結果を教えてくれました。

実施済み(こちらで対応したこと)

  1. config.json
    既に存在し、rss_folder は [ObsidianのVaultのパス]/00Inbox/RSS のまま利用可能です。
  2. スクリプトの修正
  • サブフォルダ対応: 00Inbox/RSS 直下だけでなく、 PGP/ などサブフォルダ内の .md も対象になるよう、glob(“.md”) を rglob(“.md”) に変更しました。
  • GeminiCLI の呼び出し: この環境の GeminiCLI には -f / –markdown が無いため、標準入力で本文を渡し、-p でプロンプトを渡す形に変更しました(cat file | gemini -p “…” 相当)。
  1. launchd plist
    com.rssweeklydigest.plist.example を
    ~/Library/LaunchAgents/com.rssweeklydigest.plist にコピー済みです。
  2. 利用前チェックリスト
    MacAutomator/RSSWeeklyDigest/利用前チェックリスト.md を作成し、「実施済み」と「あなたが実施すること」を書いてあります。

おお、すごいですね。RSS格納フォルダを確認したところ、直下にmdファイルがなく、サブフォルダ内にmdファイルがあることに気づき、プログラムを修正してくれました。

しかし、まだできおらず、私に何か実施するように求めてきています。AIが人間様を使おうとするとは小癪な・・・!

あなたが実施すること

  • GEMINI_API_KEY の設定
    Google AI Studio で API キーを取得し、手動実行時は
    export GEMINI_API_KEY=”あなたのキー”
    を設定してから python rss_weekly_digest.py を実行してください。
  • 手動で 1 回実行(推奨)
    成功すると 00Inbox/RSS/RSS週次要約_YYYYMMDD.md が作成されます。
  • launchd で金曜 9:00 に回す場合
  1. ~/Library/LaunchAgents/com.rssweeklydigest.plist を開き、YOUR_GEMINI_API_KEY を実際のキーに置き換える
  2. chmod 600 ~/Library/LaunchAgents/com.rssweeklydigest.plist で保護
  3. launchctl load ~/Library/LaunchAgents/com.rssweeklydigest.plist で有効化
    詳細は MacAutomator/RSSWeeklyDigest/利用前チェックリスト.md を参照してください。

おっと、ここで気づきました。GeminiCLIの使用にAPIキーを求めてきていますね。しかし、私はいつもGeminiCLIはAPIキーではなく、普通にアカウントログインして使用しています。そのため、Cursorに以下を伝えます。

このPC内で、gemini CLIはGoogle AI StudioのAPIキーがなくても使えるのでは?

その後、実際にGeminiCLIの利用方法について検索・確認してくれました。

その理解で問題ありません。
公式ドキュメントの内容
通常利用: 「Login with Google」でログインすると、認証情報がローカルにキャッシュされる。
ヘッドレスモード: 「既にキャッシュされている認証情報があれば、それを使う」と明記されている。
そのため、このPCで一度でも gemini を起動して「Login with Google」でログインしていれば、Google AI Studio の API キーは不要で、スクリプトや launchd からのヘッドレス実行でもキャッシュが使われます。
このPCで既に gemini に Google ログイン済みなら、そのまま python rss_weekly_digest.py を実行して動作確認できます。launchd で使う場合は、plist の EnvironmentVariables ブロックを削除するか、そのまま(未設定のキーは無視)で問題ありません。

その上で、APIキーなしでGeminiCLIを使う形にプログラムを修正してくれました。

さあ、では、初回実行をしましょう。・・・ではなく、Cursorにさせましょう!

では、初回実行してみて。

作成したプログラムの実行もCursorは指示すればやってくれるので、わざわざ自分でターミナルでコマンドを打つ必要もありません。

実行結果

  • 対象: 直近7日間に publish_date があった md を 50件 検出
  • 処理時間: 約 4分36秒(GeminiCLI の要約に約4分30秒)
  • 出力: 00Inbox/RSS/RSS週次要約_20260201.md を生成(約19KB)
    要約ファイルの内容は次のとおりです。
  • 見出し「### 今週のRSS要約」
  • 各記事が箇条書きで、1〜2行の要約+Obsidian のウィキリンク [[ファイル名]] 付き
  • PGP の「Cursorでバイブコーディング:…」などが含まれている
    Obsidian で 00Inbox/RSS/RSS週次要約_20260201.md を開くと、各 [[…]] から元の md に飛べます。

おお、素晴らしい、期待通りの要約ファイルができました!

当初のRSSDigestの実行結果。概ねこちらの要望通りだが・・・

あとはlaunchdで金曜日に回すためのplistの設定をしないといけませんね。早速やりま・・・Cursorにさせましょう!!!

ありがとう、素晴らしい。とてもいいプログラムです。
では、plistの認証、launchdへの読み込み、動作確認をして。

このプロンプトで実際に作業をしてくれます。
様子を見ていると、どうやらいくらか不具合(launchdの最小環境ではnodeがPATHに含まれておらず、plistにPATHを追加して解消)があったようで、プログラムの修正を始めましたが、しばらく経つと、正常に設定ができたようでした。

AIがこちらに指示してきた作業も、AIにさせてしまう!

ステップ3:実際に使ってみて、微調整する

個人的にとても気に入ったプログラムができました。これで私のRSSで収集した情報の確認が捗るようになりました。

さて、実際に使用していると、いくつか気になる点が出てきます。そんな時も、Cursorを使用して適宜プログラムの微調整をすることができるのがプログラム自作のいいところですよね。バイブコーディング様様です。

実際にこのプログラムに対してその後修正した時のプロンプトは以下のような感じです。

RSSの要約プログラムを少し修正したい。英語のRSSも要約は日本語で作成するようにして。
プログラムをさらに修正してほしい。
現在、すべてのRSSフィードの要約が並列に並んでいるが、RSSフィードが格納されているフォルダごとに並べて欲しい。つまり、たとえば「LifeHacker」フォルダ内に含まれているファイルの要約に関しては、「## LifeHacker」という見出しの後に箇条書きで要約を並べて欲しい。
要約に日付を添えてほしい。YYYY/MM/DD形式で添えるようにして。

その結果、現在の要約ファイルは以下のようになりました。

実際に使ってみて気になった点を修正依頼した結果。サイト別、日付情報付きとなり、よりわかりやすくなった。
Screenshot

振り返り:対話で形にしたポイント

  • 「実装しないで考えて」で、入力・処理・出力・確認事項が先に言語化され、後から実装するときに迷いが少なかった。
  • 確認事項への回答(フォルダ名、publish_date、launchdでの認証)を設計メモに反映してもらうことで、仕様が一箇所に固まり、実装とドキュメントが噛み合った。
  • 利用前の手順(config、手動実行、plist・launchd・動作確認)を「実施して」と頼み、Cursorにさせることで、こちらの手間も省けた。
  • 実際に使用して、修正したくなった点は適宜修正できる

バイブコーディングでのテーラーメイドプログラムの作成は、痒いところに手が届くですね。

関連記事

RSSで更新を自動収集する:情報収集の「入口」を固定して探す時間を減らす(Feedly/Inoreader→Zotero/Notion)

参考リンク(本記事で触れたツール)

免責

本記事は、筆者の作業環境とAIとの対話に基づく記録です。ツールやAPIの仕様は変更されることがあります。機密情報やAPIキーは設定ファイルに直書きせず、環境変数や権限で保護してください。

タイトルとURLをコピーしました