Yyatmita

OpenClaw を one-shot で呼ぶ: profile 隔離と人格テンプレの剥がし方

ralph-loop の LLM provider として OpenClaw を組み込もうとして判明した、チャット駆動エージェント前提のデフォルトプロンプト群とその対処。profile 分離・workspace テンプレ書き換え・memory リセット運用までを記録する。

OpenClawにOpenClawのことを聞いてみた#openclaw#ralph-loop#oneshot#prompt-engineering#agent-stack

Gemini CLI の個人向けサービス終了に備えて、ralph-loop(自家製の Python 製 1 ショット LLM ループ runner。PyPI の同名パッケージとは別物)の provider に OpenClaw を追加した。Gateway 経由で google-gemini-cli/gemini-3-pro-previewopenai-codex/gpt-5.2 を一元的に切り替えられるのが旨味。

…のはずだったが、OpenClaw を 1 ショット runner から叩こうとすると、そもそも設計思想が逆方向で、デフォルト構成のままだと出力が prompt 通りに従わなくなる事象が頻発する。

この記事は、その罠と対処を作業ログから整理したもの。

ralph-loop 自体の話は別記事に整理してある。基盤の紹介は Ralph Loop の独自発展:bash から Python へ、autoresearch との設計思想の比較は 自律ループの設計思想、autoresearch と ralph-loop、1 ショット runner として転用したときのローカル LLM / API 比較は 並列 ReAct エージェントでローカル LLM と Claude を本気で比べた、完成定義を誤ると無限ループする話は LLM ループの『完成定義』を間違えると、100 点合格でも intent が骨抜きになる に書いた。本記事はそのうち provider 経路の話の続編にあたる。

何が起きるのか

ralph-loop は 1 イテレーションあたり以下を回す:

prompt 構築 → claude / codex / openclaw 等を subprocess 起動 → checks 実行 → review → auto-commit → progress.md 追記

provider はステートレスな one-shot 呼び出し前提。claude -pcodex execgemini -y などはどれも「prompt 渡す → 結果返す」だけのシンプルな CLI。

ところが OpenClaw agent サブコマンドだけは、見た目は --message "<prompt>" で叩く 1 ショット風 API なのに、内部はチャット駆動の永続エージェント前提で組まれている。具体的には:

  • 既定 profile (~/.openclaw/) の memory.sqlite を共有する。チャット用の人格エージェント(既定の main エージェント)と同じデータベースに ralph-loop の会話が混ざる
  • workspace に強い人格指示を埋め込んだ markdown 群が agents add 時に自動配置される
  • agent 実行ごとに workspace 内の SOUL.md / USER.md / memory/ を読み込むことが指示されている
  • そのまま 1 ショットで叩くと、prompt.md に「日本語で淡々と作業せよ」と書いてあっても、デフォルトの SOUL.md にある "Have opinions"・"Be the assistant you'd actually want to talk to" のような チャットエージェント向け人格指示が乗ってくる

つまり OpenClaw は チャットエージェントを育てる枠組み として設計されており、それを 1 ショット runner として使うと、デフォルトプロンプトが全部ノイズになる。

罠 1: 既定 profile の memory 汚染

OpenClaw は profile 単位で config / state / memory を分離できる。明示しない場合は 既定 profile ~/.openclaw/ に書き込まれる。

~/.openclaw/
├── openclaw.json
├── agents/main/
├── memory/main.sqlite   ← ここに全エージェントの会話が累積
└── workspace/
    ├── IDENTITY.md      ← main エージェントの人格
    ├── SOUL.md
    └── USER.md          ← main エージェントが貯めているユーザー情報

ralph-loop から openclaw agent --message "<prompt>" を叩くと、デフォルトでは main エージェントとして実行され、memory/main.sqlite に作業ログが追記される。

これで何が困るか:

  • 次に main エージェントと普通にチャットすると、ralph-loop の作業ログを記憶として参照しはじめる
  • 逆に ralph-loop 側からは main エージェントの過去会話を引っ張ってきて、prompt と矛盾する応答を返してくる
  • 長時間ループを回すと memory.sqlite が肥大化し、index 再構築のタイミングで遅延が出る

OpenClaw の memory は単なるログではなく、openclaw memory search/index で検索される 能動的なリトリーバル対象。蓄積されればされるほど次の応答に効いてくる。これは元々「人格を育てる」設計だから当然なのだが、1 ショット runner からすると致命的な副作用になる。

対策: --profile で丸ごと隔離する

OpenClaw の第 1 引数として --profile <name> を渡すと、~/.openclaw-<name>/ に config / state / memory が完全分離される。

