---
read_when:
    - می‌خواهید یک Plugin جدید OpenClaw ایجاد کنید
    - به یک راهنمای شروع سریع برای توسعه Plugin نیاز دارید
    - شما در حال افزودن یک کانال، ارائه‌دهنده، ابزار یا قابلیت دیگری به OpenClaw هستید
sidebarTitle: Getting Started
summary: اولین Plugin OpenClaw خود را در چند دقیقه بسازید
title: ساخت Pluginها
x-i18n:
    generated_at: "2026-05-10T19:51:42Z"
    model: gpt-5.5
    provider: openai
    source_hash: 320ea03395cd702e62831e3b6bb3e44443b4a00701f3e6d35d7c9e556e3bb258
    source_path: plugins/building-plugins.md
    workflow: 16
---

Pluginها OpenClaw را با قابلیت‌های تازه گسترش می‌دهند: کانال‌ها، ارائه‌دهندگان مدل،
گفتار، رونویسی بلادرنگ، صدای بلادرنگ، درک رسانه، تولید تصویر، تولید ویدئو،
دریافت وب، جست‌وجوی وب، ابزارهای عامل، یا هر ترکیبی از آن‌ها.

لازم نیست Plugin خود را به مخزن OpenClaw اضافه کنید. در
[ClawHub](/fa/clawhub) منتشر کنید و کاربران با
`openclaw plugins install clawhub:<package-name>` نصب می‌کنند. مشخصات خام بسته همچنان
در دوره گذار راه‌اندازی از npm نصب می‌شوند.

## پیش‌نیازها

- Node >= 22 و یک مدیر بسته (npm یا pnpm)
- آشنایی با TypeScript (ESM)
- برای Pluginهای داخل مخزن: مخزن clone شده و `pnpm install` انجام شده باشد. توسعه Plugin با
  checkout منبع فقط با pnpm است، چون OpenClaw، Pluginهای بسته‌بندی‌شده را از بسته‌های workspace
  در `extensions/*` بارگذاری می‌کند.

## چه نوع Pluginی؟

<CardGroup cols={3}>
  <Card title="Channel plugin" icon="messages-square" href="/fa/plugins/sdk-channel-plugins">
    OpenClaw را به یک سکوی پیام‌رسانی وصل کنید (Discord، IRC و غیره)
  </Card>
  <Card title="Provider plugin" icon="cpu" href="/fa/plugins/sdk-provider-plugins">
    یک ارائه‌دهنده مدل اضافه کنید (LLM، پراکسی، یا endpoint سفارشی)
  </Card>
  <Card title="CLI backend plugin" icon="terminal" href="/fa/plugins/cli-backend-plugins">
    یک CLI هوش مصنوعی محلی را به اجراکننده fallback متنی OpenClaw نگاشت کنید
  </Card>
  <Card title="Tool / hook plugin" icon="wrench" href="/fa/plugins/hooks">
    ابزارهای عامل، hookهای رویداد، یا سرویس‌ها را ثبت کنید - در ادامه بخوانید
  </Card>
</CardGroup>

برای یک Plugin کانال که تضمین نمی‌شود هنگام اجرای onboarding/setup نصب شده باشد،
از `createOptionalChannelSetupSurface(...)` در
`openclaw/plugin-sdk/channel-setup` استفاده کنید. این یک جفت آداپتور setup + wizard
می‌سازد که نیاز نصب را اعلام می‌کند و تا وقتی Plugin نصب نشده باشد، در نوشتن config واقعی
بسته شکست می‌خورد.

## شروع سریع: Plugin ابزار

این راهنما یک Plugin حداقلی می‌سازد که یک ابزار عامل را ثبت می‌کند. Pluginهای کانال
و ارائه‌دهنده راهنماهای اختصاصی دارند که بالاتر لینک شده‌اند.

