Plugin development reference and workflows based on real development experience (Dirigent, ContractorAgent, PrismFacet). Docs: structure, entry-point, hooks, tools, state, config, debugging Workflows: create-plugin, add-hook Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
50 lines
1.3 KiB
Markdown
50 lines
1.3 KiB
Markdown
# Plugin Entry Point
|
|
|
|
## Format
|
|
|
|
```typescript
|
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
|
|
const _G = globalThis as Record<string, unknown>;
|
|
const LIFECYCLE_KEY = "_myPluginGatewayLifecycleRegistered";
|
|
|
|
export default {
|
|
id: "my-plugin",
|
|
name: "My Plugin",
|
|
register(api: OpenClawPluginApi) {
|
|
const config = normalizeConfig(api);
|
|
|
|
// Gateway lifecycle: only once
|
|
if (!_G[LIFECYCLE_KEY]) {
|
|
_G[LIFECYCLE_KEY] = true;
|
|
// Start sidecars, init global resources
|
|
api.on("gateway_stop", () => { _G[LIFECYCLE_KEY] = false; });
|
|
}
|
|
|
|
// Agent session hooks: every register() call (dedup inside handler)
|
|
registerMyHook(api, config);
|
|
|
|
// Tools
|
|
registerMyTools(api, config);
|
|
|
|
api.logger.info("my-plugin: registered");
|
|
},
|
|
};
|
|
```
|
|
|
|
## Why globalThis?
|
|
|
|
OpenClaw may hot-reload plugins. Module-level variables reset on reload, but `globalThis` persists. All mutable state must be on `globalThis`:
|
|
|
|
- Startup flags → prevent double initialization
|
|
- Dedup sets → prevent double hook execution
|
|
- Runtime references → keep connections alive across reloads
|
|
- Shared registries → preserve cross-plugin state
|
|
|
|
## Naming Convention
|
|
|
|
```
|
|
_<pluginId>PluginXxx # Internal state (e.g., _prismFacetRouters)
|
|
__<pluginId> # Cross-plugin public API (e.g., __yonexusClient)
|
|
```
|