From 53618cca0dfb18a43299a81acc575e0b66a11178 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Fri, 24 Apr 2026 22:26:10 -0400 Subject: [PATCH] docs: clarify plugin discovery loading --- docs/plugins/architecture.md | 5 ++++- docs/plugins/sdk-channel-plugins.md | 8 ++++++++ docs/plugins/sdk-entrypoints.md | 25 ++++++++++++++++++------- docs/tools/plugin.md | 20 ++++++++++++-------- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/docs/plugins/architecture.md b/docs/plugins/architecture.md index dbb27714b93..68fc40a5545 100644 --- a/docs/plugins/architecture.md +++ b/docs/plugins/architecture.md @@ -148,9 +148,12 @@ reserve root command names before parsing. The important design boundary: -- discovery + config validation should work from **manifest/schema metadata** +- manifest/config validation should work from **manifest/schema metadata** without executing plugin code +- native capability discovery may load trusted plugin entry code to build a + non-activating registry snapshot - native runtime behavior comes from the plugin module's `register(api)` path + with `api.registrationMode === "full"` That split lets OpenClaw validate config, explain missing/disabled plugins, and build UI/schema hints before the full runtime is active. diff --git a/docs/plugins/sdk-channel-plugins.md b/docs/plugins/sdk-channel-plugins.md index bc468b37922..445e29af12c 100644 --- a/docs/plugins/sdk-channel-plugins.md +++ b/docs/plugins/sdk-channel-plugins.md @@ -152,6 +152,14 @@ paths and should return the channel metadata, setup-safe config adapter, status adapter, and channel secret target metadata needed for those summaries. Do not start clients, listeners, or transport runtimes from the setup entry. +Keep the main channel entry import path narrow too. Discovery can evaluate the +entry and the channel plugin module to register capabilities without activating +the channel. Files such as `channel-plugin-api.ts` should export the channel +plugin object without importing setup wizards, transport clients, socket +listeners, subprocess launchers, or service startup modules. Put those runtime +pieces in modules loaded from `registerFull(...)`, runtime setters, or lazy +capability adapters. + `createOptionalChannelSetupWizard`, `DEFAULT_ACCOUNT_ID`, `createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, and `splitSetupEntries` diff --git a/docs/plugins/sdk-entrypoints.md b/docs/plugins/sdk-entrypoints.md index f87257a0b96..3ae01f6c610 100644 --- a/docs/plugins/sdk-entrypoints.md +++ b/docs/plugins/sdk-entrypoints.md @@ -127,6 +127,10 @@ export default defineChannelPluginEntry({ Use it as the canonical place for channel-owned CLI descriptors so root help stays non-activating, discovery snapshots include static command metadata, and normal CLI command registration remains compatible with full plugin loads. +- Discovery registration is non-activating, not import-free. OpenClaw may + evaluate the trusted plugin entry and channel plugin module to build the + snapshot, so keep top-level imports side-effect-free and put sockets, + clients, workers, and services behind `"full"`-only paths. - `registerFull` only runs when `api.registrationMode === "full"`. It is skipped during setup-only loading. - Like `definePluginEntry`, `configSchema` can be a lazy factory and OpenClaw @@ -198,13 +202,13 @@ setter before the full channel entry loads. `api.registrationMode` tells your plugin how it was loaded: -| Mode | When | What to register | -| ----------------- | --------------------------------- | ---------------------------------------------------------------------------------------------- | -| `"full"` | Normal gateway startup | Everything | -| `"discovery"` | Read-only capability discovery | Channel registration plus static CLI descriptors; skip sockets, workers, clients, and services | -| `"setup-only"` | Disabled/unconfigured channel | Channel registration only | -| `"setup-runtime"` | Setup flow with runtime available | Channel registration plus only the lightweight runtime needed before the full entry loads | -| `"cli-metadata"` | Root help / CLI metadata capture | CLI descriptors only | +| Mode | When | What to register | +| ----------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `"full"` | Normal gateway startup | Everything | +| `"discovery"` | Read-only capability discovery | Channel registration plus static CLI descriptors; entry code may load, but skip sockets, workers, clients, and services | +| `"setup-only"` | Disabled/unconfigured channel | Channel registration only | +| `"setup-runtime"` | Setup flow with runtime available | Channel registration plus only the lightweight runtime needed before the full entry loads | +| `"cli-metadata"` | Root help / CLI metadata capture | CLI descriptors only | `defineChannelPluginEntry` handles this split automatically. If you use `definePluginEntry` directly for a channel, check mode yourself: @@ -228,6 +232,13 @@ register(api) { } ``` +Discovery mode builds a non-activating registry snapshot. It may still evaluate +the plugin entry and the channel plugin object so OpenClaw can register channel +capabilities and static CLI descriptors. Treat module evaluation in discovery as +trusted but lightweight: no network clients, subprocesses, listeners, database +connections, background workers, credential reads, or other live runtime side +effects at top level. + Treat `"setup-runtime"` as the window where setup-only startup surfaces must exist without re-entering the full bundled channel runtime. Good fits are channel registration, setup-safe HTTP routes, setup-safe gateway methods, and diff --git a/docs/tools/plugin.md b/docs/tools/plugin.md index c6f49917513..8327b8383e0 100644 --- a/docs/tools/plugin.md +++ b/docs/tools/plugin.md @@ -368,18 +368,22 @@ public contract. `api.registrationMode` tells a plugin why its entry is being loaded: -| Mode | Meaning | -| --------------- | ------------------------------------------------------------------------------------------------------ | -| `full` | Runtime activation. Register tools, hooks, services, commands, routes, and other live side effects. | -| `discovery` | Read-only capability discovery. Register providers and metadata, but skip expensive live side effects. | -| `setup-only` | Channel setup metadata loading through a lightweight setup entry. | -| `setup-runtime` | Channel setup loading that also needs the runtime entry. | -| `cli-metadata` | CLI command metadata collection only. | +| Mode | Meaning | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `full` | Runtime activation. Register tools, hooks, services, commands, routes, and other live side effects. | +| `discovery` | Read-only capability discovery. Register providers and metadata; trusted plugin entry code may load, but skip live side effects. | +| `setup-only` | Channel setup metadata loading through a lightweight setup entry. | +| `setup-runtime` | Channel setup loading that also needs the runtime entry. | +| `cli-metadata` | CLI command metadata collection only. | Plugin entries that open sockets, databases, background workers, or long-lived clients should guard those side effects with `api.registrationMode === "full"`. Discovery loads are cached separately from activating loads and do not replace -the running Gateway registry. +the running Gateway registry. Discovery is non-activating, not import-free: +OpenClaw may evaluate the trusted plugin entry or channel plugin module to build +the snapshot. Keep module top levels lightweight and side-effect-free, and move +network clients, subprocesses, listeners, credential reads, and service startup +behind full-runtime paths. Common registration methods: