Community编程与开发github.com

tianyilt/openclaw-repair-skills

Diagnose and fix common OpenClaw / NanoClaw issues — broken skills, missing scripts, API key failures, path resolution bugs, and configuration problems. The meta-skill for when your claw is broken.

兼容平台Claude Code~Codex CLI~CursorGemini CLI
npx add-skill tianyilt/openclaw-repair-skills

name: claw-doctor description: Diagnose and fix common OpenClaw / NanoClaw issues — broken skills, missing scripts, API key failures, path resolution bugs, and configuration problems. The meta-skill for when your claw is broken. version: 1.1.0 keywords:


Claw Doctor — OpenClaw Self-Repair Skill

This skill diagnoses and fixes common OpenClaw / NanoClaw problems. When something breaks, run through the checklist below before giving up.


When to Activate

Activate this skill when the user reports any of the following:

  • "skill not found" / skill does not trigger
  • "No such file or directory" when running a skill script
  • API key errors from a skill
  • Skill produces no output or wrong output
  • "SKILL.md is invalid" / YAML parse errors
  • A skill works globally but not in workspace (or vice versa)
  • Skills were working before but stopped after an update

Skill Load Order & Paths

OpenClaw loads skills from two locations. Workspace skills take priority.

Priority 1 (high): <workspace>/skills/<skill-name>/SKILL.md
Priority 2 (low):  ~/.openclaw/skills/<skill-name>/SKILL.md

Diagnostic: list all loaded skills

# Show what's installed globally
ls ~/.openclaw/skills/ 2>/dev/null || echo "No global skills dir"

# Show what's installed in current workspace
ls ./skills/ 2>/dev/null || echo "No workspace skills dir"

If a skill appears in both, the workspace version wins — check for version mismatches.


Problem 1 — Skill Does Not Trigger

Symptom: User invokes a skill but Claude ignores it or does not follow the skill procedure.

Diagnosis checklist:

  1. Is the SKILL.md actually present and readable?

    cat ./skills/<skill-name>/SKILL.md | head -20
    
  2. Does the frontmatter YAML parse correctly?

    python3 -c "
    import re, sys
    txt = open('skills/<skill-name>/SKILL.md').read()
    fm = re.search(r'^---\n(.*?)\n---', txt, re.DOTALL)
    print('Frontmatter found:', bool(fm))
    if fm:
        import yaml; d = yaml.safe_load(fm.group(1)); print('Keys:', list(d.keys()))
    "
    
  3. Do the keywords in the SKILL.md match what the user said?

    • Add more keyword variants (synonyms, abbreviations) if not matching.
  4. Is description clear enough for the model to identify the skill?

    • Short, specific descriptions outperform vague ones.

Fix: Ensure frontmatter is valid YAML (no tabs, proper quoting, correct indentation).


Problem 2 — Script Not Found (Path Resolution)

Symptom: bash: scripts/run: No such file or directory

This is the most common skill bug. Scripts referenced in SKILL.md as scripts/foo are relative to the skill's installation directory inside the OpenClaw plugin cache, not the current working directory.

Canonical fix — resolve the script path dynamically before every use:

# For a skill named "my-skill" with a script named "run"
MY_SCRIPT=$(find ~/.openclaw -name "run" -path "*/my-skill/*/scripts/*" -type f 2>/dev/null | head -1)
# Fallback: check workspace skills
[ -z "$MY_SCRIPT" ] && MY_SCRIPT=$(find ./skills -name "run" -path "*/my-skill/scripts/*" -type f 2>/dev/null | head -1)

if [ -z "$MY_SCRIPT" ]; then
  echo "ERROR: script not found. Is the skill installed?"
  exit 1
fi

$MY_SCRIPT <args>

Also check: Is the script executable?

