Files
ClawSkills/development/workflows/openclaw-plugin-development.md
zhi 238574ffd2 feat: add development and hf-hangman-lab skills
development: absorbed openclaw-plugin-dev as a workflow, with
reference docs for plugin structure, hooks, tools, state, config.

hf-hangman-lab: hf-wakeup workflow — full agent wakeup lifecycle:
set busy → check due slots → select & defer → identify task →
plan work → create work channel → execute. All branches end with
status reset to idle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 13:31:27 +00:00

129 lines
3.4 KiB
Markdown

# OpenClaw Plugin Development
When creating or modifying an OpenClaw plugin.
> Reference docs in `{baseDir}/docs/` cover each topic in detail.
## Process
### 1. Scaffold
Create the project structure:
```
my-plugin/
plugin/
index.ts # export default { id, name, register }
openclaw.plugin.json # config schema (additionalProperties: false)
package.json # name, version, type: module
hooks/ # one file per hook handler
tools/ # tool registrations
core/ # pure logic (no plugin-sdk imports)
scripts/
install.mjs # --install / --uninstall
package.json # dev dependencies
tsconfig.plugin.json
.gitignore
```
See `{baseDir}/docs/structure.md` for conventions.
### 2. Entry Point
Follow the globalThis lifecycle pattern:
```typescript
const _G = globalThis as Record<string, unknown>;
const LIFECYCLE_KEY = "_myPluginLifecycleRegistered";
export default {
id: "my-plugin",
name: "My Plugin",
register(api) {
if (!_G[LIFECYCLE_KEY]) {
_G[LIFECYCLE_KEY] = true;
// gateway-level init (once)
api.on("gateway_stop", () => { _G[LIFECYCLE_KEY] = false; });
}
// agent-level hooks (every register call, dedup inside)
registerMyHook(api);
registerMyTools(api);
},
};
```
See `{baseDir}/docs/entry-point.md` for details.
### 3. Hooks
Each hook in its own file under `hooks/`. Must use dedup on globalThis:
- `before_model_resolve`, `before_prompt_build` → WeakSet on event object
- `agent_end` → Set on runId with size cap 500
- `gateway_start/stop` → globalThis flag
If returning `prependSystemContext`/`appendSystemContext`, set `allowPromptInjection: true` in config.
See `{baseDir}/docs/hooks.md`.
### 4. Tools
Interface is `inputSchema` + `execute` (not `parameters` + `handler`):
```typescript
api.registerTool({
name: "my-tool",
inputSchema: { type: "object", properties: { ... }, required: [...] },
execute: async (toolCallId, params) => { return { result: "ok" }; },
});
```
For agent context access, use factory form: `api.registerTool((ctx) => ({ ... }))`.
See `{baseDir}/docs/tools.md`.
### 5. State Management
All mutable state on `globalThis`, not module-level variables (hot reload resets modules).
- Business state, dedup sets, lifecycle flags → `globalThis`
- Cross-plugin API → `globalThis.__pluginId`
- Pure functions → module-level is fine
See `{baseDir}/docs/state.md`.
### 6. Config Schema
`openclaw.plugin.json` must have `additionalProperties: false`. Every config field in install script must exist in schema. Never set sensitive fields (tokens) in install script.
See `{baseDir}/docs/config.md`.
### 7. Install Script
```bash
node scripts/install.mjs --install # build, copy to ~/.openclaw/plugins/<id>, update config
node scripts/install.mjs --uninstall # remove from config and filesystem
```
See `{baseDir}/docs/config.md`.
### 8. Build & Test
```bash
npm run build
node scripts/install.mjs --install
openclaw gateway restart
openclaw logs --follow
```
### 9. Checklist Before Deploy
- [ ] Hook handlers have dedup on globalThis
- [ ] Gateway lifecycle protected by globalThis flag
- [ ] Business state on globalThis
- [ ] Schema matches actual config fields
- [ ] Install script uses setIfMissing, no sensitive fields
- [ ] Clean dist before copy (`rmSync`)
See `{baseDir}/docs/debugging.md` for full checklist.