loop-runner について
loop-runnerは、エージェントの編集・検証ループを上限付きで実行するスキルです。モデルの自己判定ではなくシェルの終了コードで成否を決め、決定論的なガードとログで再試行やエスカレーションを管理します。
主な機能
- 01シェルコマンドによる検証
- 02必須の反復回数と時間制限
- 03状態ハッシュによる停滞検出
- 04人への引き継ぎガード
- 05JSON実行ログと失敗時の教訓
活用シーン
- 01失敗したテストの反復修正
- 02厳格な停止条件での型やlintエラー修正
- 03進展のない編集の反復を停止
- 04未解決の実行を人に引き継ぐ
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rheinmir/ setup --skill loop-runnerインストール後、Claude Code で/loop-runnerを入力して読み込まれたか確認します。
詳細
スキル:loop-runner
概要
目的とコンテキスト
- 目的: 自律的な修正ループを、暴走できない形で実行します。VERIFY はシェルコマンドで、終了コード 0 は合格を意味します(pytest/tsc/リンター)。エージェントは終了コードが失敗を示している状況を言いくるめて覆せないため、LLM による自己判断よりも優先されます。終了ガードは必須で、すべて決定論的です。
- 使用するタイミング:
- エージェントが編集とチェックを繰り返す場合(失敗するテストを修正する、型チェッカー/リンターを通過させるなど)。
- 停止することを確実に保証したい場合(反復回数と実時間に上限を設け、停滞時に停止し、エスカレーションする)。
- モデルに「完了した」と判断させることなく、再生可能な実行ログとリフレクションの教訓履歴を残したい場合。
- 対象外: 「完了」の LLM 判定ではありません。設定以外の場所でガード値を調整する用途ではありません。自動呼び出しは行いません(
disable-model-invocation: true)。
基本モデル
PROPOSE (workspace state) → VERIFY (shell exit code) → GUARDS (max_iter · budget_seconds · no_progress_k · escalate_after_iter) → REFLEXION (lesson line) → CRITIQUE → REVISE (quarantined adapter) → repeat。CRITIQUE/REVISE 以外はすべて決定論的です。
今すぐ構築する部分/後から適応する部分の境界:
- 決定論的(今すぐ構築・テスト済み):制御ループ、すべてのガード、状態ハッシュによる進捗検出、実行ログの成果物、リフレクション。→
harness/scripts/loop-runner.py - 隔離されたアダプター(
verified: false):LLM による批評/修正ステップと、調整可能なガード値。→harness/loop-runner.config.yaml(適応時に編集するファイルはこれだけです)。デフォルトの修正ステップは何もしないシェルスタブなので、LLM なしでループ全体を実行し、セルフテストできます。
入出力の仕様
| フィールド | 必須? | 意味 | |
|---|---|---|---|
| 入力 | --verify | はい | シェルコマンド。終了コード 0 = 合格 |
| 入力 | --config | いいえ | ガードのデフォルト値(harness/loop-runner.config.yaml)。CLI フラグは設定を上書きします |
| 入力 | --revise | いいえ | シェルコマンドまたは実際の LLM 修正アダプター。デフォルトは何もしないスタブです |
| 入力 | --state | いいえ | 状態ハッシュの対象となる glob。指定しない場合、no_progress_k は無効です |
| 入力 | --log | いいえ | 実行ログのパス |
| 出力 | 実行ログ JSON | はい | run_log.path に、反復、判定、終了理由を記録します |
| 出力 | エピソードの教訓 | 失敗時 | reflexion.episodic_memory_page に追記します(有効なフロントマターと ## Origin を含むページを遅延作成します) |
| 出力 | 終了コード | はい | 0 SUCCESS · 2 MAX_ITER · 3 TIMEOUT · 4 NO_PROGRESS · 5 ESCALATE |
ルールと機能
- RULE-01(必須):VERIFY は決定論的です(終了コード)。LLM に「完了」を自己判定させてはいけません。
- RULE-02(必須):ガードは必須です。「完了させる」ために削除してはいけません。
- RULE-03(必須):隔離された値(ガードパラメーターと修正フック)は、設定内だけに置きます。同じ値が 2 か所にある場合は漏えいです。
- RULE-04(必須):
verified: falseの場合はフェイルセーフに動作します。適合性が証明されるまでは、修正の推測は誤りだとみなします。 - RULE-05(必須):セルフテストは常に成功する状態を維持し、実際の wiki に書き込んではいけません(エピソードページの出力先は一時ディレクトリに変更されます)。
- 機能:シェルコマンド(verify/revise)の実行、ワークスペースファイルのハッシュ化、実行ログとエピソード wiki ページの書き込み。
失敗時の境界
- VERIFY の終了コードが 0 → 成功(SUCCESS、終了コード 0)。
max_iterに到達 → 失敗(MAX_ITER、終了コード 2)。budget_secondsを超過 → 失敗(TIMEOUT、終了コード 3)。- 状態ハッシュが K 回の反復で変化しない → ブロック(NO_PROGRESS、終了コード 4)。
escalate_after_iterに到達 → 人間に引き継ぎます(ESCALATE、終了コード 5)。
使用方法
メインワークフロー
| ステップ | 種類 | 入力 | アクション | 出力/終了 | 失敗/次へ |
|---|---|---|---|---|---|
| W01 | deterministic | — | python3 harness/scripts/loop-runner.py selftest(5つのガードシナリオ、LLMなし) | 成功 | 失敗 → まずランナーを修正し、停止 |
| W02 | deterministic | ワークスペース | PROPOSE — 現在のワークスペースの状態 | 状態 | → W03 |
| W03 | deterministic | --verify | VERIFY — シェルコマンドを実行 | 終了コード 0 → SUCCESS | 0以外 → W04 |
| W04 | deterministic | カウンター、状態ハッシュ、時計 | GUARDS — max_iter、budget_seconds、no_progress_k、escalate_after_iter | 継続、または終了コード 2/3/4/5 | 終了 → run-log を書き込み、停止 |
| W05 | effect | 判定 | REFLEXION — エピソードページに教訓を1行追記 | 教訓 | → W06 |
| W06 | judgment | 失敗時の出力 | 隔離されたアダプター(LLM、スタブ、またはシェルコマンド)を介して CRITIQUE → REVISE | 新しいワークスペースの状態 | → W02 |
各ステップの詳細(W01–W06 の信頼できる唯一の情報源):
実行方法
# self-test — 5 deterministic guard scenarios, no LLM, no deps
python3 harness/scripts/loop-runner.py selftest
# real loop around a verify command (config supplies the guard defaults)
python3 harness/scripts/loop-runner.py run \
--config harness/loop-runner.config.yaml \
--verify "pytest -q" \
--revise "<shell cmd, or the real LLM-revise adapter>" \
--state "src/**" --log harness/out/loop-runner-run.json
CLI フラグは設定を上書きします。プロセスの終了コード:0 SUCCESS · 2 MAX_ITER · 3 TIMEOUT · 4 NO_PROGRESS · 5 ESCALATE。
ループ(1イテレーション)
- PROPOSE — 現在のワークスペースの状態(初期提案、または前回のイテレーションでの修正内容)。
- VERIFY — シェルコマンドを実行します。終了コード 0 → SUCCESS で停止します。
- GUARDS(すべてのイテレーションでチェックし、すべて適用):
max_iter— 強制的な最終上限(常に有効で、無効化できません)。budget_seconds— 実時間の予算(0 = 無効)。no_progress_k— 状態ハッシュが K 回連続で変化しない場合 → NO_PROGRESS(state_pathsがない場合は無効)。escalate_after_iter— 人間に引き継ぎます → ESCALATE(0 = 無効)。
- REFLEXION — 失敗時に、エピソードメモリの Wiki ページに「教訓」を1行追記します。
- CRITIQUE → REVISE — 隔離されたアダプター(LLM、またはスタブ/シェルコマンド)を実行します。その後、繰り返します。
出力
run_log.pathに実行ログ JSON(イテレーション、判定、終了理由)を出力します。- エピソードメモリの教訓を
reflexion.episodic_memory_pageに追記します(有効なフロントマターと## Originを付けて遅延作成されます)。
分岐
| ID | 種類 | ガード | 動作 | スキップ/失敗 | 再合流 |
|---|---|---|---|---|---|
| B01 | capability_optional | --state / state_paths が指定されている | no_progress_k による状態ハッシュの停滞検出を有効にします | 指定なし → ガード無効 | W04 |
| B02 | user_optional | budget_seconds または escalate_after_iter > 0 | 実時間の予算/人間へのエスカレーションを適用します | 0 → 無効(max_iter は常に有効) | W04 |
| B03 | capability_optional | 実際の LLM-revise アダプターが接続されている | W06 で LLM を使用します。verified: false → フェイルセーフ(RULE-04) | 未接続 → 何もしない/シェルスタブ | W02 |
検証と停止
停止は終了コードとガードだけで決まり、モデルが決めることはありません。max_iter は無効化できないため、実行は必ず終了します。セルフテストは常に成功し、実際の Wiki には何も書き込まないようにしてください。
例
- 成功例:
run --verify "pytest -q" --state "src/**"を実行し、2回目のイテレーションで修正によって失敗していたテストが直る → VERIFY の終了コード 0 → SUCCESS、プロセスの終了コード 0、実行ログには2イテレーションが記録されます。 - 境界/失敗例: 修正スタブが
src/**内のファイルを変更せず、no_progress_k=2→ 2イテレーションにわたり状態ハッシュが同一 → NO_PROGRESS、終了コード 4、教訓を追記します。モデルが完了したと主張しても覆せません。
コメント
Markdown 対応