Skip to content

Instantly share code, notes, and snippets.

@jmanhype
Forked from mikehostetler/OPENCLAW_OVERVIEW.md
Last active February 3, 2026 17:28
Show Gist options
  • Select an option

  • Save jmanhype/6a4be9762ac68989598023230cdb3e3e to your computer and use it in GitHub Desktop.

Select an option

Save jmanhype/6a4be9762ac68989598023230cdb3e3e to your computer and use it in GitHub Desktop.
OpenClaw Architecture Overview

OpenClaw Architecture Overview

OpenClaw is a multi-channel message routing layer wrapped around an embedded "coding agent" runtime (pi-agent-core). It enables AI agents to operate across messaging platforms (Telegram, Discord, Slack, Signal, iMessage, WhatsApp, etc.) with unified tool access, session management, and extensibility.


High-Level Architecture

┌─────────────────────────────────────────────────────────────────┐
│                     Channel Integrations                        │
│  (Telegram, Discord, Slack, Signal, iMessage, WhatsApp, etc.)   │
└──────────────────────────┬──────────────────────────────────────┘
                           │ Normalized MsgContext
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                   Auto-Reply Orchestration                      │
│  (Command handling, Session management, Reply routing)          │
└──────────────────────────┬──────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                   Embedded Agent Runtime                        │
│  (LLM execution, Tools, Streaming, Fallbacks)                   │
└─────────────────────────────────────────────────────────────────┘

Layer 1: Channel Integrations

Per-channel adapters normalize platform-specific events into a shared MsgContext and deliver replies back.

Key Files

  • src/telegram/bot.ts - Telegram Bot API integration
  • src/discord/ - Discord bot integration
  • src/slack/ - Slack integration
  • src/signal/ - Signal integration
  • src/imessage/ - iMessage integration
  • src/web/ - WhatsApp Web integration

Channel Plugin Contract

Defined in src/channels/plugins/types.plugin.ts, plugins can implement:

  • outbound - Message delivery
  • actions - Channel-specific operations (send, react, moderate, create threads)
  • threading - Thread/topic support
  • mentions - Mention stripping/parsing
  • security - Allowlists and DM policies
  • status - Health/configuration checks
  • setup, pairing, login - Channel-specific setup flows

Channel Registry

src/channels/registry.ts maintains canonical channel IDs and ordering:

  • telegram, whatsapp, discord, googlechat, slack, signal, imessage

Layer 2: Auto-Reply Orchestration

The "brainstem" that decides how to handle inbound messages.

Main Entrypoint

src/auto-reply/reply/get-reply.ts - getReplyFromConfig()

This function:

  1. Normalizes inbound context
  2. Resolves directives (model selection, elevated mode, streaming)
  3. Handles inline actions
  4. Routes to commands OR invokes the LLM agent

Session Management

src/auto-reply/reply/session.ts - initSessionState()

  • Session key ties everything together: agent selection, tool policy, transcript location
  • Sessions are scoped per-sender or per-group (configurable)
  • Reset triggers: /new, /reset, or age-based freshness policies
  • Persists delivery fields for routing/announce-back

Command Handling

src/auto-reply/reply/commands-core.ts

Commands can bypass the LLM entirely. The handler pipeline iterates through registered handlers and can short-circuit with a direct reply.

Reply Dispatching

src/auto-reply/reply/reply-dispatcher.ts

Serializes toolblockfinal outbound sequences with optional "human delay" between blocks.


Layer 3: Embedded Agent Runtime

Executes LLM "turns" with tools, streaming, retries, and fallback models.

Main Execution

  • src/agents/pi-embedded-runner/run.ts - runEmbeddedPiAgent()
  • src/agents/pi-embedded-runner/run/attempt.ts - runEmbeddedAttempt()

The execution loop:

  1. Builds tools
  2. Configures sandbox (if enabled)
  3. Loads skills prompt and bootstrap context
  4. Creates/loads session transcript (JSONL)
  5. Streams events back (assistant text, tool results, reasoning)

Streaming Subscription

src/agents/pi-embedded-subscribe.ts - subscribeEmbeddedPiSession()

Aggregates and emits:

  • Assistant text chunks
  • Tool summaries/outputs
  • Reasoning stream (optional)
  • Suppresses duplicates when messaging tools already sent content

Tool System

Core Tools

src/agents/openclaw-tools.ts:

  • message - Cross-channel message sending
  • sessions_send, sessions_spawn, sessions_list/history - Multi-session management
  • gateway, cron, nodes - Infrastructure tools
  • browser, canvas, tts, image - Media/interaction tools
  • web_search, web_fetch - Web access