chmod +x ~/.openclaw/skills/my-skill/scripts/*
chmod +x ./skills/my-skill/scripts/*

Problem 3 — API Key Not Configured

Symptom: Skill returns {"success": false, "setup_required": true} or 401/403 errors.

Standard API key setup flow:

  1. The skill's SKILL.md should document where the key is stored (usually ~/.openclaw/secrets/<skill-name>.key or an env var).
  2. Check if the key file exists:
    ls ~/.openclaw/secrets/ 2>/dev/null || echo "No secrets dir"
    
  3. Run the skill's setup command (usually scripts/run setup <api-key>).
  4. Verify the key was saved:
    cat ~/.openclaw/secrets/<skill-name>.key 2>/dev/null | head -c 20
    

If no setup command exists, ask the user to set the env var directly:

export SKILL_API_KEY="their-key-here"
# Add to ~/.zshrc or ~/.bashrc for persistence

Problem 4 — Dependency Missing (Node.js / Python / tool)

Symptom: node: command not found, python3: No such file or directory, jq: command not found

Quick dependency check:

echo "=== Core deps ===" && \
node --version 2>/dev/null || echo "MISSING: node" && \
python3 --version 2>/dev/null || echo "MISSING: python3" && \
jq --version 2>/dev/null || echo "MISSING: jq" && \
curl --version 2>/dev/null | head -1 || echo "MISSING: curl"

Fix by platform:

ToolmacOSUbuntu/Debian
Node.jsbrew install nodeapt install nodejs npm
Python 3brew install python3apt install python3
jqbrew install jqapt install jq

For Python skill dependencies:

pip3 install -r skills/<skill-name>/requirements.txt 2>/dev/null \
  || echo "No requirements.txt found"

For Node skill dependencies:

cd skills/<skill-name> && npm install 2>/dev/null \
  || echo "No package.json found"

Problem 5 — YAML Frontmatter Errors

Symptom: Skill loads but metadata is wrong / keywords not indexed.

Valid frontmatter template:

---
name: my-skill-name         # lowercase, hyphens only
description: One clear sentence describing what this skill does.
keywords:
  - keyword-one
  - keyword-two
license: MIT
---

Common mistakes:

MistakeFix
Tabs instead of spacesReplace with 2-space indentation
Unquoted : in descriptionWrap value in quotes
Missing name fieldAdd it — it's required
keywords as inline list [a, b]Use block list - a\n- b

Validate:

python3 -c "
import yaml, sys
txt = open('skills/<skill-name>/SKILL.md').read().split('---')[1]
try:
    d = yaml.safe_load(txt)
    print('OK:', d)
except yaml.YAMLError as e:
    print('YAML ERROR:', e)
    sys.exit(1)
"

Problem 6 — Skill Worked Before, Broke After Update

Symptom: OpenClaw updated and a skill stopped working.

Checklist:

  1. Check if the OpenClaw plugin cache was cleared:

    ls ~/.openclaw/plugins/cache/ 2>/dev/null | head -10
    
  2. Reinstall the skill from source:

    # From a cloned skills repo
    cp -r /path/to/skills-repo/skills/<skill-name> ~/.openclaw/skills/
    
  3. Check for breaking changes in OpenClaw's skill API — look at the OpenClaw changelog for SKILL.md format updates.

  4. Test the script directly (bypassing OpenClaw):

    bash skills/<skill-name>/scripts/<main-script> --help
    

Full Health Check

Run this to get a complete snapshot of the OpenClaw environment:

echo "=== OpenClaw Health Check ===" && \
echo "--- Global skills ---" && ls ~/.openclaw/skills/ 2>/dev/null || echo "(none)" && \
echo "--- Workspace skills ---" && ls ./skills/ 2>/dev/null || echo "(none)" && \
echo "--- Secrets ---" && ls ~/.openclaw/secrets/ 2>/dev/null || echo "(none)" && \
echo "--- Plugin cache ---" && ls ~/.openclaw/plugins/cache/ 2>/dev/null | head -5 || echo "(empty)" && \
echo "--- Dependencies ---" && \
  node --version 2>/dev/null && \
  python3 --version 2>/dev/null && \
  jq --version 2>/dev/null && \
echo "=== Done ==="

For Claude Code Users

This skill also works as a Claude Code user-invocable skill. Add the following to ~/.claude/CLAUDE.md under ## User-Invocable Skills:

### claw-doctor

Diagnose and fix OpenClaw / NanoClaw problems.

**Trigger**: user mentions skill not loading, script not found, API key error, SKILL.md broken, OpenClaw not working

**Procedure**: Follow the claw-doctor SKILL.md checklist:
1. Identify symptom category (trigger / script path / API key / dependency / YAML / post-update)
2. Run the relevant diagnostic commands
3. Apply the fix and verify with the Full Health Check

Problem 7 — 飞书 Bot 用了错误的模型

症状:飞书里回复的模型和 openclaw.json 配置的不一致,或 /new 之后还是老模型。

根因 1 — Session 里的 model override 覆盖了 agent 配置

Session 文件会持久化上一次手动切换的模型,重启后也不会清除。

# 找出哪个 session 有 model override
python3 -c "
import json
for agent in ['main', 'sii']:
    path = f'/Users/tianyiliang/.openclaw/agents/{agent}/sessions/sessions.json'  # 按实际路径调整
    try:
        data = json.load(open(path))
        for k, v in data.items():
            if v.get('model'):
                print(f'[{agent}] {k}: model={v[\"model\"]}')
    except: pass
"

修复:删掉对应 session 里的 model/modelProvider 字段,或直接删掉整个 session 条目,再重启 gateway:

openclaw gateway restart

根因 2 — main agent 不在 agents.list,binding 被忽略

bindings 里写了 "agentId": "main" 但不生效——因为 main 是内置 agent,不在 agents.list 里就不能作为路由目标。

诊断

openclaw agents list --bindings   # 看 main 是否出现

修复:把 main 显式加入 agents.list

python3 -c "
import json
path = '~/.openclaw/openclaw.json'  # 按实际路径
cfg = json.load(open(path))
if not any(a['id'] == 'main' for a in cfg['agents']['list']):
    cfg['agents']['list'].insert(0, {
        'id': 'main',
        'name': 'main',
        'workspace': cfg['agents']['defaults']['workspace'],
        'model': {'primary': 'custom-local/gemini-3-pro-preview', 'fallbacks': []}
    })
    json.dump(cfg, open(path,'w'), indent=2, ensure_ascii=False)
    print('Added main to agents.list')
"

根因 3 — Model ID 和本地代理不匹配导致 fallback

openclaw.json 里配的 model ID 在 localhost proxy 上不存在,静默 fallback 到下一个。

# 查实际可用的模型
curl -s http://localhost:8317/v1/models -H "Authorization: Bearer your-api-key-1" \
  | python3 -c "import json,sys; [print(m['id']) for m in json.load(sys.stdin)['data']]" | sort

对比 openclaw.json 里的 model ID,确保完全匹配。


Problem 8 — Cron Jobs 走了 OpenRouter

症状openclaw status 里 cron session 显示 model=openrouter/auto,不应该走云端。

根因:session 里有 authProfileOverride: openrouter:* 被持久化(某次 auth 自动切换的残留)。

诊断

python3 -c "
import json
for agent in ['main', 'sii']:
    path = f'~/.openclaw/agents/{agent}/sessions/sessions.json'
    try:
        data = json.load(open(path))
        for k, v in data.items():
            if 'cron' in k and 'openrouter' in v.get('authProfileOverride',''):
                print(f'[{agent}] {k}: auth={v[\"authProfileOverride\"]} model={v.get(\"model\")}')
    except: pass
"

修复:清掉所有 cron session 里的 openrouter 覆盖:

python3 -c "
import json, glob
for path in glob.glob('~/.openclaw/agents/*/sessions/sessions.json'):
    data = json.load(open(path))
    changed = False
    for k, v in data.items():
        if 'cron' in k and 'openrouter' in v.get('authProfileOverride',''):
            for field in ['model','modelProvider','authProfileOverride','authProfileOverrideSource','authProfileOverrideCompactionCount']:
                v.pop(field, None)
            changed = True
            print(f'Fixed: {k}')
    if changed:
        json.dump(data, open(path,'w'), ensure_ascii=False)
