Plugins (Extensions)

빠른 시작 (plugin이 처음이신가요?)

Plugin은 OpenClaw에 추가 기능(명령어, tool 및 Gateway RPC)을 추가하는 작은 코드 모듈입니다.

대부분의 경우, 아직 핵심 OpenClaw에 포함되지 않은 기능이 필요하거나 선택적 기능을 메인 설치에서 분리하고 싶을 때 plugin을 사용합니다.

빠른 경로:

  1. 이미 로드된 항목 확인:
openclaw plugins list
  1. 공식 plugin 설치 (예시: Voice Call):
openclaw plugins install @openclaw/voice-call
  1. Gateway를 재시작한 다음 plugins.entries.<id>.config에서 설정합니다.

구체적인 plugin 예시는 Voice Call을 참조하세요.

사용 가능한 plugin (공식)

  • Microsoft Teams는 2026.1.15부터 plugin 전용입니다. Teams를 사용하는 경우 @openclaw/msteams를 설치하세요.
  • Memory (Core) — 번들 memory 검색 plugin (기본적으로 plugins.slots.memory를 통해 활성화됨)
  • Memory (LanceDB) — 번들 장기 memory plugin (자동 회상/캡처; 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 (provider auth) — google-antigravity-auth로 번들 제공 (기본적으로 비활성화)
  • Gemini CLI OAuth (provider auth) — google-gemini-cli-auth로 번들 제공 (기본적으로 비활성화)
  • Qwen OAuth (provider auth) — qwen-portal-auth로 번들 제공 (기본적으로 비활성화)
  • Copilot Proxy (provider auth) — 로컬 VS Code Copilot Proxy 브리지; 내장 github-copilot 기기 로그인과는 별개 (번들 제공, 기본적으로 비활성화)

OpenClaw plugin은 jiti를 통해 런타임에 로드되는 TypeScript 모듈입니다. Config 유효성 검사는 plugin 코드를 실행하지 않습니다. 대신 plugin manifest와 JSON Schema를 사용합니다. Plugin manifest를 참조하세요.

Plugin은 다음을 등록할 수 있습니다:

  • Gateway RPC 메서드
  • Gateway HTTP 핸들러
  • Agent tool
  • CLI 명령어
  • 백그라운드 서비스
  • 선택적 config 유효성 검사
  • Skills (plugin manifest에 skills 디렉토리를 나열하여)
  • Auto-reply 명령어 (AI agent를 호출하지 않고 실행)

Plugin은 Gateway와 in-process로 실행되므로, 신뢰할 수 있는 코드로 취급하세요. Tool 작성 가이드: Plugin agent tools.

런타임 헬퍼

Plugin은 api.runtime을 통해 선택된 핵심 헬퍼에 액세스할 수 있습니다. 전화 TTS의 경우:

const result = await api.runtime.tts.textToSpeechTelephony({
  text: "Hello from OpenClaw",
  cfg: api.config,
});

참고:

  • 핵심 messages.tts 설정(OpenAI 또는 ElevenLabs)을 사용합니다.
  • PCM 오디오 버퍼 + 샘플 레이트를 반환합니다. Plugin은 provider를 위해 리샘플링/인코딩해야 합니다.
  • Edge TTS는 전화 통신에 지원되지 않습니다.

검색 및 우선순위

OpenClaw는 다음 순서로 스캔합니다:

  1. Config 경로
  • plugins.load.paths (파일 또는 디렉토리)
  1. Workspace extension
  • <workspace>/.openclaw/extensions/*.ts
  • <workspace>/.openclaw/extensions/*/index.ts
  1. 전역 extension
  • ~/.openclaw/extensions/*.ts
  • ~/.openclaw/extensions/*/index.ts
  1. 번들 extension (OpenClaw와 함께 제공, 기본적으로 비활성화)
  • <openclaw>/extensions/*

번들 plugin은 plugins.entries.<id>.enabled 또는 openclaw plugins enable <id>를 통해 명시적으로 활성화해야 합니다. 설치된 plugin은 기본적으로 활성화되지만, 동일한 방식으로 비활성화할 수 있습니다.

각 plugin은 루트에 openclaw.plugin.json 파일을 포함해야 합니다. 경로가 파일을 가리키는 경우, plugin 루트는 파일의 디렉토리이며 manifest를 포함해야 합니다.

여러 plugin이 동일한 id로 확인되면, 위 순서에서 첫 번째 일치 항목이 우선하며 낮은 우선순위의 복사본은 무시됩니다.

Package packs

Plugin 디렉토리는 openclaw.extensions가 포함된 package.json을 포함할 수 있습니다:

{
  "name": "my-pack",
  "openclaw": {
    "extensions": ["./src/safety.ts", "./src/tools.ts"]
  }
}

각 항목은 plugin이 됩니다. pack이 여러 extension을 나열하는 경우, plugin id는 name/<fileBase>가 됩니다.

Plugin이 npm 의존성을 가져오는 경우, node_modules를 사용할 수 있도록 해당 디렉토리에 설치하세요 (npm install / pnpm install).

Channel 카탈로그 메타데이터

Channel plugin은 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는 외부 channel 카탈로그도 병합할 수 있습니다 (예: 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": {...} } } ] }를 포함해야 합니다.

Plugin ID

기본 plugin id:

  • Package pack: package.jsonname
  • 독립 실행형 파일: 파일 기본 이름 (~/.../voice-call.tsvoice-call)

Plugin이 id를 내보내는 경우, OpenClaw는 이를 사용하지만 설정된 id와 일치하지 않으면 경고합니다.

설정

{
  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: allowlist (선택사항)
  • deny: denylist (선택사항; deny가 우선)
  • load.paths: 추가 plugin 파일/디렉토리
  • entries.<id>: plugin별 토글 + 설정

설정 변경은 gateway 재시작이 필요합니다.

유효성 검사 규칙 (엄격):

  • entries, allow, deny 또는 slots의 알 수 없는 plugin id는 오류입니다.
  • Plugin manifest가 channel id를 선언하지 않는 한, 알 수 없는 channels.<id> 키는 오류입니다.
  • Plugin 설정은 openclaw.plugin.json (configSchema)에 포함된 JSON Schema를 사용하여 유효성이 검사됩니다.
  • Plugin이 비활성화된 경우, 설정이 보존되고 경고가 발생합니다.

Plugin 슬롯 (독점 카테고리)

일부 plugin 카테고리는 독점적입니다 (한 번에 하나만 활성화). plugins.slots를 사용하여 슬롯을 소유하는 plugin을 선택하세요:

{
  plugins: {
    slots: {
      memory: "memory-core" // 또는 "none"으로 memory plugin 비활성화
    }
  }
}

여러 plugin이 kind: "memory"를 선언하는 경우, 선택된 것만 로드됩니다. 다른 것들은 진단과 함께 비활성화됩니다.

Control UI (schema + labels)

Control UI는 config.schema (JSON Schema + uiHints)를 사용하여 더 나은 양식을 렌더링합니다.

OpenClaw는 검색된 plugin을 기반으로 런타임에 uiHints를 보강합니다:

  • plugins.entries.<id> / .enabled / .config에 대한 plugin별 레이블 추가
  • 다음 아래에 plugin에서 제공하는 선택적 config 필드 힌트 병합: plugins.entries.<id>.config.<field>

Plugin config 필드가 좋은 레이블/placeholder를 표시하고 (그리고 비밀을 민감한 것으로 표시) 원하는 경우, plugin manifest의 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 update <id>
openclaw plugins update --all
openclaw plugins enable <id>
openclaw plugins disable <id>
openclaw plugins doctor

plugins updateplugins.installs 아래에 추적된 npm 설치에만 작동합니다.

Plugin은 자체 최상위 명령어도 등록할 수 있습니다 (예: openclaw voicecall).

Plugin API (개요)

Plugin은 다음 중 하나를 내보냅니다:

  • 함수: (api) => { ... }
  • 객체: { id, name, configSchema, register(api) { ... } }

Plugin hooks

Plugin은 hook을 제공하고 런타임에 등록할 수 있습니다. 이를 통해 plugin은 별도의 hook pack 설치 없이 이벤트 기반 자동화를 번들로 제공할 수 있습니다.

예시

import { registerPluginHooksFromDir } from "openclaw/plugin-sdk";

export default function register(api) {
  registerPluginHooksFromDir(api, "./hooks");
}

참고:

  • Hook 디렉토리는 일반 hook 구조 (HOOK.md + handler.ts)를 따릅니다.
  • Hook 적격성 규칙이 여전히 적용됩니다 (OS/bins/env/config 요구사항).
  • Plugin 관리 hook은 plugin:<id>와 함께 openclaw hooks list에 표시됩니다.
  • openclaw hooks를 통해 plugin 관리 hook을 활성화/비활성화할 수 없습니다. 대신 plugin을 활성화/비활성화하세요.

Provider plugin (model auth)

Plugin은 model provider auth 흐름을 등록하여 사용자가 OpenClaw 내부에서 OAuth 또는 API 키 설정을 실행할 수 있습니다 (외부 스크립트 필요 없음).

api.registerProvider(...)를 통해 provider를 등록하세요. 각 provider는 하나 이상의 auth 메서드(OAuth, API 키, 기기 코드 등)를 노출합니다. 이러한 메서드는 다음을 지원합니다:

  • openclaw models auth login --provider <id> [--method <id>]

예시:

api.registerProvider({
  id: "acme",
  label: "AcmeAI",
  auth: [
    {
      id: "oauth",
      label: "OAuth",
      kind: "oauth",
      run: async (ctx) => {
        // OAuth 흐름을 실행하고 auth 프로필을 반환합니다.
        return {
          profiles: [
            {
              profileId: "acme:default",
              credential: {
                type: "oauth",
                provider: "acme",
                access: "...",
                refresh: "...",
                expires: Date.now() + 3600 * 1000,
              },
            },
          ],
          defaultModel: "acme/opus-1",
        };
      },
    },
  ],
});

참고:

  • runprompter, runtime, openUrloauth.createVpsAwareHandlers 헬퍼가 포함된 ProviderAuthContext를 받습니다.
  • 기본 모델 또는 provider 설정을 추가해야 하는 경우 configPatch를 반환하세요.
  • --set-default가 agent 기본값을 업데이트할 수 있도록 defaultModel을 반환하세요.

메시징 channel 등록

Plugin은 내장 channel(WhatsApp, Telegram 등)처럼 작동하는 channel plugin을 등록할 수 있습니다. Channel 설정은 channels.<id> 아래에 있으며 channel plugin 코드에 의해 유효성이 검사됩니다.

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는 둘 다 설정될 때 자동 활성화를 건너뛸 channel id를 나열합니다.
  • meta.detailLabelmeta.systemImage를 통해 UI가 더 풍부한 channel 레이블/아이콘을 표시할 수 있습니다.

새 메시징 channel 작성 (단계별)

새 채팅 표면 ("메시징 channel")이 필요할 때 사용하세요. model provider가 아닙니다. Model provider 문서는 /providers/* 아래에 있습니다.

  1. id + 설정 형태 선택
  • 모든 channel 설정은 channels.<id> 아래에 있습니다.
  • 다중 계정 설정을 위해 channels.<id>.accounts.<accountId>를 선호하세요.
  1. Channel 메타데이터 정의
  • meta.label, meta.selectionLabel, meta.docsPath, meta.blurb는 CLI/UI 목록을 제어합니다.
  • meta.docsPath/channels/<id>와 같은 문서 페이지를 가리켜야 합니다.
  • meta.preferOver를 사용하면 plugin이 다른 channel을 대체할 수 있습니다 (자동 활성화가 선호함).
  • meta.detailLabelmeta.systemImage는 UI에서 상세 텍스트/아이콘에 사용됩니다.
  1. 필수 어댑터 구현
  • config.listAccountIds + config.resolveAccount
  • capabilities (채팅 유형, 미디어, 스레드 등)
  • outbound.deliveryMode + outbound.sendText (기본 전송용)
  1. 필요에 따라 선택적 어댑터 추가
  • setup (마법사), security (DM 정책), status (상태/진단)
  • gateway (시작/중지/로그인), mentions, threading, streaming
  • actions (메시지 동작), commands (네이티브 명령어 동작)
  1. Plugin에 channel 등록
  • api.registerChannel({ plugin })

최소 설정 예시:

{
  channels: {
    acmechat: {
      accounts: {
        default: { token: "ACME_TOKEN", enabled: true }
      }
    }
  }
}

최소 channel plugin (아웃바운드 전용):

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 }) => {
      // 여기서 channel에 `text` 전달
      return { ok: true };
    },
  },
};

export default function (api) {
  api.registerChannel({ plugin });
}

Plugin을 로드하고 (extension 디렉토리 또는 plugins.load.paths), gateway를 재시작한 다음 설정에서 channels.<id>를 설정하세요.

Agent tools

전용 가이드를 참조하세요: Plugin agent tools.

Gateway 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"] });
}

Auto-reply 명령어 등록

Plugin은 AI agent를 호출하지 않고 실행되는 사용자 정의 슬래시 명령어를 등록할 수 있습니다. 이는 토글 명령어, 상태 확인 또는 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: 명령어가 전송된 channel
  • isAuthorizedSender: 발신자가 승인된 사용자인지 여부
  • args: 명령어 뒤에 전달된 인수 (acceptsArgs: true인 경우)
  • commandBody: 전체 명령어 텍스트
  • config: 현재 OpenClaw 설정

명령어 옵션:

  • name: 명령어 이름 (앞에 / 없음)
  • 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}` };
  },
});

참고:

  • Plugin 명령어는 내장 명령어 및 AI agent 이전에 처리됩니다
  • 명령어는 전역적으로 등록되며 모든 channel에서 작동합니다
  • 명령어 이름은 대소문자를 구분하지 않습니다 (/MyStatus/mystatus와 일치)
  • 명령어 이름은 문자로 시작해야 하며 문자, 숫자, 하이픈 및 밑줄만 포함해야 합니다
  • 예약된 명령어 이름 (help, status, reset 등)은 plugin으로 재정의할 수 없습니다
  • Plugin 간 중복 명령어 등록은 진단 오류로 실패합니다

백그라운드 서비스 등록

export default function (api) {
  api.registerService({
    id: "my-service",
    start: () => api.logger.info("ready"),
    stop: () => api.logger.info("bye"),
  });
}

명명 규칙

  • Gateway 메서드: pluginId.action (예: voicecall.status)
  • Tool: snake_case (예: voice_call)
  • CLI 명령어: kebab 또는 camel, 하지만 핵심 명령어와 충돌 방지

Skills

Plugin은 저장소에 skill을 제공할 수 있습니다 (skills/<name>/SKILL.md). plugins.entries.<id>.enabled (또는 기타 config 게이트)로 활성화하고 workspace/managed skills 위치에 있는지 확인하세요.

배포 (npm)

권장 패키징:

  • 메인 패키지: openclaw (이 저장소)
  • Plugin: @openclaw/* 아래의 별도 npm 패키지 (예: @openclaw/voice-call)

게시 계약:

  • Plugin package.json은 하나 이상의 진입 파일과 함께 openclaw.extensions를 포함해야 합니다.
  • 진입 파일은 .js 또는 .ts일 수 있습니다 (jiti는 런타임에 TS를 로드함).
  • openclaw plugins install <npm-spec>npm pack을 사용하여 ~/.openclaw/extensions/<id>/로 추출하고 설정에서 활성화합니다.
  • Config 키 안정성: 범위가 지정된 패키지는 plugins.entries.*에 대해 범위가 지정되지 않은 id로 정규화됩니다.

예시 plugin: Voice Call

이 저장소에는 voice-call plugin이 포함되어 있습니다 (Twilio 또는 로그 폴백):

  • 소스: extensions/voice-call
  • Skill: skills/voice-call
  • CLI: openclaw voicecall start|status
  • Tool: voice_call
  • RPC: voicecall.start, voicecall.status
  • Config (twilio): provider: "twilio" + twilio.accountSid/authToken/from (선택적 statusCallbackUrl, twimlUrl)
  • Config (dev): provider: "log" (네트워크 없음)

설정 및 사용법은 Voice Callextensions/voice-call/README.md를 참조하세요.

보안 참고사항

Plugin은 Gateway와 in-process로 실행됩니다. 신뢰할 수 있는 코드로 취급하세요:

  • 신뢰하는 plugin만 설치하세요.
  • plugins.allow allowlist를 선호하세요.
  • 변경 후 Gateway를 재시작하세요.

Plugin 테스트

Plugin은 테스트를 제공해야 합니다 (그리고 제공할 수 있습니다):

  • In-repo plugin은 src/** 아래에 Vitest 테스트를 유지할 수 있습니다 (예: src/plugins/voice-call.plugin.test.ts).
  • 별도로 게시된 plugin은 자체 CI (lint/build/test)를 실행하고 openclaw.extensions가 빌드된 진입점 (dist/index.js)을 가리키는지 확인해야 합니다.