OpenClaw Code Deep Dive Part 2: Skills, Memory & Tools
In Part 1 we covered OpenClaw’s gateway-centric architecture and discovered that the core agent loop is delegated to an external library. Now let’s look at what OpenClaw builds on top of that: skills, memory, tools, and the plugin system.
- Part 1: Architecture
- Part 2 (this post): Skills, Memory & Tools
- Part 3: Security, Quality & Verdict
Skills: Prompts, Not Code
Location: src/agents/skills/ (16 files) + skills/ (52 bundled skills)
OpenClaw’s skill system is its most distinctive design choice. Skills are Markdown files, not executable code. Each skill is a directory containing a SKILL.md with YAML frontmatter.
How Injection Works
The system prompt only includes skill names and descriptions — not the full content:
## Skills (mandatory)
Before replying: scan <available_skills> <description> entries.
- If exactly one skill clearly applies: read its SKILL.md, then follow it.
- If multiple could apply: choose the most specific one.
- If none clearly apply: do not read any SKILL.md.The agent then uses the read tool to load the full skill content on-demand. This is lazy loading for context windows — only the selected skill consumes tokens.
5-Source Precedence
Skills load from five locations, with later sources overriding earlier:
| Priority | Source | Path |
|---|---|---|
| 1 (lowest) | Bundled | skills/ in OpenClaw distribution |
| 2 | Managed | ~/.config/openclaw/skills/ |
| 3 | Personal agents | ~/.agents/skills/ |
| 4 | Project agents | {workspace}/.agents/skills/ |
| 5 (highest) | Workspace | {workspace}/skills/ |
Size limits are enforced per source to prevent abuse. Frontmatter metadata includes install specs (brew, node, go, uv, download) and invocation policies.
52 Bundled Skills
The bundled skills cover: 1Password, Apple Notes/Reminders, Bear Notes, browser snapshots, Canvas, coding agent, Discord, GitHub/Issues, image generation (OpenAI), Notion, Obsidian, Slack, Spotify, Trello, voice calls, weather, and more.
Each skill essentially teaches the agent how to use a specific tool or service — via natural language instructions, not API bindings.
Memory: Hybrid Vector + FTS Search
Location: src/memory/ (78 files)
Architecture
The memory system combines vector embeddings and full-text search (FTS), backed by SQLite + sqlite-vec.
interface MemorySearchManager {
search(query, opts?): Promise<MemorySearchResult[]>;
readFile(params): Promise<{text, path}>;
status(): MemoryProviderStatus;
sync?(params?): Promise<void>;
}Embedding Provider Chain
Four embedding providers with automatic fallback:
| Provider | Model | Cost |
|---|---|---|
| Local (default) | GemmaEmbed 300M via node-llama-cpp |
Free, private |
| OpenAI | Configurable | Remote API |
| Gemini | Configurable | Remote API |
| Voyage | Configurable | Remote API |
In auto mode: try local first, then OpenAI, Gemini, Voyage. If all fail, degrade to FTS-only. The system never crashes on embedding failure.
Hybrid Merge Algorithm
1. Combine vector and keyword results by ID (union merge)
2. Compute weighted score: vectorWeight * vectorScore + textWeight * textScore
3. Apply temporal decay (recency boost for recently modified files)
4. Apply MMR re-ranking (Maximal Marginal Relevance for diversity)BM25 scores are normalized to 0-1 via 1 / (1 + rank). FTS queries use Unicode-aware tokenization with AND joining.
Memory as Plugin Slot
Memory is a special plugin slot — only one implementation runs at a time. The built-in memory-core registers memory_search and memory_get tools. An alternative memory-lancedb extension provides LanceDB-backed vector storage.
Tool System: 70 Files
Location: src/agents/tools/
Available Tools
| Category | Tools |
|---|---|
| Filesystem | read, write, edit, apply_patch, grep, find, ls |
| Execution | exec (shell), process (background) |
| Web | web_search (Brave API), web_fetch (with SSRF protection) |
| Browser | CDP automation via Playwright-core |
| Canvas | Visual workspace control |
| Memory | memory_search, memory_get |
| Messaging | Cross-channel message sending |
| Sessions | List, history, send, spawn sub-agents |
| Scheduling | Cron jobs and reminders |
| Media | Image analysis, TTS |
| Device | Camera, screen (via companion apps) |
| Platform | Discord, Slack, Telegram, WhatsApp specific actions |
Tool Policy Profiles
Four profiles control access:
| Profile | Access |
|---|---|
minimal |
session_status only |
coding |
Filesystem, runtime, sessions, memory, images |
messaging |
Messaging and session management |
full |
No restrictions |
Owner-only tools (like whatsapp_login) are gated to the device owner regardless of profile. Tool groups expand aliases: “filesystem” maps to read, write, edit, apply_patch.
Plugin Hook System: 20+ Lifecycle Hooks
Location: src/plugins/hooks.ts
This is where OpenClaw’s extensibility really shines. The hook system provides 20+ lifecycle points with three execution models:
Hook Categories
| Phase | Hooks | Execution |
|---|---|---|
| Model | before_model_resolve |
Sequential |
| Prompt | before_prompt_build |
Sequential |
| Agent | before_agent_start, agent_end |
Sequential / Parallel |
| LLM | llm_input, llm_output |
Parallel (observe only) |
| Compaction | before_compaction, after_compaction |
Sequential |
| Messages | message_received, message_sending, message_sent |
Mixed |
| Persistence | before_message_write, tool_result_persist |
Synchronous |
| Tools | before_tool_call, after_tool_call |
Sequential / Parallel |
| Sessions | session_start, session_end |
Parallel |
| Gateway | gateway_start, gateway_stop |
Parallel |
Execution Models
- Parallel — All hooks run concurrently. Used for observation/analytics.
- Sequential — Hooks process by priority (higher first) with result merging. Used for modification.
- Synchronous — Runs on hot paths (transcript writes). No async allowed.
Plugin Manifest
Each extension declares capabilities in openclaw.plugin.json:
{
"id": "my-plugin",
"channels": ["my-channel"],
"providers": ["my-llm"],
"skills": ["my-skill"],
"configSchema": { ... }
}The Plugin SDK (src/plugin-sdk/) provides channel adapter types, tool registration, CLI extension, HTTP route registration, webhook resolution, text chunking, media building, SSRF protection, and OAuth helpers.
The 37 Extensions
| Category | Count | Examples |
|---|---|---|
| Messaging | 20 | WhatsApp, Telegram, Discord, Slack, Signal, iMessage, Matrix, Teams, IRC, Nostr |
| Auth | 4 | Google Antigravity, Gemini CLI, MiniMax, Qwen |
| Memory | 2 | memory-core, memory-lancedb |
| Agent/LLM | 3 | copilot-proxy, llm-task, lobster |
| Device | 2 | device-pair, phone-control |
| Voice | 2 | talk-voice, voice-call |
| Other | 4 | diagnostics-otel, open-prose, shared, thread-ownership |
The messaging coverage is genuinely impressive — 20 channel adapters covering every major platform plus niche ones like Nostr, Tlon, and Zalo.
Next: Part 3 — Security, Quality & Verdict covers the Docker sandbox, security audit system, code quality assessment, ecosystem risks, and our final take.
Analysis based on OpenClaw v2026.2.18. Source: github.com/openclaw/openclaw.