openclaw-config by adisinghstudent/easyclaw
npx skills add https://github.com/adisinghstudent/easyclaw --skill openclaw-config诊断并修复实际问题。这里的每条命令都经过测试且有效。
当出现任何问题时,首先运行此命令。复制粘贴整个代码块:
echo "=== GATEWAY ===" && \
ps aux | grep -c "[o]penclaw" && \
echo "=== CONFIG JSON ===" && \
python3 -m json.tool ~/.openclaw/openclaw.json > /dev/null 2>&1 && echo "JSON: OK" || echo "JSON: BROKEN" && \
echo "=== CHANNELS ===" && \
cat ~/.openclaw/openclaw.json | jq -r '.channels | to_entries[] | "\(.key): policy=\(.value.dmPolicy // "n/a") enabled=\(.value.enabled // "implicit")"' && \
echo "=== PLUGINS ===" && \
cat ~/.openclaw/openclaw.json | jq -r '.plugins.entries | to_entries[] | "\(.key): \(.value.enabled)"' && \
echo "=== CREDS ===" && \
ls ~/.openclaw/credentials/whatsapp/default/ 2>/dev/null | wc -l | xargs -I{} echo "WhatsApp keys: {} files" && \
for d in ~/.openclaw/credentials/telegram/*/; do bot=$(basename "$d"); [ -f "$d/token.txt" ] && echo "Telegram $bot: OK" || echo "Telegram $bot: MISSING"; done && \
[ -f ~/.openclaw/credentials/bird/cookies.json ] && echo "Bird cookies: OK" || echo "Bird cookies: MISSING" && \
echo "=== CRON ===" && \
cat ~/.openclaw/cron/jobs.json | jq -r '.jobs[] | "\(.name): enabled=\(.enabled) status=\(.state.lastStatus // "never") \(.state.lastError // "")"' && \
echo "=== RECENT ERRORS ===" && \
tail -10 ~/.openclaw/logs/gateway.err.log 2>/dev/null && \
echo "=== MEMORY DB ===" && \
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT COUNT(*) || ' chunks, ' || (SELECT COUNT(*) FROM files) || ' files indexed' FROM chunks;" 2>/dev/null
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
~/.openclaw/
├── openclaw.json # 主配置文件 — 通道、认证、网关、插件、技能
├── openclaw.json.bak* # 自动备份文件 (.bak, .bak.1, .bak.2 ...)
├── exec-approvals.json # 执行批准套接字配置
│
├── agents/main/
│ ├── agent/auth-profiles.json # Anthropic 认证令牌
│ └── sessions/
│ ├── sessions.json # 会话索引 — 键类似于 agent:main:whatsapp:+1234
│ └── *.jsonl # 会话记录(每行一个 JSON)
│
├── workspace/ # 智能体工作区(git 跟踪)
│ ├── SOUL.md # 个性、写作风格、语气规则
│ ├── IDENTITY.md # 名称、生物类型、氛围
│ ├── USER.md # 所有者上下文和偏好
│ ├── AGENTS.md # 会话行为、记忆规则、安全性
│ ├── BOOT.md # 启动指令(自动驾驶通知协议)
│ ├── HEARTBEAT.md # 周期性任务清单(空 = 跳过心跳)
│ ├── MEMORY.md # 精选长期记忆(仅主会话)
│ ├── TOOLS.md # 联系人、SSH 主机、设备昵称
│ ├── memory/ # 每日日志:YYYY-MM-DD.md, topic-chat.md
│ └── skills/ # 工作区级别的技能
│
├── memory/main.sqlite # 向量记忆数据库(Gemini 嵌入,FTS5 搜索)
│
├── logs/
│ ├── gateway.log # 运行时:启动、通道初始化、配置重载、关闭
│ ├── gateway.err.log # 错误:连接断开、API 失败、超时
│ └── commands.log # 命令执行日志
│
├── cron/
│ ├── jobs.json # 任务定义(计划、负载、交付目标)
│ └── runs/ # 每个任务的运行日志:{job-uuid}.jsonl
│
├── credentials/
│ ├── whatsapp/default/ # Baileys 会话:约 1400 个 app-state-sync-key-*.json 文件
│ ├── telegram/{botname}/token.txt # 机器人令牌(每个机器人账户一个)
│ └── bird/cookies.json # X/Twitter 认证 cookies
│
├── extensions/{name}/ # 自定义插件(TypeScript)
│ ├── openclaw.plugin.json # {"id", "channels", "configSchema"}
│ ├── index.ts # 入口点
│ └── src/ # channel.ts, actions.ts, runtime.ts, types.ts
│
├── identity/ # device.json, device-auth.json
├── devices/ # paired.json, pending.json
├── media/inbound/ # 接收到的图片、音频文件
├── media/browser/ # 浏览器截图
├── browser/openclaw/user-data/ # Chromium 配置文件(约 180MB)
├── tools/signal-cli/ # Signal CLI 二进制文件
├── subagents/runs.json # 子智能体执行日志
├── canvas/index.html # Web 画布 UI
└── telegram/
├── update-offset-coder.json # {"lastUpdateId": N} — Telegram 轮询游标
└── update-offset-sales.json # 将这些重置为 0 以重放错过的消息
这是最常见的问题。消息已送达但机器人没有响应。按此顺序检查:
# 1. 机器人是否真的在运行?
grep -i "whatsapp.*starting\|whatsapp.*listening" ~/.openclaw/logs/gateway.log | tail -5
# 2. 检查 408 超时断开(WhatsApp 网页版频繁断开连接)
grep -i "408\|499\|retry" ~/.openclaw/logs/gateway.err.log | tail -10
# 如果看到 "Web connection closed (status 408). Retry 1/12" — 这是正常的,
# 它会自动恢复。但如果重试达到 12/12,则会话完全断开。
# 3. 检查跨上下文消息传递阻塞
grep -i "cross-context.*denied" ~/.openclaw/logs/gateway.err.log | tail -10
# 常见:"Cross-context messaging denied: action=send target provider "whatsapp" while bound to "signal""
# 这意味着智能体处于 Signal 会话中,并尝试在 WhatsApp 上回复。
# 修复:消息需要通过 WhatsApp 会话上下文传递,而不是 Signal。
# 4. 检查该联系人的会话是否存在
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r 'to_entries[] | select(.key | test("whatsapp")) | "\(.key) | \(.value.origin.label // "?")"'
# 5. 检查发送者是否被允许
cat ~/.openclaw/openclaw.json | jq '.channels.whatsapp | {dmPolicy, allowFrom, selfChatMode, groupPolicy}'
# 如果 dmPolicy 是 "allowlist" 且发送者不在 allowFrom 中,消息会被静默丢弃。
# 6. 检查是否是群组消息(默认禁用群组)
cat ~/.openclaw/openclaw.json | jq '.channels.whatsapp.groupPolicy'
# "disabled" 意味着所有群组消息都被忽略。
# 7. 检查通道拥塞(智能体忙于另一项任务)
grep "lane wait exceeded" ~/.openclaw/logs/gateway.err.log | tail -5
# 如果智能体卡在长时间的 LLM 调用上,新消息会排队。
# 8. 检查智能体运行超时
grep "embedded run timeout" ~/.openclaw/logs/gateway.err.log | tail -5
# 硬限制是 600 秒(10 分钟)。如果智能体的响应时间更长,它会被终止。
# 检查凭证文件是否存在(应该有约 1400 个文件)
ls ~/.openclaw/credentials/whatsapp/default/ | wc -l
# 如果 0 个文件:会话从未创建或被清空
# 修复:使用 `openclaw configure` 重新配对
# 检查 QR 码/配对事件
grep -i "pair\|link\|qr\|scan\|logged out" ~/.openclaw/logs/gateway.log | tail -10
# 检查 Baileys 错误
grep -i "baileys\|DisconnectReason\|logout\|stream:error" ~/.openclaw/logs/gateway.err.log | tail -20
# 终极修复:删除凭证并重新配对
# rm -rf ~/.openclaw/credentials/whatsapp/default/
# openclaw configure
两个看起来相同但独立的问题:
# 1. 检查配置验证错误(常见问题)
grep -i "telegram.*unrecognized\|telegram.*invalid\|telegram.*policy" ~/.openclaw/logs/gateway.err.log | tail -10
# 已知问题:accounts 下的键 "token" 和 "username" 不被识别。
# 正确的字段是 "botToken",而不是 "token"。
# 2. 检查实际配置
cat ~/.openclaw/openclaw.json | jq '.channels.telegram'
# 验证每个机器人都有 "botToken"(不是 "token")和 "name" 字段。
# 3. 检查轮询状态 — 机器人在 getUpdates 超时后死亡
grep -i "telegram.*exit\|telegram.*timeout\|getUpdates" ~/.openclaw/logs/gateway.err.log | tail -10
# "[telegram] [sales] channel exited: Request to 'getUpdates' timed out after 500 seconds"
# 这意味着机器人失去了与 Telegram API 的连接并停止监听。
# 修复:重启网关 — `openclaw gateway restart`
# 4. 检查轮询偏移量(如果机器人"忘记"或重放旧消息)
cat ~/.openclaw/telegram/update-offset-coder.json
cat ~/.openclaw/telegram/update-offset-sales.json
# 如果 lastUpdateId 卡住或为 0,机器人将重新处理旧消息。
# 要跳到最新:网关会在重启时自动设置此值。
# 5. 检查两个机器人是否都在启动
grep -i "telegram.*starting\|telegram.*coder\|telegram.*sales" ~/.openclaw/logs/gateway.log | tail -10
# 6. "机器人忘记" — 这通常是会话问题,而不是 Telegram 问题
# 每个 Telegram 用户在 sessions.json 中都有自己的会话。
# 检查会话是否存在:
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r 'to_entries[] | select(.key | test("telegram")) | "\(.key) | \(.value.origin.label // "?")"'
# 7. 检查是否发生了压缩(上下文窗口被修剪 = "忘记")
SESS_ID="粘贴会话ID"
grep '"compaction"' ~/.openclaw/agents/main/sessions/$SESS_ID.jsonl | wc -l
# 如果压缩计数 > 0,旧消息已从上下文中被修剪。
# 智能体的压缩模式是:
cat ~/.openclaw/openclaw.json | jq '.agents.defaults.compaction'
# 正确的 Telegram 配置结构:
cat ~/.openclaw/openclaw.json | jq '.channels.telegram = {
"enabled": true,
"accounts": {
"coder": {
"name": "Bot Display Name",
"enabled": true,
"botToken": "your-bot-token-here"
},
"sales": {
"name": "Sales Bot Name",
"enabled": true,
"botToken": "your-bot-token-here"
}
},
"dmPolicy": "pairing",
"groupPolicy": "disabled"
}' > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
这会阻塞 cron 任务和跨通道通知。
# 1. 检查 signal-cli 进程是否存活
ps aux | grep "[s]ignal-cli"
# 2. 检查 RPC 端点
grep -i "signal.*starting\|signal.*8080\|signal.*rpc" ~/.openclaw/logs/gateway.log | tail -10
# 应该看到:"[signal] [default] starting provider (http://127.0.0.1:8080)"
# 3. 检查连接不稳定性
grep -i "HikariPool\|reconnecting\|SSE stream error\|terminated" ~/.openclaw/logs/gateway.err.log | tail -10
# "HikariPool-1 - Thread starvation or clock leap detected" = signal-cli 内部数据库问题
# "SSE stream error: TypeError: terminated" = 与 signal-cli 守护进程的连接丢失
# 4. 检查速率限制
grep -i "signal.*rate" ~/.openclaw/logs/gateway.err.log | tail -5
# "Signal RPC -5: Failed to send message due to rate limiting"
# 5. 检查目标格式错误
grep -i "unknown target" ~/.openclaw/logs/gateway.err.log | tail -5
# "Unknown target "adi" for Signal. Hint: <E.164|uuid:ID|...>"
# 智能体必须使用电话号码(+1...)或 uuid: 格式,而不是名称。
# 6. 修复个人资料名称警告刷屏
grep -c "No profile name set" ~/.openclaw/logs/gateway.err.log
# 如果计数很高:运行 signal-cli updateProfile 来设置一个名称
# 7. 直接测试 signal-cli
ACCT=$(cat ~/.openclaw/openclaw.json | jq -r '.channels.signal.account')
echo "Account: $ACCT"
# signal-cli -a $ACCT send -m "test" +TARGET_NUMBER
# 8. 检查 signal-cli 守护进程是否需要重启
# 网关将 signal-cli 作为子进程管理。
# 重启整个网关:openclaw gateway restart
# 1. 所有任务概览
cat ~/.openclaw/cron/jobs.json | jq -r '.jobs[] | "\(.enabled | if . then "ON " else "OFF" end) \(.state.lastStatus // "never" | if . == "error" then "FAIL" elif . == "ok" then "OK " else . end) \(.name)"'
# 2. 失败的任务及其错误详情
cat ~/.openclaw/cron/jobs.json | jq '.jobs[] | select(.state.lastStatus == "error") | {name, error: .state.lastError, lastRun: (.state.lastRunAtMs | . / 1000 | todate), id}'
# 3. 读取失败任务的实际运行日志
JOB_ID="粘贴任务UUID"
tail -20 ~/.openclaw/cron/runs/$JOB_ID.jsonl | python3 -c "
import sys, json
for line in sys.stdin:
try:
obj = json.loads(line)
if obj.get('type') == 'message':
role = obj['message']['role']
text = ''.join(c.get('text','') for c in obj['message'].get('content',[]) if isinstance(c,dict))
if text.strip():
print(f'[{role}] {text[:300]}')
except: pass
"
# 4. 常见的 cron 失败原因:
# - "Signal RPC -1" → Signal 守护进程关闭,参见上面的 Signal 部分
# - "gateway timeout after 10000ms" → cron 触发时网关正在重启
# - "Brave Search 429" → 免费层速率限制达到(2000 次请求/月)
# - "embedded run timeout" → 任务耗时超过 600 秒
# 5. 下一次计划运行时间
cat ~/.openclaw/cron/jobs.json | jq -r '.jobs[] | select(.enabled) | "\(.name): \((.state.nextRunAtMs // 0) | . / 1000 | todate)"'
# 6. 临时禁用一个损坏的任务
cat ~/.openclaw/cron/jobs.json | jq '(.jobs[] | select(.name == "JOB_NAME")).enabled = false' > /tmp/cron.json && mv /tmp/cron.json ~/.openclaw/cron/jobs.json
记忆系统有 3 层。当智能体"忘记"时,其中一层出了问题:
# 检查会话的压缩计数(压缩 = 旧消息被修剪)
grep -c '"compaction"' ~/.openclaw/agents/main/sessions/SESSION_ID.jsonl
# 7 次压缩 = 智能体已经"忘记"了它最早的消息 7 次。
# 检查压缩模式
cat ~/.openclaw/openclaw.json | jq '.agents.defaults.compaction'
# "safeguard" = 仅在达到上下文限制时压缩
# 存在哪些每日记忆文件
ls -la ~/.openclaw/workspace/memory/
# MEMORY.md 中的内容(长期精选)
cat ~/.openclaw/workspace/MEMORY.md
# 在记忆文件中搜索特定内容
grep -ri "KEYWORD" ~/.openclaw/workspace/memory/
# 哪些文件被索引了
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT path, size, datetime(mtime/1000, 'unixepoch') as modified FROM files;"
# 有多少个块(文本片段)
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT COUNT(*) FROM chunks;"
# 通过文本搜索块(FTS5 全文搜索)
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT substr(text, 1, 200) FROM chunks_fts WHERE chunks_fts MATCH 'KEYWORD' LIMIT 5;"
# 检查嵌入配置
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT value FROM meta WHERE key='memory_index_meta_v1';" | python3 -m json.tool
# 检查 Gemini 嵌入速率限制(破坏索引)
grep -i "gemini.*batch.*failed\|RESOURCE_EXHAUSTED\|429" ~/.openclaw/logs/gateway.err.log | tail -10
# "embeddings: gemini batch failed (2/2); disabling batch" = 索引降级
# 重建记忆索引(重新索引所有工作区文件)
# 删除数据库并重启网关 — 它会重建:
# rm ~/.openclaw/memory/main.sqlite && openclaw gateway restart
# 通过名称搜索会话索引(不区分大小写)
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r 'to_entries[] | select(.value.origin.label // "" | test("NAME"; "i")) | "\(.value.sessionId) | \(.value.lastChannel) | \(.value.origin.label)"'
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r 'to_entries[] | select(.value.lastChannel == "whatsapp") | "\(.value.sessionId) | \(.value.origin.label // .key)"'
# 将 "whatsapp" 替换为:signal, telegram,或检查 .key 以获取 cron 会话
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r '[to_entries[] | {id: .value.sessionId, updated: .value.updatedAt, label: (.value.origin.label // .key), ch: (.value.lastChannel // "cron")}] | sort_by(.updated) | reverse | .[:10][] | "\(.updated | . / 1000 | todate) | \(.ch) | \(.label)"'
# 快速:查找包含关键字的会话文件
grep -l "KEYWORD" ~/.openclaw/agents/main/sessions/*.jsonl
# 详细:显示匹配的消息及其时间戳
grep "KEYWORD" ~/.openclaw/agents/main/sessions/*.jsonl | python3 -c "
import sys, json
for line in sys.stdin:
path, data = line.split(':', 1)
try:
obj = json.loads(data)
if obj.get('type') == 'message':
role = obj['message']['role']
text = ''.join(c.get('text','') for c in obj['message'].get('content',[]) if isinstance(c,dict))
if text.strip():
sid = path.split('/')[-1].replace('.jsonl','')[:8]
ts = obj.get('timestamp','')[:19]
print(f'{ts} [{sid}] [{role}] {text[:200]}')
except: pass
" | head -30
# 会话的最后 30 条消息
tail -50 ~/.openclaw/agents/main/sessions/SESSION_ID.jsonl | python3 -c "
import sys, json
for line in sys.stdin:
try:
obj = json.loads(line)
if obj.get('type') == 'message':
role = obj['message']['role']
text = ''.join(c.get('text','') for c in obj['message'].get('content',[]) if isinstance(c,dict))
if text.strip() and role != 'toolResult':
print(f'[{role}] {text[:300]}')
print()
except: pass
"
始终:备份,使用 jq 编辑,重启。
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.bak.manual
jq 'YOUR_EDIT_HERE' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
openclaw gateway restart
# 将 WhatsApp 切换到允许列表
jq '.channels.whatsapp.dmPolicy = "allowlist" | .channels.whatsapp.allowFrom = ["+1XXXXXXXXXX"]' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# 启用 WhatsApp 自动驾驶(机器人以你的身份回复所有人)
jq '.channels.whatsapp += {dmPolicy: "open", selfChatMode: false, allowFrom: ["*"]}' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# 将号码添加到 Signal 允许列表
jq '.channels.signal.allowFrom += ["+1XXXXXXXXXX"]' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# 更改模型
jq '.agents.defaults.models = {"anthropic/claude-sonnet-4": {"alias": "sonnet"}}' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# 设置并发数
jq '.agents.defaults.maxConcurrent = 10 | .agents.defaults.subagents.maxConcurrent = 10' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# 禁用插件
jq '.plugins.entries.imessage.enabled = false' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# 最新备份
cp ~/.openclaw/openclaw.json.bak ~/.openclaw/openclaw.json
# 按日期列出所有备份
ls -lt ~/.openclaw/openclaw.json.bak*
# 重启前验证 JSON
python3 -m json.tool ~/.openclaw/openclaw.json > /dev/null && echo "OK" || echo "BROKEN"
# 终极重置
openclaw configure
| 模式 | 行为 | 风险 |
|---|---|---|
open + allowFrom: ["*"] | 任何人都可以发消息,机器人回复所有人 | 高 — 消耗 API 积分,机器人以你的身份发言 |
allowlist + allowFrom: ["+1..."] | 只有列出的号码可以通过 | 低 — 显式控制 |
pairing | 未知发送者会收到一个代码,由你批准 | 低 — 批准门控 |
disabled | 通道完全关闭 | 无 |
cat ~/.openclaw/openclaw.json | jq '{
whatsapp: {policy: .channels.whatsapp.dmPolicy, from: .channels.whatsapp.allowFrom, groups: .channels.whatsapp.groupPolicy, selfChat: .channels.whatsapp.selfChatMode},
signal: {policy: .channels.signal.dmPolicy, from: .channels.signal.allowFrom, groups: .channels.signal.groupPolicy},
telegram: {policy: .channels.telegram.dmPolicy, groups: .channels.telegram.groupPolicy, bots: [.channels.telegram.accounts | to_entries[] | "\(.key)=\(.value.enabled)"]},
imessage: {enabled: .channels.imessage.enabled, policy: .channels.imessage.dmPolicy}
}'
| 文件 | 作用 | 何时编辑 |
|---|---|---|
SOUL.md | 个性:语气、风格("不使用破折号,小写随意") | 更改机器人说话方式时 |
IDENTITY.md | 名称(Jarvis)、生物类型、表情符号 | 重新品牌化时 |
USER.md | 所有者信息、偏好 | 用户上下文更改时 |
AGENTS.md | 操作规则:记忆协议、安全性、群聊行为、心跳指令 | 更改机器人行为时 |
BOOT.md | 启动指令(自动驾驶通知协议:WA → Signal) | 更改启动时发生的情况时 |
HEARTBEAT.md | 周期性检查清单(空 = 无心跳 API 调用) | 添加/移除周期性任务时 |
MEMORY.md | 精选长期记忆(仅在主/直接会话中加载) | 机器人自行管理此文件 |
TOOLS.md | 联系人、SSH 主机、设备昵称 | 添加本地工具笔记时 |
memory/*.md | 每日原始日志、特定主题聊天日志 | 机器人自动写入 |
每个 .jsonl 文件每行有一个 JSON 对象。类型:
| 类型 | 作用 |
|---|---|
session | 会话头:id, timestamp, cwd |
message | 对话轮次:角色(user/assistant/toolResult)、内容、模型、使用情况 |
custom | 元数据:model-snapshot, openclaw.cache-ttl |
compaction | 上下文窗口被修剪(旧消息被丢弃) |
model_change | 会话中途切换了模型 |
thinking_level_change | 思考级别被调整 |
会话索引(sessions.json)键:
agent:main:{channel}:{contact} 或 agent:main:cron:{job-uuid}sessionId(UUID = 文件名)、lastChannel、origin.label(人类可读名称)、origin.from(规范地址)、updatedAt(纪元毫秒)、chatType(direct/group)正常启动大约需要 3 秒:
[heartbeat] started
[gateway] listening on ws://127.0.0.1:18789
[browser/service] Browser control service ready
[hooks] loaded 3 internal hook handlers (boot-md, command-logger, session-memory)
[whatsapp] [default] starting provider
[signal] [default] starting provider (http://127.0.0.1:8080)
[telegram] [coder] starting provider
[telegram] [sales] starting provider
[whatsapp] Listening for personal WhatsApp inbound messages.
[signal] signal-cli: Started HTTP server on /127.0.0.1:8080
如果缺少任何一行,则该组件启动失败。检查 gateway.err.log。
| 错误 | 含义 | 修复 |
|---|---|---|
Web connection closed (status 408) | WhatsApp 网页版超时,自动重试最多 12 次 | 通常自我修复。如果达到 12/12,重启网关 |
Signal RPC -1: Failed to send message | signal-cli 守护进程连接丢失 | 重启网关 |
Signal RPC -5: Failed to send message due to rate limiting | Signal 速率限制 | 等待并重试,减少消息频率 |
No profile name set (signal-cli WARN) | 刷屏日志,无害 | signal-cli -a +ACCOUNT updateProfile --given-name "Name" |
Cross-context messaging denied | 智能体尝试跨通道发送 | 不是错误 — 安全护栏。消息必须源自正确的通道会话 |
getUpdates timed out after 500 seconds | Telegram 机器人轮询连接丢失 | 重启网关 |
Unrecognized keys: "token", "username" | Telegram 机器人的配置键错误 | 在 openclaw.json 中使用 botToken 而不是 token |
RESOURCE_EXHAUSTED (Gemini 429) | 嵌入速率限制 | 减少工作区文件变动,或升级 Gemini 配额 |
lane wait exceeded | 智能体因长时间 LLM 调用而阻塞 | 等待,如果卡住超过 2 分钟则重启 |
embedded run timeout: timeoutMs=600000 | 智能体响应超过 10 分钟 | 将任务分解成更小的部分 |
gateway timeout after 10000ms | 网关在重启窗口期间无法访问 | Cron 在网关关闭时触发 — 暂时性错误 |
OpenClaw 有 4 个扩展层。每层解决不同的问题:
| 层 | 作用 | 位置 | 如何添加 |
|---|---|---|---|
| 技能 | 智能体按需加载的知识 + 工作流 | /opt/homebrew/lib/node_modules/openclaw/skills/ 或 ~/.openclaw/workspace/skills/ | clawdhub install <slug> 或 npx add-skill <repo> |
| 扩展 | 自定义通道插件(TypeScript) | ~/.openclaw/extensions/{name}/ | 创建 openclaw.plugin.json + TypeScript 源代码 |
| 通道 | 消息传递平台(内置) | openclaw.json → channels.* + plugins.entries.* | 在 openclaw.json 中配置,添加凭证 |
| Cron 任务 | 计划的自主任务 | ~/.openclaw/cron/jobs.json | 智能体通过工具创建,或直接编辑 jobs.json |
技能是扩展智能体知识和能力的主要方式。它们是带有可选脚本/资源的 Markdown 文件,在相关时加载到上下文中。
# 搜索技能(跨注册表的向量搜索)
clawdhub search "postgres optimization"
clawdhub search "image generation"
# 浏览最新技能
clawdhub explore
# 安装技能
clawdhub install supabase-postgres-best-practices
clawdhub install nano-banana-pro
# 安装特定版本
clawdhub install my-skill --version 1.2.3
# 列出已安装内容
clawdhub list
# 更新所有已安装技能
clawdhub update --all
# 更新特定技能
clawdhub update my-skill
clawdhub update my-skill --force # 覆盖本地更改
当前已安装的技能(与 OpenClaw 捆绑):
| 类别 | 技能 |
|---|---|
| 消息传递 | discord, slack, imsg, wacli, voice-call |
| 社交/网络 | bird (X/Twitter), blogwatcher, github, trello, notion |
| gog, google-workspace-mcp, goplaces, local-places | |
| 媒体 | nano-banana-pro (Gemini 图像生成), openai-image-gen, video-frames, gifgrep, pixelation, sag (TTS), openai-whisper, sherpa-onnx-tts, songsee, camsnap |
| 编码智能体 | coding-agent (Codex/Claude Code/Pi), ccbg (后台运行器), tmux |
| 生产力 | apple-notes, apple-reminders, bear-notes, things-mac, obsidian, himalaya (电子邮件) |
| 智能家居 | openhue (Philips Hue), eightctl (Eight Sleep), sonoscli, blucli (BluOS) |
| 开发工具 | github, worktree, starter, desktop, supabase-postgres-best-practices, superdesign |
| 内容 | remotion-best-practices, remotion-fastest-tech-stack, humanizer, summarize, market, buildinpublic |
| 元 | skill-creator, clawdhub, find-skills, add-skill, model-usage, session-logs, recentplans, canvas |
一个技能只是一个包含 SKILL.md 的文件夹:
my-skill/
├── SKILL.md # 必需:YAML 前置元数据 + markdown 指令
├── scripts/ # 可选:可执行脚本
├── references/ # 可选:按需加载的文档
└── assets/ # 可选:模板、图片
SKILL.md 格式:
---
name: my-skill
description: 此技能的作用以及何时触发它。描述是主要的
触发器 — 智能体读取此描述以决定是否加载完整技能。
---
# 我的技能
指令放在这里。仅在技能触发后加载。
保持在 500 行以内。将大内容拆分为 references/ 文件。
Diagnose and fix real problems. Every command here is tested and works.
Run this first when anything seems wrong. Copy-paste the whole block:
echo "=== GATEWAY ===" && \
ps aux | grep -c "[o]penclaw" && \
echo "=== CONFIG JSON ===" && \
python3 -m json.tool ~/.openclaw/openclaw.json > /dev/null 2>&1 && echo "JSON: OK" || echo "JSON: BROKEN" && \
echo "=== CHANNELS ===" && \
cat ~/.openclaw/openclaw.json | jq -r '.channels | to_entries[] | "\(.key): policy=\(.value.dmPolicy // "n/a") enabled=\(.value.enabled // "implicit")"' && \
echo "=== PLUGINS ===" && \
cat ~/.openclaw/openclaw.json | jq -r '.plugins.entries | to_entries[] | "\(.key): \(.value.enabled)"' && \
echo "=== CREDS ===" && \
ls ~/.openclaw/credentials/whatsapp/default/ 2>/dev/null | wc -l | xargs -I{} echo "WhatsApp keys: {} files" && \
for d in ~/.openclaw/credentials/telegram/*/; do bot=$(basename "$d"); [ -f "$d/token.txt" ] && echo "Telegram $bot: OK" || echo "Telegram $bot: MISSING"; done && \
[ -f ~/.openclaw/credentials/bird/cookies.json ] && echo "Bird cookies: OK" || echo "Bird cookies: MISSING" && \
echo "=== CRON ===" && \
cat ~/.openclaw/cron/jobs.json | jq -r '.jobs[] | "\(.name): enabled=\(.enabled) status=\(.state.lastStatus // "never") \(.state.lastError // "")"' && \
echo "=== RECENT ERRORS ===" && \
tail -10 ~/.openclaw/logs/gateway.err.log 2>/dev/null && \
echo "=== MEMORY DB ===" && \
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT COUNT(*) || ' chunks, ' || (SELECT COUNT(*) FROM files) || ' files indexed' FROM chunks;" 2>/dev/null
~/.openclaw/
├── openclaw.json # MAIN CONFIG — channels, auth, gateway, plugins, skills
├── openclaw.json.bak* # Auto-backups (.bak, .bak.1, .bak.2 ...)
├── exec-approvals.json # Exec approval socket config
│
├── agents/main/
│ ├── agent/auth-profiles.json # Anthropic auth tokens
│ └── sessions/
│ ├── sessions.json # SESSION INDEX — keys are like agent:main:whatsapp:+1234
│ └── *.jsonl # Session transcripts (one JSON per line)
│
├── workspace/ # Agent workspace (git-tracked)
│ ├── SOUL.md # Personality, writing style, tone rules
│ ├── IDENTITY.md # Name, creature type, vibe
│ ├── USER.md # Owner context and preferences
│ ├── AGENTS.md # Session behavior, memory rules, safety
│ ├── BOOT.md # Boot instructions (autopilot notification protocol)
│ ├── HEARTBEAT.md # Periodic task checklist (empty = skip heartbeat)
│ ├── MEMORY.md # Curated long-term memory (main session only)
│ ├── TOOLS.md # Contacts, SSH hosts, device nicknames
│ ├── memory/ # Daily logs: YYYY-MM-DD.md, topic-chat.md
│ └── skills/ # Workspace-level skills
│
├── memory/main.sqlite # Vector memory DB (Gemini embeddings, FTS5 search)
│
├── logs/
│ ├── gateway.log # Runtime: startup, channel init, config reload, shutdown
│ ├── gateway.err.log # Errors: connection drops, API failures, timeouts
│ └── commands.log # Command execution log
│
├── cron/
│ ├── jobs.json # Job definitions (schedule, payload, delivery target)
│ └── runs/ # Per-job run logs: {job-uuid}.jsonl
│
├── credentials/
│ ├── whatsapp/default/ # Baileys session: ~1400 app-state-sync-key-*.json files
│ ├── telegram/{botname}/token.txt # Bot tokens (one per bot account)
│ └── bird/cookies.json # X/Twitter auth cookies
│
├── extensions/{name}/ # Custom plugins (TypeScript)
│ ├── openclaw.plugin.json # {"id", "channels", "configSchema"}
│ ├── index.ts # Entry point
│ └── src/ # channel.ts, actions.ts, runtime.ts, types.ts
│
├── identity/ # device.json, device-auth.json
├── devices/ # paired.json, pending.json
├── media/inbound/ # Received images, audio files
├── media/browser/ # Browser screenshots
├── browser/openclaw/user-data/ # Chromium profile (~180MB)
├── tools/signal-cli/ # Signal CLI binary
├── subagents/runs.json # Sub-agent execution log
├── canvas/index.html # Web canvas UI
└── telegram/
├── update-offset-coder.json # {"lastUpdateId": N} — Telegram polling cursor
└── update-offset-sales.json # Reset these to 0 to replay missed messages
This is the #1 issue. The message arrives but the bot doesn't respond. Check in this order:
# 1. Is the bot actually running?
grep -i "whatsapp.*starting\|whatsapp.*listening" ~/.openclaw/logs/gateway.log | tail -5
# 2. Check for 408 timeout drops (WhatsApp web disconnects frequently)
grep -i "408\|499\|retry" ~/.openclaw/logs/gateway.err.log | tail -10
# If you see "Web connection closed (status 408). Retry 1/12" — this is normal,
# it auto-recovers. But if retries reach 12/12, the session dropped completely.
# 3. Check for cross-context messaging blocks
grep -i "cross-context.*denied" ~/.openclaw/logs/gateway.err.log | tail -10
# Common: "Cross-context messaging denied: action=send target provider "whatsapp" while bound to "signal""
# This means the agent was in a Signal session and tried to reply on WhatsApp.
# FIX: The message needs to come through in the WhatsApp session context, not Signal.
# 4. Check the session exists for that contact
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r 'to_entries[] | select(.key | test("whatsapp")) | "\(.key) | \(.value.origin.label // "?")"'
# 5. Check if the sender is allowed
cat ~/.openclaw/openclaw.json | jq '.channels.whatsapp | {dmPolicy, allowFrom, selfChatMode, groupPolicy}'
# If dmPolicy is "allowlist" and the sender isn't in allowFrom, message is silently dropped.
# 6. Check if it's a group message (groups are disabled by default)
cat ~/.openclaw/openclaw.json | jq '.channels.whatsapp.groupPolicy'
# "disabled" means ALL group messages are ignored.
# 7. Check for lane congestion (agent busy with another task)
grep "lane wait exceeded" ~/.openclaw/logs/gateway.err.log | tail -5
# If the agent is stuck on a long LLM call, new messages queue up.
# 8. Check for agent run timeout
grep "embedded run timeout" ~/.openclaw/logs/gateway.err.log | tail -5
# Hard limit is 600s (10 min). If the agent's response takes longer, it's killed.
# Check credential files exist (should be ~1400 files)
ls ~/.openclaw/credentials/whatsapp/default/ | wc -l
# If 0 files: session was never created or got wiped
# Fix: re-pair with `openclaw configure`
# Check for QR/pairing events
grep -i "pair\|link\|qr\|scan\|logged out" ~/.openclaw/logs/gateway.log | tail -10
# Check for Baileys errors
grep -i "baileys\|DisconnectReason\|logout\|stream:error" ~/.openclaw/logs/gateway.err.log | tail -20
# Nuclear fix: delete credentials and re-pair
# rm -rf ~/.openclaw/credentials/whatsapp/default/
# openclaw configure
Two separate problems that look the same:
# 1. Check for config validation errors (THE COMMON ONE)
grep -i "telegram.*unrecognized\|telegram.*invalid\|telegram.*policy" ~/.openclaw/logs/gateway.err.log | tail -10
# Known issue: the keys "token" and "username" under accounts are not recognized.
# The correct field is "botToken", not "token".
# 2. Check the actual config
cat ~/.openclaw/openclaw.json | jq '.channels.telegram'
# Verify each bot has "botToken" (not "token") and "name" fields.
# 3. Check polling status — bots die after getUpdates timeout
grep -i "telegram.*exit\|telegram.*timeout\|getUpdates" ~/.openclaw/logs/gateway.err.log | tail -10
# "[telegram] [sales] channel exited: Request to 'getUpdates' timed out after 500 seconds"
# This means the bot lost connection to Telegram's API and stopped listening.
# Fix: restart gateway — `openclaw gateway restart`
# 4. Check the polling offset (if bot "forgets" or replays old messages)
cat ~/.openclaw/telegram/update-offset-coder.json
cat ~/.openclaw/telegram/update-offset-sales.json
# If lastUpdateId is stuck or 0, the bot will reprocess old messages.
# To skip to latest: the gateway sets this automatically on restart.
# 5. Check if both bots are starting
grep -i "telegram.*starting\|telegram.*coder\|telegram.*sales" ~/.openclaw/logs/gateway.log | tail -10
# 6. "Bot forgets" — this is usually a session issue, not Telegram
# Each Telegram user gets their own session in sessions.json.
# Check if the session exists:
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r 'to_entries[] | select(.key | test("telegram")) | "\(.key) | \(.value.origin.label // "?")"'
# 7. Check if compaction happened (context window pruned = "forgot")
SESS_ID="paste-session-id"
grep '"compaction"' ~/.openclaw/agents/main/sessions/$SESS_ID.jsonl | wc -l
# If compaction count > 0, old messages were pruned from context.
# The agent's compaction mode is:
cat ~/.openclaw/openclaw.json | jq '.agents.defaults.compaction'
# Correct Telegram config structure:
cat ~/.openclaw/openclaw.json | jq '.channels.telegram = {
"enabled": true,
"accounts": {
"coder": {
"name": "Bot Display Name",
"enabled": true,
"botToken": "your-bot-token-here"
},
"sales": {
"name": "Sales Bot Name",
"enabled": true,
"botToken": "your-bot-token-here"
}
},
"dmPolicy": "pairing",
"groupPolicy": "disabled"
}' > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
This blocks cron jobs and cross-channel notifications.
# 1. Check if signal-cli process is alive
ps aux | grep "[s]ignal-cli"
# 2. Check the RPC endpoint
grep -i "signal.*starting\|signal.*8080\|signal.*rpc" ~/.openclaw/logs/gateway.log | tail -10
# Should see: "[signal] [default] starting provider (http://127.0.0.1:8080)"
# 3. Check for connection instability
grep -i "HikariPool\|reconnecting\|SSE stream error\|terminated" ~/.openclaw/logs/gateway.err.log | tail -10
# "HikariPool-1 - Thread starvation or clock leap detected" = signal-cli internal DB issue
# "SSE stream error: TypeError: terminated" = lost connection to signal-cli daemon
# 4. Check for rate limiting
grep -i "signal.*rate" ~/.openclaw/logs/gateway.err.log | tail -5
# "Signal RPC -5: Failed to send message due to rate limiting"
# 5. Check for wrong target format
grep -i "unknown target" ~/.openclaw/logs/gateway.err.log | tail -5
# "Unknown target "adi" for Signal. Hint: <E.164|uuid:ID|...>"
# The agent must use phone numbers (+1...) or uuid: format, not names.
# 6. Fix profile name warning spam
grep -c "No profile name set" ~/.openclaw/logs/gateway.err.log
# If high count: run signal-cli updateProfile to set a name
# 7. Test signal-cli directly
ACCT=$(cat ~/.openclaw/openclaw.json | jq -r '.channels.signal.account')
echo "Account: $ACCT"
# signal-cli -a $ACCT send -m "test" +TARGET_NUMBER
# 8. Check if the signal-cli daemon needs restart
# The gateway manages signal-cli as a subprocess.
# Restart the whole gateway: openclaw gateway restart
# 1. Overview of all jobs
cat ~/.openclaw/cron/jobs.json | jq -r '.jobs[] | "\(.enabled | if . then "ON " else "OFF" end) \(.state.lastStatus // "never" | if . == "error" then "FAIL" elif . == "ok" then "OK " else . end) \(.name)"'
# 2. Failing jobs with error details
cat ~/.openclaw/cron/jobs.json | jq '.jobs[] | select(.state.lastStatus == "error") | {name, error: .state.lastError, lastRun: (.state.lastRunAtMs | . / 1000 | todate), id}'
# 3. Read the actual run log for a failing job
JOB_ID="paste-job-uuid-here"
tail -20 ~/.openclaw/cron/runs/$JOB_ID.jsonl | python3 -c "
import sys, json
for line in sys.stdin:
try:
obj = json.loads(line)
if obj.get('type') == 'message':
role = obj['message']['role']
text = ''.join(c.get('text','') for c in obj['message'].get('content',[]) if isinstance(c,dict))
if text.strip():
print(f'[{role}] {text[:300]}')
except: pass
"
# 4. Common cron failure causes:
# - "Signal RPC -1" → Signal daemon down, see Signal section above
# - "gateway timeout after 10000ms" → gateway was restarting when cron fired
# - "Brave Search 429" → free tier rate limit hit (2000 req/month)
# - "embedded run timeout" → job took longer than 600s
# 5. Next scheduled run times
cat ~/.openclaw/cron/jobs.json | jq -r '.jobs[] | select(.enabled) | "\(.name): \((.state.nextRunAtMs // 0) | . / 1000 | todate)"'
# 6. Disable a broken job temporarily
cat ~/.openclaw/cron/jobs.json | jq '(.jobs[] | select(.name == "JOB_NAME")).enabled = false' > /tmp/cron.json && mv /tmp/cron.json ~/.openclaw/cron/jobs.json
The memory system has 3 layers. When the agent "forgets," one of these broke:
# Check compaction count for a session (compaction = old messages pruned)
grep -c '"compaction"' ~/.openclaw/agents/main/sessions/SESSION_ID.jsonl
# 7 compactions = the agent has "forgotten" its earliest messages 7 times.
# Check compaction mode
cat ~/.openclaw/openclaw.json | jq '.agents.defaults.compaction'
# "safeguard" = only compacts when hitting context limit
# What daily memory files exist
ls -la ~/.openclaw/workspace/memory/
# What's in MEMORY.md (long-term curated)
cat ~/.openclaw/workspace/MEMORY.md
# Search memory files for something specific
grep -ri "KEYWORD" ~/.openclaw/workspace/memory/
# What files are indexed
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT path, size, datetime(mtime/1000, 'unixepoch') as modified FROM files;"
# How many chunks (text fragments) exist
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT COUNT(*) FROM chunks;"
# Search chunks by text (FTS5 full-text search)
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT substr(text, 1, 200) FROM chunks_fts WHERE chunks_fts MATCH 'KEYWORD' LIMIT 5;"
# Check embedding config
sqlite3 ~/.openclaw/memory/main.sqlite "SELECT value FROM meta WHERE key='memory_index_meta_v1';" | python3 -m json.tool
# Check for Gemini embedding rate limits (breaks indexing)
grep -i "gemini.*batch.*failed\|RESOURCE_EXHAUSTED\|429" ~/.openclaw/logs/gateway.err.log | tail -10
# "embeddings: gemini batch failed (2/2); disabling batch" = indexing degraded
# Rebuild memory index (re-index all workspace files)
# Delete the DB and restart gateway — it will rebuild:
# rm ~/.openclaw/memory/main.sqlite && openclaw gateway restart
# Search session index by name (case-insensitive)
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r 'to_entries[] | select(.value.origin.label // "" | test("NAME"; "i")) | "\(.value.sessionId) | \(.value.lastChannel) | \(.value.origin.label)"'
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r 'to_entries[] | select(.value.lastChannel == "whatsapp") | "\(.value.sessionId) | \(.value.origin.label // .key)"'
# Replace "whatsapp" with: signal, telegram, or check .key for cron sessions
cat ~/.openclaw/agents/main/sessions/sessions.json | jq -r '[to_entries[] | {id: .value.sessionId, updated: .value.updatedAt, label: (.value.origin.label // .key), ch: (.value.lastChannel // "cron")}] | sort_by(.updated) | reverse | .[:10][] | "\(.updated | . / 1000 | todate) | \(.ch) | \(.label)"'
# Quick: find which session files contain a keyword
grep -l "KEYWORD" ~/.openclaw/agents/main/sessions/*.jsonl
# Detailed: show matching messages with timestamps
grep "KEYWORD" ~/.openclaw/agents/main/sessions/*.jsonl | python3 -c "
import sys, json
for line in sys.stdin:
path, data = line.split(':', 1)
try:
obj = json.loads(data)
if obj.get('type') == 'message':
role = obj['message']['role']
text = ''.join(c.get('text','') for c in obj['message'].get('content',[]) if isinstance(c,dict))
if text.strip():
sid = path.split('/')[-1].replace('.jsonl','')[:8]
ts = obj.get('timestamp','')[:19]
print(f'{ts} [{sid}] [{role}] {text[:200]}')
except: pass
" | head -30
# Last 30 messages from a session
tail -50 ~/.openclaw/agents/main/sessions/SESSION_ID.jsonl | python3 -c "
import sys, json
for line in sys.stdin:
try:
obj = json.loads(line)
if obj.get('type') == 'message':
role = obj['message']['role']
text = ''.join(c.get('text','') for c in obj['message'].get('content',[]) if isinstance(c,dict))
if text.strip() and role != 'toolResult':
print(f'[{role}] {text[:300]}')
print()
except: pass
"
Always: backup, edit with jq, restart.
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.bak.manual
jq 'YOUR_EDIT_HERE' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
openclaw gateway restart
# Switch WhatsApp to allowlist
jq '.channels.whatsapp.dmPolicy = "allowlist" | .channels.whatsapp.allowFrom = ["+1XXXXXXXXXX"]' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# Enable WhatsApp autopilot (bot responds as you to everyone)
jq '.channels.whatsapp += {dmPolicy: "open", selfChatMode: false, allowFrom: ["*"]}' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# Add number to Signal allowlist
jq '.channels.signal.allowFrom += ["+1XXXXXXXXXX"]' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# Change model
jq '.agents.defaults.models = {"anthropic/claude-sonnet-4": {"alias": "sonnet"}}' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# Set concurrency
jq '.agents.defaults.maxConcurrent = 10 | .agents.defaults.subagents.maxConcurrent = 10' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# Disable a plugin
jq '.plugins.entries.imessage.enabled = false' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# Latest backup
cp ~/.openclaw/openclaw.json.bak ~/.openclaw/openclaw.json
# List all backups by date
ls -lt ~/.openclaw/openclaw.json.bak*
# Validate JSON before restart
python3 -m json.tool ~/.openclaw/openclaw.json > /dev/null && echo "OK" || echo "BROKEN"
# Nuclear reset
openclaw configure
| Mode | Behavior | Risk |
|---|---|---|
open + allowFrom: ["*"] | Anyone can message, bot responds to all | HIGH — burns API credits, bot speaks as you |
allowlist + allowFrom: ["+1..."] | Only listed numbers get through | LOW — explicit control |
pairing | Unknown senders get a code, you approve | LOW — approval gate |
disabled | Channel completely off |
cat ~/.openclaw/openclaw.json | jq '{
whatsapp: {policy: .channels.whatsapp.dmPolicy, from: .channels.whatsapp.allowFrom, groups: .channels.whatsapp.groupPolicy, selfChat: .channels.whatsapp.selfChatMode},
signal: {policy: .channels.signal.dmPolicy, from: .channels.signal.allowFrom, groups: .channels.signal.groupPolicy},
telegram: {policy: .channels.telegram.dmPolicy, groups: .channels.telegram.groupPolicy, bots: [.channels.telegram.accounts | to_entries[] | "\(.key)=\(.value.enabled)"]},
imessage: {enabled: .channels.imessage.enabled, policy: .channels.imessage.dmPolicy}
}'
| File | What | When to edit |
|---|---|---|
SOUL.md | Personality: tone, style ("no em dashes, lowercase casual") | To change how the bot talks |
IDENTITY.md | Name (Jarvis), creature type, emoji | To rebrand |
USER.md | Owner info, preferences | When user context changes |
AGENTS.md | Operating rules: memory protocol, safety, group chat behavior, heartbeat instructions | To change bot behavior |
BOOT.md |
Each .jsonl file has one JSON object per line. Types:
| type | What |
|---|---|
session | Session header: id, timestamp, cwd |
message | Conversation turn: role (user/assistant/toolResult), content, model, usage |
custom | Metadata: model-snapshot, openclaw.cache-ttl |
compaction | Context window was pruned (old messages dropped) |
model_change |
Session index (sessions.json) keys:
agent:main:{channel}:{contact} or agent:main:cron:{job-uuid}sessionId (UUID = filename), lastChannel, origin.label (human name), origin.from (canonical address), updatedAt (epoch ms), chatType (direct/group)Normal startup takes ~3 seconds:
[heartbeat] started
[gateway] listening on ws://127.0.0.1:18789
[browser/service] Browser control service ready
[hooks] loaded 3 internal hook handlers (boot-md, command-logger, session-memory)
[whatsapp] [default] starting provider
[signal] [default] starting provider (http://127.0.0.1:8080)
[telegram] [coder] starting provider
[telegram] [sales] starting provider
[whatsapp] Listening for personal WhatsApp inbound messages.
[signal] signal-cli: Started HTTP server on /127.0.0.1:8080
If any line is missing, that component failed to start. Check gateway.err.log.
| Error | Meaning | Fix |
|---|---|---|
Web connection closed (status 408) | WhatsApp web timeout, auto-retries up to 12x | Usually self-heals. If reaches 12/12, restart gateway |
Signal RPC -1: Failed to send message | signal-cli daemon lost connection | Restart gateway |
Signal RPC -5: Failed to send message due to rate limiting | Signal rate limit | Wait and retry, reduce message frequency |
No profile name set (signal-cli WARN) | Floods logs, harmless | signal-cli -a +ACCOUNT updateProfile --given-name "Name" |
OpenClaw has 4 extension layers. Each solves a different problem:
| Layer | What | Where | How to add |
|---|---|---|---|
| Skills | Knowledge + workflows the agent loads on demand | /opt/homebrew/lib/node_modules/openclaw/skills/ or ~/.openclaw/workspace/skills/ | clawdhub install <slug> or npx add-skill <repo> |
| Extensions | Custom channel plugins (TypeScript) | ~/.openclaw/extensions/{name}/ | Create openclaw.plugin.json + TypeScript source |
Skills are the primary way to extend what the agent knows and can do. They're markdown files with optional scripts/assets that get loaded into context when relevant.
# Search for skills (vector search across the registry)
clawdhub search "postgres optimization"
clawdhub search "image generation"
# Browse latest skills
clawdhub explore
# Install a skill
clawdhub install supabase-postgres-best-practices
clawdhub install nano-banana-pro
# Install a specific version
clawdhub install my-skill --version 1.2.3
# List what's installed
clawdhub list
# Update all installed skills
clawdhub update --all
# Update a specific skill
clawdhub update my-skill
clawdhub update my-skill --force # overwrite local changes
Currently installed skills (bundled with OpenClaw):
| Category | Skills |
|---|---|
| Messaging | discord, slack, imsg, wacli, voice-call |
| Social/Web | bird (X/Twitter), blogwatcher, github, trello, notion |
| gog, google-workspace-mcp, goplaces, local-places | |
| Media | nano-banana-pro (Gemini image gen), openai-image-gen, video-frames, gifgrep, pixelation, sag (TTS), openai-whisper, sherpa-onnx-tts, songsee, camsnap |
| Coding agents | coding-agent (Codex/Claude Code/Pi), ccbg (background runner), tmux |
| Productivity | apple-notes, apple-reminders, bear-notes, things-mac, obsidian, himalaya (email) |
| Smart home | openhue (Philips Hue), eightctl (Eight Sleep), sonoscli, blucli (BluOS) |
| Dev tools | github, worktree, starter, desktop, supabase-postgres-best-practices, superdesign |
| Content | remotion-best-practices, remotion-fastest-tech-stack, humanizer, summarize, market, buildinpublic |
A skill is just a folder with a SKILL.md:
my-skill/
├── SKILL.md # Required: YAML frontmatter + markdown instructions
├── scripts/ # Optional: executable scripts
├── references/ # Optional: docs loaded on demand
└── assets/ # Optional: templates, images
SKILL.md format:
---
name: my-skill
description: What this does and WHEN to trigger it. The description is the primary
trigger — the agent reads this to decide whether to load the full skill.
---
# My Skill
Instructions go here. Only loaded AFTER the skill triggers.
Keep under 500 lines. Split large content into references/ files.
Key principle: the context window is a shared resource. Only include what the agent doesn't already know. Prefer concise examples over verbose explanations.
# Publish to ClawdHub
clawdhub login
clawdhub publish ./my-skill --slug my-skill --name "My Skill" --version 1.0.0
# Or publish to GitHub for npx add-skill
# (see add-skill skill for details)
OpenClaw can spawn other AI agents (Codex, Claude Code, Pi) as background workers. This is how you run parallel coding tasks, reviews, or any work that benefits from multiple agents.
The pattern: bash pty:true background:true workdir:/path command:"agent 'task'"
# Spawn Codex to build something (background, auto-approve)
bash pty:true workdir:~/project background:true command:"codex exec --full-auto 'Build a REST API for todos'"
# Returns sessionId for tracking
# Spawn Claude Code on a different task
bash pty:true workdir:~/other-project background:true command:"claude 'Refactor the auth module'"
# Monitor all running agents
process action:list
# Check output of a specific agent
process action:log sessionId:XXX
# Send input if agent asks a question
process action:submit sessionId:XXX data:"yes"
# Kill a stuck agent
process action:kill sessionId:XXX
Parallel PR reviews:
# Fetch all PR refs
git fetch origin '+refs/pull/*/head:refs/remotes/origin/pr/*'
# Launch one agent per PR
bash pty:true workdir:~/project background:true command:"codex exec 'Review PR #86. git diff origin/main...origin/pr/86'"
bash pty:true workdir:~/project background:true command:"codex exec 'Review PR #87. git diff origin/main...origin/pr/87'"
Parallel issue fixing with git worktrees:
git worktree add -b fix/issue-78 /tmp/issue-78 main
git worktree add -b fix/issue-99 /tmp/issue-99 main
bash pty:true workdir:/tmp/issue-78 background:true command:"codex --yolo 'Fix issue #78: description. Commit and push.'"
bash pty:true workdir:/tmp/issue-99 background:true command:"codex --yolo 'Fix issue #99: description. Commit and push.'"
Auto-notify when agent finishes:
bash pty:true workdir:~/project background:true command:"codex --yolo exec 'Your task.
When completely finished, run: openclaw gateway wake --text \"Done: summary\" --mode now'"
Channels are messaging platforms the agent can communicate through. Built-in: WhatsApp, Signal, Telegram, iMessage, Discord, Slack.
Enable a built-in channel:
# 1. Enable the plugin
jq '.plugins.entries.discord.enabled = true' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# 2. Add channel config
jq '.channels.discord = {enabled: true, dmPolicy: "pairing", groupPolicy: "disabled"}' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
# 3. Add credentials (channel-specific)
# 4. Restart gateway
openclaw gateway restart
Build a custom channel extension:
~/.openclaw/extensions/{name}/
├── openclaw.plugin.json # {"id": "name", "channels": ["name"], "configSchema": {...}}
├── package.json # Standard npm package
├── index.ts # Entry point
└── src/
├── channel.ts # Inbound message handling + outbound send
├── actions.ts # Tool actions the agent can invoke
├── runtime.ts # Lifecycle: start, stop, health check
├── config-schema.ts # JSON schema for plugin config
└── types.ts # TypeScript types
# List installed extensions
ls ~/.openclaw/extensions/
# View extension manifests
cat ~/.openclaw/extensions/*/openclaw.plugin.json | jq .
# Check extension source files
find ~/.openclaw/extensions/ -name "*.ts" -not -path "*/node_modules/*"
The agent can receive on one channel and send on another, but there are guardrails:
# Check cross-context settings
cat ~/.openclaw/openclaw.json | jq '.tools.message.crossContext'
# allowAcrossProviders: true = agent CAN send across channels
# marker.enabled: false = no "[via Signal]" prefix on cross-channel messages
# If you see "Cross-context messaging denied" errors:
# The agent tried to send from a session bound to channel A to channel B.
# This is a security feature. To allow it:
jq '.tools.message.crossContext.allowAcrossProviders = true' ~/.openclaw/openclaw.json > /tmp/oc.json && mv /tmp/oc.json ~/.openclaw/openclaw.json
BOOT.md notification protocol (already configured): The agent receives WhatsApp messages, responds on WhatsApp, then sends a notification summary to Signal. This is the primary cross-channel pattern — autopilot on one channel, control center on another.
Push HTML/games/dashboards to connected Mac/iOS/Android nodes:
# Check canvas config
cat ~/.openclaw/openclaw.json | jq '.canvasHost // "not configured"'
# List connected nodes
openclaw nodes list
# Present HTML content on a node
# canvas action:present node:<node-id> target:http://localhost:18793/__moltbot__/canvas/my-page.html
# Canvas files live in:
ls ~/.openclaw/canvas/
Initiate phone calls via Twilio/Telnyx/Plivo:
# Check if voice-call plugin is enabled
cat ~/.openclaw/openclaw.json | jq '.plugins.entries["voice-call"] // "not configured"'
# CLI usage
openclaw voicecall call --to "+15555550123" --message "Hello"
openclaw voicecall status --call-id <id>
# View all jobs
cat ~/.openclaw/cron/jobs.json | jq '.jobs[] | {name, enabled, schedule: .schedule, channel: .payload.channel, to: .payload.to}'
# Job schedule types:
# "kind": "at", "atMs": <epoch> — one-shot at specific time
# "kind": "every", "everyMs": <ms> — recurring interval
# Job delivery targets:
# channel + to fields determine where results go (signal, whatsapp, telegram)
# sessionTarget: "isolated" = fresh context each run (no memory of previous runs)
# To add a job, the agent creates it via tool, or edit jobs.json:
# See existing jobs as templates in ~/.openclaw/cron/jobs.json
MIT
Weekly Installs
2.0K
Repository
GitHub Stars
8
First Seen
Feb 1, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode1.8K
codex1.8K
gemini-cli1.8K
github-copilot1.8K
kimi-cli1.7K
amp1.7K
Azure Data Explorer (Kusto) 查询技能:KQL数据分析、日志遥测与时间序列处理
93,700 周安装
| NONE |
| Startup instructions (autopilot notification protocol: WA → Signal) |
| To change what happens on boot |
HEARTBEAT.md | Periodic checklist (empty = no heartbeat API calls) | To add/remove periodic tasks |
MEMORY.md | Curated long-term memory (loaded only in main/direct sessions) | Bot manages this itself |
TOOLS.md | Contacts, SSH hosts, device nicknames | To add local tool notes |
memory/*.md | Daily raw logs, topic-specific chat logs | Bot writes automatically |
| Model was switched mid-session |
thinking_level_change | Thinking level adjusted |
Cross-context messaging denied | Agent tried to send across channels | Not a bug — security guardrail. Message must originate from correct channel session |
getUpdates timed out after 500 seconds | Telegram bot lost polling connection | Restart gateway |
Unrecognized keys: "token", "username" | Wrong config keys for Telegram bots | Use botToken not token in openclaw.json |
RESOURCE_EXHAUSTED (Gemini 429) | Embedding rate limit | Reduce workspace file churn, or upgrade Gemini quota |
lane wait exceeded | Agent blocked on long LLM call | Wait, or restart if stuck > 2 min |
embedded run timeout: timeoutMs=600000 | Agent response exceeded 10 min | Break task into smaller pieces |
gateway timeout after 10000ms | Gateway unreachable during restart window | Cron fired while gateway was down — transient |
| Channels | Messaging platforms (built-in) | openclaw.json → channels.* + plugins.entries.* | Configure in openclaw.json, add credentials |
| Cron jobs | Scheduled autonomous tasks | ~/.openclaw/cron/jobs.json | Agent creates them via tool, or edit jobs.json directly |
| Meta | skill-creator, clawdhub, find-skills, add-skill, model-usage, session-logs, recentplans, canvas |