" && openclaw gateway restart

Problem 9 — Gateway 无反应 / device signature invalid

症状openclaw statusRPC probe: failed,错误为 gateway closed (1008): device signature invalid。飞书 bot 不回复,gateway 看起来在跑但 CLI 连不上。

根因:升级 openclaw 版本后,旧版 LaunchAgent(com.clawdbot.gateway,加载 openclaw-cn)没有被清理,与新版 ai.openclaw.gateway 同时注册开机启动。旧进程先抢占 18789 端口,新版 CLI 因 device signature 格式不兼容被拒绝。

诊断

launchctl list | grep -i claw
# 如果同时出现 com.clawdbot.gateway 和 ai.openclaw.gateway,就是这个问题

openclaw gateway status 2>&1 | grep -E "RPC|device|pid"

修复

# 1. 备份并禁用旧版 LaunchAgent
cp ~/Library/LaunchAgents/com.clawdbot.gateway.plist \
   ~/Library/LaunchAgents/com.clawdbot.gateway.plist.bak
launchctl bootout gui/$UID/com.clawdbot.gateway
mv ~/Library/LaunchAgents/com.clawdbot.gateway.plist \
   ~/Library/LaunchAgents/com.clawdbot.gateway.plist.disabled

# 2. 重启新版 gateway
openclaw gateway restart

