OpenClaw Architecture Overview
OpenClaw Architecture Overview
OpenClaw is a self-hosted AI agent platform — an operating system for AI agents. It wraps the pi-agent-core runtime inside a central Gateway process and exposes agents to humans and other systems via pluggable channel adapters.
System Shape
graph LR
subgraph Adapters["Channel Adapters"]
WA[WhatsApp]
TG[Telegram]
DC[Discord]
SL[Slack]
IM[iMessage]
end
subgraph Control["Control Interfaces"]
WEB[Web UI]
CLI[CLI]
APP[macOS App]
MOB[Mobile]
end
subgraph GW["Gateway (127.0.0.1:18789)"]
direction TB
ROUTER[Session Router]
CRON[Cron Scheduler]
HOOKS[Webhook Endpoints]
TASKS[Task Ledger]
end
subgraph RT["Agent Runtime"]
CTX[Context Assembly]
LLM[Model Invocation]
TOOLS[Tool Execution]
end
Adapters --> GW
Control --> GW
GW --> RT
RT --> GW
GW --> AdaptersThe Gateway is the single choke point for all traffic. Adapters and control interfaces never speak to the runtime directly.
Critical Components
1. Gateway (Control Plane)
Node.js 22+ process binding to 127.0.0.1:18789 by default.
Responsibilities:
- Ingest messages from all sources (adapters + control interfaces)
- Route messages to the correct session lane
- Own all session state (routing tables,
.jsonltranscripts) - Host the cron scheduler, webhook endpoints, and background task ledger
- Deliver formatted responses back through the originating adapter
The loopback bind is the first security layer — no external network access without an explicit tunnel (SSH or Tailscale).
2. Channel Adapters
Platform-specific connectors plugged into the Gateway's hub:
- Authenticate with upstream platform
- Normalize inbound messages
- Enforce per-channel allowlists
- Format outbound responses per platform conventions
Supported: WhatsApp, Telegram, Discord, Slack, iMessage, and others.
3. Session Manager
The Gateway owns all session state. Each session maps to:
- A
.jsonltranscript (append-only, per-session) - A
sessions.jsonmetadata file
Session assignment is determined by message origin (DM → main, group/room → isolated, cron → fresh per run). The session.dmScope config controls isolation granularity for DMs (from shared main to per-channel-peer).
Sessions expire via daily reset (4 AM), idle timeout, or manual /reset.
4. Agent Runtime (pi-agent-core)
The inner execution engine wrapping pi-agent-core. Runs serialized within a session lane — one active turn per session at a time.
Six-phase execution per message:
sequenceDiagram
participant A as Channel Adapter
participant G as Gateway
participant S as Session Manager
participant R as Agent Runtime
participant L as LLM API
A->>G: Inbound message (Phase 1: Ingestion)
G->>G: Auth check + allowlist (Phase 2: Access Control)
G->>S: Assign session lane
S-->>G: Session context (.jsonl transcript)
G->>R: Dispatch to runtime
rect rgb(40, 60, 80)
note over R: Phase 3 – Context Assembly
R->>R: Load SOUL.md / AGENTS.md / TOOLS.md
R->>R: Hybrid memory search
R->>R: Inject session history
end
R->>L: Assembled context (Phase 4: Model Invocation)
L-->>R: Response + tool calls
rect rgb(40, 80, 60)
note over R: Phase 5 – Tool Execution
R->>R: Dispatch tool calls
R->>L: Tool results → follow-up if needed
L-->>R: Final response
end
R->>G: Completed turn output
G->>S: Append to .jsonl transcript
G->>A: Formatted reply (Phase 6: Response Delivery)The Gateway owns phases 1–2 and 6. The Agent Runtime owns phases 3–5.
5. Context Assembly
Phase 3 — builds the full context window before each model call:
graph TD
MSG[Current Message]
subgraph SYS["System Prompt"]
SOUL[SOUL.md
persona / values / guidelines]
AGENTS[AGENTS.md
sub-agents + Standing Orders]
TOOLS[TOOLS.md
tool definitions]
end
subgraph MEM["Memory"]
HYBRID[Hybrid Search
vector + keyword]
end
subgraph HIST["Session History"]
JSONL[.jsonl transcript
recent turns]
end
SYS --> CTX[Context Window]
MEM --> CTX
HIST --> CTX
MSG --> CTX
CTX --> LLM[Model Invocation]6. Hook System
Two layers of extension points:
| Type | Registration | Scope |
|---|---|---|
| Internal gateway hooks | Shell scripts, auto-discovered | Session lifecycle (/new, /reset, /stop), bootstrap |
| Plugin hooks | Plugin API | Full pipeline: model resolve → prompt build → tool call → compaction → message in/out |
Key plugin hook order: before_model_resolve → agent:bootstrap → before_prompt_build → before_agent_reply → before_tool_call / after_tool_call → tool_result_persist → agent_end.
Block/cancel semantics are terminal: a block: true on before_tool_call stops all lower-priority handlers.
7. Memory & Compaction
- Long-term memory: hybrid (vector + keyword) search at context assembly time — injects semantically relevant memories into every turn.
- Session pruning: per-request in-memory trimming of large tool results (soft trim → hard trim) to stay within token limits without touching the transcript.
- Compaction: when context overflows, summarizes the full conversation into a durable replacement transcript. Configurable model, identifier policy, and user notification. Triggered automatically or via
/compact.
8. Automation Subsystems
All hosted inside the Gateway process:
| Mechanism | Timing model | Record created? |
|---|---|---|
| Cron | Precise: --at, --every, --cron |
Yes — Background Task |
| Heartbeat | Fuzzy: default 30-min interval | No |
| Background Tasks | Passive ledger (no scheduling) | — |
| Task Flow | Multi-step workflow orchestration | Yes |
| Hooks | Lifecycle event-driven | No |
| Standing Orders | Injected every session via context assembly | No |
graph TD
CRON["Cron
precise schedule"]
HB["Heartbeat
fuzzy 30-min tick"]
HOOKS["Hooks
lifecycle events"]
SO["Standing Orders
every session"]
CRON -->|"--session main → enqueues into"| HB
CRON -->|"--wake → triggers early"| HB
CRON -->|"--session isolated"| TURN
HB --> TURN["Agent Turn"]
HOOKS --> TURN
SO -->|"injected via context assembly"| TURN
TURN -->|"spawns detached work"| BG["Background Tasks
audit ledger"]
TURN -->|"multi-step work"| TF["Task Flow
orchestration"]9. Security Model (Layered)
Outer → inner:
graph TD
NET["① Network Isolation
loopback bind · SSH tunnel / Tailscale for remote"]
AUTH["② Authentication
token / password for all clients"]
PAIR["③ Device Pairing
explicit pairing step for new nodes"]
ALLOW["④ Channel Allowlists
unknown senders rejected at Gateway"]
SAND["⑤ Tool Sandboxing
Docker containers for untrusted sessions"]
INJ["⑥ Prompt Injection Defenses
untrusted content isolated from system prompt"]
NET --> AUTH --> PAIR --> ALLOW --> SAND --> INJ10. Plugin System
The Gateway exposes extension points for:
- Channel plugins (new adapters)
- Memory plugins (alternative memory backends)
- Tool plugins (new agent capabilities)
- Provider plugins (alternative LLM providers)
Skills are loaded as a snapshot and injected into the environment and system prompt.
Deployment Topologies
| Mode | How |
|---|---|
| Local dev | Gateway on localhost; control via CLI/Web UI |
| macOS background | LaunchAgent keeps Gateway alive across reboots |
| Linux/VPS | SSH tunnel or Tailscale exposes the loopback port securely |
| Cloud container | Fly.io (or similar); same loopback isolation inside the container |
graph LR
subgraph LOCAL["Local Dev"]
L_GW["Gateway
127.0.0.1:18789"]
L_CLI["CLI / Web UI"]
L_CLI --> L_GW
end
subgraph MACOS["macOS Background"]
M_LA["LaunchAgent"]
M_GW["Gateway"]
M_LA -->|"keeps alive"| M_GW
end
subgraph VPS["Linux / VPS"]
V_SSH["SSH Tunnel
or Tailscale"]
V_GW["Gateway
127.0.0.1:18789"]
V_SSH --> V_GW
end
subgraph CLOUD["Cloud Container (Fly.io)"]
C_GW["Gateway
loopback inside container"]
C_PROXY["Reverse Proxy / Fly proxy"]
C_PROXY --> C_GW
end
ADAPTERS["Channel Adapters
(Slack, Telegram…)"]
ADAPTERS --> V_SSH
ADAPTERS --> C_PROXY
ADAPTERS --> L_GW
ADAPTERS --> M_GWKey References
- OpenClaw Gateway — detailed control plane reference
- Agent Loop (OpenClaw) — phases 3–5 internals, RPC surface, timeout hierarchy
- Context Assembly — phase 3 detail
- Session Management — routing, isolation scopes, storage layout
- Security Model — full layered defense stack
- OpenClaw Hooks — complete hook event reference
- Automation & Tasks — six mechanisms + decision guide
- Compaction — context overflow handling
- pi-mono — underlying
pi-agent-coreruntime that the Gateway wraps