OpenClaw Training (I): Growing into a Personal Assistant
OpenClaw is a locally deployable AI assistant framework that supports behavior customization through config files, capability extension via a Skills system, and cross-session persistent memory. This post documents the complete process of configuring it from a default installation into a personal assistant with identity, memory, and the ability to work proactively.
1. Starting from Default
After installation, OpenClaw is essentially a general-purpose AI assistant: it has tool-calling capabilities, can search and execute code, but knows nothing about you, each session is independent, and there’s no extensible business logic.
This default state is fine for light use, but if you want it to genuinely integrate into your workflow, there are four core problems to solve:
- It doesn’t know who you are — no background context, you have to re-establish context every time
- It has no memory — everything resets when a session ends; next time it has no idea what happened last time
- Unclear behavioral boundaries — no rules for what it can do directly vs. what needs confirmation
- Fixed capabilities — the default skills set can’t cover all personal use cases
The configuration process below addresses each of these in turn.
2. Identity and Behavioral Guidelines
OpenClaw supports placing Markdown config files in the workspace directory (~/.openclaw/workspace/), which the AI loads on startup. This is the foundation of the entire configuration system.
2.1 SOUL.md — Behavioral Principles
This file defines not style, but baselines.
# SOUL.md
**Be genuinely helpful, not performatively helpful.**
Skip "Sure, I'd be happy to help!" — get straight to the task.
**Have opinions.**
It's okay to disagree with the user's judgment; call out problems directly.
**Be resourceful before asking.**
Read files and look things up first; only ask when you genuinely can't find the answer.
The effect of these rules on an LLM is anchoring style through few-shot examples — not command-and-control, but giving it a “default direction when facing a fork in the road.”
2.2 IDENTITY.md — Identity Definition
# IDENTITY.md
- Name: [give your AI a name]
- Description: [one-line description of its role]
- Emoji: [a representative emoji]
Having a concrete identity improves behavioral consistency across sessions. Giving the model a name isn’t just decoration — it influences how it positions itself and sets its response tone in ambiguous situations.
2.3 USER.md — User Profile
# USER.md
- Name: [your name]
- Timezone: [your timezone]
- Work: [professional background]
- Interests: [areas of interest]
- Reply style: [preferred style]
- Language: [language preference]
This profile is in context every session — no need to re-introduce yourself. The user’s professional background and interests also influence how the AI prioritizes information retrieval and analysis.
2.4 AGENTS.md — Behavioral Guidelines
This is the most critical config file, defining tiered operation permissions:
**No confirmation needed, can execute directly:**
- Read files, browse directories
- Web search, query calendar and email
- File operations within the workspace
**Must confirm before executing:**
- Send emails, messages, social media content
- Delete or overwrite important files
- Any write operations to external systems
Beyond permissions, AGENTS.md also contains memory write rules, group chat behavior guidelines, and heartbeat process documentation — essentially the AI’s job description, re-read at the start of every session.
3. Memory System
This is the most technically involved part of the configuration.
3.1 Why Context Window ≠ Memory
An LLM’s context window is temporary — when conversations get too long, the system auto-compresses (Compaction), discarding early content; everything resets when a session ends. This means:
Session A: Discussed and finalized Plan X → not written to file
Session B: AI has no idea about Plan X → repeat discussion → wasted time
There’s only one solution: write important information to files; files are the physical medium of memory.
Why Markdown over a database:
| Dimension | Markdown Files | Database |
|---|---|---|
| Readability | View and edit directly in any text editor | Requires query tools |
| Debugging | Open the file to see full state | Requires SQL/API |
| Version control | Native git support | Needs additional tooling |
| AI read/write | Native Read/Write tool support | Needs additional integration |
3.2 Three-Layer Architecture
Conversation/event occurs
│ Written in real time
▼
memory/YYYY-MM-DD.md ← Daily log (append-only, raw records)
│ Distilled nightly at 23:45 via cron
▼
memory/knowledge/ ← Structured knowledge base
├── lessons/ ← Reusable lessons / pitfall records
├── decisions/ ← Important decision records
└── people/ ← People / project info
│ Weekly GC archival on Sundays
▼
memory/.archive/ ← Cold storage (not actively loaded)
Two special files:
MEMORY.md— Global index, hard-capped at 40 lines, contains only the most critical information, read on every startup.NOW.md— Current state snapshot, overwritten (not appended) on every heartbeat, records current focus and pending items.
3.3 Daily Log Writing
Log files are append-only with a fixed format:
# 2026-03-06 · Thursday
## Event Stream
### 14:30 — Completed Research Report
Research topic X, collected Y sources, conclusion is Z.
Key judgment: chose Plan A over Plan B because...
---
## Takeaways & Reflections
>
## Tomorrow / Pending
- [ ]
To prevent the AI from using hallucinated timestamps or accidentally overwriting files with write, a memlog.sh script handles all log appending:
#!/usr/bin/env bash
# Usage: bash memlog.sh "event title" "detailed content"
# Automatically gets system time, appends to memory/YYYY-MM-DD.md
WORKSPACE_DIR="~/.openclaw/workspace"
DAILY_DIR="$WORKSPACE_DIR/memory"
TODAY=$(TZ=Asia/Shanghai date +%Y-%m-%d)
NOW=$(TZ=Asia/Shanghai date +%H:%M)
FILE="$DAILY_DIR/$TODAY.md"
TITLE="${1:?Title required}"
BODY="${2:-}"
# Create from template if file doesn't exist
if [[ ! -f "$FILE" ]]; then
cat > "$FILE" << EOF
# $TODAY
## Event Stream
---
## Takeaways & Reflections
>
## Tomorrow / Pending
- [ ]
EOF
fi
# Insert new event before the "Takeaways" separator (not at end of file)
ENTRY=$(printf "\n### %s — %s\n\n%s\n" "$NOW" "$TITLE" "$BODY")
python3 - "$FILE" "$ENTRY" << 'PYEOF'
import sys
filepath, entry = sys.argv[1], sys.argv[2]
with open(filepath, 'r') as f:
content = f.read()
marker = "\n---\n\n## Takeaways"
idx = content.find(marker)
content = content[:idx] + entry + content[idx:] if idx != -1 else content + entry
with open(filepath, 'w') as f:
f.write(content)
PYEOF
Write prohibitions, enforced via AGENTS.md:
| Prohibited | Reason |
|---|---|
❌ Use write to overwrite memory/ files | Overwriting = data loss (NOW.md is the only exception) |
| ❌ Write to knowledge files without reading first | Creates duplicate entries and contradictions |
| ❌ Hardcode timestamps | LLMs can hallucinate times; always get system time from the script |
| ❌ Write records with no substantive content | Wastes retrieval space, degrades signal-to-noise ratio |
3.4 Knowledge Base Standards
Files under lessons/, decisions/, and people/ must include YAML frontmatter:
---
title: "ClawHub Publishing Process Notes"
date: 2026-02-27
category: lessons
priority: 🔴 # 🔴 Core, never archive | 🟡 Important | ⚪ Reference
status: active # active | superseded | conflict
last_verified: 2026-03-01
tags: [clawhub, cli, deployment]
---
INDEX.md is the navigation hub — the AI scans it on startup to decide which files to load:
# Memory Vault Index
## Lessons
| File | Priority | Status | Last Verified | Notes |
|------|----------|--------|---------------|-------|
| [[clawhub-publish]] | 🟡 | ✅ active | 2026-02-27 | Publishing pitfalls |
| [[network-constraints]] | ⚪ | ⚠️ stale | 2026-02-27 | Sandbox network limits |
## Decisions
| File | Date | Notes |
|------|------|-------|
| [[2026-02-27-memory-architecture]] | 2026-02-27 | Memory system architecture decision |
⚠️ stale means unverified for over 30 days — content may be outdated. 🔴 priority files are never archived.
3.5 Pre-Write CRUD Validation
Before writing to a knowledge file, a “read before write” check must be performed:
Preparing to write lessons/xxx.md
│
├─ Step 1: Read current content of target file (create if doesn't exist)
├─ Step 2: Compare new knowledge with existing content
│ ├─ Existing content fully covers new content → NOOP (don't write)
│ ├─ New content updates old content → UPDATE (mark old as ~~Superseded~~)
│ ├─ The two contradict each other → CONFLICT (keep both, add ⚠️, status: conflict)
│ └─ Entirely new content → ADD (append new section)
└─ Step 3: Update frontmatter's last_verified date
Conflict resolution principle: expose conflicts rather than silently overwrite. When contradictions are found, keep both versions and wait for human judgment before reverting to active.
4. Heartbeat and Scheduled Tasks
4.1 Two Mechanisms Compared
OpenClaw provides two automatic task mechanisms:
| Mechanism | Use Case |
|---|---|
| Heartbeat | Multiple periodic checks can be batched together (email + calendar + status update); timing precision not critical |
| Cron | Requires precise timing (run exactly at 23:45 every day), or tasks that need to be isolated from the main session |
4.2 Heartbeat Configuration
Heartbeat triggers every 60 minutes. HEARTBEAT.md defines the execution checklist for each run:
# HEARTBEAT.md
## Required Every Time
### 1. Overwrite NOW.md
Use the write tool (not edit/append) to overwrite NOW.md with this format:
# NOW.md — Current State Snapshot
_Last updated: YYYY-MM-DD HH:MM (Asia/Shanghai)_
## Current Focus
(One sentence describing what's currently being worked on)
## Recent Events
- HH:MM — Event title (max 5 items, extracted from today's log)
## Pending
- [ ] Incomplete todos
### 2. Check External Service Status
(Configure as needed, e.g. check if a custom API has new instructions)
4.3 Proactive Notification Rules
Not every heartbeat needs to interrupt the user. Trigger conditions are defined in HEARTBEAT.md:
## When to Proactively Reach Out
Trigger contact:
- Important unread email (prioritized by keywords/sender)
- Calendar event within 2 hours
- Found information worth sharing
Don't contact:
- 23:00–08:00 (unless urgent)
- Less than 60 minutes since last contact
- No new information
4.4 Scheduled Task: Nightly Reflection (23:45 Daily)
This is the core integration step of the memory system — essentially converting “workbench records” into “long-term usable knowledge.”
OpenClaw cron config:
{
"crons": [
{
"name": "daily-reflection",
"schedule": "45 23 * * *",
"task": "Execute daily reflection: read today's memory/YYYY-MM-DD.md, distill valuable content into corresponding knowledge base files (lessons/decisions/people), update core information in MEMORY.md, clean up noise records."
}
]
}
Reflection process steps:
Step 1: Read today's log (memory/YYYY-MM-DD.md)
Step 2: Identify content worth preserving
- Pitfalls encountered → lessons/
- Important choices made → decisions/
- New information about people → people/
Step 3: Run CRUD validation, write to corresponding files
Step 4: Update MEMORY.md (if core information has changed)
Step 5: Append a summary of this reflection to the end of the log
4.5 Scheduled Task: Weekly Knowledge Distillation (Every Sunday 00:00)
{
"name": "weekly-knowledge-distill",
"schedule": "0 0 * * 0",
"task": "Scan the last 7 days of logs, check knowledge/INDEX.md for stale markers (>30 days unverified), flag expired entries with ⚠️, move old logs past the threshold into memory/.archive/ (preserve 🔴 priority knowledge files)."
}
Archival rules:
| File Type | Archive Condition | Protection Rule |
|---|---|---|
Log YYYY-MM-DD.md | >30 days + no references in last 7 days | Keep if referenced |
decisions/ | Never archive | Strategic decisions are permanent |
lessons/ 🔴 | Never archive | Core lessons are permanent |
people/ | Never archive | People info is relationship-critical |
.archive/ uses a dot-prefixed directory. OpenClaw’s semantic search engine (QMD) automatically skips directories starting with . during scans — zero-config hot/cold separation.
5. Skills System
Skills are OpenClaw’s capability extension mechanism. Each skill is a directory containing:
SKILL.md: Usage instructions that the AI reads when neededscripts/: The actual execution scripts (Node.js, Python, etc.)
The official distribution includes about 50 pre-built skills covering weather, GitHub, email, notes, music, and other common scenarios. Below are the custom additions built on top.
5.1 Search Enhancement: Perplexity
How it works
OpenClaw’s default web_search tool calls the Brave Search API and returns a list of raw results (title + URL + snippet) — the AI then has to decide which ones are worth following up, fetch them, and synthesize the content itself. Perplexity works differently: it’s an AI-native search engine that takes a question and returns a synthesized answer directly, with a list of cited sources. It handles the full search → fetch → distill pipeline on its servers, so what you receive is already a conclusion, not raw results.
A simple analogy: web_search is searching Google. Perplexity is having another AI pre-digest those results before handing them to you.
Use cases in OpenClaw
This skill calls the Perplexity API and is useful in two main scenarios:
- First step in research tasks: For unfamiliar topics, use Perplexity to build an information overview — much faster than scraping raw search results one by one
- Fallback when
web_fetchis blocked: In sandbox environments,web_fetchis blocked by SSRF policy. Perplexity fetches on its servers, bypassing this constraint
# Single query
node skills/perplexity/scripts/search.mjs "some research topic"
# Batch queries (same API call, saves context)
node skills/perplexity/scripts/search.mjs "question A" "question B" "question C"
Limitations: Perplexity excels at factual and overview-style questions. It’s not suited for cases where you need to access a specific URL or real-time data (e.g. the latest version of a GitHub README). For those, the browser tool is more appropriate.
Using the Perplexity skill requires a PERPLEXITY_API_KEY environment variable.
5.2 Research Learning Workflow: research-learning
The design of this skill draws from Karpathy’s autoresearch project — instead of giving the AI a checklist of steps, it defines an autonomous research protocol: explicit permission boundaries, completion criteria, error-handling rules, and autonomy level, so the AI can run a full research session without supervision.
autoresearch’s approach: give the AI a program.md defining the research strategy (what it can modify, what it can’t, and how to measure success), then let it loop autonomously. The human sleeps and wakes up to results. Their metric is val_bpb (model training loss); this skill’s metric is research note completion quality.
How the workflow runs
Each research session follows a fixed protocol:
Setup: Confirm topic → read the master index _index.md → create directory + index.md → inform the user, then begin.
Permission boundaries:
- Autonomous: switch sources, decide file count and naming, self-check quality and fix
- Must ask: topic scope is fundamentally ambiguous, core materials are completely unavailable
Completion criteria (all must be met):
| Criterion | Description |
|---|---|
index.md exists and is complete | Includes research goal, file map, OpenClaw’s judgment |
| Zero placeholders | No TBD / “to be filled” / placeholder text |
| Clear context | Why it was done, what problem it solves, what the core insight is |
| OpenClaw has a judgment | A real evaluation, not a templated summary |
| git pushed | Vault is synced |
Simplicity Criterion: Good enough is good enough — don’t pad. If 3 files cover the topic, don’t create 6. Deleting redundant content beats adding more. Better to skip a section entirely than fill it with placeholder text.
Core loop:
Gather materials (parallel) → Sufficient?
→ No: switch source, max 3 attempts
→ Yes: write notes → quality check
→ Fail: fix without interrupting the user
→ Pass: git push → notify completion
Async mode: Once the user says “research XX,” OpenClaw goes straight into the loop and notifies when done — no mid-task check-ins. Research sessions can complete in the background while the user is offline.
Vault directory structure
Research output goes into the Learning/ directory of your Obsidian vault, one subdirectory per topic:
Learning/
├── _index.md ← Status overview of all topics, updated after each session
└── [topic name]/
├── index.md ← Topic entry point (required, should be detailed)
└── [other files] ← Count and naming decided autonomously by OpenClaw
_index.md is the global progress table — analogous to the results.tsv in autoresearch that logs every experiment’s outcome:
| Topic | Directory | Status | Completed | Score | Notes |
|-------|-----------|--------|-----------|-------|-------|
| Solo Company × AI Agent | solo-ai-agent | ✅ Done | 2026-03-01 | 4/5 | — |
index.md is the entry point for each topic and should be substantive — covering the research goal, core conclusions, a file map, key data points, and OpenClaw’s overall judgment. Detailed enough that reopening a topic weeks later requires no context recovery.
5.3 Newsletter Archiving: newsletter-archiver
Archives newsletter emails/articles as Obsidian notes — not just saving the original, but including deep analysis.
Note structure:
---
title: "Title"
date: YYYY-MM-DD
source: "Source - Sub-column"
tags: [tag1, tag2]
url: "original link"
---
## Main Content
(Core summary of the original)
---
# AI Analysis
## Key Insights
(1-3 most important judgments)
## Related Context
(Industry/technical background supplemented via web_search)
## What This Means for You
(Specific actionable recommendations based on user's professional background — no generic advice)
---
## Selected Quotes (Bilingual)
> **Original**
> "..."
**Translation**: ...
Execution flow: fetch original → deep analysis → web_search for background → write to newsletter/<source>/YYYY-MM-DD-<slug>.md → memlog records archival log.
5.4 Financial Data
Three skills covering different layers:
akshare-cn-market — A-share data based on the AKShare library:
- Individual stock K-lines (daily/weekly/monthly)
- Market indices (CSI 300, ChiNext, etc.)
- Macro data: GDP, CPI, PMI, M2, China/US treasury yields
# Example: get recent daily K-line for a stock
python3 scripts/akshare_query.py --type kline --code "600XXX" --period daily --limit 30
stock-info-explorer — Yahoo Finance real-time quotes + chart generation:
- Real-time quotes, 52-week range, volume
- High-resolution technical charts with overlaid indicators: MA/RSI/MACD/Bollinger/VWAP/ATR
us-stock-analysis — Comprehensive US stock analysis framework:
- Fundamentals: financial metrics, business quality assessment, valuation analysis
- Technicals: trend, pattern recognition, support/resistance levels
- Competitive comparison analysis
- Generates structured investment reports
Use cases: stock-info-explorer for daily market checks, us-stock-analysis for deep research, akshare-cn-market for macro data.
5.5 Google Workspace: gog
After OAuth authentication is configured, you can directly operate Gmail, Calendar, Drive, Sheets, and Docs:
# Search unread emails from last 7 days
gog gmail search 'is:unread newer_than:7d' --max 10 --json
# Query this week's calendar events
gog calendar events primary \
--from 2026-03-04 \
--to 2026-03-08 \
--json
# Read Google Sheets data
gog sheets get <sheet-id> "Sheet1!A1:D20" --json
# Update Sheets cells
gog sheets update <sheet-id> "Sheet1!A1:B2" \
--values-json '[["value A","value B"]]' \
--input USER_ENTERED
Used with Heartbeat: each heartbeat uses gog gmail search to check priority emails, only pushing notifications when important mail arrives.
6. Obsidian Integration
Obsidian serves as the note library. Integration with OpenClaw mainly works in two directions: AI writing notes, and AI retrieving notes.
6.1 Vault Configuration
OpenClaw interacts with Obsidian vaults via obsidian-cli, a command-line tool. OpenClaw will automatically install obsidian-cli the first time it’s needed — no manual setup required. If you prefer to install it manually:
npm install -g obsidian-cli
After installing, set your vault directory as the default:
obsidian-cli set-default /path/to/your/vault
Once configured, all write operations target .md files directly — no Obsidian client needs to be running:
# View current default vault path
obsidian-cli print-default --path-only
# Search note titles
obsidian-cli search "keyword"
# Search note content (returns summaries and line numbers)
obsidian-cli search-content "keyword"
# Move note (also updates all WikiLinks)
obsidian-cli move "old-path/note" "new-path/note"
Writing .md files directly with the write tool is more efficient; obsidian-cli is mainly used for cross-note link maintenance and search.
6.2 Learning Notes Directory Structure
The research-learning skill uses a flexible structure. Each topic gets its own directory, with index.md as the only required file — everything else is created based on the topic’s complexity:
DigitalGarden/
└── Learning/
├── _index.md ← Master progress tracker (status of all topics at a glance)
└── [topic name]/
├── index.md ← Topic entry point (required — see template below)
└── [other files] ← Count and naming decided autonomously by the AI
_index.md is the global status table, updated after each research session:
# Learning Index
| Topic | Directory | Status | Completed | Score | Notes |
|-------|-----------|--------|-----------|-------|-------|
| Topic A | topic-a | ✅ Done | 2026-03-01 | 4/5 | — |
| Topic B | topic-b | 🔄 In progress | — | — | — |
index.md is the topic entry point — detailed enough that an agent picking it up can immediately understand what coverage exists and what’s left:
---
tags: [learning, topic-tag]
date: YYYY-MM-DD
status: in-progress | complete
research_goal: "One sentence describing the research goal"
---
# [Topic Name] · Index
> One-line definition: what this is and why it's worth researching.
## Research Goal
(What to find out, and what's explicitly out of scope)
## Core Conclusions
(Written after completion — 3-5 sentences of judgment, not summary)
## File Map
| File | Content | Status |
|------|---------|--------|
| index.md | This file | ✅ |
| [filename] | [content description] | ✅ |
## Key Data / Facts
(Most important data points, with source links)
## AI's Overall Judgment
(Not a summary — a real evaluation: how to think about this topic, what's worth acting on)
## Learning Status
- Started: YYYY-MM-DD
- Completed: YYYY-MM-DD
- Next: [next step]
The benefit works in both directions: file count is flexible (a quick overview can be just one file, a deep dive might have ten), but the entry point format is consistent across topics — making cross-topic status comparison effortless.
6.3 Newsletter Archive Structure
DigitalGarden/
└── newsletter/
└── [source name]/
└── YYYY-MM-DD-slug.md
Slug rules: lowercase English + hyphens, drop articles (a/the/an), use 3-5 keywords. Example: 2026-03-01-glp1-next-generation-drugs.md.
6.4 Git Sync
Git sync is configured inside Obsidian itself — OpenClaw doesn’t handle this part. The recommended approach is the Obsidian Git community plugin. Here’s the full setup:
Step 1: Initialize the Git repository
In your vault directory, initialize git and connect it to a remote repository (GitHub, GitLab, etc.):
cd /path/to/your/vault
git init
git remote add origin https://github.com/your-username/your-repo.git
git add -A && git commit -m "init vault"
git push -u origin main
Step 2: Install the Obsidian Git plugin
- Open Obsidian → Settings → Community Plugins → Browse
- Search for Obsidian Git, install and enable it
- Open the plugin settings and configure:
- Auto pull interval:
10(pull from remote every 10 minutes) - Auto push interval (or Auto backup interval):
10(commit and push every 10 minutes) - Commit message:
vault backup: {{date}} - Pull on startup: Enable (pull the latest version each time Obsidian opens)
- Auto pull interval:
Step 3: Verify
Trigger a manual backup: Command Palette (Cmd+P) → search Obsidian Git: Create backup → run it and confirm there are no errors.
Once configured, OpenClaw can write files freely — Obsidian Git will commit and push on its schedule automatically.
Note: If your vault is stored inside iCloud Drive or another cloud sync folder, it’s best to disable iCloud sync for that directory (right-click in Finder → Don’t sync) to avoid conflicts between iCloud and Git.
7. Cursor Agent Integration
Cursor has a little-known CLI subcommand cursor agent that can invoke Cursor Agent in non-interactive mode from the terminal, making it callable by OpenClaw as a coding sub-agent.
7.1 Cursor’s Capability
One line in Cursor’s --help output:
agent Start the Cursor agent in your terminal.
cursor agent --help shows the full parameter list:
cursor agent [options] [prompt]
Options:
--print Non-interactive mode, exits after outputting result (key parameter)
--workspace <path> Specify working directory
--model <model> Specify model (claude-sonnet-4, gpt-4o, etc.)
--force Auto-approve all commands without asking for confirmation
7.2 Usage
Login first:
cursor agent login # Opens browser for authorization
After login, OpenClaw can call it like this:
# Have Cursor Agent analyze the current project and answer questions
cursor agent --print \
--workspace /path/to/project \
--model claude-sonnet-4 \
"Analyze this project's architecture and identify potential performance bottlenecks"
# Execute a specific coding task (--force skips confirmation)
cursor agent --print \
--workspace /path/to/project \
--model claude-sonnet-4 \
--force \
"Add a date formatting utility function under src/utils/ with timezone support"
7.3 Position in the Toolchain
OpenClaw (coordination layer)
│
├─ Lightweight tasks (search, file read/write, calendar/email)
│ └─ Call individual skill tools directly
│
├─ Complex coding tasks
│ └─ cursor agent --print (has full IDE context, suited for in-codebase operations)
│
└─ Independent feature development
└─ sessions_spawn (Claude Code / Codex, suited for brand-new modules)
Cursor Agent’s advantage over other coding agents: it reads the project’s .cursorrules, indexes the entire codebase, understands workspace configuration — for modifications and debugging of existing projects, context quality is higher.
7.4 Known Limitations
In sandbox environments, cursor agent has PTY compatibility issues — the process starts but produces no output, because the sandbox restricts terminal I/O. Solution: ensure cursor agent runs on the host machine, not inside the sandbox.
8. Channel Configuration: Telegram
OpenClaw supports multiple channels (Telegram, Discord, Signal, WhatsApp, etc.), with Telegram currently offering the most complete experience. In March 2026, Telegram Bot API 9.5 opened the sendMessageDraft endpoint to all bots, meaning OpenClaw can now update draft messages in real time as the AI generates — i.e., Streaming Preview.
8.1 Basic Configuration
First create a Bot via BotFather and get the token, then add to your OpenClaw config:
{
channels: {
telegram: {
enabled: true,
botToken: "YOUR_BOT_TOKEN",
dmPolicy: "pairing", // pairing | allowlist | open | disabled
allowFrom: [123456789], // Allowed Telegram user numeric IDs
},
},
}
After starting the gateway, the first DM requires a pairing flow:
openclaw gateway # Start
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>
dmPolicy: "pairing" (default) is recommended — after the first pairing, the user is automatically added to the allowlist without needing to configure allowFrom each time.
8.2 Streaming Preview
This is the core advantage of Telegram as the best interface.
OpenClaw has two layers of streaming:
| Layer | Mechanism | Description |
|---|---|---|
| Preview streaming | channels.telegram.streaming | Updates message content in real time during generation |
| Block streaming | agents.defaults.blockStreamingDefault | Splits long replies into multiple messages sent progressively |
Preview streaming config:
{
channels: {
telegram: {
streaming: "partial", // off | partial | block | progress
},
},
}
partial(recommended): UsessendMessageDraftfor in-place updates in DMs; sends a preview message and continuously edits it in groups. No second message after generation completes — clean.block: Updates the preview by appending chunks, suited for very long replies.off: Disables preview; waits for full generation before sending.
In private chats, partial mode delivers an experience close to the streaming effect of Claude Web on desktop: text appears progressively without waiting for the full reply.
Block streaming config (optional):
{
agents: {
defaults: {
blockStreamingDefault: "off", // Off by default; when enabled, long replies are sent in segments
},
},
}
Note: when both Preview and Block streaming are enabled, Telegram automatically skips Preview to avoid double-streaming and prioritizes Block mode. Generally, only enabling Preview streaming is sufficient.
8.3 Access Control
DM permissions:
{
channels: {
telegram: {
dmPolicy: "allowlist",
allowFrom: [123456789], // Numeric ID only, @username not supported
},
},
}
If you have old entries in @username format, running openclaw doctor --fix will automatically resolve them to numeric IDs.
Group permissions:
{
channels: {
telegram: {
groupPolicy: "allowlist", // open | allowlist | disabled
groups: {
"-1001234567890": { // Group numeric ID (negative number)
requireMention: true, // Whether @bot mention is required to respond
groupPolicy: "open", // This group allows all members
},
"*": {
requireMention: true, // Global default: @mention required
},
},
},
},
}
To get a group ID: forward a group message to @getidsbot, or read chat.id from openclaw logs --follow.
Group bots have Privacy Mode enabled by default — they can only receive messages that @mention them. To receive all group messages: BotFather → /setprivacy → Disable, then remove the bot from the group and re-add it.
8.4 Inline Buttons and Reactions
Inline Buttons allow the AI to send clickable buttons in replies, useful for confirmation flows and quick selections:
{
channels: {
telegram: {
capabilities: {
inlineButtons: "allowlist", // off | dm | group | all | allowlist
},
},
},
}
AI usage example (sending a message with buttons):
{
action: "send",
channel: "telegram",
to: "123456789",
message: "Confirm this action?",
buttons: [
[
{ text: "Confirm", callback_data: "confirm", style: "success" },
{ text: "Cancel", callback_data: "cancel", style: "danger" },
],
],
}
Reactions config (show Ack emoji during message processing):
{
channels: {
telegram: {
ackReaction: "👀", // Ack emoji shown while processing
reactionLevel: "minimal", // off | ack | minimal | extensive
reactionNotifications: "own", // Whether to trigger notification when user reacts to bot message
},
},
}
8.5 Custom Command Menu
In Telegram, bots can register a command menu (the / list in the bottom left):
{
channels: {
telegram: {
customCommands: [
{ command: "brief", description: "Daily briefing" },
{ command: "stock", description: "Query stock" },
{ command: "archive", description: "Archive current content" },
],
},
},
}
Commands are just menu entry points — behavior is determined by the AI based on skills and context; no handler functions need to be implemented.
8.6 Why Telegram Is Currently the Best Interface
Compared to other channels, the combined advantages after Telegram Bot API 9.5:
- Streaming preview: Native
sendMessageDraftsupport — no flicker, no duplicate messages in DMs - Inline Buttons: Enables interactive confirmation flows; other channels have limited support
- Forum Topics: One bot can maintain independent conversations under different Topics in a supergroup — great for multi-topic management
- Reactions: Can serve as a lightweight processing status indicator
- No extra app needed: Mobile Telegram is always available with low latency
The Dashboard (web UI) is suited for extended desktop work sessions; Telegram is better for mobile scenarios and tasks requiring instant notifications. Currently using both, with Telegram as the primary entry point.
9. Multi-Model Switching
OpenClaw supports switching models within the same gateway instance without restarting the service. This is useful across different task scenarios — use a powerful model for writing and research, a fast model for simple Q&A.
9.1 Model Configuration
Set the primary model and fallback chain in the config file:
{
agents: {
defaults: {
model: {
primary: "openrouter/anthropic/claude-sonnet-4-6",
fallbacks: [
"openrouter/google/gemini-2.5-pro",
"openrouter/deepseek/deepseek-chat",
],
},
},
},
}
Fallback chain trigger order: primary model fails (rate limit, outage, timeout) → try fallbacks in sequence.
Advantage of using OpenRouter as a unified gateway: one API key accesses dozens of models without managing separate keys and quotas for each provider.
9.2 Model Aliases
With aliases configured, you don’t need to type full model paths when switching:
{
agents: {
defaults: {
models: {
"openrouter/anthropic/claude-sonnet-4-6": { alias: "sonnet" },
"openrouter/google/gemini-2.5-pro": { alias: "gemini" },
"openrouter/deepseek/deepseek-chat": { alias: "deepseek" },
"openrouter/deepseek/deepseek-reasoner": { alias: "r1" },
"minimax/MiniMax-M2.5": { alias: "minimax" },
},
},
},
}
CLI alias configuration:
openclaw models aliases add sonnet openrouter/anthropic/claude-sonnet-4-6
openclaw models aliases add r1 openrouter/deepseek/deepseek-reasoner
9.3 Runtime Switching
In a Telegram (or any channel) conversation, send the /model command directly:
/model → Open model selector (numbered list)
/model list → List all available models
/model sonnet → Switch to claude-sonnet-4-6
/model r1 → Switch to DeepSeek R1 (reasoning model)
/model status → View current model and auth status
Switching only affects the current session — the config file is not modified. Starting a new session with /new restores the default model.
9.4 Model Selection by Task Type
Experience from actual use:
| Task Type | Recommended Model | Reason |
|---|---|---|
| Daily Q&A, writing | Claude Sonnet (default) | Best balance of speed and quality |
| Long document processing | Gemini 2.5 Pro | 2M token context window |
| Code tasks | Claude Sonnet / Cursor Agent | Cursor has project context advantage |
| Quick search / simple answers | DeepSeek V3 | Fast, low cost |
Reasoning models (R1, etc.) are suited for tasks requiring step-by-step analysis, but response times are noticeably longer — no need to use them for regular conversation.
A practical pattern: run Sonnet once, let cheaper models follow the playbook. For repetitive flows like scheduled tasks and heartbeats, run through the process once with claude-sonnet-4-6 and have it document its reasoning, steps, and edge cases into the skill’s SKILL.md. Then switch those tasks to MiniMax or DeepSeek V3 as the default model — with a detailed skill document to reference, they perform close to Sonnet at a fraction of the cost. Essentially, one Sonnet run buys quality assurance for all the cheap runs that follow.
9.5 Model Failover
OpenClaw has built-in provider-level automatic failover:
graph LR
A[Primary model request] --> B{Rate limited 429?}
B -- No --> Z[Return result]
B -- Yes --> C[Switch to Fallback 1]
C --> D{Rate limited 429?}
D -- No --> Z
D -- Yes --> E[Switch to Fallback 2]
E --> F{Failed?}
F -- No --> Z
F -- Yes --> G[Return error]
This is useful for availability-critical scenarios — for example, the nightly reflection cron doesn’t need to worry about a provider temporarily rate-limiting and causing the task to fail.
9.6 Multi-Provider Authentication
Current providers and their key configuration:
| Provider | Environment Variable | Notes |
|---|---|---|
| OpenRouter | OPENROUTER_API_KEY | Unified gateway, recommended |
| Anthropic | ANTHROPIC_API_KEY | Direct connection, no OpenRouter needed |
GEMINI_API_KEY | Gemini series | |
| DeepSeek | DEEPSEEK_API_KEY | Direct connection, low cost |
Key rotation support: for providers with multiple keys, configure OPENROUTER_API_KEYS (comma-separated) for automatic rotation on rate limits — no manual intervention needed.
10. macOS Security Configuration
Running OpenClaw on a Mac means it continuously has network access, file read/write permissions, and the ability to execute local CLI tools in the background. After completing the core functional configuration, it’s worth doing a security audit of the host machine.
10.1 Port Exposure Check
First, confirm which ports are listening for external connections:
# View all listening TCP/UDP ports and their associated processes
sudo /usr/sbin/lsof -iTCP -sTCP:LISTEN -n -P
sudo /usr/sbin/lsof -iUDP -n -P
Note: macOS’s default PATH doesn’t include
/usr/sbin— use the full path/usr/sbin/lsof, otherwise the command won’t be found.
Interpreting typical output:
| Port | Common Source | Risk Assessment |
|---|---|---|
| 5900 | Screen Sharing / VNC client (e.g. UURemote) | Confirm password protection and LAN-only access |
| 22 | SSH (system remote login) | Close if remote SSH isn’t needed |
| 8080 | OrbStack / container management | Normal dev tool, low risk |
| 3000–9000 | Local development/debug processes | Normal — just confirm it’s your own project |
Port 5900 is a common false alarm — many third-party remote desktop tools (UURemote, etc.) reuse the VNC port but aren’t bare VNC. As long as the tool itself has password protection, the risk is manageable.
10.2 Firewall Configuration
macOS has a built-in application firewall, but it may not be enabled by default after installation:
Check firewall status:
/usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate
# Output: Firewall is enabled. (State = 1) means it's on
Check Stealth Mode:
/usr/libexec/ApplicationFirewall/socketfilterfw --getstealthmode
# Output: Stealth mode enabled means it's on
Enable Stealth Mode:
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode on
Or via GUI: System Settings → Network → Firewall → Options → Enable Stealth Mode
What Stealth Mode does: normally, a Mac responds to external pings and port probes (even with “this port is closed”). With Stealth Mode on, it silently drops packets without responding, making automated scanners unable to determine whether the IP is online. No impact on normal usage — only affects passive probing behavior.
View firewall application allowlist:
/usr/libexec/ApplicationFirewall/socketfilterfw --listapps
Check whether the allowlist contains apps that have been uninstalled or are no longer in use but still have allow rules. TeamViewer is a classic example — firewall rules may persist after uninstallation and need to be manually cleaned up.
10.3 OpenClaw Security Audit
OpenClaw has a built-in security audit command that scans skill scripts for suspicious behavior:
openclaw security audit
The audit checks:
- Environment variable access in skill scripts (to prevent credential harvesting)
- Outbound network requests (especially patterns of reading sensitive env vars immediately followed by network requests)
- Validity of denyCommands in the config file
Actual output format (0 critical is the target state):
OpenClaw security audit
Summary: 0 critical · 2 warn · 1 info
Run deeper: openclaw security audit --deep
WARN
gateway.trusted_proxies_missing Reverse proxy headers are not trusted
gateway.bind is loopback and gateway.trustedProxies is empty. If you expose
the Control UI through a reverse proxy, configure trusted proxies so
local-client checks cannot be spoofed.
Fix: Set gateway.trustedProxies to your proxy IPs or keep the Control UI local-only.
gateway.nodes.deny_commands_ineffective Some gateway.nodes.denyCommands entries are ineffective
gateway.nodes.denyCommands uses exact node command-name matching only
(for example `system.run`), not shell-text filtering inside a command payload.
- Unknown command names: camera.snap, camera.clip, screen.record, calendar.add
Fix: Use exact command names (for example: canvas.present, canvas.hide).
INFO
summary.attack_surface Attack surface summary
groups: open=0, allowlist=2
tools.elevated: enabled
hooks.webhooks: disabled
hooks.internal: enabled
browser control: enabled
trust model: personal assistant (one trusted operator boundary)
How to handle the two common WARN items:
gateway.trusted_proxies_missing: Safe to ignore if you’re accessing the Control UI locally without a reverse proxygateway.nodes.deny_commands_ineffective:denyCommandsonly does exact command name matching — the listed unknown command names mean those entries don’t exist in the default command set; update them to correct command IDs (e.g.canvas.present)
For a deeper scan, add the --deep flag:
openclaw security audit --deep
10.4 SSH Management
If you don’t need to SSH into this Mac from outside, disabling the remote login service reduces the attack surface:
GUI: System Settings → General → Sharing → Disable “Remote Login”
Command line:
# Stop SSH service
sudo systemsetup -setremotelogin off
# Confirm status
sudo systemsetup -getremotelogin
If SSH access is genuinely needed, recommendations:
- Disable password login, allow only key-based authentication (
PasswordAuthentication no) - Change the default port (reduces automated scan hit rate)
- Consider a zero-trust solution like Tailscale to avoid directly exposing port 22
10.5 Remote Access Tool Cleanup
Remote desktop tools (TeamViewer, UU Remote, Sunflower, AnyDesk, etc.) share these characteristics: persistent background processes, auto-start on boot, continuously listening on ports. Even when not actively in use, having them installed is a potential attack surface.
If you have TeamViewer or UU Remote installed, there are two things to specifically check:
- Whether auto-connect is enabled — many tools enable unattended access by default, meaning someone can remote in without any confirmation on your end. Verify this option is disabled, or that the access password is a strong one you set yourself rather than a weak auto-generated one.
- That it’s logged into your own account — confirm the tool is bound to your account and hasn’t been associated with someone else’s. For TeamViewer specifically, check the “Trusted Devices” list and remove any devices you don’t recognize.
Cleanup recommendations:
- If you only use it occasionally, launch it when needed and quit the background process when done
- If you no longer need it at all, delete it from
/Applicationsand clean up the firewall rules - Keep at most one — don’t have multiple overlapping tools
Check whether a tool is still running:
# Using UURemote as an example
pgrep -l UURemote
# or
ps aux | grep -i uuremote
10.6 Scheduled Security Checks
Consider adding a security check to OpenClaw’s cron tasks, running once a week:
{
"name": "weekly-security-check",
"schedule": "0 10 * * 1",
"task": "Run security check: execute openclaw security audit, compare listening ports against last result, push Telegram alert if any new issues or unknown ports are found. Log results to memory/YYYY-MM-DD.md."
}
No need to manually remember to check — you only get notified when something changes; otherwise it runs silently.
11. Complete Directory Structure
~/.openclaw/workspace/
│
├── AGENTS.md # Behavioral guidelines (read on startup)
├── SOUL.md # Behavioral principles
├── IDENTITY.md # Identity definition
├── USER.md # User profile
├── HEARTBEAT.md # Heartbeat execution checklist
├── MEMORY.md # Global memory index (≤40 lines)
├── NOW.md # Current state (overwritten each heartbeat)
│
├── memory/
│ ├── 2026-03-06.md # Today's log
│ ├── heartbeat-state.json # Heartbeat state tracking
│ ├── projects.md # Project progress
│ ├── infra.md # Infrastructure configuration
│ ├── knowledge/
│ │ ├── INDEX.md # Knowledge navigation
│ │ ├── lessons/ # Lessons / pitfalls
│ │ ├── decisions/ # Important decisions
│ │ └── people/ # People information
│ └── .archive/ # Cold storage
│
├── scripts/
│ └── memlog.sh # Log append script
│
└── skills/
├── gog/ # Google Workspace
├── perplexity/ # AI search
├── research-learning/ # Research learning workflow
├── newsletter-archiver/ # Newsletter archiving
├── akshare-cn-market/ # A-share data
├── us-stock-analysis/ # US stock analysis
├── stock-info-explorer/ # Real-time quotes + charts
├── xmind-generator/ # Mind map generation
└── s1cli/ # Forum operations
12. Some Observations
A few things worth noting from the process of building this system.
Configuring AI is a process of self-clarification. Writing USER.md requires being explicit about your work and interests; writing SOUL.md requires thinking through your preferences for collaboration style; designing the knowledge base structure is essentially deciding what information has long-term value to you. These are questions you don’t usually think about explicitly — the configuration process forces them out.
Markdown files as AI memory storage are more stable than expected. Humans can edit them directly, git can version-control them, and debugging means just opening the file to see the full state — this kind of transparency is hard to get with other approaches. The trade-off is retrieval efficiency, but combined with OpenClaw’s semantic search (memory_search), the difference is barely noticeable in practice.
The skill iteration feedback loop matters. Each skill’s SKILL.md ends with an “Experience Log” section, where improvement notes are appended whenever a problem is found. These notes aren’t for humans — they’re for the AI to reference the next time it executes a similar task. It’s essentially delegating the iteration of operational SOPs to the system itself.