플러그인 (확장)
빠른 시작 (플러그인이 처음이신가요?)
플러그인은 OpenClaw에 추가 기능(명령, 도구, 게이트웨이 RPC)을 확장하는 작은 코드 모듈입니다.
대부분의 경우 핵심 OpenClaw에 아직 내장되지 않은 기능을 원하거나 선택적 기능을 메인 설치에서 분리하고 싶을 때 플러그인을 사용합니다.
빠른 경로:
- 이미 로드된 항목 확인:
openclaw plugins list
- 공식 플러그인 설치 (예: Voice Call):
openclaw plugins install @openclaw/voice-call
npm 사양은 레지스트리 전용입니다(패키지 이름 + 선택적 정확한 버전 또는 dist-tag). Git/URL/파일 사양과 semver 범위는 거부됩니다.
베어 사양과 @latest는 안정 트랙을 유지합니다. npm이 이 중 하나를 프리릴리스로 해석하면,
OpenClaw는 중단하고 @beta/@rc 같은 프리릴리스 태그나 정확한 프리릴리스 버전으로
명시적으로 옵트인하도록 요청합니다.
- 게이트웨이를 재시작하고,
plugins.entries.<id>.config에서 설정합니다.
구체적인 플러그인 예시는 Voice Call을 참고하세요. 서드파티 목록은 커뮤니티 플러그인을 참고하세요.
아키텍처
OpenClaw의 플러그인 시스템은 네 개의 레이어로 구성됩니다:
- 매니페스트 + 탐색
OpenClaw는 설정된 경로, 워크스페이스 루트, 전역 확장 루트, 번들 확장에서
후보 플러그인을 찾습니다. 탐색 시 먼저
openclaw.plugin.json과 패키지 메타데이터를 읽습니다. - 활성화 + 검증 코어가 탐색된 플러그인의 활성화, 비활성화, 차단 또는 메모리 같은 배타적 슬롯 선택 여부를 결정합니다.
- 런타임 로딩 활성화된 플러그인은 jiti를 통해 인프로세스로 로드되고 중앙 레지스트리에 기능을 등록합니다.
- 표면 소비 OpenClaw의 나머지 부분이 레지스트리를 읽어 도구, 채널, 프로바이더 설정, 훅, HTTP 라우트, CLI 명령, 서비스를 노출합니다.
중요한 설계 경계:
- 탐색 + 설정 검증은 플러그인 코드를 실행하지 않고 매니페스트/스키마 메타데이터에서 작동해야 합니다
- 런타임 동작은 플러그인 모듈의
register(api)경로에서 옵니다
이 분리 덕분에 OpenClaw는 전체 런타임이 활성화되기 전에 설정을 검증하고, 누락/비활성 플러그인을 설명하고, UI/스키마 힌트를 구성할 수 있습니다.
실행 모델
플러그인은 게이트웨이와 인프로세스로 실행됩니다. 샌드박스되지 않습니다. 로드된 플러그인은 코어 코드와 동일한 프로세스 수준 신뢰 경계를 가집니다.
의미:
- 플러그인은 도구, 네트워크 핸들러, 훅, 서비스를 등록할 수 있습니다
- 플러그인 버그는 게이트웨이를 충돌시키거나 불안정하게 만들 수 있습니다
- 악의적인 플러그인은 OpenClaw 프로세스 내에서의 임의 코드 실행과 동등합니다
비번들 플러그인에는 허용 목록과 명시적 설치/로드 경로를 사용하세요. 워크스페이스 플러그인은 개발 시 코드로 취급하고 프로덕션 기본값으로 사용하지 마세요.
중요 신뢰 참고:
plugins.allow는 소스 출처가 아닌 플러그인 ID를 신뢰합니다.- 번들 플러그인과 동일한 ID를 가진 워크스페이스 플러그인은 해당 워크스페이스 플러그인이 활성화/허용 목록에 있을 때 의도적으로 번들 복사본을 섀도잉합니다.
- 이는 로컬 개발, 패치 테스트, 핫픽스에 정상적이고 유용합니다.
사용 가능한 플러그인 (공식)
- Microsoft Teams는 2026.1.15부터 플러그인 전용입니다. Teams를 사용하면
@openclaw/msteams를 설치하세요. - Memory (Core) — 번들 메모리 검색 플러그인 (기본적으로
plugins.slots.memory를 통해 활성화) - Memory (LanceDB) — 번들 장기 메모리 플러그인 (자동 회수/캡처;
plugins.slots.memory = "memory-lancedb"설정) - Voice Call —
@openclaw/voice-call - Zalo Personal —
@openclaw/zalouser - Matrix —
@openclaw/matrix - Nostr —
@openclaw/nostr - Zalo —
@openclaw/zalo - Microsoft Teams —
@openclaw/msteams - Google Antigravity OAuth (프로바이더 인증) —
google-antigravity-auth로 번들 (기본 비활성) - Gemini CLI OAuth (프로바이더 인증) —
google-gemini-cli-auth로 번들 (기본 비활성) - Qwen OAuth (프로바이더 인증) —
qwen-portal-auth로 번들 (기본 비활성) - Copilot Proxy (프로바이더 인증) — 로컬 VS Code Copilot Proxy 브릿지; 내장
github-copilot디바이스 로그인과 별개 (번들, 기본 비활성)
OpenClaw 플러그인은 jiti를 통해 런타임에 로드되는 TypeScript 모듈입니다. 설정 검증은 플러그인 코드를 실행하지 않습니다. 대신 플러그인 매니페스트와 JSON Schema를 사용합니다. 플러그인 매니페스트를 참고하세요.
플러그인이 등록할 수 있는 것:
- 게이트웨이 RPC 메서드
- 게이트웨이 HTTP 라우트
- 에이전트 도구
- CLI 명령
- 백그라운드 서비스
- 컨텍스트 엔진
- 선택적 설정 검증
- 스킬 (플러그인 매니페스트에
skills디렉터리를 나열) - 자동 응답 명령 (AI 에이전트를 호출하지 않고 실행)
플러그인은 게이트웨이와 인프로세스로 실행되므로 신뢰할 수 있는 코드로 취급하세요. 도구 작성 가이드: 플러그인 에이전트 도구.
로드 파이프라인
시작 시 OpenClaw는 대략 다음을 수행합니다:
- 후보 플러그인 루트 탐색
openclaw.plugin.json및 패키지 메타데이터 읽기- 안전하지 않은 후보 거부
- 플러그인 설정 정규화 (
plugins.enabled,allow,deny,entries,slots,load.paths) - 각 후보의 활성화 결정
- jiti를 통해 활성화된 모듈 로드
register(api)호출 및 등록을 플러그인 레지스트리에 수집- 명령/런타임 표면에 레지스트리 노출
안전 게이트는 런타임 실행 이전에 발생합니다. 항목이 플러그인 루트를 벗어나거나, 경로가 월드 쓰기 가능하거나, 비번들 플러그인의 경로 소유권이 의심스러우면 후보가 차단됩니다.
매니페스트 우선 동작
매니페스트는 제어 플레인의 진실의 원천입니다. OpenClaw는 이를 사용하여:
- 플러그인을 식별
- 선언된 채널/스킬/설정 스키마를 탐색
plugins.entries.<id>.config검증- Control UI 레이블/플레이스홀더 보강
- 설치/카탈로그 메타데이터 표시
런타임 모듈은 데이터 플레인 부분입니다. 훅, 도구, 명령, 프로바이더 흐름 같은 실제 동작을 등록합니다.
로더가 캐시하는 것
OpenClaw는 다음에 대한 짧은 인프로세스 캐시를 유지합니다:
- 탐색 결과
- 매니페스트 레지스트리 데이터
- 로드된 플러그인 레지스트리
이 캐시는 폭발적인 시작과 반복 명령 오버헤드를 줄입니다. 단기 성능 캐시로 생각하세요, 영속성이 아닙니다.
런타임 헬퍼
플러그인은 api.runtime을 통해 선택된 코어 헬퍼에 접근할 수 있습니다. 전화 TTS의 경우:
const result = await api.runtime.tts.textToSpeechTelephony({
text: "Hello from OpenClaw",
cfg: api.config,
});
참고:
- 코어
messages.tts설정(OpenAI 또는 ElevenLabs)을 사용합니다. - PCM 오디오 버퍼 + 샘플 레이트를 반환합니다. 플러그인은 프로바이더용으로 리샘플링/인코딩해야 합니다.
- Edge TTS는 전화에 지원되지 않습니다.
STT/전사의 경우, 플러그인은 다음을 호출할 수 있습니다:
const { text } = await api.runtime.stt.transcribeAudioFile({
filePath: "/tmp/inbound-audio.ogg",
cfg: api.config,
// MIME을 안정적으로 추론할 수 없을 때 선택 사항:
mime: "audio/ogg",
});
참고:
- 코어 미디어 이해 오디오 설정(
tools.media.audio)과 프로바이더 폴백 순서를 사용합니다. - 전사 출력이 생성되지 않으면(예: 건너뛴/지원되지 않는 입력)
{ text: undefined }를 반환합니다.
게이트웨이 HTTP 라우트
플러그인은 api.registerHttpRoute(...)로 HTTP 엔드포인트를 노출할 수 있습니다.
api.registerHttpRoute({
path: "/acme/webhook",
auth: "plugin",
match: "exact",
handler: async (_req, res) => {
res.statusCode = 200;
res.end("ok");
return true;
},
});
라우트 필드:
path: 게이트웨이 HTTP 서버의 라우트 경로.auth: 필수. 일반 게이트웨이 인증에는"gateway", 플러그인 관리 인증/웹훅 검증에는"plugin"사용.match: 선택 사항."exact"(기본값) 또는"prefix".replaceExisting: 선택 사항. 동일 플러그인이 기존 라우트 등록을 교체할 수 있도록 허용.handler: 라우트가 요청을 처리했으면true반환.
참고:
api.registerHttpHandler(...)는 폐기되었습니다.api.registerHttpRoute(...)를 사용하세요.- 플러그인 라우트는 명시적으로
auth를 선언해야 합니다. replaceExisting: true가 아닌 한 정확한path + match충돌은 거부되며, 한 플러그인이 다른 플러그인의 라우트를 교체할 수 없습니다.- 서로 다른
auth수준의 겹치는 라우트는 거부됩니다.exact/prefix폴스루 체인은 동일한 auth 수준에서만 유지하세요.
플러그인 SDK 임포트 경로
플러그인 작성 시 모놀리식 openclaw/plugin-sdk 임포트 대신 SDK 하위 경로를 사용하세요:
openclaw/plugin-sdk/core— 일반 플러그인 API, 프로바이더 인증 타입, 공유 헬퍼.openclaw/plugin-sdk/compat—core보다 넓은 공유 런타임 헬퍼가 필요한 번들/내부 플러그인 코드용.openclaw/plugin-sdk/telegram— Telegram 채널 플러그인용.openclaw/plugin-sdk/discord— Discord 채널 플러그인용.openclaw/plugin-sdk/slack— Slack 채널 플러그인용.openclaw/plugin-sdk/signal— Signal 채널 플러그인용.openclaw/plugin-sdk/imessage— iMessage 채널 플러그인용.openclaw/plugin-sdk/whatsapp— WhatsApp 채널 플러그인용.openclaw/plugin-sdk/line— LINE 채널 플러그인용.openclaw/plugin-sdk/msteams— 번들 Microsoft Teams 플러그인 표면용.- 번들 확장별 하위 경로도 사용 가능합니다:
openclaw/plugin-sdk/acpx,openclaw/plugin-sdk/bluebubbles,openclaw/plugin-sdk/copilot-proxy,openclaw/plugin-sdk/device-pair,openclaw/plugin-sdk/diagnostics-otel,openclaw/plugin-sdk/diffs,openclaw/plugin-sdk/feishu,openclaw/plugin-sdk/google-gemini-cli-auth,openclaw/plugin-sdk/googlechat,openclaw/plugin-sdk/irc,openclaw/plugin-sdk/llm-task,openclaw/plugin-sdk/lobster,openclaw/plugin-sdk/matrix,openclaw/plugin-sdk/mattermost,openclaw/plugin-sdk/memory-core,openclaw/plugin-sdk/memory-lancedb,openclaw/plugin-sdk/minimax-portal-auth,openclaw/plugin-sdk/nextcloud-talk,openclaw/plugin-sdk/nostr,openclaw/plugin-sdk/open-prose,openclaw/plugin-sdk/phone-control,openclaw/plugin-sdk/qwen-portal-auth,openclaw/plugin-sdk/synology-chat,openclaw/plugin-sdk/talk-voice,openclaw/plugin-sdk/test-utils,openclaw/plugin-sdk/thread-ownership,openclaw/plugin-sdk/tlon,openclaw/plugin-sdk/twitch,openclaw/plugin-sdk/voice-call,openclaw/plugin-sdk/zalo,openclaw/plugin-sdk/zalouser.
호환성 참고:
openclaw/plugin-sdk는 기존 외부 플러그인을 위해 계속 지원됩니다.- 새로운 및 마이그레이션된 번들 플러그인은 채널 또는 확장별 하위 경로를 사용해야 합니다.
일반 표면에는
core, 넓은 공유 헬퍼가 필요한 경우에만compat을 사용하세요.
읽기 전용 채널 검사
플러그인이 채널을 등록하는 경우, resolveAccount(...)와 함께
plugin.config.inspectAccount(cfg, accountId) 구현을 선호하세요.
이유:
resolveAccount(...)는 런타임 경로입니다. 인증 정보가 완전히 구체화되었다고 가정할 수 있으며 필수 시크릿이 누락되면 즉시 실패할 수 있습니다.openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolve, 닥터/설정 복구 흐름 같은 읽기 전용 명령 경로는 설정을 설명하기 위해 런타임 인증 정보를 구체화할 필요가 없어야 합니다.
권장 inspectAccount(...) 동작:
- 설명적 계정 상태만 반환합니다.
enabled와configured를 보존합니다.- 관련 시 인증 정보 소스/상태 필드를 포함합니다:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- 읽기 전용 가용성을 보고하기 위해 원시 토큰 값을 반환할 필요가 없습니다.
tokenStatus: "available"(및 일치하는 소스 필드)를 반환하면 상태 스타일 명령에 충분합니다. - 인증 정보가 SecretRef를 통해 설정되었지만 현재 명령 경로에서 사용할 수 없을 때
configured_unavailable을 사용합니다.
이를 통해 읽기 전용 명령이 충돌하거나 계정이 설정되지 않은 것으로 잘못 보고하는 대신 “설정되었지만 이 명령 경로에서 사용 불가”를 보고할 수 있습니다.
성능 참고:
- 플러그인 탐색과 매니페스트 메타데이터는 폭발적인 시작/리로드 작업을 줄이기 위해 짧은 인프로세스 캐시를 사용합니다.
- 이 캐시를 비활성화하려면
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1또는OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1을 설정합니다. - 캐시 창은
OPENCLAW_PLUGIN_DISCOVERY_CACHE_MS와OPENCLAW_PLUGIN_MANIFEST_CACHE_MS로 조정합니다.
탐색 & 우선순위
OpenClaw는 순서대로 스캔합니다:
- 설정 경로
plugins.load.paths(파일 또는 디렉터리)
- 워크스페이스 확장
<workspace>/.openclaw/extensions/*.ts<workspace>/.openclaw/extensions/*/index.ts
- 전역 확장
~/.openclaw/extensions/*.ts~/.openclaw/extensions/*/index.ts
- 번들 확장 (OpenClaw와 함께 제공, 대부분 기본 비활성)
<openclaw>/extensions/*
대부분의 번들 플러그인은 plugins.entries.<id>.enabled 또는 openclaw plugins enable <id>로 명시적으로 활성화해야 합니다.
기본 활성 번들 플러그인 예외:
device-pairphone-controltalk-voice- 활성 메모리 슬롯 플러그인 (기본 슬롯:
memory-core)
설치된 플러그인은 기본적으로 활성화되지만, 같은 방법으로 비활성화할 수 있습니다.
워크스페이스 플러그인은 명시적으로 활성화하거나 허용 목록에 추가하지 않는 한 기본적으로 비활성화됩니다. 이는 의도적입니다: 체크아웃된 레포가 조용히 프로덕션 게이트웨이 코드가 되어서는 안 됩니다.
보안 강화 참고:
plugins.allow가 비어 있고 비번들 플러그인이 탐색 가능하면, OpenClaw는 플러그인 ID와 소스가 포함된 시작 경고를 기록합니다.- 후보 경로는 탐색 허용 전 안전 검사를 받습니다. OpenClaw는 다음과 같은 경우 후보를 차단합니다:
- 확장 항목이 심볼릭 링크/경로 순회 이탈을 포함하여 플러그인 루트 외부로 해석되는 경우,
- 플러그인 루트/소스 경로가 월드 쓰기 가능한 경우,
- 비번들 플러그인의 경로 소유권이 의심스러운 경우(POSIX 소유자가 현재 uid도 root도 아닌 경우).
- 설치/로드 경로 출처 없이 로드된 비번들 플러그인은 경고를 발생시키므로 신뢰(
plugins.allow)를 고정하거나 설치 추적(plugins.installs)을 수행할 수 있습니다.
각 플러그인은 루트에 openclaw.plugin.json 파일을 포함해야 합니다. 경로가 파일을 가리키면
플러그인 루트는 파일의 디렉터리이며 매니페스트를 포함해야 합니다.
여러 플러그인이 동일한 ID로 해석되면 위 순서에서 첫 번째 매치가 우선하고 하위 우선순위 복사본은 무시됩니다.
이는 다음을 의미합니다:
- 워크스페이스 플러그인이 동일한 ID를 가진 번들 플러그인을 의도적으로 섀도잉합니다
plugins.allow: ["foo"]는 활성 복사본이 번들 확장 루트 대신 워크스페이스에서 온 경우에도 활성foo플러그인을 ID로 인가합니다- 더 엄격한 출처 제어가 필요하면, 명시적 설치/로드 경로를 사용하고 활성화 전 해석된 플러그인 소스를 검사하세요
활성화 규칙
활성화는 탐색 후 결정됩니다:
plugins.enabled: false는 모든 플러그인을 비활성화plugins.deny는 항상 우선plugins.entries.<id>.enabled: false는 해당 플러그인 비활성화- 워크스페이스 출처 플러그인은 기본 비활성
plugins.allow가 비어 있지 않으면 허용 목록이 활성 세트를 제한- 허용 목록은 소스 기반이 아닌 ID 기반
- 번들 플러그인은 다음이 아닌 한 기본 비활성:
- 번들 ID가 내장 기본 활성 세트에 있거나
- 명시적으로 활성화하거나
- 채널 설정이 암시적으로 번들 채널 플러그인을 활성화
- 배타적 슬롯이 해당 슬롯의 선택된 플러그인을 강제 활성화할 수 있음
현재 코어에서 번들 기본 활성 ID에는 ollama, sglang, vllm 같은 로컬/프로바이더 헬퍼와
device-pair, phone-control, talk-voice가 포함됩니다.
패키지 팩
플러그인 디렉터리에 openclaw.extensions가 있는 package.json을 포함할 수 있습니다:
{
"name": "my-pack",
"openclaw": {
"extensions": ["./src/safety.ts", "./src/tools.ts"]
}
}
각 항목이 플러그인이 됩니다. 팩이 여러 확장을 나열하면 플러그인 ID는 name/<fileBase>가 됩니다.
플러그인이 npm 의존성을 임포트하면 해당 디렉터리에서 설치하여 node_modules를 사용할 수 있도록 하세요(npm install / pnpm install).
보안 가드레일: 모든 openclaw.extensions 항목은 심볼릭 링크 해석 후 플러그인 디렉터리 내에 있어야 합니다. 패키지 디렉터리를 벗어나는 항목은 거부됩니다.
보안 참고: openclaw plugins install은 npm install --ignore-scripts(라이프사이클 스크립트 없음)로 플러그인 의존성을 설치합니다. 플러그인 의존성 트리를 “순수 JS/TS”로 유지하고 postinstall 빌드가 필요한 패키지를 피하세요.
채널 카탈로그 메타데이터
채널 플러그인은 openclaw.channel을 통해 온보딩 메타데이터를, openclaw.install을 통해
설치 힌트를 알릴 수 있습니다. 이를 통해 코어 카탈로그를 데이터 없이 유지합니다.
예시:
{
"name": "@openclaw/nextcloud-talk",
"openclaw": {
"extensions": ["./index.ts"],
"channel": {
"id": "nextcloud-talk",
"label": "Nextcloud Talk",
"selectionLabel": "Nextcloud Talk (self-hosted)",
"docsPath": "/channels/nextcloud-talk",
"docsLabel": "nextcloud-talk",
"blurb": "Self-hosted chat via Nextcloud Talk webhook bots.",
"order": 65,
"aliases": ["nc-talk", "nc"]
},
"install": {
"npmSpec": "@openclaw/nextcloud-talk",
"localPath": "extensions/nextcloud-talk",
"defaultChoice": "npm"
}
}
}
OpenClaw는 외부 채널 카탈로그(예: MPM 레지스트리 내보내기)도 병합할 수 있습니다. 다음 위치에 JSON 파일을 넣으세요:
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
또는 OPENCLAW_PLUGIN_CATALOG_PATHS(또는 OPENCLAW_MPM_CATALOG_PATHS)를 하나 이상의 JSON 파일로 지정합니다(쉼표/세미콜론/PATH 구분). 각 파일은 { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }를 포함해야 합니다.
플러그인 ID
기본 플러그인 ID:
- 패키지 팩:
package.jsonname - 독립 파일: 파일 기본 이름 (
~/.../voice-call.ts→voice-call)
플러그인이 id를 내보내면 OpenClaw가 이를 사용하지만, 설정된 ID와 일치하지 않으면 경고합니다.
레지스트리 모델
로드된 플러그인은 임의의 코어 전역 변수를 직접 변경하지 않습니다. 중앙 플러그인 레지스트리에 등록합니다.
레지스트리가 추적하는 것:
- 플러그인 레코드 (ID, 소스, 출처, 상태, 진단)
- 도구
- 레거시 훅 및 타입 훅
- 채널
- 프로바이더
- 게이트웨이 RPC 핸들러
- HTTP 라우트
- CLI 등록자
- 백그라운드 서비스
- 플러그인 소유 명령
코어 기능은 플러그인 모듈에 직접 통신하는 대신 해당 레지스트리에서 읽습니다. 이를 통해 로딩이 단방향으로 유지됩니다:
- 플러그인 모듈 -> 레지스트리 등록
- 코어 런타임 -> 레지스트리 소비
이 분리는 유지보수에 중요합니다. 대부분의 코어 표면이 “모든 플러그인 모듈을 특수 처리”하는 대신 하나의 통합 지점(“레지스트리 읽기”)만 필요합니다.
설정
{
plugins: {
enabled: true,
allow: ["voice-call"],
deny: ["untrusted-plugin"],
load: { paths: ["~/Projects/oss/voice-call-extension"] },
entries: {
"voice-call": { enabled: true, config: { provider: "twilio" } },
},
},
}
필드:
enabled: 마스터 토글 (기본값: true)allow: 허용 목록 (선택 사항)deny: 차단 목록 (선택 사항; deny가 우선)load.paths: 추가 플러그인 파일/디렉터리slots:memory와contextEngine같은 배타적 슬롯 선택기entries.<id>: 플러그인별 토글 + 설정
설정 변경에는 게이트웨이 재시작이 필요합니다.
검증 규칙 (엄격):
entries,allow,deny,slots의 알 수 없는 플러그인 ID는 오류입니다.- 알 수 없는
channels.<id>키는 플러그인 매니페스트가 해당 채널 ID를 선언하지 않는 한 오류입니다. - 플러그인 설정은
openclaw.plugin.json의configSchema에 내장된 JSON Schema를 사용하여 검증됩니다. - 플러그인이 비활성화되면 설정은 보존되고 경고가 발생합니다.
비활성 vs 누락 vs 유효하지 않음
이 상태는 의도적으로 다릅니다:
- 비활성: 플러그인이 존재하지만 활성화 규칙에 의해 꺼짐
- 누락: 설정이 탐색에서 찾지 못한 플러그인 ID를 참조
- 유효하지 않음: 플러그인이 존재하지만 설정이 선언된 스키마와 일치하지 않음
OpenClaw는 비활성 플러그인의 설정을 보존하여 다시 활성화할 때 파괴적이지 않도록 합니다.
플러그인 슬롯 (배타적 카테고리)
일부 플러그인 카테고리는 배타적입니다(한 번에 하나만 활성). plugins.slots로 해당 슬롯을 소유할 플러그인을 선택합니다:
{
plugins: {
slots: {
memory: "memory-core", // 또는 메모리 플러그인을 비활성화하려면 "none"
contextEngine: "legacy", // 또는 "lossless-claw" 같은 플러그인 ID
},
},
}
지원되는 배타적 슬롯:
memory: 활성 메모리 플러그인 ("none"은 메모리 플러그인 비활성화)contextEngine: 활성 컨텍스트 엔진 플러그인 ("legacy"는 내장 기본값)
여러 플러그인이 kind: "memory" 또는 kind: "context-engine"을 선언하면
선택된 플러그인만 해당 슬롯에 로드됩니다. 나머지는 진단과 함께 비활성화됩니다.
컨텍스트 엔진 플러그인
컨텍스트 엔진 플러그인은 수집, 조립, 압축을 위한 세션 컨텍스트 오케스트레이션을 소유합니다. 플러그인에서 api.registerContextEngine(id, factory)로 등록하고, plugins.slots.contextEngine으로 활성 엔진을 선택합니다.
기본 컨텍스트 파이프라인을 교체하거나 확장해야 할 때 메모리 검색이나 훅을 추가하는 것 이상이 필요한 경우에 사용합니다.
Control UI (스키마 + 레이블)
Control UI는 config.schema(JSON Schema + uiHints)를 사용하여 더 나은 폼을 렌더링합니다.
OpenClaw는 탐색된 플러그인에 기반하여 런타임에 uiHints를 보강합니다:
plugins.entries.<id>/.enabled/.config에 플러그인별 레이블 추가- 선택적 플러그인 제공 설정 필드 힌트를 다음 아래에 병합:
plugins.entries.<id>.config.<field>
플러그인 설정 필드에 좋은 레이블/플레이스홀더를 표시하고(시크릿을 민감으로 표시),
플러그인 매니페스트에서 JSON Schema와 함께 uiHints를 제공하세요.
예시:
{
"id": "my-plugin",
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"apiKey": { "type": "string" },
"region": { "type": "string" }
}
},
"uiHints": {
"apiKey": { "label": "API Key", "sensitive": true },
"region": { "label": "Region", "placeholder": "us-east-1" }
}
}
CLI
openclaw plugins list
openclaw plugins info <id>
openclaw plugins install <path> # 로컬 파일/디렉터리를 ~/.openclaw/extensions/<id>에 복사
openclaw plugins install ./extensions/voice-call # 상대 경로 가능
openclaw plugins install ./plugin.tgz # 로컬 tarball에서 설치
openclaw plugins install ./plugin.zip # 로컬 zip에서 설치
openclaw plugins install -l ./extensions/voice-call # 개발용 링크 (복사 없음)
openclaw plugins install @openclaw/voice-call # npm에서 설치
openclaw plugins install @openclaw/voice-call --pin # 해석된 정확한 name@version 저장
openclaw plugins update <id>
openclaw plugins update --all
openclaw plugins enable <id>
openclaw plugins disable <id>
openclaw plugins doctor
plugins update는 plugins.installs에 추적된 npm 설치에만 작동합니다.
업데이트 간 저장된 무결성 메타데이터가 변경되면 OpenClaw가 경고하고 확인을 요청합니다(프롬프트 우회에 전역 --yes 사용).
플러그인은 자체 최상위 명령도 등록할 수 있습니다(예: openclaw voicecall).
플러그인 API (개요)
플러그인은 다음 중 하나를 내보냅니다:
- 함수:
(api) => { ... } - 객체:
{ id, name, configSchema, register(api) { ... } }
register(api)는 플러그인이 동작을 연결하는 곳입니다. 일반적인 등록:
registerToolregisterHookon(...)— 타입 라이프사이클 훅registerChannelregisterProviderregisterHttpRouteregisterCommandregisterCliregisterContextEngineregisterService
컨텍스트 엔진 플러그인은 런타임 소유 컨텍스트 관리자도 등록할 수 있습니다:
export default function (api) {
api.registerContextEngine("lossless-claw", () => ({
info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
async ingest() {
return { ingested: true };
},
async assemble({ messages }) {
return { messages, estimatedTokens: 0 };
},
async compact() {
return { ok: true, compacted: false };
},
}));
}
설정에서 활성화:
{
plugins: {
slots: {
contextEngine: "lossless-claw",
},
},
}
플러그인 훅
플러그인은 런타임에 훅을 등록할 수 있습니다. 이를 통해 플러그인이 별도의 훅 팩 설치 없이 이벤트 기반 자동화를 번들할 수 있습니다.
예시
export default function register(api) {
api.registerHook(
"command:new",
async () => {
// 훅 로직 여기에.
},
{
name: "my-plugin.command-new",
description: "Runs when /new is invoked",
},
);
}
참고:
api.registerHook(...)를 통해 명시적으로 훅을 등록합니다.- 훅 적격성 규칙이 여전히 적용됩니다(OS/bins/env/config 요구 사항).
- 플러그인 관리 훅은
openclaw hooks list에서plugin:<id>로 표시됩니다. openclaw hooks를 통해 플러그인 관리 훅을 활성화/비활성화할 수 없습니다. 대신 플러그인을 활성화/비활성화하세요.
에이전트 라이프사이클 훅 (api.on)
타입 런타임 라이프사이클 훅의 경우 api.on(...)을 사용합니다:
export default function register(api) {
api.on(
"before_prompt_build",
(event, ctx) => {
return {
prependSystemContext: "Follow company style guide.",
};
},
{ priority: 10 },
);
}
프롬프트 구성을 위한 중요 훅:
before_model_resolve: 세션 로드 전에 실행(messages사용 불가).modelOverride또는providerOverride를 결정적으로 재정의하는 데 사용합니다.before_prompt_build: 세션 로드 후 실행(messages사용 가능). 프롬프트 입력을 형성하는 데 사용합니다.before_agent_start: 레거시 호환 훅. 위의 두 명시적 훅을 선호하세요.
코어 적용 훅 정책:
- 운영자는
plugins.entries.<id>.hooks.allowPromptInjection: false로 플러그인별 프롬프트 변경 훅을 비활성화할 수 있습니다. - 비활성화되면 OpenClaw는
before_prompt_build를 차단하고 레거시before_agent_start에서 반환된 프롬프트 변경 필드를 무시하면서 레거시modelOverride와providerOverride는 보존합니다.
before_prompt_build 결과 필드:
prependContext: 이 실행의 사용자 프롬프트 앞에 텍스트를 추가합니다. 턴별 또는 동적 콘텐츠에 적합합니다.systemPrompt: 전체 시스템 프롬프트 재정의.prependSystemContext: 현재 시스템 프롬프트 앞에 텍스트를 추가합니다.appendSystemContext: 현재 시스템 프롬프트 뒤에 텍스트를 추가합니다.
임베디드 런타임의 프롬프트 구성 순서:
- 사용자 프롬프트에
prependContext적용. - 제공된 경우
systemPrompt재정의 적용. prependSystemContext + 현재 시스템 프롬프트 + appendSystemContext적용.
병합 및 우선순위 참고:
- 훅 핸들러는 우선순위 순(높은 것 먼저)으로 실행됩니다.
- 병합된 컨텍스트 필드의 경우, 값은 실행 순서로 연결됩니다.
before_prompt_build값은 레거시before_agent_start폴백 값보다 먼저 적용됩니다.
마이그레이션 안내:
- 정적 안내를
prependContext에서prependSystemContext(또는appendSystemContext)로 이동하여 프로바이더가 안정적인 시스템 접두사 콘텐츠를 캐시할 수 있도록 합니다. - 사용자 메시지에 연결되어야 하는 턴별 동적 컨텍스트에는
prependContext를 유지합니다.
프로바이더 플러그인 (모델 인증)
플러그인은 모델 프로바이더를 등록하여 사용자가 OpenClaw 내에서 OAuth 또는 API 키 설정을 실행하고, 온보딩/모델 선택기에 프로바이더 설정을 표시하며, 암시적 프로바이더 검색에 기여할 수 있습니다.
프로바이더 플러그인은 모델 프로바이더 설정을 위한 모듈형 확장 이음매입니다. 더 이상 “OAuth 헬퍼”만이 아닙니다.
프로바이더 플러그인 라이프사이클
프로바이더 플러그인은 다섯 가지 고유한 단계에 참여할 수 있습니다:
- 인증
auth[].run(ctx)는 OAuth, API 키 캡처, 디바이스 코드 또는 사용자 정의 설정을 수행하고 인증 프로파일과 선택적 설정 패치를 반환합니다. - 비대화형 설정
auth[].runNonInteractive(ctx)는 프롬프트 없이openclaw onboard --non-interactive를 처리합니다. 내장 단순 API 키 경로를 넘어 사용자 정의 헤드리스 설정이 필요한 프로바이더에 사용합니다. - 마법사 통합
wizard.onboarding은openclaw onboard에 항목을 추가합니다.wizard.modelPicker는 모델 선택기에 설정 항목을 추가합니다. - 암시적 검색
discovery.run(ctx)는 모델 해석/목록 중 자동으로 프로바이더 설정에 기여할 수 있습니다. - 선택 후 후속 작업
onModelSelected(ctx)는 모델이 선택된 후 실행됩니다. 로컬 모델 다운로드 같은 프로바이더별 작업에 사용합니다.
이 단계들은 서로 다른 라이프사이클 요구 사항을 가지므로 권장 분할입니다:
- 인증은 대화형이며 인증 정보/설정을 기록
- 비대화형 설정은 플래그/환경 기반이며 프롬프트 금지
- 마법사 메타데이터는 정적이며 UI 대면
- 검색은 안전하고, 빠르고, 실패 허용적
- 선택 후 훅은 선택된 모델에 연결된 부작용
프로바이더 인증 계약
auth[].run(ctx)는 다음을 반환합니다:
profiles: 기록할 인증 프로파일configPatch: 선택적openclaw.json변경defaultModel: 선택적provider/model참조notes: 선택적 사용자 대면 참고
코어는 그 다음:
- 반환된 인증 프로파일 기록
- 인증 프로파일 설정 연결 적용
- 설정 패치 병합
- 선택적으로 기본 모델 적용
- 적절한 경우 프로바이더의
onModelSelected훅 실행
프로바이더 플러그인이 프로바이더별 설정 로직을 소유하고, 코어가 일반 영속성과 설정 병합 경로를 소유합니다.
프로바이더 비대화형 계약
auth[].runNonInteractive(ctx)는 선택 사항입니다. 내장 일반 API 키 흐름으로 표현할 수 없는 헤드리스 설정이 필요한 프로바이더에 구현합니다.
비대화형 컨텍스트에는 다음이 포함됩니다:
- 현재 및 기본 설정
- 파싱된 온보딩 CLI 옵션
- 런타임 로깅/오류 헬퍼
- 에이전트/워크스페이스 디렉터리
resolveApiKey(...)—--secret-input-mode를 준수하면서 플래그, 환경, 기존 인증 프로파일에서 프로바이더 키를 읽음toApiKeyCredential(...)— 해석된 키를 올바른 평문 vs secret-ref 저장의 인증 프로파일 인증 정보로 변환
다음 프로바이더에 이 표면을 사용합니다:
--custom-base-url+--custom-model-id가 필요한 셀프 호스팅 OpenAI 호환 런타임- 프로바이더별 비대화형 검증 또는 설정 합성
runNonInteractive에서 프롬프트를 표시하지 마세요. 누락된 입력은 실행 가능한 오류로 거부하세요.
프로바이더 마법사 메타데이터
wizard.onboarding은 그룹화된 온보딩에서 프로바이더가 표시되는 방법을 제어합니다:
choiceId: 인증 선택 값choiceLabel: 옵션 레이블choiceHint: 짧은 힌트groupId: 그룹 버킷 IDgroupLabel: 그룹 레이블groupHint: 그룹 힌트methodId: 실행할 인증 메서드
wizard.modelPicker는 모델 선택에서 프로바이더가 “지금 설정” 항목으로 표시되는 방법을 제어합니다:
labelhintmethodId
프로바이더에 여러 인증 메서드가 있으면, 마법사가 하나의 명시적 메서드를 가리키거나 OpenClaw가 메서드별 선택지를 합성할 수 있습니다.
OpenClaw는 플러그인 등록 시 프로바이더 마법사 메타데이터를 검증합니다:
- 중복 또는 빈 인증 메서드 ID는 거부
- 프로바이더에 인증 메서드가 없으면 마법사 메타데이터 무시
- 유효하지 않은
methodId바인딩은 경고로 다운그레이드되고 프로바이더의 나머지 인증 메서드로 폴백
프로바이더 검색 계약
discovery.run(ctx)는 다음 중 하나를 반환합니다:
{ provider }{ providers }null
플러그인이 하나의 프로바이더 ID를 소유하는 일반적인 경우에 { provider }를 사용합니다.
플러그인이 여러 프로바이더 항목을 검색하는 경우 { providers }를 사용합니다.
검색 컨텍스트에는 다음이 포함됩니다:
- 현재 설정
- 에이전트/워크스페이스 디렉터리
- 프로세스 환경
- 프로바이더 API 키 해석 및 검색 안전 API 키 값을 위한 헬퍼
검색은:
- 빠르고
- 최선 노력이며
- 실패 시 안전하게 건너뛰고
- 부작용에 주의해야 합니다
프롬프트나 장시간 설정에 의존해서는 안 됩니다.
검색 순서
프로바이더 검색은 순서가 있는 단계로 실행됩니다:
simpleprofilepairedlate
사용:
simple— 저렴한 환경 전용 검색profile— 인증 프로파일에 의존하는 검색paired— 다른 검색 단계와 조율이 필요한 프로바이더late— 비용이 많이 드는 또는 로컬 네트워크 탐색
대부분의 셀프 호스팅 프로바이더는 late를 사용해야 합니다.
좋은 프로바이더 플러그인 경계
프로바이더 플러그인에 적합한 경우:
- 사용자 정의 설정 흐름이 있는 로컬/셀프 호스팅 프로바이더
- 프로바이더별 OAuth/디바이스 코드 로그인
- 로컬 모델 서버의 암시적 검색
- 모델 풀 같은 선택 후 부작용
덜 적합한 경우:
- 환경 변수, base URL, 하나의 기본 모델만 다른 간단한 API 키 전용 프로바이더
이런 것도 플러그인이 될 수 있지만, 주요 모듈성 이점은 동작이 풍부한 프로바이더를 먼저 추출할 때 옵니다.
api.registerProvider(...)로 프로바이더를 등록합니다. 각 프로바이더는 하나 이상의 인증 메서드(OAuth, API 키, 디바이스 코드 등)를 노출합니다. 이 메서드는 다음을 지원할 수 있습니다:
openclaw models auth login --provider <id> [--method <id>]openclaw onboard- 모델 선택기 “사용자 정의 프로바이더” 설정 항목
- 모델 해석/목록 중 암시적 프로바이더 검색
예시:
api.registerProvider({
id: "acme",
label: "AcmeAI",
auth: [
{
id: "oauth",
label: "OAuth",
kind: "oauth",
run: async (ctx) => {
// OAuth 흐름을 실행하고 인증 프로파일을 반환합니다.
return {
profiles: [
{
profileId: "acme:default",
credential: {
type: "oauth",
provider: "acme",
access: "...",
refresh: "...",
expires: Date.now() + 3600 * 1000,
},
},
],
defaultModel: "acme/opus-1",
};
},
},
],
wizard: {
onboarding: {
choiceId: "acme",
choiceLabel: "AcmeAI",
groupId: "acme",
groupLabel: "AcmeAI",
methodId: "oauth",
},
modelPicker: {
label: "AcmeAI (custom)",
hint: "Connect a self-hosted AcmeAI endpoint",
methodId: "oauth",
},
},
discovery: {
order: "late",
run: async () => ({
provider: {
baseUrl: "https://acme.example/v1",
api: "openai-completions",
apiKey: "${ACME_API_KEY}",
models: [],
},
}),
},
});
참고:
run은prompter,runtime,openUrl,oauth.createVpsAwareHandlers헬퍼가 있는ProviderAuthContext를 받습니다.runNonInteractive는 헤드리스 온보딩을 위한opts,resolveApiKey,toApiKeyCredential헬퍼가 있는ProviderAuthMethodNonInteractiveContext를 받습니다.- 기본 모델이나 프로바이더 설정을 추가해야 하면
configPatch를 반환합니다. --set-default가 에이전트 기본값을 업데이트할 수 있도록defaultModel을 반환합니다.wizard.onboarding은openclaw onboard에 프로바이더 선택지를 추가합니다.wizard.modelPicker는 모델 선택기에 “이 프로바이더 설정” 항목을 추가합니다.discovery.run은 플러그인 자체 프로바이더 ID에 대해{ provider }를, 멀티 프로바이더 검색에 대해{ providers }를 반환합니다.discovery.order는 내장 검색 단계 대비 프로바이더가 실행되는 시점을 제어합니다:simple,profile,paired,late.onModelSelected는 로컬 모델 풀 같은 프로바이더별 후속 작업을 위한 선택 후 훅입니다.
메시징 채널 등록
플러그인은 내장 채널(WhatsApp, Telegram 등)처럼 동작하는 채널 플러그인을 등록할 수 있습니다. 채널 설정은 channels.<id> 아래에 있으며 채널 플러그인 코드에 의해 검증됩니다.
const myChannel = {
id: "acmechat",
meta: {
id: "acmechat",
label: "AcmeChat",
selectionLabel: "AcmeChat (API)",
docsPath: "/channels/acmechat",
blurb: "demo channel plugin.",
aliases: ["acme"],
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) =>
cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? {
accountId,
},
},
outbound: {
deliveryMode: "direct",
sendText: async () => ({ ok: true }),
},
};
export default function (api) {
api.registerChannel({ plugin: myChannel });
}
참고:
- 설정은
channels.<id>아래에 넣으세요(plugins.entries가 아닌). meta.label은 CLI/UI 목록의 레이블에 사용됩니다.meta.aliases는 정규화 및 CLI 입력에 대체 ID를 추가합니다.meta.preferOver는 둘 다 설정된 경우 자동 활성화를 건너뛸 채널 ID를 나열합니다.meta.detailLabel과meta.systemImage로 UI가 더 풍부한 채널 레이블/아이콘을 표시할 수 있습니다.
채널 온보딩 훅
채널 플러그인은 plugin.onboarding에 선택적 온보딩 훅을 정의할 수 있습니다:
configure(ctx)는 기본 설정 흐름입니다.configureInteractive(ctx)는 설정된/미설정된 상태 모두에서 대화형 설정을 완전히 소유할 수 있습니다.configureWhenConfigured(ctx)는 이미 설정된 채널에서만 동작을 재정의할 수 있습니다.
마법사에서의 훅 우선순위:
configureInteractive(있는 경우)configureWhenConfigured(채널 상태가 이미 설정된 경우만)configure로 폴백
컨텍스트 세부 정보:
configureInteractive와configureWhenConfigured는 다음을 받습니다:configured(true또는false)label(프롬프트에 사용되는 사용자 대면 채널 이름)- 공유 config/runtime/prompter/options 필드
"skip"반환은 선택 및 계정 추적을 변경하지 않습니다.{ cfg, accountId? }반환은 설정 업데이트를 적용하고 계정 선택을 기록합니다.
새 메시징 채널 작성 (단계별)
모델 프로바이더가 아닌 새 채팅 표면(“메시징 채널”)을 원할 때 사용합니다.
모델 프로바이더 문서는 /providers/* 아래에 있습니다.
- ID + 설정 형태 선택
- 모든 채널 설정은
channels.<id>아래에 있습니다. - 멀티 계정 설정에는
channels.<id>.accounts.<accountId>를 선호합니다.
- 채널 메타데이터 정의
meta.label,meta.selectionLabel,meta.docsPath,meta.blurb가 CLI/UI 목록을 제어합니다.meta.docsPath는/channels/<id>같은 문서 페이지를 가리켜야 합니다.meta.preferOver는 플러그인이 다른 채널을 대체할 수 있게 합니다(자동 활성화가 이를 선호).meta.detailLabel과meta.systemImage는 UI에서 상세 텍스트/아이콘에 사용됩니다.
- 필수 어댑터 구현
config.listAccountIds+config.resolveAccountcapabilities(채팅 유형, 미디어, 스레드 등)outbound.deliveryMode+outbound.sendText(기본 전송용)
- 필요에 따라 선택적 어댑터 추가
setup(마법사),security(DM 정책),status(상태/진단)gateway(시작/중지/로그인),mentions,threading,streamingactions(메시지 동작),commands(네이티브 명령 동작)
- 플러그인에 채널 등록
api.registerChannel({ plugin })
최소 설정 예시:
{
channels: {
acmechat: {
accounts: {
default: { token: "ACME_TOKEN", enabled: true },
},
},
},
}
최소 채널 플러그인 (아웃바운드 전용):
const plugin = {
id: "acmechat",
meta: {
id: "acmechat",
label: "AcmeChat",
selectionLabel: "AcmeChat (API)",
docsPath: "/channels/acmechat",
blurb: "AcmeChat messaging channel.",
aliases: ["acme"],
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) =>
cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? {
accountId,
},
},
outbound: {
deliveryMode: "direct",
sendText: async ({ text }) => {
// 여기서 `text`를 채널에 전달
return { ok: true };
},
},
};
export default function (api) {
api.registerChannel({ plugin });
}
플러그인을 로드하고(extensions 디렉터리 또는 plugins.load.paths), 게이트웨이를 재시작한 후 설정에서 channels.<id>를 설정합니다.
에이전트 도구
전용 가이드: 플러그인 에이전트 도구.
게이트웨이 RPC 메서드 등록
export default function (api) {
api.registerGatewayMethod("myplugin.status", ({ respond }) => {
respond(true, { ok: true });
});
}
CLI 명령 등록
export default function (api) {
api.registerCli(
({ program }) => {
program.command("mycmd").action(() => {
console.log("Hello");
});
},
{ commands: ["mycmd"] },
);
}
자동 응답 명령 등록
플러그인은 AI 에이전트를 호출하지 않고 실행되는 사용자 정의 슬래시 명령을 등록할 수 있습니다. 토글 명령, 상태 확인, LLM 처리가 필요 없는 빠른 작업에 유용합니다.
export default function (api) {
api.registerCommand({
name: "mystatus",
description: "Show plugin status",
handler: (ctx) => ({
text: `Plugin is running! Channel: ${ctx.channel}`,
}),
});
}
명령 핸들러 컨텍스트:
senderId: 발신자 ID (사용 가능한 경우)channel: 명령이 전송된 채널isAuthorizedSender: 발신자가 인가된 사용자인지 여부args: 명령 뒤에 전달된 인수 (acceptsArgs: true인 경우)commandBody: 전체 명령 텍스트config: 현재 OpenClaw 설정
명령 옵션:
name: 명령 이름 (선행/없이)nativeNames: 슬래시/메뉴 표면용 선택적 네이티브 명령 별칭. 모든 네이티브 프로바이더에default, 프로바이더별 키(discord등) 사용description: 명령 목록에 표시되는 도움말 텍스트acceptsArgs: 명령이 인수를 받는지 여부 (기본값: false). false이고 인수가 제공되면 명령이 매치되지 않고 메시지가 다른 핸들러로 전달됨requireAuth: 인가된 발신자를 요구하는지 여부 (기본값: true)handler:{ text: string }을 반환하는 함수 (비동기 가능)
인가 및 인수 예시:
api.registerCommand({
name: "setmode",
description: "Set plugin mode",
acceptsArgs: true,
requireAuth: true,
handler: async (ctx) => {
const mode = ctx.args?.trim() || "default";
await saveMode(mode);
return { text: `Mode set to: ${mode}` };
},
});
참고:
- 플러그인 명령은 내장 명령과 AI 에이전트 이전에 처리됩니다
- 명령은 전역으로 등록되며 모든 채널에서 작동합니다
- 명령 이름은 대소문자를 구분하지 않습니다 (
/MyStatus는/mystatus와 매치) - 명령 이름은 문자로 시작하고 문자, 숫자, 하이픈, 언더스코어만 포함해야 합니다
- 예약된 명령 이름(
help,status,reset등)은 플러그인으로 재정의할 수 없습니다 - 플러그인 간 중복 명령 등록은 진단 오류와 함께 실패합니다
백그라운드 서비스 등록
export default function (api) {
api.registerService({
id: "my-service",
start: () => api.logger.info("ready"),
stop: () => api.logger.info("bye"),
});
}
명명 규칙
- 게이트웨이 메서드:
pluginId.action(예:voicecall.status) - 도구:
snake_case(예:voice_call) - CLI 명령: kebab 또는 camel, 코어 명령과 충돌하지 않게
스킬
플러그인은 레포에 스킬을 제공할 수 있습니다(skills/<name>/SKILL.md).
plugins.entries.<id>.enabled(또는 다른 설정 게이트)로 활성화하고
워크스페이스/관리 스킬 위치에 있는지 확인하세요.
배포 (npm)
권장 패키징:
- 메인 패키지:
openclaw(이 레포) - 플러그인:
@openclaw/*아래의 별도 npm 패키지 (예:@openclaw/voice-call)
퍼블리싱 계약:
- 플러그인
package.json에 하나 이상의 진입 파일이 있는openclaw.extensions를 포함해야 합니다. - 진입 파일은
.js또는.ts일 수 있습니다(jiti가 런타임에 TS를 로드). openclaw plugins install <npm-spec>은npm pack을 사용하고~/.openclaw/extensions/<id>/에 추출하여 설정에서 활성화합니다.- 설정 키 안정성: 스코프 패키지는
plugins.entries.*에서 스코프 없는 ID로 정규화됩니다.
플러그인 예시: Voice Call
이 레포에 음성 통화 플러그인(Twilio 또는 로그 폴백)이 포함되어 있습니다:
- 소스:
extensions/voice-call - 스킬:
skills/voice-call - CLI:
openclaw voicecall start|status - 도구:
voice_call - RPC:
voicecall.start,voicecall.status - 설정 (twilio):
provider: "twilio"+twilio.accountSid/authToken/from(선택적statusCallbackUrl,twimlUrl) - 설정 (dev):
provider: "log"(네트워크 없음)
설정 및 사용법은 Voice Call과 extensions/voice-call/README.md를 참고하세요.
안전 참고
플러그인은 게이트웨이와 인프로세스로 실행됩니다. 신뢰할 수 있는 코드로 취급하세요:
- 신뢰할 수 있는 플러그인만 설치하세요.
plugins.allow허용 목록을 선호하세요.plugins.allow는 ID 기반이므로 활성화된 워크스페이스 플러그인이 동일한 ID를 가진 번들 플러그인을 의도적으로 섀도잉할 수 있습니다.- 변경 후 게이트웨이를 재시작하세요.
플러그인 테스트
플러그인은 테스트를 포함할 수 있습니다(그리고 포함해야 합니다):
- 레포 내 플러그인은
src/**아래에 Vitest 테스트를 유지할 수 있습니다(예:src/plugins/voice-call.plugin.test.ts). - 별도로 퍼블리싱된 플러그인은 자체 CI(lint/build/test)를 실행하고
openclaw.extensions가 빌드된 엔트리포인트(dist/index.js)를 가리키는지 검증해야 합니다.