# 验证
openclaw gateway status 2>&1 | grep "RPC probe"
# 期望输出:RPC probe: ok

说明.plist.disabled 文件 launchd 开机不会加载(只识别 .plist 后缀),相当于禁用但保留备份。


Problem 10 — 非 Owner 用户被拦截(OAuth 授权 / 工具调用)

症状:非应用 Owner 的飞书用户发消息后,授权入口或工具调用被拒绝,日志中出现 OwnerAccessDeniedErrorPermission denied: Only the app owner is authorized

根因assertOwnerAccessStrict 默认 ownerOnly=true,所有非 Owner 用户全部拒绝。这是 openclaw-lark 上游的已知问题(issues #5、#12)。

修复方案 A — 配置关闭(推荐):在 openclaw.json 的飞书 channel 里加 uat.ownerOnly: false

# 用 python3 安全写入,避免手编 JSON 出错
python3 - <<'EOF'
import json

path = '/Users/tianyiliang/.openclaw/openclaw.json'  # 按实际路径调整
cfg = json.load(open(path))
ch = cfg.setdefault('channels', {}).setdefault('feishu', {})
uat = ch.setdefault('uat', {})
uat['enabled'] = True
uat['ownerOnly'] = False
json.dump(cfg, open(path, 'w'), indent=2, ensure_ascii=False)
print('Done. Run: openclaw gateway restart')
EOF

修复方案 B — 升级插件:如果你使用 workspace 源码版插件(openclaw-lark),该 patch 已包含在 PR #11 中:

  • src/core/config-schema.tsUATConfigSchemaownerOnly?: boolean
  • src/core/owner-policy.tsassertOwnerAccessStrict 里检查 ownerOnly flag

验证:重启 gateway 后,非 Owner 用户发消息,日志中不再出现 OwnerAccessDeniedError


Contributing

Found a new OpenClaw failure mode? Open a PR with:

  1. The symptom (exact error message or behavior)
  2. Root cause
  3. Diagnostic command
  4. Fix

Keep entries short and command-first. The doctor should be fast to consult.

相关技能