この章で分かること
- ゲートウェイが「単一プロセスで複数のチャットプラットフォームに同時接続する」仕組みと、公式ドキュメントが実際に何種類のプラットフォームを比較表に載せているか
- Telegram を例に、BotFather でのトークン発行から
hermes gateway setup・DM ペアリングまでの最短経路 - 既定が「全員拒否」であること、許可リスト環境変数と
GATEWAY_ALLOW_ALL_USERSの危険性 - 管理者/一般ユーザーの権限分離と、チャット内から使えるスラッシュコマンド
- 常駐サービス化(systemd / launchd)の手順と、障害時に自動停止する循環ブレーカーの挙動
これは何か
ゲートウェイ(messaging gateway)は、Telegram・Discord・Slack のようなチャットアプリから Hermes に話しかけられるようにする、単一のバックグラウンドプロセスである。設定した数だけプラットフォームアダプタを同時に立ち上げ、チャットごとのセッション管理・cron ジョブの配信・音声メッセージの送受信までを 1 つのプロセスの中でまとめて面倒を見る。CLI(第 4 章)が「自分のターミナルから 1 対 1 で話す」入り口だとすれば、ゲートウェイは「自分以外の人やデバイスからも届く入り口」を増やす仕組みだと考えるとよい。
触る場所は 4 つに整理できる。
- CLI サブコマンド —
hermes gateway系(起動・停止・状態確認・常駐サービス化) - チャット内のスラッシュコマンド —
/whoamiや/modelなど、接続後にチャットの中から打つコマンド ~/.hermes/config.yamlの設定キー — プラットフォームごとの許可リスト・権限分離・チャンネルオーバーライドなど、秘密でない設定はここに書く(第 2 章で見た「秘密は.env、それ以外はconfig.yaml」という区分がここでもそのまま当てはまる)~/.hermes/配下のファイル — ボットトークンを置く.env、稼働ログlogs/gateway.log、配信の記録が残るstate.db
対応プラットフォームは公式ドキュメントの Platform Comparison 表に一覧がある。voice(音声)・images(画像)・files(ファイル)・threads(スレッド)・reactions(リアクション)・typing(入力中表示)・streaming(応答の逐次更新)の 7 機能について、プラットフォームごとの対応可否がまとめられている。代表的な行を抜粋する。
| プラットフォーム | Voice | Images | Files | Threads | Reactions | Typing | Streaming |
|---|---|---|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| Discord | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Slack | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| — | ✅ | ✅ | — | — | ✅ | ✅ | |
| Signal | — | ✅ | ✅ | — | — | ✅ | — |
| SMS | — | — | — | — | — | — | — |
| Home Assistant | — | — | — | — | — | — | — |
この表は全部で 28 行あり、WhatsApp(通常版と WhatsApp Cloud API 版で 2 行)・WeCom(通常版と WeCom Callback 版で 2 行)のように同じサービスが接続方式違いで 2 行になっている箇所があるため、実質のサービス数は 26 になる。第 2 章で触れた「アダプタは 25 種類以上」はこの内訳を指している。実装上も 2 系統に分かれており、gateway/platforms/ に置かれた組み込みアダプタ(Signal・Weixin・BlueBubbles・QQBot・WhatsApp Cloud API・Yuanbao・Webhook・API Server など)と、plugins/platforms/ に置かれたプラグイン型プラットフォーム(Telegram・Discord・Slack・WhatsApp・Matrix・Mattermost・Email・SMS など大半のプラットフォーム)に分かれる。使う側から見た挙動の違いはないので、この区別は「コードのどこを読めばよいか」を知りたいとき以外は意識しなくてよい。
いつ使うのか
典型的な使いどころは次の 4 つである。
- 自宅サーバーや VPS で動かしている Hermes に、外出先からスマホの Telegram や Discord アプリ経由で話しかけたい
- チームやグループチャットで、複数人が同じエージェントに Slack・Discord のチャンネル越しにアクセスしたい(権限分離で「誰が何をできるか」を制御する)
- Home Assistant・Microsoft Teams・DingTalk・Feishu/Lark・WeCom のような、すでに使っている業務ツールやスマートホームの入り口に Hermes を統合したい
- cron ジョブ(第 8 章)の実行結果や、バックグラウンドセッション(第 4 章の
/bg)の完了通知を、自分の使い慣れたチャットアプリへ配信したい
Hermes に外から話しかける経路はゲートウェイだけではない。似た入り口との使い分けは次のとおり。
| 経路 | 向いている用途 |
|---|---|
| CLI 対話モード(第 4 章) | 自分のターミナルから最速・最もフル機能で操作したい |
| メッセージングゲートウェイ(本章) | スマホや複数人から、普段使いのチャットアプリ経由で話しかけたい |
| API Server(OpenAI 互換) | 自作フロントエンドや他のプログラムから、OpenAI 互換 API としてプログラム的に叩きたい |
| Webhooks | 外部システムのイベント(CI 完了・監視アラート等)をきっかけに Hermes を動かしたい |
API Server は clarify(選択肢を提示して待つツール)や音声合成のような「対話中の人間」を前提にしたツールを外し、それ以外のフル機能を提供する専用のツールセットで動く。プログラム的な呼び出しには受け手がいないため、この違いを意識しておくと動作の差に戸惑わない。
アーキテクチャ — 単一プロセスに集約する
ゲートウェイの核心は「1 つのプロセスが全部を面倒見る」という設計にある。設定したプラットフォームの数だけアダプタが起動するが、それぞれが独立したサービスとして動くわけではない。全アダプタはチャットごとのセッションストアを共有し、そこから run_agent.py が実装する AIAgent に処理を渡す。cron スケジューラも同じプロセス内で 60 秒ごとにティックし、期限が来たジョブを同じセッションストア経由で実行する。
この設計のいちばんの利点は、プラットフォームを何個増やしてもエージェントの人格・メモリ・スキルが分裂しないことである。Telegram で話した内容を Discord から参照することはできない(セッションはチャットごとに分かれる)が、どちらから話しかけても同じ SOUL.md・同じ永続メモリ(第 5 章)を持つ同一のエージェントが応答する。
トークンの取得と許可リスト
ここから先は、初心者が最初に触ることになる Telegram を代表例にして、接続の最短経路を追う。他のプラットフォームも手順の骨格は同じで、「発行元の管理ツールでボットを作りトークンをもらう」→「hermes gateway setup か .env に登録する」→「許可リストか DM ペアリングでアクセスできる人を絞る」の 3 段階を踏む。
hermes pairing approve による承認まで、Telegram 接続は 6 段階で完了する。トークンの取得は Telegram の公式ボット管理ツール「@BotFather」に /newbot を送るだけである。表示名とユーザー名(bot で終わる必要がある)を決めると、123456789:ABCdefGHIjklMNOpqrSTUvwxYZ のような API トークンが返る。このトークンを持つ人は誰でもボットを操作できるため、漏れたら BotFather で /revoke して即座に無効化する。
取得したトークンは hermes gateway setup の対話ウィザードで Telegram を選べば、ボットトークンと許可するユーザー ID を聞かれるままに答えるだけで ~/.hermes/.env に書き込まれる。手動で書く場合も、書き込み先は config.yaml ではなく .env になる点は他の秘密情報と同じである。
# ~/.hermes/.env
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
TELEGRAM_ALLOWED_USERS=123456789 # カンマ区切りで複数指定可
許可リストの環境変数はプラットフォームごとに名前が決まっている。ユーザー ID や電話番号・メールアドレスなど、プラットフォームが識別子として使う値をそのまま並べる。
TELEGRAM_ALLOWED_USERS=123456789,987654321
DISCORD_ALLOWED_USERS=123456789012345678
SIGNAL_ALLOWED_USERS=+15551234567
EMAIL_ALLOWED_USERS=trusted@example.com
GATEWAY_ALLOWED_USERS=123456789 # 全プラットフォーム横断で許可
GATEWAY_ALLOW_ALL_USERS=true # 全員許可(非推奨)
既定の挙動は「全員拒否」である。許可リストが 1 つも設定されず GATEWAY_ALLOW_ALL_USERS も指定していない場合、すべてのユーザーからのメッセージが拒否され、起動時のログに警告が出る。ターミナル権限を持つボットにとって安全側に倒した設計であり、「動かない」と感じたらまずここを疑うとよい。
DM ペアリングと権限分離
ユーザー ID を事前に調べて許可リストへ手打ちする代わりに、未知のユーザーが DM を送ると 1 回限りのペアリングコードが発行される仕組みもある(メールだけは例外で、ペアリングを明示的に有効にしない限り未知の送信者は無視される)。コードは 1 時間で失効し、レート制限がかかり、暗号学的乱数で生成される。
# ユーザーには「Pairing code: XKGH5N7P」と表示される
hermes pairing approve telegram XKGH5N7P
hermes pairing list # 承認待ち・承認済みを確認
hermes pairing revoke telegram 123456789 # アクセスを取り消す
許可リストと DM ペアリングが答えるのは「そもそも Hermes に届くか」という入り口の可否だけである。届いた後に「何をしてよいか」を分けるのが、管理者(admin)/一般ユーザー(user)の権限分離である。DM とグループ/チャンネルはそれぞれ独立した設定を持ち、DM で管理者でもグループでは一般ユーザーということがあり得る。
# ~/.hermes/config.yaml
gateway:
platforms:
discord:
extra:
allow_from: ["111", "222", "333"]
allow_admin_from: ["111"] # 管理者 → 全スラッシュコマンド
user_allowed_commands: [status, model] # 一般ユーザーが打てるコマンド
allow_admin_from を設定しなければ階層分けそのものが無効になり、許可された全員が管理者と同じ扱いになる(既存の設定を壊さないための後方互換)。この階層が制御するのはスラッシュコマンドの実行範囲だけで、普通の会話(チャットそのもの)は一般ユーザーでも変わらず行える。
自分がどちらの扱いになっているかは、チャット内で /whoami を打てば確認できる。今の適用スコープと階層(admin / user / unrestricted)、打てるコマンドの一覧がそのまま返ってくる。
チャット内コマンドとチャンネルごとの設定
接続後は、プラットフォームを問わず共通のスラッシュコマンドでエージェントを操作する。代表的なものを挙げる(全コマンドは /help で確認できる)。
| コマンド | 用途 |
|---|---|
/new, /reset | 会話を最初からやり直す |
/whoami | 自分の権限(admin / user / unrestricted)と実行可能コマンドを表示 |
/status | セッション情報を表示 |
/model [provider:model] | 使用モデルの表示・変更 |
/approve, /deny | 保留中の危険なコマンドを承認・却下 |
/sethome | このチャットをホームチャンネルに設定 |
/sessions [search <query>] | 過去セッションの一覧・検索 |
/bg <prompt> | バックグラウンドセッションでプロンプトを実行 |
/stop | 実行中のエージェントを停止 |
/<skill-name> | インストール済みのスキルを呼び出す |
複数チャンネルを抱える運用では、チャンネルごとに使うモデルやシステムプロンプトを変えられる。安いモデルの雑談チャンネルと、フロンティアモデル+専門プロンプトの開発チャンネルを、同じ 1 つのゲートウェイで共存させる設定である。
# ~/.hermes/config.yaml
platforms:
discord:
channel_overrides:
"123456789012345678": # チャンネル/スレッド ID
model: anthropic/claude-sonnet-4.6
system_prompt: "You are the #dev channel code-review specialist."
チャットでの /model による切り替えはこのチャンネル既定より優先され、Discord のスレッドは親チャンネルの設定を自動的に継承する。なお公式ドキュメントはこの設定を指して「gateway-config.yaml」という呼び方もしているが、そういう名前の別ファイルは存在せず、実体は ~/.hermes/config.yaml 1 ファイルである。上の例のようにトップレベルの platforms: として書いても、gateway: キーの下にネストして書いても同じ設定として受理され、両方が指定された場合はトップレベルが優先される。読み込みの優先順位は環境変数が最も高く、次に config.yaml、最後に旧形式の ~/.hermes/gateway.json(レガシー、config.yaml が上書きする)の順である。
サービス化と障害対応
動作確認が終わったら、ターミナルを閉じても動き続けるように常駐サービス化する。Linux では systemd、macOS では launchd のサービスとして登録される。
Linux(systemd)
hermes gateway install # ユーザーサービスとして登録
hermes gateway start
hermes gateway status
journalctl --user -u hermes-gateway -f # ログを見る
sudo loginctl enable-linger $USER # ログアウト後も動かし続ける
ラップトップや開発機にはユーザーサービスで十分だが、ログインしないヘッドレスな VPS では sudo hermes gateway install --system による起動時システムサービスも選べる。ただしシステムサービスは再起動のたびに root 権限が要るため、hermes update が自動再起動できず手動コマンドの案内で止まることがある。ヘッドレス運用ではユーザーサービス+loginctl enable-lingerの組み合わせのほうが root 操作なしで同じ「起動時に立ち上がる」状態を作れる。
macOS(launchd)
hermes gateway install # launchd agent として登録
hermes gateway start
hermes gateway status
tail -f ~/.hermes/logs/gateway.log
生成される plist は ~/Library/LaunchAgents/ai.hermes.gateway.plist に置かれ、インストール時点の PATH・Python 仮想環境の場所・HERMES_HOME を環境変数として埋め込む。Homebrew で ffmpeg を入れ直すなど、インストール後にツールを追加した場合は hermes gateway install を再実行して plist を作り直す必要がある。
複数のプラットフォームを同時運用していると、どれか 1 つだけが不調になることがある。各アダプタは循環ブレーカー(circuit breaker)で保護されており、ネットワーク瞬断・レート制限・5xx・WebSocket 切断のような再試行可能な失敗が連続すると自動的にトリップし、そのアダプタだけを一時停止する。自動では復帰しないのが意図的な設計で、障害が続いているプラットフォームに再接続を延々と試み続ける事態を避けている。復旧を確認したら、チャットまたは CLI から次のコマンドで手動再開する。
/platform list # 稼働中・一時停止中・ブレーカー作動中を一覧表示
/platform resume telegram # 手動で再開
停止中のアダプタの原因は ~/.hermes/logs/gateway.log(プラットフォーム名と「circuit breaker」「paused」で検索)と /platform list の出力、そしてプラットフォーム側のステータスページの 3 か所で切り分けるのが早い。
ハンズオン 7-1 Telegram ボットを作り、gateway setup で繋ぐ
- Telegram で @BotFather を検索し、
/newbotを送る。表示名とユーザー名(botで終わる必要がある)を聞かれるので答える。 - 返ってきた API トークンを控える。
このトークンを知っている人は誰でもボットを完全に操作できる。チャットのスクリーンショットや公開リポジトリに貼らないこと。漏れた場合は BotFather に /revoke を送って即座に無効化する。
- 自分の Telegram ユーザー ID を調べる。@userinfobot にメッセージを送ると数字の ID が返る。
- 対話ウィザードを起動する。
hermes gateway setup
Telegram を選び、ボットトークンと先ほど調べたユーザー ID を入力する。完了すると ~/.hermes/.env に TELEGRAM_BOT_TOKEN と TELEGRAM_ALLOWED_USERS が書き込まれる。
ハンズオン 7-2 フォアグラウンドで起動し、疎通を確認する
- ゲートウェイをフォアグラウンドで起動する。
hermes gateway
数秒でボットがオンラインになる。ターミナルにはアダプタの起動ログが流れ続ける。
- Telegram アプリから、作成したボットに何かメッセージを送る。応答が返れば疎通は成功。許可リストに入れていないユーザーから送った場合は拒否されるか、DM ペアリングが有効ならペアリングコードが返る。
- 確認できたら
Ctrl+Cでフォアグラウンドのプロセスを止める。
ハンズオン 7-3 常駐サービス化し、後片付けまで行う
この先はターミナルを閉じても動き続ける常駐プロセスを作る操作である。動作確認だけが目的なら、最後の手順で必ずアンインストールして片付けること。
- 常駐サービスとして登録する(Linux は systemd のユーザーサービス、macOS は launchd agent になる)。
hermes gateway install
hermes gateway start
hermes gateway status
status が実行中を示せば成功。Linux は journalctl --user -u hermes-gateway -f、macOS は tail -f ~/.hermes/logs/gateway.log でログを確認できる。
- 試し終えたら、サービスを止めて登録ごと取り除く。
hermes gateway stop
hermes gateway uninstall
uninstall は登録したサービス定義(systemd unit / launchd plist)を削除する。常駐が要らないなら、これで元の状態に戻る。
つまずきポイント
「誰にも反応しない」は既定の安全動作 — 許可リストも GATEWAY_ALLOW_ALL_USERS も設定していなければ、ゲートウェイは全員を拒否する deny-all が既定である。焦って GATEWAY_ALLOW_ALL_USERS=true(非推奨)に頼る前に、まず許可リストか DM ペアリングで自分のユーザー ID を許可しているか確認する。
循環ブレーカーは自力で戻ってこない — トリップしたアダプタは、原因のプラットフォーム障害が復旧しても自動では再開しない。「直ったはずなのに反応しない」ときは /platform list でブレーカー作動中になっていないか確認し、/platform resume <name> を打つ。
ボットトークンは .env、config.yaml に平文で書かない — hermes gateway setup を使えば自動的に .env に書かれるが、手動で設定するときに config.yaml へ書いてしまうと、リポジトリ共有や画面共有でそのまま流出しやすい。第 2 章で見た「秘密は .env」の区分はゲートウェイのトークンにもそのまま適用される。
systemd ユニットに自前の kill 用 drop-in を足さない — Hermes が生成する unit は KillMode=mixed・Restart=always ですでにクリーンな再起動ができるよう作られている。ここに ExecStopPost=/bin/kill -9 $MAINPID のような drop-in を追加すると、通常の再起動のたびに起動直後の新プロセスを SIGKILL してしまい、Restart=always が即座に再起動して無限ループになる(Telegram では再起動通知が延々と届く)。すでに追加してしまった場合は systemctl --user edit hermes-gateway で該当行を削除し、daemon-reload する。
理解度チェック
Q1. 許可リストも GATEWAY_ALLOW_ALL_USERS も設定していない場合、ゲートウェイは新規ユーザーからのメッセージにどう応答しますか。
全員拒否(deny-all)が既定の挙動で、メッセージは拒否され、起動時のログに警告が出る。ターミナル権限を持つボットとして安全側に倒した設計であり、意図的な仕様である。
Q2. DM ペアリングで発行されるコードの性質を、有効期限とレート制限の観点から説明してください。
コードは 1 時間で失効し、レート制限がかかり、暗号学的乱数で生成される。メールだけは例外で、ペアリングを明示的に有効化しない限り未知の送信者は無視される。
Q3. 循環ブレーカーがトリップしてアダプタが一時停止した後、プラットフォーム側の障害が復旧すれば自動的に再接続されますか。
されない。循環ブレーカーは意図的に自動復帰しない設計になっており、復旧を確認したうえで /platform resume <name> を手動で実行する必要がある。
Q4. 管理者/一般ユーザーの権限分離は何を制御し、何を制御しませんか。
制御するのはスラッシュコマンドの実行範囲だけである。一般ユーザーは allow_admin_from が設定されたスコープでは許可されたコマンド(既定で /help と /whoami)しか打てないが、普通の会話(チャットそのもの)は管理者かどうかにかかわらず行える。
まとめ
- ゲートウェイは単一プロセスで複数のプラットフォームアダプタを束ね、セッションストアを介して同じ AIAgent に処理を渡す。公式の Platform Comparison 表は 28 行・実質 26 サービスに及ぶ
- Telegram なら BotFather でのトークン発行 →
hermes gateway setup→ DM ペアリングまたは許可リストという最短経路で接続できる - 既定は deny-all。許可リスト環境変数か DM ペアリングで「誰が届くか」を、
allow_admin_from/user_allowed_commandsで「届いた後に何ができるか」を別々に制御する - 常駐サービス化は systemd / launchd で行い、循環ブレーカーは障害時に自動停止するが自動復帰はしない設計になっている
- 次の第 8 章では、このゲートウェイに結果を配信する cron スケジューラを扱う