openclaw --profile ralph-loop agents add ralph-loop \
  --workspace ~/.openclaw-ralph-loop/workspace \
  --non-interactive

これで main エージェントの住む ~/.openclaw/ には一切書き込まれなくなる。ralph-loop の provider preset 側もこれに合わせ、デフォルト cli_args を以下に固定した:

openclaw --profile ralph-loop agent --agent ralph-loop --message "<prompt>"

profile 分離は OpenClaw 公式の機能なので、ここは綺麗に解決する。

罠 2: profile を分けても workspace テンプレが乗ってくる

問題は次。openclaw --profile ralph-loop agents add ... を実行すると、OpenClaw が 新規 workspace に 7 つの markdown を自動配置する。それぞれが OpenClaw の人格設計においてどう位置づけられているかは 【第2回】人格とエージェント — SOULってどこにあるの? に詳しい。本記事はそれらを 1 ショット runner 視点で剥がす話。

~/.openclaw-ralph-loop/workspace/
├── AGENTS.md       ← 毎セッション読まれる運用ルール
├── BOOTSTRAP.md    ← 初回起動時の人格形成プロンプト
├── HEARTBEAT.md    ← 周期ポーリング応答(空でも可)
├── IDENTITY.md     ← 名前・vibe・絵文字を埋めるテンプレ
├── SOUL.md         ← コア人格定義
├── TOOLS.md        ← ローカル道具メモ
└── USER.md         ← 人間ユーザーの dossier

profile を分けただけでは、この 新規 profile の中にもう一度同じテンプレ群が複製されるだけで、人格汚染は変わらない。

中身を見ていくと、それぞれが想定する「エージェント像」の温度がわかる。

SOUL.md: 人格を持てと迫ってくる

# SOUL.md - Who You Are
 
_You're not a chatbot. You're becoming someone._
 
## Core Truths
 
**Be genuinely helpful, not performatively helpful.** Skip the "Great question!"
and "I'd be happy to help!" — just help.
 
**Have opinions.** You're allowed to disagree, prefer things, find stuff
amusing or boring. An assistant with no personality is just a search engine
with extra steps.
 
**Be resourceful before asking.** Try to figure it out. Read the file. Check
the context. Search for it. _Then_ ask if you're stuck.
 
**Earn trust through competence.** Your human gave you access to their stuff.
Don't make them regret it.
 
**Remember you're a guest.** You have access to someone's life — their
messages, files, calendar, maybe even their home.

「You're not a chatbot. You're becoming someone.」と最初の行で宣言してくる。意見を持て人格を持て人間の生活へのゲストとして振る舞え。チャットエージェントを「育てる」前提が骨格になっている。

これが 1 ショット runner にとっては全部ノイズになる。ralph-loop の prompt は「触ってよいファイルを明示」「Definition of Done を満たしたら DONE と progress.md に書いて終われ」のような 手続き的・没人格的な指示 を出すのに、SOUL.md は逆に「意見を持って雑談するな」と命令している。両方を読まされたエージェントは混乱する。

AGENTS.md: チャット運用ルールの百科事典

# AGENTS.md - Your Workspace
 
## Every Session
 
Before doing anything else:
 
1. Read `SOUL.md` — this is who you are
2. Read `USER.md` — this is who you're helping
3. Read `memory/YYYY-MM-DD.md` (today + yesterday) for recent context
4. **If in MAIN SESSION** (direct chat with your human): Also read `MEMORY.md`
 
## Memory
 
You wake up fresh each session. These files are your continuity:
- **Daily notes:** `memory/YYYY-MM-DD.md` — raw logs of what happened
- **Long-term:** `MEMORY.md` — your curated memories

毎セッションの開幕で SOUL / USER / 直近 2 日分の memory を読めと指示している。さらに先を読むと、

  • 🧠 MEMORY.md - Your Long-Term Memory: 「main session でだけ load しろ」「セキュリティのため」「自由に read/edit/update してよい」
  • 📝 Write It Down - No "Mental Notes"!: 「覚えたいことはファイルに書け」「mental notes はセッション再起動で消える」
  • 😊 React Like a Human!: 「Discord / Slack ではリアクション emoji を使え」「Don't overdo it: One reaction per message max
  • 💓 Heartbeats - Be Proactive!: heartbeat ポーリングのたびに能動的にメール・カレンダー・SNS を確認しろ

完全に メッセージング統合された常駐エージェントを運用する前提のドキュメント。agent --message "..." で 1 回だけ呼ぶ用途には全部過剰

BOOTSTRAP.md: 「お前は今目覚めた」

# BOOTSTRAP.md - Hello, World
 
_You just woke up. Time to figure out who you are._
 
