Tools
Skill Search
OpenClaw skill discovery plugin with BM25 + semantic vector search
Install
npm install
#
Configuration Example
# skills/github/manifest.yaml
intentExamples:
- check if my PR is passing CI
- create a GitHub issue for this bug
- list open pull requests assigned to me
- review someone's code changes
- view failed GitHub Actions logs
README
# openclaw-skill-search
OpenClaw plugin for on-demand skill discovery. Instead of loading all Skills into the system prompt on every turn, Claude searches for relevant Skills on demand using BM25 keyword search (with optional vector/semantic search).
## Why
OpenClaw normally injects every enabled Skill's full content into the system prompt. With 50+ Skills this:
- Consumes thousands of tokens per API call (even with prompt caching)
- Degrades Claude's ability to pick the right Skill as the list grows
- Breaks prompt cache whenever any Skill is updated
This plugin replaces that with an on-demand pattern: Skills are indexed locally, and Claude calls `skill_search` when it needs a specific capability.
## How It Works
```
User sends message
↓
Claude receives task involving an external service or workflow
↓
Calls skill_search("send a GitHub PR review comment")
↓
BM25Index searches skill index in memory
↓
Returns matching SKILL.md content to Claude
↓
Claude reads the instructions and acts
```
Skills are excluded from the system prompt via `disable-model-invocation: true` in their SKILL.md frontmatter. The plugin injects a system prompt rule telling Claude to call `skill_search` **first** whenever a task involves an external service, app, or multi-step workflow.
## Search Quality
The index is built from each skill's `manifest.yaml` when present. If no `manifest.yaml` exists, the plugin falls back to reading `name` and `description` from the `SKILL.md` frontmatter automatically — so any skill with a `SKILL.md` is searchable out of the box.
When a `manifest.yaml` is present, the BM25 index uses:
| Field | Weight | Notes |
|-------|--------|-------|
| `name` | 2× | Repeated to increase weight |
| `intentExamples` | high | Most important for retrieval — write as real user phrases |
| `semanticDescription` | normal | Short description from user's POV |
| `tags` | normal | Keywords |
| `category` | low | code / communication / content / data |
**To improve search accuracy**, edit `manifest.yaml` and add realistic `intentExamples`:
```yaml
# skills/github/manifest.yaml
intentExamples:
- check if my PR is passing CI
- create a GitHub issue for this bug
- list open pull requests assigned to me
- review someone's code changes
- view failed GitHub Actions logs
```
Optionally add vector/semantic search by configuring an OpenAI-compatible embedding API (see Configuration below).
## Installation
```bash
# 1. Install dependencies
cd /path/to/openclaw-skill-search
npm install
# 2. Link to your OpenClaw installation
openclaw plugins install --link /path/to/openclaw-skill-search
openclaw plugins enable skill-search
# 3. Configure skillsDirs (path to your workspace skills)
openclaw config set plugins.entries.skill-search.config.skillsDirs[0] \
"$HOME/.openclaw/workspace/skills"
# 4. Restart gateway (Mac: menubar → Restart Gateway)
```
## Preparing Skills
Any skill directory containing a `SKILL.md` is indexed automatically — no `manifest.yaml` required. The plugin reads `name` and `description` from the frontmatter as a fallback.
To get better search accuracy, run the migration script which copies bundled OpenClaw skills to your workspace and generates a `manifest.yaml` (with `intentExamples`) for each:
- Copy bundled OpenClaw skills to workspace (upgrade-safe)
- Add `disable-model-invocation: true` to each SKILL.md (excludes from system prompt)
- Generate `manifest.yaml` for higher-quality BM25 indexing
```bash
# From the openclaw source repo directory:
node --import tsx/esm scripts/migrate-skills-to-workspace.ts
# Dry-run first to preview:
node --import tsx/esm scripts/migrate-skills-to-workspace.ts --dry-run
```
## Configuration
All config goes under `plugins.entries.skill-search.config` in `~/.openclaw/openclaw.json`.
```yaml
# ~/.openclaw/openclaw.json (excerpt)
plugins:
entries:
skill-search:
enabled: true
config:
# Directories to scan for skills (required)
skillsDirs:
- /Users/you/.openclaw/workspace/skills
# Max results per search (default: 5)
topK: 5
# Min relevance score 0–1, 0 = no filter (default: 0)
minScore: 0
# Optional: enable vector/semantic search
# Any OpenAI-compatible embedding API works
embedding:
baseUrl: https://ark.cn-beijing.volces.com/api/v3 # ByteDance Ark
# baseUrl: https://api.openai.com/v1 # OpenAI
# baseUrl: http://localhost:11434/v1 # Ollama
model: doubao-embedding
apiKey: your-api-key
timeoutMs: 10000
```
## Upgrade Safety
- **Plugin code** lives in its own directory, independent of OpenClaw
- **Workspace skills** live in `~/.openclaw/workspace/skills/`, never touched by `npm update openclaw`
- **Manifest files** (`manifest.yaml`) are generated once and stay alongside SKILL.md
When OpenClaw upgrades its bundled skills, your workspace copies take precedence (workspace > bundled in OpenClaw's loading order). Re-run the migration script with `--force` to pull in updated SKILL.md content from new OpenClaw versions.
## File Structure
```
openclaw-skill-search/
├── index.ts # Plugin entry point
├── openclaw.plugin.json # Plugin manifest (id, configSchema)
├── package.json
└── src/
├── skill-index.ts # BM25 + cosine vector index + RRF fusion
├── skill-registry.ts # Manifest loader, search, singleton
├── skill-search-tool.ts # Claude tool definition
└── types.ts # SkillManifest, SkillSearchConfig types
```
tools
Comments
Sign in to leave a comment