Claw Doctor — OpenClaw 자가 수리 스킬
이 스킬은 일반적인 OpenClaw/NanoClaw 문제를 진단하고 수정합니다. 문제가 발생하면 포기하기 전에 아래 체크리스트를 확인하세요.
활성화 시점
다음 중 하나라도 사용자가 보고하면 이 스킬을 활성화하세요:
- "스킬을 찾을 수 없습니다" / 스킬이 실행되지 않음
- 스킬 스크립트 실행 시 "해당 파일 또는 디렉터리가 없습니다"
- 스킬에서 API 키 오류 발생
- 스킬이 출력을 생성하지 않거나 잘못된 출력을 생성함
- "SKILL.md가 유효하지 않습니다" / YAML 파싱 오류
- 스킬이 전역적으로는 작동하지만 작업 공간에서는 작동하지 않음 (또는 그 반대)
- 업데이트 후 스킬이 작동하지 않음
스킬 로드 순서 및 경로
OpenClaw는 두 위치에서 스킬을 로드합니다. 작업 공간 스킬이 우선 순위를 가집니다.
우선 순위 1 (높음): <작업공간>/skills/<스킬-이름>/SKILL.md
우선 순위 2 (낮음): ~/.openclaw/skills/<스킬-이름>/SKILL.md
진단: 설치된 모든 스킬 나열
# 전역 설치 항목 확인
ls ~/.openclaw/skills/ 2>/dev/null || echo "전역 스킬 디렉터리가 없습니다"
# 현재 작업 공간의 설치 항목 확인
ls ./skills/ 2>/dev/null || echo "작업 공간 스킬 디렉터리가 없습니다"
두 곳에 모두 스킬이 나타나면 작업 공간 버전이 우선이므로 버전 불일치를 확인하세요.
문제 1 — 스킬이 실행되지 않음
증상: 사용자가 스킬을 호출했지만 Claude가 무시하거나 절차를 따르지 않음.
진단 체크리스트:
-
SKILL.md가 실제로 존재하고 읽을 수 있는가?cat ./skills/<스킬-이름>/SKILL.md | head -20 -
프론트매터 YAML이 올바르게 파싱되는가?
python3 -c " import re, sys txt = open('skills/<스킬-이름>/SKILL.md').read() fm = re.search(r'^---\n(.*?)\n---', txt, re.DOTALL) print('프론트매터 발견:', bool(fm)) if fm: import yaml; d = yaml.safe_load(fm.group(1)); print('키:', list(d.keys())) " -
SKILL.md의
keywords가 사용자가 말한 내용과 일치하는가?- 일치하지 않으면 더 많은 키워드 변형(동의어, 약어)을 추가하세요.
-
description이 모델이 스킬을 식별하기에 충분히 명확한가?- 짧고 구체적인 설명이 모호한 설명보다 효과적입니다.
수정: 프론트매터가 유효한 YAML인지 확인하세요(탭 없음, 적절한 인용, 올바른 들여쓰기).
문제 2 — 스크립트를 찾을 수 없음 (경로 해석)
증상: bash: scripts/run: 해당 파일 또는 디렉터리가 없습니다
가장 흔한 스킬 버그입니다. SKILL.md에서 scripts/foo로 참조된 스크립트는 현재 작업 디렉터리가 아닌 OpenClaw 플러그인 캐시 내 스킬의 설치 디렉터리에 상대적입니다.
표준 수정 — 사용하기 전에 스크립트 경로를 동적으로 확인:
# "my-skill"이라는 스킬과 "run"이라는 스크립트의 경우
MY_SCRIPT=$(find ~/.openclaw -name "run" -path "*/my-skill/*/scripts/*" -type f 2>/dev/null | head -1)
# 대체: 작업 공간 스킬 확인
[ -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 "오류: 스크립트를 찾을 수 없습니다. 스킬이 설치되었는지 확인하세요."
exit 1
fi
$MY_SCRIPT <인수>
또한 확인: 스크립트가 실행 가능한가?
chmod +x ~/.openclaw/skills/my-skill/scripts/*
chmod +x ./skills/my-skill/scripts/*
문제 3 — API 키가 설정되지 않음
증상: 스킬이 {"success": false, "setup_required": true} 또는 401/403 오류를 반환합니다.
표준 API 키 설정 흐름:
- 스킬의 SKILL.md에 키가 저장된 위치가 문서화되어 있어야 합니다(보통
~/.openclaw/secrets/<스킬-이름>.key또는 환경 변수). - 키 파일이 존재하는지 확인:
ls ~/.openclaw/secrets/ 2>/dev/null || echo "시크릿 디렉터리가 없습니다" - 스킬의 설정 명령어(보통
scripts/run setup <api-key>)를 실행합니다. - 키가 저장되었는지 확인:
cat ~/.openclaw/secrets/<스킬-이름>.key 2>/dev/null | head -c 20
설정 명령어가 없는 경우, 사용자에게 환경 변수를 직접 설정하도록 요청:
export SKILL_API_KEY="사용자의-키-입력"
# 지속성을 위해 ~/.zshrc 또는 ~/.bashrc에 추가
문제 4 — 종속성 누락 (Node.js / Python / 도구)
증상: node: 명령을 찾을 수 없습니다, python3: 해당 파일 또는 디렉터리가 없습니다, jq: 명령을 찾을 수 없습니다
빠른 종속성 확인:
echo "=== 핵심 종속성 ===" && \
node --version 2>/dev/null || echo "누락: node" && \
python3 --version 2>/dev/null || echo "누락: python3" && \
jq --version 2>/dev/null || echo "누락: jq" && \
curl --version 2>/dev/null | head -1 || echo "누락: curl"
플랫폼별 수정:
| 도구 | 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 |
Python 스킬 종속성의 경우:
pip3 install -r skills/<스킬-이름>/requirements.txt 2>/dev/null \
|| echo "requirements.txt를 찾을 수 없습니다"
Node 스킬 종속성의 경우:
cd skills/<스킬-이름> && npm install 2>/dev/null \
|| echo "package.json을 찾을 수 없습니다"
문제 5 — YAML 프론트매터 오류
증상: 스킬이 로드되지만 메타데이터가 잘못되었거나 키워드가 인덱싱되지 않음.
유효한 프론트매터 템플릿:
---
name: my-skill-name # 소문자, 하이픈만 사용
description: 이 스킬이 수행하는 작업을 설명하는 한 문장.
keywords:
- keyword-one
- keyword-two
license: MIT
---
일반적인 실수:
| 실수 | 수정 |
|---|---|
| 들여쓰기에 공백 대신 탭 사용 | 2칸 공백 들여쓰기로 교체 |
설명에 인용되지 않은 : | 값을 따옴표로 감싸기 |
name 필드 누락 | 필수 항목이므로 추가 |
keywords를 인라인 목록 [a, b]로 사용 | 블록 목록 - a\n- b 사용 |
검증:
python3 -c "
import yaml, sys
txt = open('skills/<스킬-이름>/SKILL.md').read().split('---')[1]
try:
d = yaml.safe_load(txt)
print('OK:', d)
except yaml.YAMLError as e:
print('YAML 오류:', e)
sys.exit(1)
"
문제 6 — 이전에 작동하던 스킬이 업데이트 후 중단됨
증상: OpenClaw가 업데이트되었고 스킬이 작동을 멈춤.
체크리스트:
-
OpenClaw 플러그인 캐시가 지워졌는지 확인:
ls ~/.openclaw/plugins/cache/ 2>/dev/null | head -10 -
소스에서 스킬 재설치:
# 복제된 스킬 저장소에서 cp -r /path/to/skills-repo/skills/<스킬-이름> ~/.openclaw/skills/ -
OpenClaw 스킬 API의 변경 사항 확인 — OpenClaw 변경 로그에서
SKILL.md형식 업데이트를 확인하세요. -
스크립트를 직접 테스트(OpenClaw 우회):
bash skills/<스킬-이름>/scripts/<주-스크립트> --help
전체 상태 점검
OpenClaw 환경의 전체 스냅샷을 보려면 다음을 실행하세요:
echo "=== OpenClaw 상태 점검 ===" && \
echo "--- 전역 스킬 ---" && ls ~/.openclaw/skills/ 2>/dev/null || echo "(없음)" && \
echo "--- 작업 공간 스킬 ---" && ls ./skills/ 2>/dev/null || echo "(없음)" && \
echo "--- 시크릿 ---" && ls ~/.openclaw/secrets/ 2>/dev/null || echo "(없음)" && \
echo "--- 플러그인 캐시 ---" && ls ~/.openclaw/plugins/cache/ 2>/dev/null | head -5 || echo "(비어 있음)" && \
echo "--- 종속성 ---" && \
node --version 2>/dev/null && \
python3 --version 2>/dev/null && \
jq --version 2>/dev/null && \
echo "=== 완료 ==="
Claude Code 사용자용
이 스킬은 Claude Code 사용자가 직접 호출할 수 있는 스킬로도 작동합니다. 다음을 ~/.claude/CLAUDE.md의 ## 사용자 호출 가능 스킬 아래에 추가하세요:
### claw-doctor
OpenClaw / NanoClaw 문제 진단 및 수정.
**트리거**: 사용자가 스킬 로딩 안 됨, 스크립트 찾을 수 없음, API 키 오류, SKILL.md 손상, OpenClaw 작동 안 함을 언급할 때
**절차**: claw-doctor SKILL.md 체크리스트를 따르세요:
1. 증상 카테고리 식별 (트리거 / 스크립트 경로 / API 키 / 종속성 / YAML / 업데이트 후)
2. 관련 진단 명령어 실행
3. 수정 적용 및 전체 상태 점검으로 확인
문제 7 — Flobase 봇이 잘못된 모델을 사용함
증상: Flobase 응답 모델이 openclaw.json 설정과 일치하지 않거나 /new 후에도 이전 모델이 유지됨.
근본 원인 1 — 세션의 model override가 에이전트 설정을 덮어씀
세션 파일은 마지막으로 수동 전환한 모델을 영구 저장하며, 재시작 후에도 지워지지 않습니다.
# 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
"
수정: 해당 세션에서 model/modelProvider 필드를 삭제하거나 세션 항목 자체를 삭제한 후 게이트웨이 재시작:
openclaw gateway restart
근본 원인 2 — main 에이전트가 agents.list에 없어 바인딩이 무시됨
bindings에 "agentId": "main"이 있어도 작동하지 않습니다. main은 내장 에이전트이므로 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('main을 agents.list에 추가함')
"
근본 원인 3 — Model ID가 로컬 프록시와 일치하지 않아 fallback 발생
openclaw.json에 설정된 model ID가 localhost 프록시에 존재하지 않아 자동으로 다음 모델로 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와 완전히 일치하는지 비교하세요.
문제 8 — Cron 작업이 OpenRouter로 라우팅됨
증상: openclaw status에서 cron 세션이 model=openrouter/auto로 표시되며, 클라우드로 전송되면 안 됩니다.
근본 원인: 세션에 authProfileOverride: openrouter:*가 영구 저장됨(이전 인증 자동 전환의 잔재).
진단:
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 세션에서 openrouter override를 제거:
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'수정됨: {k}')
if changed:
json.dump(data, open(path,'w'), ensure_ascii=False)
" && openclaw gateway restart
문제 9 — 게이트웨이 응답 없음 / device signature invalid
증상: openclaw status에 RPC probe: failed가 표시되고 오류는 gateway closed (1008): device signature invalid입니다. Flobase 봇이 응답하지 않고 게이트웨이는 실행 중인 것처럼 보이지만 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. 새 게이트웨이 재시작
openclaw gateway restart
# 확인
openclaw gateway status 2>&1 | grep "RPC probe"
# 예상 출력: RPC probe: ok
설명: .plist.disabled 파일은 launchd가 시작 시 로드하지 않습니다(.plist 접미사만 인식). 비활성화되었지만 백업은 유지됩니다.
문제 10 — 소유자가 아닌 사용자 차단됨 (OAuth 권한 부여 / 도구 호출)
증상: 앱 소유자가 아닌 Flobase 사용자가 메시지를 보내면 권한 부여 진입점이나 도구 호출이 거부되고 로그에 OwnerAccessDeniedError 또는 Permission denied: Only the app owner is authorized가 표시됩니다.
근본 원인: assertOwnerAccessStrict는 기본적으로 ownerOnly=true이며, 소유자가 아닌 모든 사용자를 거부합니다. 이는 openclaw-lark 상위 프로젝트의 알려진 문제입니다(이슈 #5, #12).
수정 방법 A — 설정에서 비활성화(권장): openclaw.json의 Flobase 채널에 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('완료. 실행: openclaw gateway restart')
EOF
수정 방법 B — 플러그인 업그레이드: 작업 공간 소스 코드 버전 플러그인(openclaw-lark)을 사용하는 경우, 이 패치는 PR #11에 포함되어 있습니다:
src/core/config-schema.ts:UATConfigSchema에ownerOnly?: boolean추가src/core/owner-policy.ts:assertOwnerAccessStrict에서ownerOnly플래그 확인
확인: 게이트웨이 재시작 후 소유자가 아닌 사용자가 메시지를 보내면 로그에 OwnerAccessDeniedError가 더 이상 나타나지 않습니다.
기여하기
새로운 OpenClaw 오류 모드를 발견하셨나요? 다음을 포함한 PR을 열어주세요:
- 증상 (정확한 오류 메시지 또는 동작)
- 근본 원인
- 진단 명령어
- 수정 방법
항목은 짧게 유지하고 명령어를 먼저 배치하세요. 의사는 빠르게 참고할 수 있어야 합니다.