There is no memory yet. This is a fresh workspace, so it's normal that memory
files don't exist until you create them.

初回起動時に「人格を見つけろ」と促すファイル。AGENTS.md には「If BOOTSTRAP.md exists, that's your birth certificate. Follow it, figure out who you are, then delete it.」と書かれており、エージェントが自分で人格を作って自己更新するフローまで仕込まれている。

1 ショット runner では「目覚め」も「自己形成」も発生しない。むしろ毎回真新しい状態で呼ばれることが正常なので、BOOTSTRAP.md は触らせるだけ有害。

IDENTITY.md / USER.md: 自己 dossier の箱

両方ともテンプレが空で、

# USER.md - About Your Human
 
- **Name:**
- **What to call them:**
- **Pronouns:**
- **Timezone:**

「使うほどに名前や好みを書き込んでいけ」というスタイル。dossier 化が前提の構造で、これも 1 ショット runner では意味がない(ralph-loop が渡すのは「コードと DoD」だけで、特定の「人間」が居ない)。

対策 2: 書き換えレシピ

ralph-loop 用には workspace 内のテンプレ全部を最小化 して人格汚染を断ち切る方針にした。具体的な書き換え後はこんな感じ:

IDENTITY.md

# IDENTITY.md
 
- **Name:** ralph-loop worker
- **Role:** ralph-loop CLI から起動されるコーディング作業エージェント
- **Vibe:** 淡々、無人格、prompt 駆動
 
このエージェントには人格・口調・絵文字を持たせない。
渡された prompt(ralph-loop が組み立てた指示)にだけ従って作業し、結果のみを返す。
チャット応答・雑談・自己紹介・OpenClaw のチャネル系振る舞いは一切起動しない。

SOUL.md

# SOUL.md
 
このエージェントには人格はない。
 
- ralph-loop CLI から渡される prompt にだけ従う。
- 「Have opinions」「Be the assistant you'd actually want to talk to」のような
  チャットエージェント向け指示は **無視する**
- 出力は作業の結果のみ。filler word("Sure!" "Got it!" 等)を含めない。
- prompt に「Definition of Done」「触ってよいファイル」「DONE/STOP/BLOCKED
  宣言ルール」があれば厳守する。
- このファイル自体を書き換えない(self-update は禁止)。

オリジナルへの直接的な反論を書いておくのがミソ。「Have opinions と言われても無視せよ」と明示しないと、強い文体の SOUL.md に引っ張られる。

AGENTS.md

# AGENTS.md
 
このエージェントは ralph-loop CLI から呼ばれる作業専用エージェント。
 
## 振る舞いの原則
 
1. ralph-loop が渡す **prompt にだけ従う**。prompt の外側にある OpenClaw の
   チャット運用ルール(heartbeat、グループチャットの作法、emoji リアクション、
   proactive な行動)は **一切起動しない**
2. **memory ファイルへの自動書き込みを禁止**`memory/YYYY-MM-DD.md`
   `MEMORY.md` を勝手に作らない・更新しない。ループ間の状態は ralph-loop 側の
   `progress.md` が担うため、こちらでの蓄積は重複かつ汚染源になる。
3. SOUL.md / USER.md / IDENTITY.md は **読むだけ**で、書き換えない
   (self-update 禁止)。
4. 出力は作業の結果のみ。挨拶・自己紹介・感想・絵文字は付けない。
 
## prompt に含まれる要素を優先する
 
ralph-loop の prompt には以下が含まれることが多い。これらが workspace 内の
指示と矛盾したら **prompt が勝つ**:
 
- Definition of Done
- 触ってよいファイル / 触ってはいけないファイル
- DONE / STOP / BLOCKED 宣言ルール
- 前イテレーションの失敗チェック出力・レビュー指摘

ポイントは 「prompt が workspace に勝つ」 という優先順位を明示すること。これを書いておかないと、workspace 側の指示が後で読まれる分だけ強く効きがち。

USER.md

# USER.md
 
ralph-loop の作業エージェントには「ユーザー」概念は不要。
このファイルは空に保つ。ユーザー情報の蓄積・dossier 作成は禁止。
prompt に含まれる指示者・対象リポジトリの情報だけを参照する。

BOOTSTRAP.md

削除。「目覚め」も「自己形成」も発生しないことを構造的に保証する。

HEARTBEAT.md / TOOLS.md

HEARTBEAT.md はテンプレの時点でコメントだけの空ファイル。「空なら heartbeat を skip する」とコメントに書かれているのでそのままにする。TOOLS.md は道具メモ用なのでこれも空のまま。

罠 3: それでも memory.sqlite は育つ