Coding Tools

src/agents/pi-tools.ts - createOpenClawCodingTools():

  • Filesystem: read, write, edit
  • Process execution with policy enforcement

Memory Tools

src/agents/tools/memory-tool.ts:

  • memory_search - Semantic recall from MEMORY.md + memory/*.md
  • memory_get - Direct memory retrieval

Tool Policy System

Policies are layered and merged:

Global (cfg.tools)
    └── Agent-specific (cfg.agents.list[].tools)
        └── Provider/model-specific (tools.byProvider)
            └── Group policy (per channel group)
                └── Sandbox policy (workspace access)
                    └── Subagent policy (default-deny for sensitive tools)

Key files:

  • src/agents/tool-policy.ts - Profiles and groups (group:fs, group:runtime, etc.)
  • src/agents/pi-tools.policy.ts - Policy resolution and merging

Agent Identity & Configuration

OpenClaw doesn't use long-lived "Agent" objects. Instead, agent identity is configuration-driven and session-key-driven.

Agent Selection

src/agents/agent-scope.ts:

  • resolveDefaultAgentId(cfg)
  • resolveSessionAgentId({ sessionKey, config })
  • resolveAgentWorkspaceDir(cfg, agentId)

Configuration Surfaces

  • cfg.agents.defaults - Default workspace, model, typing interval, etc.
  • cfg.agents.list[] - Per-agent overrides (workspace, model, tools, sandbox, subagents)

Memory & Context Management

1. Conversation Context (LLM Transcript)

  • Persisted as JSONL transcripts per session (SessionManager)
  • Session metadata in session store (SessionEntry)
  • Reset policies prevent unbounded growth

2. Project/User Memory (Semantic Recall)

  • memory_search and memory_get tools
  • Sources: MEMORY.md, memory/*.md, optionally transcripts
  • Gated by resolveMemorySearchConfig(cfg, agentId)

3. Group History Buffer

src/auto-reply/reply/history.ts:

  • In-memory rolling map with LRU eviction
  • Provides "messages since last reply" context for group chats

Plugin System

Plugin Hooks

Defined in src/plugins/types.ts:

  • before_agent_start, agent_end - Lifecycle hooks
  • before_tool_call, after_tool_call, tool_result_persist - Tool hooks
  • message_received, message_sending, message_sent - Message hooks
  • Compaction, session, and gateway hooks

Plugin Registry

  • src/plugins/runtime.ts - Global plugin registry
  • Plugins loaded from bundled/global/workspace/config paths

Plugin Tools

src/plugins/tools.ts - resolvePluginTools()

  • Plugins can expose their own tools
  • Gated by toolAllowlist

Agent Lifecycle

Session Lifecycle

  • Identity: Session key
  • Content: Transcript file (JSONL)
  • Metadata: SessionEntry (last delivery, toggles, etc.)

Run Lifecycle

Each agent invocation has a unique runId.

Events published via src/infra/agent-events.ts:

  • lifecycle (start/end/error)
  • assistant (text chunks)
  • tool (tool calls/results)
  • error

Extension Points

Add a New Messaging Channel

  1. Implement ChannelPlugin contract
  2. Register via plugin registry
  3. Implement adapters: inbound normalization, outbound delivery, actions, threading

Add New Tools

  • Core: Add to createOpenClawTools() or createOpenClawCodingTools()
  • Plugin: Implement plugin tool factories in resolvePluginTools()

Add Lifecycle/Message/Tool Hooks

Implement hooks defined in src/plugins/types.ts

Add Commands (Bypass LLM)

  • Plugin commands (registered before built-ins)
  • Or add to HANDLERS[] in commands-core.ts

Alter Tool Policies

  • Tool profiles/groups: src/agents/tool-policy.ts
  • Policy merging: src/agents/pi-tools.policy.ts

Quick Reference: Where to Look

What Where
Inbound normalization / session keys src/<channel>/*
Main reply entrypoint src/auto-reply/reply/get-reply.ts
Session state logic src/auto-reply/reply/session.ts
Command handling src/auto-reply/reply/commands-core.ts
LLM execution orchestration src/auto-reply/reply/agent-runner.ts
Fallback + run loop src/auto-reply/reply/agent-runner-execution.ts
Embedded Pi agent runtime src/agents/pi-embedded-runner/run.ts
Tools and tool policies src/agents/pi-tools.ts, src/agents/tool-policy.ts
Plugins and hooks src/plugins/types.ts, src/plugins/runtime.ts
Channel plugin contracts src/channels/plugins/types.plugin.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment