最近、OpenClaw(旧称 Clawdbot → Moltbot)が気になり、アーキテクチャをじっくり調べてみました。GitHub スター数は 230,000+ を超え、2026年初頭に最も急成長したOSSプロジェクトの一つです。
何がそんなに面白いかというと、OpenClawの核心的な設計思想が「AIアシスタントはプロンプトエンジニアリングの問題ではなく、インフラストラクチャの問題である」という捉えた点にあります。 つまり、いわゆるLLM(ChatGPTなど)を利用するインフラから提供するという点で、OpenClawはより上位概念の一つと言えます。
ということで、この記事ではOpenClawのアーキテクチャを各コンポーネントに分解しながら、その設計思想を深掘りしていきます。
テクノロジースタック
まずは技術スタックの全体像を押さえておきましょう。
| レイヤー | 技術 |
|---|---|
| 言語 | TypeScript |
| ランタイム | Node.js 22+(tsx で直接実行、または tsdown でビルド後 Node で実行) |
| パッケージ管理 | pnpm ワークスペース(モノレポ構成) |
| ビルドツール | tsdown(バンドラー)、oxlint / oxfmt(リンター/フォーマッター) |
| テスト | Vitest |
| 型チェック | tsgo(TypeScript native preview を利用) |
| ネイティブアプリ | Swift(macOS/iOS)、Kotlin(Android) |
| DB | SQLite(sqlite-vec + FTS5 拡張) |
| プロトコル | WebSocket(JSON Schema バリデーション付き) |
TypeScript ベースのモノレポ構成で、ネイティブアプリも Swift / Kotlin で提供しています。ビルドツールに tsdown や oxlint を採用しているあたり、新しいツールチェインへの感度が高いですね。
全体アーキテクチャ — Hub-and-Spoke 構成
OpenClaw のアーキテクチャの全体像は、Gateway を中枢に据えた Hub-and-Spoke 構成です。
WhatsApp / Telegram / Slack / Discord / Signal / iMessage / Teams / WebChat / ...
│
▼
┌──────────────────────┐
│ Gateway │
│ (Control Plane) │
│ ws://127.0.0.1:18789│
└──────────┬───────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
Pi Agent (RPC) CLI / WebChat UI macOS / iOS / Android Nodes
ここで最も重要なのは、Interface 層(メッセージの入り口)と Assistant Runtime(インテリジェンスと実行)を完全に分離していることです。
どのチャネルからでも同一のアシスタントにアクセスでき、会話状態やツールアクセスはすべてユーザーの手元で中央管理されます。WhatsApp で始めた会話を Slack で続けられる、みたいなことが自然にできるわけですね。
コアコンポーネント詳細
ここからは各コンポーネントをもう少し掘り下げていきます。
Channel Adapters(チャネルアダプター)
各メッセージングプラットフォームの差異を吸収して、統一メッセージ形式に正規化するレイヤーです。
コアチャネルとして src/ 内に直接実装されているものは以下の通りです。
- WhatsApp → Baileys
- Telegram → grammY
- Discord → @buape/carbon
- Slack → @slack/bolt
- iMessage、Signal
さらに エクステンションチャネル として extensions/ ディレクトリに独立パッケージとして配置されているものもあります。Matrix、Google Chat、Microsoft Teams、LINE、Feishu/Lark、Zalo などですね。
それぞれのアダプターは Plugin SDK で定義されたインターフェースに準拠しています。
// plugin-sdk で定義されるアダプターインターフェース(概念図)
interface ChannelMessagingAdapter { /* メッセージ送受信 */ }
interface ChannelGatewayAdapter { /* Gatewayとの接続管理 */ }
interface ChannelAuthAdapter { /* 認証・ペアリング */ }
認証、インバウンドメッセージのパース、アクセス制御(DM allowlist / pairing)、アウトバウンドフォーマッティングを各アダプターが担当します。チャネルが増えてもコアロジックに影響しないのは綺麗な設計だなと思います。
Gateway(コントロールプレーン)
Gateway は OpenClaw の唯一の WebSocket サーバーで、システム全体のオーケストレーション層です。やっていることを列挙するとこんな感じです。
- チャネル管理・セッション管理
- ツールルーティング・イベントディスパッチ
- デバイスペアリング・認証(connect.challenge nonce 署名)
- 静的 UI(Control UI + WebChat)のサーブ
- プロバイダー接続の維持
- JSON Schema によるインバウンドフレームバリデーション
- イベント発行(
agent,chat,presence,health,heartbeat,cron)
Gateway は port 18789 で起動し、1ホストにつき1つの Bailey セッション(WhatsApp)を制御します。ハンドシェイクは必須で、非 JSON または non-connect の最初のフレームは即座にクローズされます。
面白いのは、Idempotency Key が副作用のあるメソッド(send, agent)に必須になっている点です。短寿命の重複排除キャッシュでリトライ安全性を担保していて、ネットワークの不安定さに起因する二重実行を防いでいます。
Lane Queue(レーンキュー)— 並行制御の核心
個人的に OpenClaw のアーキテクチャで最も面白いと感じたのが、この Lane Queue です。
Lane Queue は純粋な TypeScript + Promises の In-Process Queue です。外部ワーカーも Background Thread も使いません。
不変量(Invariants) として守られるルールは3つだけです。
- 1セッションにつき1レーン → 書き込みのシリアライズ
- Global Throttling
- 新しい入力が実行中に到着した場合の振る舞いを明示的に定義
そしてキューモードが3種類あります。
| モード | 振る舞い |
|---|---|
collect | 実行中のタスクが終わるまで新メッセージを Buffering |
steer | ツール境界で Preempt(中断・方向転換)。安全に割り込み可能 |
followup | 現在の実行完了後に Follow-up として処理 |
この設計の素晴らしいところは、「ゴーストバグ」(非同期並行環境で再現困難なバグ)を根本的に排除しているところです。デバッグ時に「どのスレッドで起きた?」という疑問がそもそも発生しない。シンプル。
Agent Runner(エージェントランナー)
LLM 呼び出しの「アセンブリライン」にあたるコンポーネントです。担当する処理は以下の通り。
- モデル選択・API キーの Cooling(Rate Limit 時の自動 Rotation)
- Prompt Assembly(システムプロンプト + スキル + Bootstrap Context + Session History)
- Context Window 管理(Token 上限の監視、不足時の Compaction or グレースフル失敗)
- Model Failover(プライマリ → Fallback モデルへの自動切替)
主要なソースファイルの場所は以下です。
src/agents/pi-embedded-runner/run.ts— メインのエージェント実行ループsrc/agents/pi-embedded-runner/compact.ts— セッションコンパクションsrc/agents/system-prompt.ts— システムプロンプト構築src/agents/agent-scope.ts— エージェントスコープ解決
Agentic Loop(エージェントループ)
モデルがツール呼び出しを提案 → システムが実行 → 結果を Backfill → 解決 or 上限到達まで繰り返す、という反復 Cycle です。Claude Code を使っている方ならおなじみの、あのループですね。
ループに入る前の準備ステップが結構しっかりしていて、順を追うとこんな流れです。
- ワークスペース解決・作成(サンドボックス実行時はリダイレクト)
- スキルのロード(or スナップショットからの再利用)→ env とプロンプトに注入
- ブートストラップ/コンテキストファイルの解決 → システムプロンプトレポートに注入
- セッション書き込みロックの取得
- SessionManager のオープン・準備
- システムプロンプト構築(ベースプロンプト + スキル + ブートストラップ + per-run オーバーライド)
- モデル固有のリミット・コンパクション予約トークンの適用
コンテキスト圧縮の仕組みも用意されていて、コンテキストがほぼ満杯になるとセッション履歴を要約圧縮し、readPostCompactionContext でワークスペーススナップショットを次ターンに注入します。圧縮自体が失敗した場合はセッションをリセットして、ゼロからリスタートするというフォールバックもあります。
ツールシステム
組み込みツール
| ツール | 説明 |
|---|---|
| Bash/Shell | 安全なコマンド(jq, grep, sort 等)はプリ承認。危険なシェル構造(リダイレクト、サブシェル)はデフォルトブロック |
| File System | ファイルの読み書き。ワークスペース内に限定 |
| Browser | Chrome/Chromium の CDP 制御。Semantic Snapshots を使用 |
| Canvas / A2UI | エージェント主導のビジュアルワークスペース |
| Cron / Webhooks | スケジュール実行、外部トリガー |
Semantic Snapshots(セマンティックスナップショット)
ブラウザ自動化において、OpenClaw が取っているアプローチがかなり面白いです。
従来のスクリーンショットベースのアプローチではなく、アクセシビリティツリー(ARIA)のテキスト表現をパースして使います。スクリーンショットが ~5MB なのに対して、セマンティックスナップショットは ~50KB と、トークンコストを約90%削減しています。
LLM はピクセル座標を推測するのではなく、構造化されたノード参照でボタン・リンク・フォームを選択できるので、精度も高い。見た目の情報よりも構造の情報のほうが LLM にとっては扱いやすいという、考えてみれば当然のアプローチなんですが、実際にここまで徹底しているのはさすがだなと思います。
ツールポリシーと安全性
ツールの安全性については、設定ファイルで許可コマンドを明示的にリスト化するという方法を取っています。モデルに「やらないで」と頼むのではなく、システムレベルで制御する。これもまた、「モデル問題ではなくインフラ問題」という思想の表れですね。
データ管理
セッション管理
セッションの管理は JSONL トランスクリプトで行われていて、行ごとに事実の監査記録(ユーザーメッセージ、ツール呼び出し、実行結果)が残ります。
セッションキーは構造化文字列で、エージェントルーティングコンテキストをエンコードしています。各セッションは独立分離されていて、ワークスペース解決、ファイルパス、コマンドレーンルーティング、ツールポリシーがそれぞれ独立しています。
メモリシステム
すべてのデータは ~/.openclaw/ にローカル保存されます。ここも OpenClaw らしい「ユーザーの手元で管理する」という思想が貫かれていますね。
メモリは2層構造です。
- セッショントランスクリプト(JSONL)— 何が起きたかの事実記録
- メモリファイル(
MEMORY.mdormemory/フォルダ、Markdown)— 覚えておくべきこと(要約、経験、蒸留された知識)
そして検索にはハイブリッドアプローチを採用しています。
| 方式 | 技術 | 用途 |
|---|---|---|
| ベクトル類似検索 | sqlite-vec | セマンティックな類似想起(「authentication bug」→「login issues」) |
| キーワード検索 | SQLite FTS5 | 正確な技術用語のマッチ |
ベクトル検索だけだと「セマンティックノイズ」が発生するし、キーワード検索だけだとパラフレーズを見逃してしまう。両方を組み合わせることで一貫して高い精度を実現しているというのは、実際にメモリ検索を運用してみた人なら「わかる」となるポイントだと思います。
さらに面白いのが「スマートシンク」で、エージェントがメモリファイルに書き込むとファイルモニターが自動でインデックス更新をトリガーし、次のプロンプトで即座に利用可能になります。
設定
openclaw.json にエージェント設定を宣言する形式で、agents.defaults(ベースライン)と agents.<agentId>(個別オーバーライド)の2層構造になっています。
プラグインシステム
OpenClaw はコアコードを変更せずに拡張できるプラグインアーキテクチャを備えています。4種類のプラグインがあります。
| 種別 | 説明 |
|---|---|
| Channel | 追加メッセージングプラットフォーム |
| Memory | 代替ストレージバックエンド(ベクトルストア、ナレッジグラフ等) |
| Tool | 組み込みの bash/browser/file 以外のカスタムツール |
| Provider | カスタム LLM プロバイダー or セルフホストモデル |
プラグインの発見メカニズムもシンプルで、extensions/ ディレクトリに配置して、src/plugins/loader.ts のプラグインローダーがワークスペースパッケージの package.json 内の openclaw.extensions フィールドをスキャンして、宣言されたスキーマに対してバリデーションし、設定が存在する場合に Hot-Load するという流れです。
フックシステムも2種類あって、内部フック(Gateway hooks)がコマンドやライフサイクルイベント用、プラグインフックがエージェント/ツールライフサイクルおよび Gateway パイプライン内の拡張ポイントとして機能します。
メッセージフロー(6フェーズパイプライン)
一つのメッセージがどう処理されるか、End-to-End のフローを見てみましょう。
Phase 1: Ingestion(取り込み)
└─ Channel Adapter がプラットフォーム固有のメッセージを統一形式に正規化
Phase 2: Access Control & Routing(アクセス制御 & ルーティング)
└─ DM ポリシー (allowlist / pairing) チェック → セッション解決 → レーンキューへ
Phase 3: Context Assembly(コンテキスト組立)
└─ セッション履歴 + メモリ検索 + スキル + ブートストラップファイル → システムプロンプト構築
Phase 4: Model Invocation(モデル呼び出し)
└─ Agent Runner がモデル選択 → API 呼び出し → ストリーミングレスポンス
Phase 5: Tool Execution(ツール実行)
└─ モデルがツール呼び出しを提案 → システムが実行 → 結果バックフィル → ループ継続
Phase 6: Response Delivery(レスポンス配信)
└─ チャネルアダプターが元のプラットフォーム形式にフォーマット → チャンキング → 送信
Phase 1 でプラットフォームの差異を吸収して、Phase 6 で再びプラットフォーム固有のフォーマットに変換するというサンドイッチ構造が、Hub-and-Spoke アーキテクチャの設計思想を如実に表しています。
マルチエージェントルーティング
単一アシスタントだけでなく、分離されたワークスペース・セッション履歴・ツールアクセスを持つ複数のエージェントを構成できるのも特徴的です。
resolveSessionAgentIds() (src/agents/agent-scope.ts)がセッションキーと設定から { defaultAgentId, sessionAgentId } をマッピングします。例えば、Slack は仕事エージェント、WhatsApp は個人アシスタントのように使い分けることが可能です。
Agent-to-Agent 通信も sessions_send ツールや agentToAgent プリミティブで実現されていますし、Lobster というワークフローエンジンで YAML ベースの決定論的パイプライン(サブワークフロー・ループ対応)も組めます。
セキュリティアーキテクチャ
セキュリティは多層防御のアプローチです。
| レイヤー | メカニズム |
|---|---|
| ネットワーク | WebSocket は現在デフォルトで 127.0.0.1 にバインド(初期バージョンでは 0.0.0.0 がデフォルトで深刻なセキュリティ問題となった)。外部公開は SSH トンネル or Tailscale Serve/Funnel |
| 認証 | OPENCLAW_GATEWAY_TOKEN による接続認証。デバイスペアリング(connect.challenge nonce 署名) |
| チャネルアクセス | DM ポリシー(allowlist / pairing)でインバウンドメッセージをゲーティング |
| ツールサンドボックス | セッションベースのセキュリティ境界。許可コマンドの明示的リスト。危険なシェル構造のブロック |
| プロンプトインジェクション防御 | システムレベルのツールポリシーで制御(モデルに依存しない) |
なお、初期バージョンでは 0.0.0.0:18789 がデフォルトだったため、40,000以上のインスタンスがインターネットに露出するという深刻な事態が発生しました。さらに CVE-2026-25253(CVSS 8.8)として、localhost にバインドしていても Cross-Site WebSocket Hijacking でリモートコード実行が可能な脆弱性も発見されています。現在は 127.0.0.1 バインドがデフォルトに修正され、外部公開には SSH トンネルや Tailscale が推奨されています。急成長したプロジェクトゆえのセキュリティの課題が垣間見える部分です。
Heartbeat(自律的定期実行)
ほとんどのエージェントはユーザーメッセージを待つ受動的なモデルですが、OpenClaw はBackground Daemon + 設定可能な Heartbeat 間隔(デフォルト30分)を提供しています。
ティックごとにワークスペースの HEARTBEAT.md チェックリストを読み、自律的にタスクを実行するという仕組みです。エージェントが自律的に動くという方向性は今後さらに重要になってくると思います。
ディレクトリ構造
リポジトリの構造を推定すると以下のようになります。
openclaw/
├── src/
│ ├── agents/
│ │ ├── pi-embedded-runner/ # メインのエージェント実行エンジン
│ │ │ ├── run.ts # runEmbeddedPiAgent
│ │ │ ├── compact.ts # セッションコンパクション
│ │ │ └── types.ts
│ │ ├── agent-scope.ts # エージェントスコープ解決
│ │ └── system-prompt.ts # システムプロンプト構築
│ ├── gateway/ # Gateway サーバー
│ ├── auto-reply/ # コマンド & オートリプライ
│ │ └── reply/
│ │ └── agent-runner.ts
│ ├── plugins/
│ │ └── loader.ts # プラグインローダー
│ ├── channels/ # コアチャネル実装
│ │ ├── whatsapp/ # Baileys
│ │ ├── telegram/ # grammY
│ │ ├── discord/ # @buape/carbon
│ │ └── slack/ # @slack/bolt
│ └── ...
├── extensions/ # エクステンションチャネル(独立パッケージ)
├── apps/
│ ├── ios/ # Swift
│ ├── macos/ # Swift
│ └── android/ # Kotlin
├── skills/ # 組み込みスキル
├── scripts/ # ビルド・ユーティリティスクリプト
├── package.json # pnpm ワークスペースルート
├── pnpm-workspace.yaml
├── tsdown.config.ts
└── vitest.config.ts
Pi(pi-mono)との関係 — OpenClaw の心臓部
ここからは OpenClaw を語るうえで欠かせない、Pi(pi-mono)との関係について掘り下げていきます。一言で言うと、Pi はエンジン、OpenClaw は車体です。
Pi(pi-mono)とは
libGDX ゲームフレームワークの作者である Mario Zechner が、Claude Code の肥大化に不満を感じて自作した AI コーディングエージェントです。
設計哲学が潔くて、「不要な機能は作らない」を徹底しています。デフォルトはわずか4つのツール(read, write, edit, bash)と1,000トークン以下のシステムプロンプトだけで構成されています(後に read-only mode 用に grep, find, ls も built-in に追加)。
リポジトリは badlogic/pi-mono で、TypeScript モノレポ(npm workspaces)の3パッケージ構成です。
| パッケージ | 役割 |
|---|---|
@mariozechner/pi-ai | Anthropic、OpenAI、Google 等を横断する統一 LLM API 抽象層 |
@mariozechner/pi-agent-core | ツール実行、イベントストリーミング、会話管理を備えたステートフルなエージェントランタイム |
@mariozechner/pi-coding-agent | 対話型コーディングエージェント CLI(pi コマンド) |
pi-mono は 2025年8月に誕生し、OpenClaw より3ヶ月先行しています。
OpenClaw が Pi をどう使っているか
OpenClaw は Pi を SDK として消費し、その上に Gateway レイヤーを追加しています。概念的にはこんな感じです。
import { AgentLoop, Context, getModel } from '@mariozechner/pi-agent-core';
import { createGateway } from './gateway';
const gateway = createGateway({
port: 18789,
channels: ['whatsapp', 'telegram', 'slack', 'discord']
});
gateway.on('message', async (channel, userId, text) => {
const session = await getSession(userId);
const agent = new AgentLoop({
model: getModel('anthropic', 'claude-sonnet-4-20250514'),
context: session.context,
tools: [...builtinTools, ...session.customTools]
});
for await (const event of agent.run(text)) {
if (event.type === 'text_delta') {
await channel.send(userId, event.delta);
}
}
await saveSession(userId, session);
});
コード内で頻繁に登場する pi-embedded-runner、runEmbeddedPiAgent()、EmbeddedPiAgentMeta、compactEmbeddedPiSession() 等の命名はすべて、Pi Agent Core の SessionManager が .jsonl トランスクリプトで会話履歴を維持し、すべてのパスが runEmbeddedPiAgent() に収束することに由来しています。
役割分担
両者の役割分担を整理するとこうなります。
| 担当 | Pi(pi-mono) | OpenClaw |
|---|---|---|
| LLM 呼び出し | ✅ 統一 API 抽象 | Pi に委譲 |
| エージェントループ | ✅ ツール実行・ストリーミング | Pi を埋め込みで実行 |
| セッション/トランスクリプト | ✅ JSONL 管理 | Pi の SessionManager を利用 |
| Gateway / WebSocket | — | ✅ コントロールプレーン |
| チャネルアダプター | — | ✅ WhatsApp / Telegram / Slack 等 |
| Lane Queue(並行制御) | — | ✅ シリアル実行保証 |
| メモリ検索(ベクトル+FTS) | — | ✅ sqlite-vec + FTS5 |
| スキルエコシステム | — | ✅ ClawHub(5,700+ スキル) |
| ブラウザ自動化 | — | ✅ Semantic Snapshots |
| ネイティブアプリ | — | ✅ Swift / Kotlin |
Pi がエージェントの核を担当し、OpenClaw がその周辺のすべてを担当するという、綺麗な分業です。
Pi のミニマリスト設計哲学
Mario Zechner は「やらないことリスト」を明確に掲げています。
- MCP 不採用 — Playwright MCP(21ツール、13.7kトークン)や Chrome DevTools MCP(26ツール、18kトークン)はコンテキストウィンドウの7-9%を占有してしまう。代わりに README 付き CLI ツールを「On-Demand Load」する方式を採用
- 最小システムプロンプト — 1,000トークン以下。「Frontier Model は RL で十分訓練されており、コーディングエージェントが何かを本質的に理解している」という前提
- ツリー構造のセッション — 各メッセージに
idとparentIdを持たせた JSONL 形式。会話の任意ノードから分岐可能
MCP を不採用にした理由が「コンテキストウィンドウの7-9%を占有するから」というのは、なかなか刺さる指摘ですよね。
二人の協力関係
OpenClaw の README には「Special thanks to Mario Zechner for his support and for pi-mono」と明記されています。
OpenClaw の要望が pi-mono の機能追加を駆動し、pi-mono の改善が OpenClaw の安定性を向上させるという好循環が生まれています。
Mario Zechner と Peter Steinberger は両方ともオーストリア人で、成功したテック企業を創業・売却後に「引退」を宣言し、2025年に AI の波に乗って復帰したという似た経歴を持っています。一方がエンジンを磨き、もう一方がその上にプロダクトを組み立てるという補完的な分業で、お互いの強みがうまくかみ合っている良い関係だなと思います。
なお、2026年2月15日に Peter Steinberger は OpenAI への入社を発表し、OpenClaw は OpenAI がスポンサーとなる独立したオープンソース財団に移管されることになりました。
まとめ
ここまで OpenClaw のアーキテクチャを一通り見てきました。
OpenClaw の核心的な洞察は、パーソナル AI エージェントは本質的に「Gateway 問題」であり「モデル問題」ではないということです。
ランタイムの正しさ(Queuing、チャネル正規化、メモリ、拡張性)は、どの LLM を使うかよりも重要だという主張には個人的にかなり同意しています。特に注目すべきアーキテクチャパターンを改めて整理すると以下の通りです。
- Lane Queue によるセッション単位のシリアル実行 — 並行制御の最小不変量で最大の信頼性
- Semantic Snapshots — スクリーンショットではなくアクセシビリティツリーによるブラウザ自動化
- ハイブリッドメモリ検索 — ベクトル + キーワードの組み合わせでセマンティックノイズを排除
- プラグインベースの拡張性 — コア変更不要で4方向に拡張可能
- JSONL トランスクリプト + Markdown メモリ — 人間が監査・差分確認可能なシンプルな永続化
- Hub-and-Spoke Gateway — インターフェース層とランタイム層の明確な分離
“Build agents that are reliable before they are clever. OpenClaw got that part right.”
「賢くする前に、まず信頼できるエージェントを作れ」。この言葉がOpenClawの設計思想を最もよく表しているのではないでしょうか。