<Steps>
  <Step title="Create the package and manifest">
    <CodeGroup>
    ```json package.json
    {
      "name": "@myorg/openclaw-my-plugin",
      "version": "1.0.0",
      "type": "module",
      "openclaw": {
        "extensions": ["./index.ts"],
        "compat": {
          "pluginApi": ">=2026.3.24-beta.2",
          "minGatewayVersion": "2026.3.24-beta.2"
        },
        "build": {
          "openclawVersion": "2026.3.24-beta.2",
          "pluginSdkVersion": "2026.3.24-beta.2"
        }
      }
    }
    ```

    ```json openclaw.plugin.json
    {
      "id": "my-plugin",
      "name": "My Plugin",
      "description": "Adds a custom tool to OpenClaw",
      "contracts": {
        "tools": ["my_tool"]
      },
      "activation": {
        "onStartup": true
      },
      "configSchema": {
        "type": "object",
        "additionalProperties": false
      }
    }
    ```
    </CodeGroup>

    هر Plugin به یک manifest نیاز دارد، حتی اگر config نداشته باشد. ابزارهایی که در runtime ثبت می‌شوند
    باید در `contracts.tools` فهرست شوند تا OpenClaw بتواند Plugin مالک را بدون بارگذاری
    runtime همه Pluginها کشف کند. Pluginها همچنین باید `activation.onStartup` را آگاهانه اعلام کنند.
    این مثال آن را روی `true` تنظیم می‌کند. برای schema کامل، [Manifest](/fa/plugins/manifest) را ببینید. snippetهای canonical انتشار ClawHub
    در `docs/snippets/plugin-publish/` قرار دارند.

  </Step>

  <Step title="Write the entry point">

    ```typescript
    // index.ts
    import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
    import { Type } from "@sinclair/typebox";

    export default definePluginEntry({
      id: "my-plugin",
      name: "My Plugin",
      description: "Adds a custom tool to OpenClaw",
      register(api) {
        api.registerTool({
          name: "my_tool",
          description: "Do a thing",
          parameters: Type.Object({ input: Type.String() }),
          async execute(_id, params) {
            return { content: [{ type: "text", text: `Got: ${params.input}` }] };
          },
        });
      },
    });
    ```

    `definePluginEntry` برای Pluginهای غیرکانالی است. برای کانال‌ها، از
    `defineChannelPluginEntry` استفاده کنید - [Channel Plugins](/fa/plugins/sdk-channel-plugins) را ببینید.
    برای گزینه‌های کامل entry point، [Entry Points](/fa/plugins/sdk-entrypoints) را ببینید.

  </Step>

  <Step title="Test and publish">

    **Pluginهای خارجی:** با ClawHub اعتبارسنجی و منتشر کنید، سپس نصب کنید:

    ```bash
    clawhub package publish your-org/your-plugin --dry-run
    clawhub package publish your-org/your-plugin
    openclaw plugins install clawhub:@myorg/openclaw-my-plugin
    ```

    مشخصات خام بسته مانند `@myorg/openclaw-my-plugin` در دوره گذار راه‌اندازی از npm نصب می‌شوند.
    وقتی resolve از ClawHub را می‌خواهید، از `clawhub:` استفاده کنید.

    **Pluginهای داخل مخزن:** زیر درخت workspace Pluginهای بسته‌بندی‌شده قرار دهید - خودکار کشف می‌شود.

    ```bash
    pnpm test -- <bundled-plugin-root>/my-plugin/
    ```

  </Step>
</Steps>

## قابلیت‌های Plugin

یک Plugin می‌تواند از طریق شیء `api` هر تعداد قابلیت را ثبت کند:

