繰り返しのループ(/loop)
/loop は、プロンプト(またはスラッシュコマンド)を いま開いているセッションの中で 決まった間隔ごとに流し直します。起こされるたびに本物のエージェントのターンが1回走ります。Hermes はそのときの状態を読み直し — 最新の CI の結果、いまのキューの深さ、いまのファイルの中身 — 作業をして、結果を返し、次の合図まで静かに待ちます。
これは Claude Code の /loop に対する Hermes なりの答えです(別名の /proactive もそのまま使えます)。/goal が判定役に引っぱられる仕組み — 「この目標が達成されるまで作業を続けて」 — なのに対して、/loop は時計に引っぱられます。「これを N 分ごとに(あるいは頃合いを見て)もう一度やって。止めろと言われるまで」という形です。
使いどころ
- 外の状態を見張る。 「デプロイ/CI の実行/キューを見ていて、変化したら教えて」。いちばん代表的な使い方です。
- 通るまで繰り返す。 「テストを走らせて、落ちたところを直して、通るまで繰り返して」。
- 作業中の見張り。 同じ会話の中で別のことをしている間、エラー率や長いジョブの進み具合に目を配らせておきます。
- 定期的な片付け。 長いセッションのあいだ、N 分ごとに lint をかけ直したり、状況のまとめを出し直したりします。
作業を 人が見ていない状態で 走らせたいとき — 夜通し、本物のスケジュールで、ターミナルを再起動しても生き残ってほしいとき — は、代わりに cron ジョブ を使ってください。/loop はセッションの内側に住み、cron はどのセッションの外側にも住みます。また、やることが1つの目標で、完了の定義がはっきりしているなら、たいていは /goal のほうが向いています。
手早く試す
/loop 5m check the deploy status and tell me if it's live yetこう見えます。
- ループを受け付けた —
↻ Loop set (every 5m): check the deploy status… - 1回目はすぐ起きる — 次のアイドル確認のタイミング(ゲートウェイなら次の 15 秒ごとの見張り)で、Hermes が起床の合図を差し込み、いまの状態に対して普通のターンを1回走らせます。
- 繰り返す — そのあとは5分ごとに、停止条件が発火するか、こちらが止めるまで続きます。
ループが立っているあいだは、どの画面でもループが見えるところに出ていて、次に起きるまでの残り時間がその場で減っていきます。
| 画面 | 出る場所 |
|---|---|
| Classic CLI | プロンプトの上にある作業中の欄に1行出ます: ↻ loop · every 5m · 2 runs · next in 4m · <prompt>(分刻みで、最後の1分だけ秒で表示します。起きて動いているあいだは running now、一時停止中はその理由が出ます)。Ctrl+R でたたむと ↻ loop next in 4m まで縮みます。 |
| TUI | ゴールの帯の下に同じ行が出ます。 |
| Desktop | 入力欄の上のループのカードに Loop active · 2 runs · next 00:04:12 と出て、1秒ごとに数えていきます。 |
スラッシュコマンドも同じ手軽さでループにできます。
/loop 10m /recap2つのテンポの決め方
間隔を決め打ちする — 時計はこちらが持つ。 間隔(30s、5m、2h、1h30m)を渡すと、その予定どおりに発火します。見張る対象が自分のペースで動いていくときに使います。
/loop 2m poll the build at ci.example.com/job/42 and ping me the moment it finishes自分でテンポを決める — 時計は Hermes が持つ。 間隔を書かずに渡すと、ループは自分でペースを作ります。下限(既定では1分)から始めて、エージェントの返事が変わらないあいだは指数的に間隔を伸ばしていき — 2分、4分、8分と、上限(既定では15分)まで広がります。返事が前回と違った瞬間、テンポは下限まで戻ります。変化の判定はローカルでのダイジェスト比較(時刻は無視されます)なので、何も起きない待ち時間に余計な費用はかかりません。
/loop keep an eye on the migration and summarize progress目安はこうです。外の時計が仕事を動かすなら間隔を決め打ち、仕事のほうがリズムを作るなら自分でテンポを決めさせる。
停止条件
次のどれかが発火すると、ループは終わります。
| 条件 | やり方 |
|---|---|
| エージェントが終わったと判断する | 起床の合図となるプロンプトが、作業が終わったか意味をなさなくなったときに LOOP_COMPLETE だけの行で返事を締めるよう、エージェントに教えます。 |
| 実行回数の上限 | --times N — N 回起きたら止めます。 |
| 証拠にもとづく条件 | --until <condition> — 起きるたびに、/goal を支えているのと同じ補助の判定役が、返事をこちらの条件に照らします。判定役が「この条件は達成できない」と裁定した場合、ループは再発火せずに理由付きで 一時停止 し、合図の予算を使い切らずに済みます(フェイルオープン: 判定役が壊れてもループが詰まることはありません)。 |
| こちらの手で | /loop stop(残しておきたいなら /loop pause)。 |
| 最後の砦としての予算 | loops.max_ticks(既定は 100)に達するとループを一時停止し、人が見ていないセッションがトークンを永遠に燃やし続けないようにします。0 で無制限です。 |
例:
/loop 2m poll CI --times 30
/loop 5m watch the queue --until queue depth reaches zeroコマンド
| コマンド | 何をするか |
|---|---|
/loop [interval] <prompt> [--times N] [--until <cond>] |
このセッションのループを開始(または置き換え)します。1回目はすぐ発火し、以降はテンポに従います。 |
/loop または /loop status |
テンポ、これまでに発火した回数、次に起きるまでの時間を表示します。 |
/loop pause |
ループを失わずに、発火だけ止めます。 |
/loop resume |
続きから再開します。 |
/loop stop |
ループを終わらせます。 |
/proactive … |
/loop の別名です(Claude Code に合わせたもの)。 |
CLI、TUI(hermes --tui)、Web ダッシュボードのチャット、デスクトップアプリ、そしてすべてのゲートウェイ(Telegram、Discord、Slack、WhatsApp、…)で動きます。メッセージ系のサービスでは、こちらのメッセージとメッセージのあいだでもゲートウェイが起床の合図を送ります — ループはそのチャットのセッションのものなので、結果は普通の返信として届きます — そのセッションを TUI やデスクトップアプリで開いているときも同じで、振り分けられた起床はゲートウェイに任されます。
デスクトップアプリとダッシュボードのチャットでは、ウィンドウを閉じたりアプリの接続が切れたりしても、動いているループをバックエンドが起こし続けます。/loop(または /heartbeat)が動いているセッションは、接続の切れたセッションを片付ける処理の対象から外れるので、開き直したときには起床とその結果がそろっています。この除外は、ループが止まるか、一時停止するか、回数の上限に達した時点で終わり、そのあとセッションは通常どおり片付けられます。ただし、バックエンドのプロセスそのものは動き続けている必要があります。アプリと一緒に終了してしまうと、戻ってくるまで何も起きません。放っておいて回したいループは、長く動き続けるバックエンド(リモートの hermes serve か、ダッシュボード)の上のセッションで動かしてください。
/goal と混ぜる
どちらの機能も、手が空いた境目で合成のターンを差し込みます。そのため1つの決まりに従います。動いている goal がセッションの主導権を持つ。 /goal が実際に引っぱっているあいだ(判定役が「続行」と言っているあいだ)、ループの起床は後回しになります。goal が終わるか、一時停止するか、待ちの関門(/goal wait、または判定役が自動で出す WAIT の裁定)で自ら停まった時点で、ループは空いた時間を使って再開します。停まった goal と /loop の組み合わせは自然な形です。goal が大きな非同期の何かを待っているあいだ、ループが別のものの脈を取り続けます。
本物のこちらのメッセージは、いつでも両方に優先します — 起床が発火するのは、セッションが空いていて、こちらの用事が何も待たされていないあいだだけです。
動きの細かいところ
- 起床は普通のユーザー役のターン。 システムプロンプトの書き換えもツールセットの入れ替えもないので、プロンプトのキャッシュはそのまま効きます。メッセージのゲートウェイでは、起床はループを設定したメッセージへの返信ではないので、その出力はそのメッセージを引用せずにチャットやトピックへ投稿されます。
/resumeと圧縮を越えて生き残る。 ループの状態はセッションごとに保存され、文脈の圧縮の境目も/goalと同じように越えていきます。- 1セッションに1つのループ。 新しく
/loopを設定すると、前のものと入れ替わります。複数のループを回したいときは、複数のセッションを走らせてください(スケジュールをまとめて持ちたいなら cron を使います)。 - 起床のターンを中断(Ctrl+C)するとループは一時停止します —
/loop resumeで戻せるので、取り消しはちゃんと取り消しとして働きます。 - トークンの費用はテンポに比例します。 1回の合図がまるごと1ターンです。状態が実際に変わる頻度に間隔を合わせてください。何も起きない待ちには、自分でテンポを決めさせるほうが向いています。
設定
# ~/.hermes/config.yaml
loops:
min_interval_seconds: 30 # floor for fixed intervals
max_ticks: 100 # backstop budget (0 = unlimited)
self_paced_floor_seconds: 60 # self-paced starting cadence
self_paced_ceiling_seconds: 900 # self-paced max backoff--until の判定役は goal_judge という補助タスクを通るので、auxiliary.goal_judge.* の振り分けの上書き(プロバイダ、モデル)はループの条件にもそのまま効きます。
/loop と /goal と cron
/loop |
/goal |
cron | |
|---|---|---|---|
| きっかけ | タイマー(または自分で決めたテンポ) | 各ターンのあとの判定役の裁定 | スケジュール。どのセッションの外側でも |
| 住んでいる場所 | いま開いているセッション | いま開いているセッション | 実行ごとに自分のセッション |
| 終わるとき | 停止条件 / 上限 / こちらの手で | 目標の達成 / 予算 / こちらの手で | ジョブを消したとき |
| 向いていること | 見張り、監視、定期的なやり直し | 目標を1つ決めて、終わるまで繰り返す | 人が見ていない、長い時間軸のスケジュール |