mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 16:30:47 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
536
openclaw/docs/plugins/sdk-setup.md
Normal file
536
openclaw/docs/plugins/sdk-setup.md
Normal file
|
|
@ -0,0 +1,536 @@
|
|||
---
|
||||
title: "Plugin Setup and Config"
|
||||
sidebarTitle: "Setup and Config"
|
||||
summary: "Setup wizards, setup-entry.ts, config schemas, and package.json metadata"
|
||||
read_when:
|
||||
- You are adding a setup wizard to a plugin
|
||||
- You need to understand setup-entry.ts vs index.ts
|
||||
- You are defining plugin config schemas or package.json openclaw metadata
|
||||
---
|
||||
|
||||
# Plugin Setup and Config
|
||||
|
||||
Reference for plugin packaging (`package.json` metadata), manifests
|
||||
(`openclaw.plugin.json`), setup entries, and config schemas.
|
||||
|
||||
<Tip>
|
||||
**Looking for a walkthrough?** The how-to guides cover packaging in context:
|
||||
[Channel Plugins](/plugins/sdk-channel-plugins#step-1-package-and-manifest) and
|
||||
[Provider Plugins](/plugins/sdk-provider-plugins#step-1-package-and-manifest).
|
||||
</Tip>
|
||||
|
||||
## Package metadata
|
||||
|
||||
Your `package.json` needs an `openclaw` field that tells the plugin system what
|
||||
your plugin provides:
|
||||
|
||||
**Channel plugin:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@myorg/openclaw-my-channel",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"openclaw": {
|
||||
"extensions": ["./index.ts"],
|
||||
"setupEntry": "./setup-entry.ts",
|
||||
"channel": {
|
||||
"id": "my-channel",
|
||||
"label": "My Channel",
|
||||
"blurb": "Short description of the channel."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Provider plugin / ClawHub publish baseline:**
|
||||
|
||||
```json openclaw-clawhub-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"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you publish the plugin externally on ClawHub, those `compat` and `build`
|
||||
fields are required. The canonical publish snippets live in
|
||||
`docs/snippets/plugin-publish/`.
|
||||
|
||||
### `openclaw` fields
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------ | ---------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `extensions` | `string[]` | Entry point files (relative to package root) |
|
||||
| `setupEntry` | `string` | Lightweight setup-only entry (optional) |
|
||||
| `channel` | `object` | Channel catalog metadata for setup, picker, quickstart, and status surfaces |
|
||||
| `providers` | `string[]` | Provider ids registered by this plugin |
|
||||
| `install` | `object` | Install hints: `npmSpec`, `localPath`, `defaultChoice`, `minHostVersion`, `allowInvalidConfigRecovery` |
|
||||
| `startup` | `object` | Startup behavior flags |
|
||||
|
||||
### `openclaw.channel`
|
||||
|
||||
`openclaw.channel` is cheap package metadata for channel discovery and setup
|
||||
surfaces before runtime loads.
|
||||
|
||||
| Field | Type | What it means |
|
||||
| -------------------------------------- | ---------- | ----------------------------------------------------------------------------- |
|
||||
| `id` | `string` | Canonical channel id. |
|
||||
| `label` | `string` | Primary channel label. |
|
||||
| `selectionLabel` | `string` | Picker/setup label when it should differ from `label`. |
|
||||
| `detailLabel` | `string` | Secondary detail label for richer channel catalogs and status surfaces. |
|
||||
| `docsPath` | `string` | Docs path for setup and selection links. |
|
||||
| `docsLabel` | `string` | Override label used for docs links when it should differ from the channel id. |
|
||||
| `blurb` | `string` | Short onboarding/catalog description. |
|
||||
| `order` | `number` | Sort order in channel catalogs. |
|
||||
| `aliases` | `string[]` | Extra lookup aliases for channel selection. |
|
||||
| `preferOver` | `string[]` | Lower-priority plugin/channel ids this channel should outrank. |
|
||||
| `systemImage` | `string` | Optional icon/system-image name for channel UI catalogs. |
|
||||
| `selectionDocsPrefix` | `string` | Prefix text before docs links in selection surfaces. |
|
||||
| `selectionDocsOmitLabel` | `boolean` | Show the docs path directly instead of a labeled docs link in selection copy. |
|
||||
| `selectionExtras` | `string[]` | Extra short strings appended in selection copy. |
|
||||
| `markdownCapable` | `boolean` | Marks the channel as markdown-capable for outbound formatting decisions. |
|
||||
| `exposure` | `object` | Channel visibility controls for setup, configured lists, and docs surfaces. |
|
||||
| `quickstartAllowFrom` | `boolean` | Opt this channel into the standard quickstart `allowFrom` setup flow. |
|
||||
| `forceAccountBinding` | `boolean` | Require explicit account binding even when only one account exists. |
|
||||
| `preferSessionLookupForAnnounceTarget` | `boolean` | Prefer session lookup when resolving announce targets for this channel. |
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"openclaw": {
|
||||
"channel": {
|
||||
"id": "my-channel",
|
||||
"label": "My Channel",
|
||||
"selectionLabel": "My Channel (self-hosted)",
|
||||
"detailLabel": "My Channel Bot",
|
||||
"docsPath": "/channels/my-channel",
|
||||
"docsLabel": "my-channel",
|
||||
"blurb": "Webhook-based self-hosted chat integration.",
|
||||
"order": 80,
|
||||
"aliases": ["mc"],
|
||||
"preferOver": ["my-channel-legacy"],
|
||||
"selectionDocsPrefix": "Guide:",
|
||||
"selectionExtras": ["Markdown"],
|
||||
"markdownCapable": true,
|
||||
"exposure": {
|
||||
"configured": true,
|
||||
"setup": true,
|
||||
"docs": true
|
||||
},
|
||||
"quickstartAllowFrom": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`exposure` supports:
|
||||
|
||||
- `configured`: include the channel in configured/status-style listing surfaces
|
||||
- `setup`: include the channel in interactive setup/configure pickers
|
||||
- `docs`: mark the channel as public-facing in docs/navigation surfaces
|
||||
|
||||
`showConfigured` and `showInSetup` remain supported as legacy aliases. Prefer
|
||||
`exposure`.
|
||||
|
||||
### `openclaw.install`
|
||||
|
||||
`openclaw.install` is package metadata, not manifest metadata.
|
||||
|
||||
| Field | Type | What it means |
|
||||
| ---------------------------- | -------------------- | -------------------------------------------------------------------------------- |
|
||||
| `npmSpec` | `string` | Canonical npm spec for install/update flows. |
|
||||
| `localPath` | `string` | Local development or bundled install path. |
|
||||
| `defaultChoice` | `"npm"` \| `"local"` | Preferred install source when both are available. |
|
||||
| `minHostVersion` | `string` | Minimum supported OpenClaw version in the form `>=x.y.z`. |
|
||||
| `allowInvalidConfigRecovery` | `boolean` | Lets bundled-plugin reinstall flows recover from specific stale-config failures. |
|
||||
|
||||
If `minHostVersion` is set, install and manifest-registry loading both enforce
|
||||
it. Older hosts skip the plugin; invalid version strings are rejected.
|
||||
|
||||
`allowInvalidConfigRecovery` is not a general bypass for broken configs. It is
|
||||
for narrow bundled-plugin recovery only, so reinstall/setup can repair known
|
||||
upgrade leftovers like a missing bundled plugin path or stale `channels.<id>`
|
||||
entry for that same plugin. If config is broken for unrelated reasons, install
|
||||
still fails closed and tells the operator to run `openclaw doctor --fix`.
|
||||
|
||||
### Deferred full load
|
||||
|
||||
Channel plugins can opt into deferred loading with:
|
||||
|
||||
```json
|
||||
{
|
||||
"openclaw": {
|
||||
"extensions": ["./index.ts"],
|
||||
"setupEntry": "./setup-entry.ts",
|
||||
"startup": {
|
||||
"deferConfiguredChannelFullLoadUntilAfterListen": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When enabled, OpenClaw loads only `setupEntry` during the pre-listen startup
|
||||
phase, even for already-configured channels. The full entry loads after the
|
||||
gateway starts listening.
|
||||
|
||||
<Warning>
|
||||
Only enable deferred loading when your `setupEntry` registers everything the
|
||||
gateway needs before it starts listening (channel registration, HTTP routes,
|
||||
gateway methods). If the full entry owns required startup capabilities, keep
|
||||
the default behavior.
|
||||
</Warning>
|
||||
|
||||
If your setup/full entry registers gateway RPC methods, keep them on a
|
||||
plugin-specific prefix. Reserved core admin namespaces (`config.*`,
|
||||
`exec.approvals.*`, `wizard.*`, `update.*`) stay core-owned and always resolve
|
||||
to `operator.admin`.
|
||||
|
||||
## Plugin manifest
|
||||
|
||||
Every native plugin must ship an `openclaw.plugin.json` in the package root.
|
||||
OpenClaw uses this to validate config without executing plugin code.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "my-plugin",
|
||||
"name": "My Plugin",
|
||||
"description": "Adds My Plugin capabilities to OpenClaw",
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"webhookSecret": {
|
||||
"type": "string",
|
||||
"description": "Webhook verification secret"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For channel plugins, add `kind` and `channels`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "my-channel",
|
||||
"kind": "channel",
|
||||
"channels": ["my-channel"],
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Even plugins with no config must ship a schema. An empty schema is valid:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "my-plugin",
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [Plugin Manifest](/plugins/manifest) for the full schema reference.
|
||||
|
||||
## ClawHub publishing
|
||||
|
||||
For plugin packages, use the package-specific ClawHub command:
|
||||
|
||||
```bash
|
||||
clawhub package publish your-org/your-plugin --dry-run
|
||||
clawhub package publish your-org/your-plugin
|
||||
```
|
||||
|
||||
The legacy skill-only publish alias is for skills. Plugin packages should
|
||||
always use `clawhub package publish`.
|
||||
|
||||
## Setup entry
|
||||
|
||||
The `setup-entry.ts` file is a lightweight alternative to `index.ts` that
|
||||
OpenClaw loads when it only needs setup surfaces (onboarding, config repair,
|
||||
disabled channel inspection).
|
||||
|
||||
```typescript
|
||||
// setup-entry.ts
|
||||
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";
|
||||
import { myChannelPlugin } from "./src/channel.js";
|
||||
|
||||
export default defineSetupPluginEntry(myChannelPlugin);
|
||||
```
|
||||
|
||||
This avoids loading heavy runtime code (crypto libraries, CLI registrations,
|
||||
background services) during setup flows.
|
||||
|
||||
Bundled workspace channels that keep setup-safe exports in sidecar modules can
|
||||
use `defineBundledChannelSetupEntry(...)` from
|
||||
`openclaw/plugin-sdk/channel-entry-contract` instead of
|
||||
`defineSetupPluginEntry(...)`. That bundled contract also supports an optional
|
||||
`runtime` export so setup-time runtime wiring can stay lightweight and explicit.
|
||||
|
||||
**When OpenClaw uses `setupEntry` instead of the full entry:**
|
||||
|
||||
- The channel is disabled but needs setup/onboarding surfaces
|
||||
- The channel is enabled but unconfigured
|
||||
- Deferred loading is enabled (`deferConfiguredChannelFullLoadUntilAfterListen`)
|
||||
|
||||
**What `setupEntry` must register:**
|
||||
|
||||
- The channel plugin object (via `defineSetupPluginEntry`)
|
||||
- Any HTTP routes required before gateway listen
|
||||
- Any gateway methods needed during startup
|
||||
|
||||
Those startup gateway methods should still avoid reserved core admin
|
||||
namespaces such as `config.*` or `update.*`.
|
||||
|
||||
**What `setupEntry` should NOT include:**
|
||||
|
||||
- CLI registrations
|
||||
- Background services
|
||||
- Heavy runtime imports (crypto, SDKs)
|
||||
- Gateway methods only needed after startup
|
||||
|
||||
### Narrow setup helper imports
|
||||
|
||||
For hot setup-only paths, prefer the narrow setup helper seams over the broader
|
||||
`plugin-sdk/setup` umbrella when you only need part of the setup surface:
|
||||
|
||||
| Import path | Use it for | Key exports |
|
||||
| ---------------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `plugin-sdk/setup-runtime` | setup-time runtime helpers that stay available in `setupEntry` / deferred channel startup | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` |
|
||||
| `plugin-sdk/setup-adapter-runtime` | environment-aware account setup adapters | `createEnvPatchedAccountSetupAdapter` |
|
||||
| `plugin-sdk/setup-tools` | setup/install CLI/archive/docs helpers | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` |
|
||||
|
||||
Use the broader `plugin-sdk/setup` seam when you want the full shared setup
|
||||
toolbox, including config-patch helpers such as
|
||||
`moveSingleAccountChannelSectionToDefaultAccount(...)`.
|
||||
|
||||
The setup patch adapters stay hot-path safe on import. Their bundled
|
||||
single-account promotion contract-surface lookup is lazy, so importing
|
||||
`plugin-sdk/setup-runtime` does not eagerly load bundled contract-surface
|
||||
discovery before the adapter is actually used.
|
||||
|
||||
### Channel-owned single-account promotion
|
||||
|
||||
When a channel upgrades from a single-account top-level config to
|
||||
`channels.<id>.accounts.*`, the default shared behavior is to move promoted
|
||||
account-scoped values into `accounts.default`.
|
||||
|
||||
Bundled channels can narrow or override that promotion through their setup
|
||||
contract surface:
|
||||
|
||||
- `singleAccountKeysToMove`: extra top-level keys that should move into the
|
||||
promoted account
|
||||
- `namedAccountPromotionKeys`: when named accounts already exist, only these
|
||||
keys move into the promoted account; shared policy/delivery keys stay at the
|
||||
channel root
|
||||
- `resolveSingleAccountPromotionTarget(...)`: choose which existing account
|
||||
receives promoted values
|
||||
|
||||
Matrix is the current bundled example. If exactly one named Matrix account
|
||||
already exists, or if `defaultAccount` points at an existing non-canonical key
|
||||
such as `Ops`, promotion preserves that account instead of creating a new
|
||||
`accounts.default` entry.
|
||||
|
||||
## Config schema
|
||||
|
||||
Plugin config is validated against the JSON Schema in your manifest. Users
|
||||
configure plugins via:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
"my-plugin": {
|
||||
config: {
|
||||
webhookSecret: "abc123",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Your plugin receives this config as `api.pluginConfig` during registration.
|
||||
|
||||
For channel-specific config, use the channel config section instead:
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
"my-channel": {
|
||||
token: "bot-token",
|
||||
allowFrom: ["user1", "user2"],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Building channel config schemas
|
||||
|
||||
Use `buildChannelConfigSchema` from `openclaw/plugin-sdk/core` to convert a
|
||||
Zod schema into the `ChannelConfigSchema` wrapper that OpenClaw validates:
|
||||
|
||||
```typescript
|
||||
import { z } from "zod";
|
||||
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/core";
|
||||
|
||||
const accountSchema = z.object({
|
||||
token: z.string().optional(),
|
||||
allowFrom: z.array(z.string()).optional(),
|
||||
accounts: z.object({}).catchall(z.any()).optional(),
|
||||
defaultAccount: z.string().optional(),
|
||||
});
|
||||
|
||||
const configSchema = buildChannelConfigSchema(accountSchema);
|
||||
```
|
||||
|
||||
## Setup wizards
|
||||
|
||||
Channel plugins can provide interactive setup wizards for `openclaw onboard`.
|
||||
The wizard is a `ChannelSetupWizard` object on the `ChannelPlugin`:
|
||||
|
||||
```typescript
|
||||
import type { ChannelSetupWizard } from "openclaw/plugin-sdk/channel-setup";
|
||||
|
||||
const setupWizard: ChannelSetupWizard = {
|
||||
channel: "my-channel",
|
||||
status: {
|
||||
configuredLabel: "Connected",
|
||||
unconfiguredLabel: "Not configured",
|
||||
resolveConfigured: ({ cfg }) => Boolean((cfg.channels as any)?.["my-channel"]?.token),
|
||||
},
|
||||
credentials: [
|
||||
{
|
||||
inputKey: "token",
|
||||
providerHint: "my-channel",
|
||||
credentialLabel: "Bot token",
|
||||
preferredEnvVar: "MY_CHANNEL_BOT_TOKEN",
|
||||
envPrompt: "Use MY_CHANNEL_BOT_TOKEN from environment?",
|
||||
keepPrompt: "Keep current token?",
|
||||
inputPrompt: "Enter your bot token:",
|
||||
inspect: ({ cfg, accountId }) => {
|
||||
const token = (cfg.channels as any)?.["my-channel"]?.token;
|
||||
return {
|
||||
accountConfigured: Boolean(token),
|
||||
hasConfiguredValue: Boolean(token),
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
The `ChannelSetupWizard` type supports `credentials`, `textInputs`,
|
||||
`dmPolicy`, `allowFrom`, `groupAccess`, `prepare`, `finalize`, and more.
|
||||
See bundled plugin packages (for example the Discord plugin `src/channel.setup.ts`) for
|
||||
full examples.
|
||||
|
||||
For DM allowlist prompts that only need the standard
|
||||
`note -> prompt -> parse -> merge -> patch` flow, prefer the shared setup
|
||||
helpers from `openclaw/plugin-sdk/setup`: `createPromptParsedAllowFromForAccount(...)`,
|
||||
`createTopLevelChannelParsedAllowFromPrompt(...)`, and
|
||||
`createNestedChannelParsedAllowFromPrompt(...)`.
|
||||
|
||||
For channel setup status blocks that only vary by labels, scores, and optional
|
||||
extra lines, prefer `createStandardChannelSetupStatus(...)` from
|
||||
`openclaw/plugin-sdk/setup` instead of hand-rolling the same `status` object in
|
||||
each plugin.
|
||||
|
||||
For optional setup surfaces that should only appear in certain contexts, use
|
||||
`createOptionalChannelSetupSurface` from `openclaw/plugin-sdk/channel-setup`:
|
||||
|
||||
```typescript
|
||||
import { createOptionalChannelSetupSurface } from "openclaw/plugin-sdk/channel-setup";
|
||||
|
||||
const setupSurface = createOptionalChannelSetupSurface({
|
||||
channel: "my-channel",
|
||||
label: "My Channel",
|
||||
npmSpec: "@myorg/openclaw-my-channel",
|
||||
docsPath: "/channels/my-channel",
|
||||
});
|
||||
// Returns { setupAdapter, setupWizard }
|
||||
```
|
||||
|
||||
`plugin-sdk/channel-setup` also exposes the lower-level
|
||||
`createOptionalChannelSetupAdapter(...)` and
|
||||
`createOptionalChannelSetupWizard(...)` builders when you only need one half of
|
||||
that optional-install surface.
|
||||
|
||||
The generated optional adapter/wizard fail closed on real config writes. They
|
||||
reuse one install-required message across `validateInput`,
|
||||
`applyAccountConfig`, and `finalize`, and append a docs link when `docsPath` is
|
||||
set.
|
||||
|
||||
For binary-backed setup UIs, prefer the shared delegated helpers instead of
|
||||
copying the same binary/status glue into every channel:
|
||||
|
||||
- `createDetectedBinaryStatus(...)` for status blocks that vary only by labels,
|
||||
hints, scores, and binary detection
|
||||
- `createCliPathTextInput(...)` for path-backed text inputs
|
||||
- `createDelegatedSetupWizardStatusResolvers(...)`,
|
||||
`createDelegatedPrepare(...)`, `createDelegatedFinalize(...)`, and
|
||||
`createDelegatedResolveConfigured(...)` when `setupEntry` needs to forward to
|
||||
a heavier full wizard lazily
|
||||
- `createDelegatedTextInputShouldPrompt(...)` when `setupEntry` only needs to
|
||||
delegate a `textInputs[*].shouldPrompt` decision
|
||||
|
||||
## Publishing and installing
|
||||
|
||||
**External plugins:** publish to [ClawHub](/tools/clawhub) or npm, then install:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @myorg/openclaw-my-plugin
|
||||
```
|
||||
|
||||
OpenClaw tries ClawHub first and falls back to npm automatically. You can also
|
||||
force ClawHub explicitly:
|
||||
|
||||
```bash
|
||||
openclaw plugins install clawhub:@myorg/openclaw-my-plugin # ClawHub only
|
||||
```
|
||||
|
||||
There is no matching `npm:` override. Use the normal npm package spec when you
|
||||
want the npm path after ClawHub fallback:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @myorg/openclaw-my-plugin
|
||||
```
|
||||
|
||||
**In-repo plugins:** place under the bundled plugin workspace tree and they are automatically
|
||||
discovered during build.
|
||||
|
||||
**Users can install:**
|
||||
|
||||
```bash
|
||||
openclaw plugins install <package-name>
|
||||
```
|
||||
|
||||
<Info>
|
||||
For npm-sourced installs, `openclaw plugins install` runs
|
||||
`npm install --ignore-scripts` (no lifecycle scripts). Keep plugin dependency
|
||||
trees pure JS/TS and avoid packages that require `postinstall` builds.
|
||||
</Info>
|
||||
|
||||
## Related
|
||||
|
||||
- [SDK Entry Points](/plugins/sdk-entrypoints) -- `definePluginEntry` and `defineChannelPluginEntry`
|
||||
- [Plugin Manifest](/plugins/manifest) -- full manifest schema reference
|
||||
- [Building Plugins](/plugins/building-plugins) -- step-by-step getting started guide
|
||||
Loading…
Add table
Add a link
Reference in a new issue