Yyatmita

Ralph Loop の独自発展:bash から Python へ

bash スクリプトの限界を超えて、TOML 設定・スコアリング・複数プロバイダ対応の Python ツールに書き直した話

サイトをつくってみた#ralph-loop#python#automation#tooling
← 前の記事: Ralph Wiggum Loop でコンテンツを作る

bash 版は yatmita 専用だった

yatmita でサイトを自動構築した bash スクリプトは、思った以上によく動いた。コンテンツの自動生成にも使い始めて、そのうち「これ、別のプロジェクトでも使えるんじゃないか」と思い始めた。

別プロジェクトというのは CLI ツールの開発だ。コードを書かせて、コンパイルとテストが通るまでループする——そういう使い方をしたかった。

ところが、bash 版のスクリプトを見直してみると、npm run build がベタ書きしてある。テストも npm test、リントも npm run lint。別のプロジェクトでは cargo check だったり pytest だったりする。チェック項目を差し替えられないと使えない。

設定を外に出せる仕組みが必要だった。

自動修復が肝——だから bash では辛い

「Ralph Loop を Python で書き直したい」と ChatGPT に相談した。

会話の中で bash の弱点が整理されてきた。JSON の書き換えは jq 依存になってエスケープ地獄になる。エラー分岐はネストで読めなくなる。再試行ロジックが複雑になる。

ただ、これだけなら「bash より Python が読みやすい」程度の話だ。本質はもう少し深いところにある。

自動修復が Ralph Loop の肝だ。

失敗したら、エラー内容を渡して再実行して、また検証する。この「失敗 → 修正 → 再検証」のサイクルを bash で書くと、制御構造が急速に複雑になる。単純な while ループなら bash で十分だ。でも「状態を持つエージェント制御」をやるなら、Python の方が自然に書ける——その結論になった。

ChatGPT も同じことを言った。「自動修復をやるなら Python 一択です」。

TOML 設定で用途を切り替える

解決策は TOML 設定ファイルだ。プロジェクトごとに TOML を書けば、チェック項目もスコア閾値も最大イテレーション数も、全部そこで切り替えられる。

実際の TOML を3パターン見てもらうと、この設計の意図がわかりやすい。

レシピ生成(スコア100必達・カスタムチェック・自動コミット):

[loop]
max_iterations = 5
score_threshold = 100
 
[checks]
items = [
  { name = "build",        command = "pnpm run build",                        score = 30 },
  { name = "tomato-sauce", command = "bash scripts/check-pasta-recipe.sh ...", score = 35 },
  { name = "tuna-wakame",  command = "bash scripts/check-pasta-recipe.sh ...", score = 35 },
]
 
[git]
auto_commit = true

レシピには独自のチェックスクリプトがある。分量が入っているか、調理時間が記載されているか——こういった項目を点数化して、合計が100を超えたら合格だ。自動コミットも有効にしてある。

記事執筆(チェックなし・自動コミットなし):

[loop]
max_iterations = 3
score_threshold = 0
 
[checks]
 
[git]
auto_commit = false

記事を書かせるときはチェックしない。「品質を点数で測れない」からだ。3回回して、いちばん良さそうなものを自分で選ぶ。自動コミットも切ってある——人間が確認してから手動でコミットしたい。

ドメイン構築(build チェックのみ):

score_threshold = 70 にして、build が通れば70点で合格。チェックは最小限にして、ループを速く回す。

同じツールなのに、TOML を差し替えるだけで全く別の用途に使える。これが一番やりたかったことだ。

Python 版で増えた機能

bash 版は 214 行だった。Python に書き直した後、少しずつ機能が生えてきた。

スコアリング: チェック項目ごとに点数を配分できるようになった。build が通れば30点、テストが通れば50点——合計が閾値を超えたら合格。全項目の合否を一まとめにするより、進捗がわかりやすい。

プロバイダ抽象化: [provider] セクションに Claude 以外のコマンドも書けるようになった。Codex も Gemini も、コマンドを差し替えるだけで同じループで動く。

サーキットブレーカー: 連続エラー5回、またはスコアが3回進捗なしで自動停止する。暴走して API 代だけ消える——という事態を防ぐ。

予算管理: トークン使用量を追跡して、設定した金額を超えたら止まる。max_total_cost_usd = 1.0 のように書いておけばいい。

並列実行(Best-of-N): 複数のプロバイダで同時に生成して、スコアが最も高い結果を採用する。同じプロンプトを3回並列で回して、一番よかった出力を使う——という実験もした。

どれも「bash でも書けないことはないが、書くと読めなくなる」種類の機能だ。

50 個の TOML ファイル

現在、yatmita プロジェクトには TOML ファイルが 50 個以上ある。

ブッダイズム。の記事11本、たんぱくパスタのレシピ群、食材リファレンス、ストーリー記事、そして今書いているこの labo 記事——全部 Ralph Loop で生成した。バッチスクリプトを組んで、8記事を同時に並列実行したこともある。

コンテンツの量産が一気に楽になった。

ツールを汎用化したことで、「TOML を1枚書けば動く」という状態になった。新しいコンテンツを追加するたびに bash スクリプトをコピーして編集する——という作業がなくなった。

道具を育てることの快感

yatmita 専用の bash スクリプトから始まって、どのプロジェクトでも使える Python ツールになった。

一番の変化は、TOML 設定で「何をチェックするか」を差し替えられるようになったことだ。コード生成なら build チェックを厳しく、レシピ生成なら独自スクリプトで点数化、記事執筆ならチェックなし——用途に合わせて検証戦略を選べる。

これがコンテンツ自動化の設計原則になったと思っている。「一つのループで全部やる」ではなく、「チェック戦略だけを差し替えて同じループを使い回す」。

道具を汎用化するのは面倒だ。最初から汎用ツールを作ろうとすると、過剰設計になりやすい。でも「これ別のプロジェクトでも使いたいな」というタイミングで書き直すのは楽しかった。自分が作ったものが、用途を超えて動くようになる——その感覚がある。

bash 版の 214 行が、こういう機能を持つツールに育っていくとは思っていなかった。