| قابلیت                  | روش ثبت                                          | راهنمای تفصیلی                                                                  |
| ---------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------- |
| استنتاج متن (LLM)      | `api.registerProvider(...)`                      | [Provider Plugins](/fa/plugins/sdk-provider-plugins)                               |
| backend استنتاج CLI    | `api.registerCliBackend(...)`                    | [CLI Backend Plugins](/fa/plugins/cli-backend-plugins)                             |
| کانال / پیام‌رسانی     | `api.registerChannel(...)`                       | [Channel Plugins](/fa/plugins/sdk-channel-plugins)                                 |
| گفتار (TTS/STT)        | `api.registerSpeechProvider(...)`                | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| رونویسی بلادرنگ        | `api.registerRealtimeTranscriptionProvider(...)` | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| صدای بلادرنگ           | `api.registerRealtimeVoiceProvider(...)`         | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| درک رسانه              | `api.registerMediaUnderstandingProvider(...)`    | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| تولید تصویر            | `api.registerImageGenerationProvider(...)`       | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| تولید موسیقی           | `api.registerMusicGenerationProvider(...)`       | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| تولید ویدئو            | `api.registerVideoGenerationProvider(...)`       | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| دریافت وب              | `api.registerWebFetchProvider(...)`              | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| جست‌وجوی وب            | `api.registerWebSearchProvider(...)`             | [Provider Plugins](/fa/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) |
| middleware نتیجه ابزار | `api.registerAgentToolResultMiddleware(...)`     | [SDK Overview](/fa/plugins/sdk-overview#registration-api)                          |
| ابزارهای عامل          | `api.registerTool(...)`                          | پایین                                                                           |
| commandهای سفارشی      | `api.registerCommand(...)`                       | [Entry Points](/fa/plugins/sdk-entrypoints)                                        |
| hookهای Plugin         | `api.on(...)`                                    | [Plugin hooks](/fa/plugins/hooks)                                                  |
| hookهای رویداد داخلی   | `api.registerHook(...)`                          | [Entry Points](/fa/plugins/sdk-entrypoints)                                        |
| مسیرهای HTTP           | `api.registerHttpRoute(...)`                     | [Internals](/fa/plugins/architecture-internals#gateway-http-routes)                |
| subcommandهای CLI      | `api.registerCli(...)`                           | [Entry Points](/fa/plugins/sdk-entrypoints)                                        |

برای API کامل ثبت، [SDK Overview](/fa/plugins/sdk-overview#registration-api) را ببینید.

Pluginهای بسته‌بندی‌شده می‌توانند وقتی به بازنویسی async نتیجه ابزار پیش از دیده شدن خروجی توسط مدل
نیاز دارند، از `api.registerAgentToolResultMiddleware(...)` استفاده کنند. runtimeهای هدف را در
`contracts.agentToolResultMiddleware` اعلام کنید، برای مثال
`["pi", "codex"]`. این یک seam مورد اعتماد برای Pluginهای بسته‌بندی‌شده است؛ Pluginهای خارجی
باید hookهای معمول OpenClaw Plugin را ترجیح دهند، مگر اینکه OpenClaw برای این قابلیت
یک سیاست اعتماد صریح اضافه کند.

اگر Plugin شما روش‌های RPC سفارشی Gateway ثبت می‌کند، آن‌ها را روی یک پیشوند
اختصاصی Plugin نگه دارید. namespaceهای ادمین core (`config.*`,
`exec.approvals.*`, `wizard.*`, `update.*`) رزرو می‌مانند و همیشه به
`operator.admin` resolve می‌شوند، حتی اگر یک Plugin scope محدودتری بخواهد.

معنای guard hookها که باید در نظر داشته باشید:

- `before_tool_call`: `{ block: true }` نهایی است و handlerهای با اولویت پایین‌تر را متوقف می‌کند.
- `before_tool_call`: `{ block: false }` به‌عنوان نبود تصمیم تلقی می‌شود.
- `before_tool_call`: `{ requireApproval: true }` اجرای عامل را pause می‌کند و از کاربر از طریق overlay تأیید exec، دکمه‌های Telegram، interactionهای Discord، یا command `/approve` در هر کانالی درخواست تأیید می‌کند.
- `before_install`: `{ block: true }` نهایی است و handlerهای با اولویت پایین‌تر را متوقف می‌کند.
- `before_install`: `{ block: false }` به‌عنوان نبود تصمیم تلقی می‌شود.
- `message_sending`: `{ cancel: true }` نهایی است و handlerهای با اولویت پایین‌تر را متوقف می‌کند.
- `message_sending`: `{ cancel: false }` به‌عنوان نبود تصمیم تلقی می‌شود.
- `message_received`: وقتی به routing thread/topic ورودی نیاز دارید، فیلد typed `threadId` را ترجیح دهید. `metadata` را برای موارد اضافی مختص کانال نگه دارید.
- `message_sending`: فیلدهای routing typed یعنی `replyToId` / `threadId` را به کلیدهای metadata مختص کانال ترجیح دهید.

command `/approve` هم تأییدهای exec و هم Plugin را با fallback محدود مدیریت می‌کند: وقتی id تأیید exec پیدا نشود، OpenClaw همان id را در تأییدهای Plugin دوباره امتحان می‌کند. forwarding تأیید Plugin را می‌توان به‌طور مستقل از طریق `approvals.plugin` در config پیکربندی کرد.

اگر plumbing تأیید سفارشی نیاز دارد همان حالت fallback محدود را تشخیص دهد،
به‌جای matching دستی رشته‌های انقضای تأیید، `isApprovalNotFoundError` را از
`openclaw/plugin-sdk/error-runtime` ترجیح دهید.

برای مثال‌ها و مرجع hook، [Plugin hooks](/fa/plugins/hooks) را ببینید.

## ثبت ابزارهای عامل

ابزارها توابع typed هستند که LLM می‌تواند فراخوانی کند. آن‌ها می‌توانند الزامی باشند (همیشه
در دسترس) یا اختیاری باشند (opt-in کاربر):

```typescript
register(api) {
  // Required tool - always available
  api.registerTool({
    name: "my_tool",
    description: "Do a thing",
    parameters: Type.Object({ input: Type.String() }),
    async execute(_id, params) {
      return { content: [{ type: "text", text: params.input }] };
    },
  });

  // Optional tool - user must add to allowlist
  api.registerTool(
    {
      name: "workflow_tool",
      description: "Run a workflow",
      parameters: Type.Object({ pipeline: Type.String() }),
      async execute(_id, params) {
        return { content: [{ type: "text", text: params.pipeline }] };
      },
    },
    { optional: true },
  );
}
```

کارخانه‌های ابزار یک شیء زمینه‌ای تامین‌شده توسط زمان اجرا دریافت می‌کنند. وقتی یک ابزار نیاز دارد مدل فعال در نوبت فعلی را ثبت، نمایش، یا خود را با آن سازگار کند، از
`ctx.activeModel` استفاده کنید. این شیء می‌تواند شامل `provider`، `modelId` و
`modelRef` باشد. آن را فرادادهٔ اطلاعاتی زمان اجرا در نظر بگیرید، نه یک مرز امنیتی
در برابر اپراتور محلی، کد Plugin نصب‌شده، یا زمان اجرای تغییریافتهٔ
OpenClaw. برای ابزارهای محلی حساس، opt-in صریح Plugin یا اپراتور را نگه دارید
و وقتی فرادادهٔ مدل فعال موجود نیست یا مناسب نیست، به‌صورت بسته شکست بخورید.

هر ابزاری که با `api.registerTool(...)` ثبت می‌شود باید در manifest
Plugin نیز اعلام شود:

```json
{
  "contracts": {
    "tools": ["my_tool", "workflow_tool"]
  },
  "toolMetadata": {
    "workflow_tool": {
      "optional": true
    }
  }
}
```

OpenClaw توصیفگر اعتبارسنجی‌شده را از ابزار ثبت‌شده ثبت و cache می‌کند،
بنابراین Pluginها داده‌های `description` یا schema را در manifest تکرار نمی‌کنند. قرارداد
manifest فقط مالکیت و کشف را اعلام می‌کند؛ اجرا همچنان پیاده‌سازی زندهٔ ابزار ثبت‌شده را
فراخوانی می‌کند.
برای ابزارهایی که با
`api.registerTool(..., { optional: true })` ثبت شده‌اند، مقدار
`toolMetadata.<tool>.optional: true` را تنظیم کنید تا OpenClaw بتواند تا زمانی که ابزار
به‌صراحت allowlist نشده است، از بارگذاری زمان اجرای آن Plugin خودداری کند.

کاربران ابزارهای اختیاری را در پیکربندی فعال می‌کنند:

```json5
{
  tools: { allow: ["workflow_tool"] },
}
```

- نام ابزارها نباید با ابزارهای core تداخل داشته باشد (تداخل‌ها نادیده گرفته می‌شوند)
- ابزارهایی با اشیای ثبت‌نام بدشکل، از جمله نبود `parameters`، به‌جای شکستن اجرای agent، نادیده گرفته می‌شوند و در diagnostics مربوط به Plugin گزارش می‌شوند
- برای ابزارهایی که اثر جانبی یا نیازمندی binary اضافی دارند، از `optional: true` استفاده کنید
- کاربران می‌توانند با افزودن شناسهٔ Plugin به `tools.allow` همهٔ ابزارهای یک Plugin را فعال کنند

## ثبت فرمان‌های CLI

Pluginها می‌توانند با `api.registerCli` گروه‌های فرمان ریشهٔ `openclaw` اضافه کنند. برای
هر ریشهٔ فرمان سطح بالا، `descriptors` ارائه کنید تا OpenClaw بتواند بدون بارگذاری مشتاقانهٔ
زمان اجرای هر Plugin، فرمان را نمایش دهد و مسیریابی کند.

```typescript
register(api) {
  api.registerCli(
    ({ program }) => {
      const demo = program
        .command("demo-plugin")
        .description("Run demo plugin commands");

      demo
        .command("ping")
        .description("Check that the plugin CLI is executable")
        .action(() => {
          console.log("demo-plugin:pong");
        });
    },
    {
      descriptors: [
        {
          name: "demo-plugin",
          description: "Run demo plugin commands",
          hasSubcommands: true,
        },
      ],
    },
  );
}
```

پس از نصب، ثبت زمان اجرا را بررسی و فرمان را اجرا کنید:

```bash
openclaw plugins inspect demo-plugin --runtime --json
openclaw demo-plugin ping
```

## قراردادهای import

همیشه از مسیرهای متمرکز `openclaw/plugin-sdk/<subpath>` import کنید:

```typescript
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";

// Wrong: monolithic root (deprecated, will be removed)
import { ... } from "openclaw/plugin-sdk";
```

برای مرجع کامل subpath، [نمای کلی SDK](/fa/plugins/sdk-overview) را ببینید.

درون Plugin خود، برای importهای داخلی از فایل‌های barrel محلی (`api.ts`، `runtime-api.ts`) استفاده کنید -
هرگز Plugin خودتان را از طریق مسیر SDK آن import نکنید.

برای Pluginهای ارائه‌دهنده، helperهای مخصوص ارائه‌دهنده را در همان barrelهای ریشهٔ package
نگه دارید، مگر اینکه seam واقعاً عمومی باشد. نمونه‌های bundled فعلی:

- Anthropic: wrapperهای stream Claude و helperهای `service_tier` / beta
- OpenAI: builderهای ارائه‌دهنده، helperهای مدل پیش‌فرض، ارائه‌دهنده‌های realtime
- OpenRouter: builder ارائه‌دهنده به‌همراه helperهای onboarding/config

اگر یک helper فقط داخل یک package ارائه‌دهندهٔ bundled مفید است، آن را به‌جای ارتقا به
`openclaw/plugin-sdk/*` روی همان seam ریشهٔ package نگه دارید.

برخی seamهای helper تولیدشدهٔ `openclaw/plugin-sdk/<bundled-id>` هنوز برای
نگهداری bundled-Pluginها، وقتی استفادهٔ owner رهگیری‌شده دارند، وجود دارند. با آن‌ها به‌عنوان
سطوح رزرو‌شده رفتار کنید، نه الگوی پیش‌فرض برای Pluginهای جدید شخص ثالث.

## چک‌لیست پیش از ارسال

<Check>**package.json** فرادادهٔ درست `openclaw` را دارد</Check>
<Check>manifest **openclaw.plugin.json** موجود و معتبر است</Check>
<Check>نقطهٔ ورود از `defineChannelPluginEntry` یا `definePluginEntry` استفاده می‌کند</Check>
<Check>همهٔ importها از مسیرهای متمرکز `plugin-sdk/<subpath>` استفاده می‌کنند</Check>
<Check>importهای داخلی از ماژول‌های محلی استفاده می‌کنند، نه self-importهای SDK</Check>
<Check>تست‌ها pass می‌شوند (`pnpm test -- <bundled-plugin-root>/my-plugin/`)</Check>
<Check>`pnpm check` pass می‌شود (برای Pluginهای داخل repo)</Check>

## تست انتشار beta

1. tagهای انتشار GitHub را در [openclaw/openclaw](https://github.com/openclaw/openclaw/releases) زیر نظر بگیرید و از مسیر `Watch` > `Releases` مشترک شوید. tagهای beta شبیه `v2026.3.N-beta.1` هستند. همچنین می‌توانید اعلان‌های حساب رسمی X مربوط به OpenClaw، [@openclaw](https://x.com/openclaw)، را برای اطلاعیه‌های انتشار فعال کنید.
2. به‌محض ظاهر شدن tag beta، Plugin خود را در برابر آن تست کنید. بازهٔ پیش از stable معمولاً فقط چند ساعت است.
3. پس از تست، در thread مربوط به Plugin خود در کانال Discord با نام `plugin-forum`، یا `all good` را پست کنید یا چیزی را که خراب شده بنویسید. اگر هنوز thread ندارید، یکی ایجاد کنید.
4. اگر چیزی خراب شد، issueای با عنوان `Beta blocker: <plugin-name> - <summary>` باز یا به‌روزرسانی کنید و label `beta-blocker` را اعمال کنید. لینک issue را در thread خود بگذارید.
5. یک PR به `main` با عنوان `fix(<plugin-id>): beta blocker - <summary>` باز کنید و issue را هم در PR و هم در thread Discord خود لینک کنید. مشارکت‌کنندگان نمی‌توانند PRها را label کنند، بنابراین عنوان، سیگنال سمت PR برای maintainers و automation است. blockerهایی که PR دارند merge می‌شوند؛ blockerهای بدون PR ممکن است به هر حال ship شوند. maintainers در طول تست beta این threadها را زیر نظر دارند.
6. سکوت یعنی سبز. اگر این بازه را از دست بدهید، احتمالاً fix شما در چرخهٔ بعدی land می‌شود.

## گام‌های بعدی

<CardGroup cols={2}>
  <Card title="Pluginهای کانال" icon="messages-square" href="/fa/plugins/sdk-channel-plugins">
    یک Plugin کانال پیام‌رسانی بسازید
  </Card>
  <Card title="Pluginهای ارائه‌دهنده" icon="cpu" href="/fa/plugins/sdk-provider-plugins">
    یک Plugin ارائه‌دهندهٔ مدل بسازید
  </Card>
  <Card title="Pluginهای backend CLI" icon="terminal" href="/fa/plugins/cli-backend-plugins">
    یک backend محلی CLI هوش مصنوعی ثبت کنید
  </Card>
  <Card title="نمای کلی SDK" icon="book-open" href="/fa/plugins/sdk-overview">
    مرجع import map و API ثبت
  </Card>
  <Card title="Helperهای زمان اجرا" icon="settings" href="/fa/plugins/sdk-runtime">
    TTS، جست‌وجو، subagent از طریق api.runtime
  </Card>
  <Card title="تست" icon="test-tubes" href="/fa/plugins/sdk-testing">
    ابزارها و الگوهای تست
  </Card>
  <Card title="Manifest Plugin" icon="file-json" href="/fa/plugins/manifest">
    مرجع کامل schemaی manifest
  </Card>
</CardGroup>

## مرتبط

- [معماری Plugin](/fa/plugins/architecture) - بررسی عمیق معماری داخلی
- [نمای کلی SDK](/fa/plugins/sdk-overview) - مرجع Plugin SDK
- [Manifest](/fa/plugins/manifest) - قالب manifest Plugin
- [Pluginهای کانال](/fa/plugins/sdk-channel-plugins) - ساخت Pluginهای کانال
- [Pluginهای ارائه‌دهنده](/fa/plugins/sdk-provider-plugins) - ساخت Pluginهای ارائه‌دهنده
