O que Claw Doctor — Habilidade de Auto-Reparo do OpenClaw faz?
Esta habilidade diagnostica e corrige problemas comuns do OpenClaw/NanoClaw. Quando algo quebrar, percorra a lista de verificação abaixo antes de desistir.
Quando Ativar
Ative esta habilidade quando o usuário relatar qualquer um dos seguintes:
- "skill not found" / habilidade não dispara
- "No such file or directory" ao executar um script de habilidade
- Erros de chave de API vindos de uma habilidade
- Habilidade não produz saída ou produz saída incorreta
- "SKILL.md is invalid" / erros de parse YAML
- Uma habilidade funciona globalmente, mas não no workspace (ou vice-versa)
- Habilidades funcionavam antes, mas pararam após uma atualização
Ordem de Carregamento e Caminhos
O OpenClaw carrega habilidades de dois locais. Habilidades do workspace têm prioridade.
Priority 1 (high): <workspace>/skills/<skill-name>/SKILL.md
Priority 2 (low): ~/.openclaw/skills/<skill-name>/SKILL.md
Diagnóstico: liste todas as habilidades carregadas
# Mostra o que está instalado globalmente
ls ~/.openclaw/skills/ 2>/dev/null || echo "No global skills dir"
# Mostra o que está instalado no workspace atual
ls ./skills/ 2>/dev/null || echo "No workspace skills dir"
Se uma habilidade aparecer em ambos, a versão do workspace vence — verifique se há incompatibilidades de versão.
Problema 1 — Habilidade Não Dispara
Sintoma: O usuário invoca uma habilidade, mas o Claude a ignora ou não segue o procedimento.
Lista de verificação de diagnóstico:
-
O arquivo
SKILL.mdestá realmente presente e legível?cat ./skills/<skill-name>/SKILL.md | head -20 -
O frontmatter YAML é analisado corretamente?
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())) " -
As
keywordsno SKILL.md correspondem ao que o usuário disse?- Adicione mais variantes de palavras-chave (sinônimos, abreviações) se não estiverem correspondendo.
-
A
descriptioné clara o suficiente para o modelo identificar a habilidade?- Descrições curtas e específicas superam as vagas.
Correção: Garanta que o frontmatter seja YAML válido (sem tabs, aspas adequadas, indentação correta).
Problema 2 — Script Não Encontrado (Resolução de Caminho)
Sintoma: bash: scripts/run: No such file or directory
Este é o bug de habilidade mais comum. Scripts referenciados no SKILL.md como scripts/foo são relativos ao diretório de instalação da habilidade dentro do cache de plugins do OpenClaw, não ao diretório de trabalho atual.
Correção canônica — resolva o caminho do script dinamicamente antes de cada uso:
# Para uma habilidade chamada "my-skill" com um script chamado "run"
MY_SCRIPT=$(find ~/.openclaw -name "run" -path "*/my-skill/*/scripts/*" -type f 2>/dev/null | head -1)
# Fallback: verifique as habilidades do workspace
[ -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>
Verifique também: O script é executável?
chmod +x ~/.openclaw/skills/my-skill/scripts/*
chmod +x ./skills/my-skill/scripts/*
Problema 3 — Chave de API Não Configurada
Sintoma: Habilidade retorna {"success": false, "setup_required": true} ou erros 401/403.
Fluxo padrão de configuração de chave de API:
- O SKILL.md da habilidade deve documentar onde a chave é armazenada (geralmente
~/.openclaw/secrets/<skill-name>.keyou uma variável de ambiente). - Verifique se o arquivo de chave existe:
ls ~/.openclaw/secrets/ 2>/dev/null || echo "No secrets dir" - Execute o comando de configuração da habilidade (geralmente
scripts/run setup <api-key>). - Verifique se a chave foi salva:
cat ~/.openclaw/secrets/<skill-name>.key 2>/dev/null | head -c 20
Se não houver comando de configuração, peça ao usuário para definir a variável de ambiente diretamente:
export SKILL_API_KEY="their-key-here"
# Adicione ao ~/.zshrc ou ~/.bashrc para persistência
Problema 4 — Dependência Ausente (Node.js / Python / ferramenta)
Sintoma: node: command not found, python3: No such file or directory, jq: command not found
Verificação rápida de dependências:
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"
Correção por plataforma:
| Ferramenta | macOS | Ubuntu/Debian |
|---|---|---|
| Node.js | brew install node | apt install nodejs npm |
| Python 3 | brew install python3 | apt install python3 |
| jq | brew install jq | apt install jq |
Para dependências Python da habilidade:
pip3 install -r skills/<skill-name>/requirements.txt 2>/dev/null \
|| echo "No requirements.txt found"
Para dependências Node da habilidade:
cd skills/<skill-name> && npm install 2>/dev/null \
|| echo "No package.json found"
Problema 5 — Erros no Frontmatter YAML
Sintoma: Habilidade carrega, mas os metadados estão errados / palavras-chave não indexadas.
Template de frontmatter válido:
---
name: my-skill-name # minúsculas, apenas hífens
description: Uma frase clara descrevendo o que esta habilidade faz.
keywords:
- keyword-one
- keyword-two
license: MIT
---
Erros comuns:
| Erro | Correção |
|---|---|
| Tabs em vez de espaços | Substitua por indentação de 2 espaços |
: sem aspas na descrição | Coloque o valor entre aspas |
Campo name ausente | Adicione-o — é obrigatório |
keywords como lista inline [a, b] | Use lista de blocos - a\n- b |
Validar:
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)
"
Problema 6 — Habilidade Funcionava Antes, Quebrou Após Atualização
Sintoma: O OpenClaw foi atualizado e uma habilidade parou de funcionar.
Lista de verificação:
-
Verifique se o cache de plugins do OpenClaw foi limpo:
ls ~/.openclaw/plugins/cache/ 2>/dev/null | head -10 -
Reinstale a habilidade a partir da fonte:
# De um repositório de habilidades clonado cp -r /path/to/skills-repo/skills/<skill-name> ~/.openclaw/skills/ -
Verifique se há mudanças disruptivas na API de habilidades do OpenClaw — consulte o changelog do OpenClaw para atualizações do formato
SKILL.md. -
Teste o script diretamente (ignorando o OpenClaw):
bash skills/<skill-name>/scripts/<main-script> --help
Verificação Completa de Saúde
Execute isto para obter um instantâneo completo do ambiente OpenClaw:
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 ==="
Para Usuários do Claude Code
Esta habilidade também funciona como uma habilidade invocável pelo usuário no Claude Code. Adicione o seguinte a ~/.claude/CLAUDE.md sob ## User-Invocable Skills:
### claw-doctor
Diagnostica e corrige problemas do OpenClaw / NanoClaw.
**Trigger**: usuário menciona habilidade não carregando, script não encontrado, erro de chave de API, SKILL.md quebrado, OpenClaw não funcionando
**Procedimento**: Siga a lista de verificação do claw-doctor SKILL.md:
1. Identifique a categoria do sintoma (disparo / caminho do script / chave de API / dependência / YAML / pós-atualização)
2. Execute os comandos de diagnóstico relevantes
3. Aplique a correção e verifique com a Verificação Completa de Saúde
Problema 7 — Bot do Feishu Usando o Modelo Errado
Sintoma: O modelo respondido no Feishu não corresponde ao configurado em openclaw.json, ou após /new ainda é o modelo antigo.
Causa Raiz 1 — O model override na sessão sobrescreve a configuração do agente
O arquivo de sessão persiste a última troca manual de modelo e não é limpo ao reiniciar.
# Descubra qual sessão tem model override
python3 -c "
import json
for agent in ['main', 'sii']:
path = f'/Users/tianyiliang/.openclaw/agents/{agent}/sessions/sessions.json' # ajuste o caminho conforme necessário
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
"
Correção: Remova o campo model/modelProvider da sessão correspondente, ou exclua toda a entrada da sessão e reinicie o gateway:
openclaw gateway restart
Causa Raiz 2 — O agente main não está em agents.list, o binding é ignorado
O bindings tem "agentId": "main" mas não funciona — porque main é um agente interno e não está em agents.list como alvo de roteamento.
Diagnóstico:
openclaw agents list --bindings # veja se main aparece
Correção: Adicione main explicitamente a agents.list:
python3 -c "
import json
import os
path = os.path.expanduser('~/.openclaw/openclaw.json') # ajuste o caminho conforme necessário
cfg = json.load(open(path))
if not any(a['id'] == 'main' for a in cfg.get('agents', {}).get('list', [])):
cfg.setdefault('agents', {}).setdefault('list', []).insert(0, {
'id': 'main',
'name': 'main',
'workspace': cfg.get('agents', {}).get('defaults', {}).get('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')
"
Causa Raiz 3 — O ID do modelo não corresponde ao proxy local, causando fallback
O model ID configurado em openclaw.json não existe no proxy localhost, causando fallback silencioso para o próximo.
# Verifique os modelos realmente disponíveis
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
Compare com o model ID em openclaw.json e garanta correspondência exata.
Problema 8 — Cron Jobs Indo pelo OpenRouter
Sintoma: Em openclaw status, a sessão cron mostra model=openrouter/auto, não deveria ir para a nuvem.
Causa Raiz: A sessão tem authProfileOverride: openrouter:* persistido (resquício de uma troca automática de autenticação).
Diagnóstico:
python3 -c "
import json
import os
for agent in ['main', 'sii']:
path = os.path.expanduser(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
"
Correção: Limpe todos os overrides do OpenRouter nas sessões cron:
python3 -c "
import json, glob
import os
for path in glob.glob(os.path.expanduser('~/.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
Problema 9 — Gateway Sem Resposta / device signature invalid
Sintoma: openclaw status reporta RPC probe: failed, erro gateway closed (1008): device signature invalid. Bot do Feishu não responde, gateway parece estar rodando, mas o CLI não consegue conectar.
Causa Raiz: Após atualizar a versão do OpenClaw, o LaunchAgent antigo (com.clawdbot.gateway, carregando openclaw-cn) não foi removido e registra inicialização junto com o novo ai.openclaw.gateway. O processo antigo ocupa a porta 18789 primeiro, e o novo CLI é rejeitado devido à incompatibilidade no formato do device signature.
Diagnóstico:
launchctl list | grep -i claw
# Se aparecerem tanto com.clawdbot.gateway quanto ai.openclaw.gateway, este é o problema
openclaw gateway status 2>&1 | grep -E "RPC|device|pid"
Correção:
# 1. Faça backup e desabilite o LaunchAgent antigo
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. Reinicie o novo gateway
openclaw gateway restart
# Verifique
openclaw gateway status 2>&1 | grep "RPC probe"
# Saída esperada: RPC probe: ok
Explicação: O arquivo .plist.disabled não é carregado pelo launchd na inicialização (que só reconhece extensão .plist), efetivamente desabilitando-o, mas mantendo um backup.
Problema 10 — Usuário Não Owner Bloqueado (Autorização OAuth / Chamada de Ferramenta)
Sintoma: Usuários do Feishu que não são o Owner do aplicativo enviam mensagens e a entrada de autorização ou chamada de ferramenta é rejeitada, com logs mostrando OwnerAccessDeniedError ou Permission denied: Only the app owner is authorized.
Causa Raiz: assertOwnerAccessStrict tem como padrão ownerOnly=true, rejeitando todos os usuários não Owner. Este é um problema conhecido do openclaw-lark upstream (issues #5, #12).
Solução A — Desligar via Configuração (Recomendado): Adicione uat.ownerOnly: false no canal Feishu em openclaw.json:
# Use python3 para escrita segura, evitando erros de edição manual de JSON
python3 - <<'EOF'
import json
import os
path = os.path.expanduser('~/.openclaw/openclaw.json') # ajuste o caminho conforme necessário
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
Solução B — Atualizar o Plugin: Se você usa a versão plugin do código fonte do workspace (openclaw-lark), este patch já está incluído no PR #11:
src/core/config-schema.ts:UATConfigSchemaadicionaownerOnly?: booleansrc/core/owner-policy.ts:assertOwnerAccessStrictverifica a flagownerOnly
Verificação: Após reiniciar o gateway, usuários não Owner devem conseguir enviar mensagens sem que o log exiba OwnerAccessDeniedError.
Contribuindo
Encontrou um novo modo de falha do OpenClaw? Abra um PR com:
- O sintoma (mensagem de erro exata ou comportamento)
- Causa raiz
- Comando de diagnóstico
- Correção
Mantenha as entradas curtas e priorize comandos. O médico deve ser rápido de consultar.