WSL2 に Hermes Agent という常駐型の AI エージェントを入れて、ニュース収集・個人 wiki の維持・Steam ライブラリの記録みたいな細々した作業を全部 cron で任せる環境を組んだ。2日くらいでだいたい形になったので、構成とハマったところをメモしておく。
何を組んだか
エージェントは Discord と繋がっていて、成果物は全部 Discord のチャンネルに届く。いま動いているのはこんな感じ。
毎日のダイジェスト系
- 朝8:30 開発トレンド(GitHub Trending + Hacker News を収集して、自分のスタック向けに10件くらいに絞って日本語でまとめる)
- 朝9:30 AIニュース(過去24時間の記事から5〜7本選んで要約)
- 平日20:00 X の技術系話題まとめ
趣味系
- 土曜 ゲームの厳選情報(フレンドが遊んでるタイトルや好みに合う新作だけ。弱いネタしかない週は黙る)
- 日曜 Steam ライブラリの同期。プレイ時間の差分を見て、遊んだ記録を wiki に書く
個人 wiki の自動維持
Karpathy が言っていた LLM Wiki パターン(RAG と違って、LLM が知識を一度構造化して wiki として蓄積・維持し続けるやつ)を実践していて、その維持作業が全部 cron に乗っている。
- 毎晩22:00 wiki の未コミット変更を commit & push
- 月曜 inbox の取り込み。自分は気になった URL やメモを inbox.md に放り込むだけで、週次で LLM がページ化・リンク張り・索引更新までやる
- 月曜 lint(矛盾・壊れたリンク・孤立ページのチェック)
- 日曜 「穴埋めインタビュー」。wiki の各ページに「埋めたいところ」という節を作ってあって、そこから質問を選んで Discord で自分に聞いてくる。答えを返信すると翌週の取り込みでページに反映される
wiki のボトルネックは知識の獲得じゃなくてブックキーピング(リンク更新、索引維持、矛盾の記録)で、人間がやると保守コストが価値を超えて廃れる。そこを全部 LLM に投げたら、inbox に放り込むだけで wiki が育つようになった。
仕組み
各ジョブは「収集スクリプト(Python)+プロンプト」のペアでできている。スクリプトの標準出力がそのままプロンプトの文脈として注入されて、エージェントの最終応答が Discord に配信される。収集は決定的な処理なのでスクリプトで、選別・要約・翻訳は LLM で、という分担。
お金の話
最初は構築作業そのものも OpenRouter 経由のエージェントにやらせていた。設定の試行錯誤って要するに「エージェントと長い対話を延々続ける」ことなので、従量課金だとクレジットがみるみる溶けていく。気づいたときには結構減っていた。
なので役割を分けた。
- 構築・試行錯誤: Claude Max のサブスク(Claude Code)でやる。定額なので、設定をいじって壊して直すみたいな回数の読めない作業を気兼ねなくやれる
- 通常稼働: OpenRouter の従量課金。cron ジョブは1回あたりの処理量がだいたい一定なので、単価の安いモデルをジョブごとにピン留めしておけばコストが読める
「回数が読めない作業は定額、回数が読める作業は従量で安く」という分担に落ち着いてからは、クレジットの減りが気にならなくなった。
ハマったところ
ここからが本題。この手の環境は「無言で壊れる」パターンが豊富だった。
「succeeded」は何も保証しない
cron の実行結果が succeeded でも、それは「ジョブが起動した」という意味しかない。中身が妥当かは実行記録(注入されたプロンプト+最終応答)を読むまで分からない。「設定した、動いた、OK」で放置すると、翌朝ゴミが届く。
存在しないサブコマンドを推測で書くと無音で死ぬ
配信用のスクリプトに hermes deliver と書いていたことがあった。そんなサブコマンドは存在しない(正しくは hermes send --to discord)。最悪なのは、これでもジョブ自体は「正常終了」すること。エラーは出ず、ただ何も届かない。CLI のサブコマンドは --help で実在確認してから書く。当たり前のことを LLM と一緒に作業していると忘れる。
LLM を使わないモードで「要約して」と頼んでいた
Hermes の cron には --no-agent という、スクリプトの標準出力をそのまま配信するモードがある。死活監視みたいな定型文の通知にはこれでいいんだけど、このモードのジョブに「要約してまとめて」というプロンプトを付けても原理的に何も起きない。LLM が呼ばれないんだから当然。これも正常終了する。
残高が残っていても HTTP 402 で全ジョブ停止
クレジットを溶かした直後に踏んだやつ。OpenRouter は実行前に「max_tokens 分を残高で賄えるか」を検査する。だから残高が $0.76 残っていても、上限トークンの見積もりに届かなければ推論前に拒否される。この状態になると LLM を使うジョブが一斉に止まる。
グローバルのモデル設定を変えたら翌朝全部止まっていた
試しにグローバルのモデルを切り替えたら、モデルを明示的にピン留めしていないジョブが全部「意図しない出費を防ぐためスキップしました」で止まった。故障じゃなくて安全設計なんだけど、知らないと朝の Discord が静まり返っていて焦る。定期ジョブのモデルはジョブごとにピン留めしておくのが正解だった。
手動テストしたら翌朝の配信が空になった
収集スクリプトを既読/未読の状態に依存させると、手動テストで既読になって翌朝の本番実行が空振りする。選別は「過去24時間」みたいな日付窓でやる。
収集スクリプトを bash で書くと静かにデータが消える
bash でパイプ越しの while read の中で変数に蓄積すると、サブシェルの中なので全部捨てられる。カウンタも増えない。エラーにはならない。収集系は最初から Python で書くことにした。
まとめ
並べてみると、ハマりの大半が「エラーにならずに壊れる」パターンだった。エージェントに作業を任せる環境は、動いているかどうかの確認まで含めて設計しないと、静かに死んでいるのに気づかない。逆にそこさえ押さえれば、毎朝ダイジェストが届いて wiki が勝手に育つのはかなり快適で、もう手動には戻れない気がしている。