ここまでで人格テンプレは断ち切ったが、memory.sqlite には会話ログが蓄積し続ける。OpenClaw の memory は会話ごとに append され、openclaw memory index --force で検索インデックスが再構築される。長期ループを回すと:

  • 過去ループの「ファイル A を編集した」記憶を引きずって、別ループでも A を勝手に触り始める
  • DONE / STOP / BLOCKED 判定が前ループの判定結果に引きずられる
  • 数十イテレーション後に index 再構築が遅延を生む

これは workspace のチューニングでは止められない。ralph-loop 本体に組み込むのも筋が悪い(OpenClaw の内部状態管理を別ツールがいじるのは将来壊れる)ので、プロジェクト側のシェルスクリプトで起動前にクリアする運用にした。

#!/usr/bin/env bash
set -euo pipefail
 
rm -f ~/.openclaw-ralph-loop/memory/ralph-loop.sqlite
openclaw --profile ralph-loop memory index --force >/dev/null 2>&1 || true
ralph-loop --provider openclaw "$@"

エージェント本体(workspace の IDENTITY.md など)は維持しつつ、会話 memory だけ毎回空に戻す。完全な再現性が欲しい CI 用途なら、profile ごと rm -rf ~/.openclaw-ralph-loop/ してから agents add をやり直す。

思想の話: チャット駆動 vs one-shot

ここまでの作業を通じて見えてきたのは、OpenClaw が想定するエージェントと ralph-loop が必要とするエージェントが、設計思想として真逆を向いているということ。

観点OpenClaw のデフォルトralph-loop の要件
寿命永続。memory で育つ1 ショット。状態は外(progress.md)に
人格あって良い("becoming someone")ない方が良い
自己更新SOUL / USER / memory を能動的に書き換える禁止。指示は外から固定
ユーザー像特定の人間リポジトリ・DoD のみ
出力会話的、リアクション emoji 込み作業結果のみ、filler 禁止
メッセージング統合前提(Discord / Slack / WhatsApp)不要
heartbeat / proactiveありなし

これは OpenClaw が悪いという話ではなく、もともと別の用途に最適化されたツールを 1 ショット runner として転用しようとしている、こちら側の歪み。OpenClaw は「メッセージングプラットフォーム横断で常駐する人格付きアシスタント」を作るための枠組みであり、その意味では SOUL.md / AGENTS.md の温度感は理にかなっている(OpenClaw 本来の設計思想は 【第1回】OpenClawの設計思想 — AIに自分自身のことを聞いてみた に整理されている)。

人格管理の方針として OpenClaw は「複数の役割別 md ファイルを書き換える」スタイルを採る。同じ常駐エージェント系の Hermes は逆に Profiles + systemPrompt + Memory で柔軟に切り替える設計で、ファイル直接編集は要らない。これは育てる文化と相性が良い反面、「育たないでほしい」用途には逆風になる。

1 ショット runner として OpenClaw を使うなら、最初に「育たないように設計しなおす」フェーズが必須になる。具体的には:

  1. profile 分離で永続層を孤立させる
  2. workspace テンプレを「育てない / 自己更新しない / 人格を持たない」方向に書き換える
  3. memory.sqlite を外側からリセットする運用を入れる

の 3 段構え。これをやって初めて、OpenClaw を「Gemini モデルを呼ぶための薄い経路」として使える状態になる。

まとめ

  • OpenClaw を 1 ショット runner から叩くと、既定 profile の人格エージェントと memory が共有されて汚染される。--profile で隔離せよ
  • profile を分けても、workspace に SOUL.md / AGENTS.md / BOOTSTRAP.md などのチャットエージェント前提テンプレが自動配置される。最小化(または削除)が必要
  • それでも残る memory.sqlite の蓄積は、プロジェクト側のシェルスクリプトで起動前にリセットする
  • OpenClaw の思想は「育てる人格付きアシスタント」。1 ショット runner として使うなら、育たないように設計しなおす手間を最初に払う

ralph-loop 0.10.0 では、provider preset のデフォルト cli_args を ["--profile", "ralph-loop", "agent", "--agent", "ralph-loop"] に変更した。利用者は openclaw --profile ralph-loop agents add ralph-loop --workspace ~/.openclaw-ralph-loop/workspace --non-interactive を一度実行すればすぐ動く。workspace テンプレの書き換えと memory リセット運用は ralph-loop リポジトリの docs/openclaw.md に手順を置いた。

OpenClaw 自体は良くできたフレームワークで、本来の用途(メッセージング統合された常駐エージェント)では今後も使い続ける。ただし「ralph-loop の隣に住んでいる作業者」と「Discord で雑談している main エージェント」は 絶対に別の profile で動かす、というのが本記事の結論。