Problem: OpenClaw's 700+ Skills Don't Cover Your Workflow
You're running OpenClaw as your personal AI assistant, but none of the bundled or community skills handle your specific use case - whether it's a custom API integration, domain-specific tooling, or a unique automation workflow.
You'll learn:
- How to structure an AgentSkills-compatible skill
- When to build custom vs. using existing skills
- How to integrate Python scripts and external tools
- Testing and debugging your skills
Time: 20 min | Level: Intermediate
Why Build Custom Skills
OpenClaw ships with 50+ bundled skills and has 700+ community skills available on ClawdHub. But the real power comes from creating skills tailored to your exact workflow.
Common symptoms you need a custom skill:
- Repetitive tasks with no existing automation
- Domain-specific tools not covered by bundled skills
- Deep integration needs with a specific service
- Workflows combining multiple steps uniquely
What skills enable:
- Persistent automation across extended timeframes
- Context-aware workflows that understand your data
- Self-hosted control without SaaS limitations
Solution
Step 1: Set Up Your Skills Directory
OpenClaw loads skills from three locations with specific precedence:
# Create workspace skill (highest precedence)
cd ~/.openclaw/workspace/skills
mkdir my-custom-skill
cd my-custom-skill
Skill directory precedence:
<workspace>/skills- Highest, per-agent~/.openclaw/skills- Shared across agents- Bundled skills - Lowest
Why this works: Workspace skills override everything, letting you customize without modifying bundled code.
Step 2: Create the SKILL.md Structure
Every skill needs a SKILL.md file with YAML frontmatter and instructions:
---
name: wine-cellar-tracker
description: Track wine inventory with vintage, region, and drinking windows
metadata:
openclaw:
requires:
bins: ["python3"]
env: ["CELLAR_DB_PATH"]
primaryEnv: "CELLAR_DB_PATH"
---
# Wine Cellar Tracker
Use this skill when the user wants to:
- Add wine to inventory
- Check drinking windows
- Query by region or vintage
- Get tasting notes
## Tools
This skill uses a Python script for database operations.
## Instructions
When the user asks to add wine:
1. Run `python3 scripts/add_wine.py --name "Wine Name" --vintage 2018 --region "Napa Valley"`
2. Confirm the addition with the database ID
When querying inventory:
1. Run `python3 scripts/query_wines.py --filter "region=Napa"`
2. Present results in a readable format
## Example Usage
User: "Add the 2018 Caymus to my cellar"
Agent: [Runs add_wine.py with parsed parameters]
Agent: "Added Caymus 2018 Napa Valley to your cellar (ID: 42)"
Critical fields:
name: Unique identifier, use kebab-casedescription: Triggers when OpenClaw should load this skillmetadata.openclaw.requires.bins: Required executablesmetadata.openclaw.requires.env: Environment variables needed
Step 3: Add Supporting Scripts
Create a scripts/ directory for helper code:
# scripts/add_wine.py
import argparse
import json
import os
from pathlib import Path
def add_wine(name, vintage, region, notes=""):
db_path = Path(os.getenv("CELLAR_DB_PATH", "~/wine_cellar.json")).expanduser()
# Load existing data
if db_path.exists():
with open(db_path) as f:
cellar = json.load(f)
else:
cellar = {"wines": []}
# Add new entry
wine_id = len(cellar["wines"]) + 1
cellar["wines"].append({
"id": wine_id,
"name": name,
"vintage": vintage,
"region": region,
"notes": notes,
"added": "2026-02-06"
})
# Save back
with open(db_path, "w") as f:
json.dump(cellar, f, indent=2)
print(f"Added {name} {vintage} (ID: {wine_id})")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--name", required=True)
parser.add_argument("--vintage", type=int, required=True)
parser.add_argument("--region", required=True)
parser.add_argument("--notes", default="")
args = parser.parse_args()
add_wine(args.name, args.vintage, args.region, args.notes)
Why Python here: AgentSkills can use any language. Python is ideal for data manipulation, API calls, and file operations.
Make it executable:
chmod +x scripts/add_wine.py
Step 4: Configure in openclaw.json
Register your skill and provide environment variables:
{
"skills": {
"entries": {
"wine-cellar-tracker": {
"enabled": true,
"env": {
"CELLAR_DB_PATH": "/Users/you/Documents/wine_cellar.json"
}
}
}
}
}
If it fails:
- Skill not loading: Check that
namein SKILL.md matches the key inopenclaw.json - Binary not found: Verify Python is in PATH with
which python3 - Env vars not set: OpenClaw only injects these at runtime for that skill
Step 5: Test Your Skill
Refresh skills without restarting:
# Force skill reload
openclaw agent --message "refresh skills"
# Or restart gateway
openclaw gateway restart
Test via chat interface:
You: Add 2018 Opus One to my wine cellar, Napa Valley region
Bot: [Uses wine-cellar-tracker skill]
Bot: Added Opus One 2018 (ID: 1) to your cellar
Debug mode:
# Run with debug logging
DEBUG=* openclaw gateway
# Check skill was loaded
openclaw skills list
You should see: Your skill name in the eligible skills list, and successful execution in logs.
Verification
Test the complete workflow:
# Add a wine
echo "Add 2019 Screaming Eagle to cellar, notes: Needs 5 more years" | openclaw agent
# Query by region
echo "Show me all Napa Valley wines" | openclaw agent
You should see: The agent using your custom skill and returning accurate data from your JSON database.
Advanced Patterns
Multi-Step Workflows
Skills can orchestrate complex operations:
## Instructions
When the user wants to prepare a wine for serving:
1. Query optimal temperature: `python3 scripts/get_temp.py --wine-id {id}`
2. Check decant time: `python3 scripts/decant_time.py --vintage {vintage}`
3. Set reminder: `python3 scripts/set_reminder.py --minutes {decant_minutes}`
API Integrations
Connect to external services:
# scripts/wine_rating.py
import requests
import os
def get_rating(wine_name, vintage):
api_key = os.getenv("WINE_API_KEY")
response = requests.get(
f"https://api.wine-searcher.com/rating",
params={"name": wine_name, "vintage": vintage},
headers={"Authorization": f"Bearer {api_key}"}
)
return response.json()["rating"]
Then add to openclaw.json:
{
"skills": {
"entries": {
"wine-cellar-tracker": {
"apiKey": "wine_searcher_key",
"env": {
"WINE_API_KEY": "your-api-key-here"
}
}
}
}
}
Using MCP Servers
Skills can leverage Model Context Protocol servers for deeper integrations:
---
name: database-ops
description: Direct PostgreSQL operations via MCP
metadata:
openclaw:
requires:
bins: ["npx"]
---
# Database Operations
This skill uses the PostgreSQL MCP server.
## Instructions
When querying the database:
1. Use the MCP postgres tool to execute queries
2. Return results in a formatted table
What You Learned
- Skills are folders with SKILL.md plus optional scripts
- AgentSkills format works across Claude Code, Cursor, and other tools
- Workspace skills override bundled skills by design
- Python is ideal for data/API tasks, but any language works
When NOT to build:
- Existing bundled skills can be composed together
- The workflow is too simple to justify maintenance
- A community skill already exists on ClawdHub
Limitations:
- Skills load at session start (changes need refresh)
- Binary requirements must exist both on host and in Docker sandboxes
- Environment variables are scoped to agent runs, not global
Next:
Real-World Examples from the Community
Image Watermarking Skill
A user created a skill to resize photos and add watermarks from WhatsApp:
---
name: image-watermark
description: Resize images and add watermarks
metadata:
openclaw:
requires:
bins: ["python3"]
env: ["LOGO_PATH"]
---
# Image Watermark
When user sends an image and asks to watermark:
1. Save image to temp location
2. Run `python3 scripts/watermark.py --input {path} --output {output} --size {dimensions}`
3. Return watermarked image
The Python script uses PIL to composite the watermark and resize. Now the user can send photos from their phone and get back watermarked, resized versions ready for LinkedIn.
Asana Task Management
Deep integration with project management:
---
name: asana-workflow
description: Create tasks, query projects, update status
metadata:
openclaw:
requires:
env: ["ASANA_TOKEN", "ASANA_WORKSPACE_ID"]
---
# Asana Workflow
When user creates a task:
1. Parse task details (title, description, due date)
2. Call Asana API via Python requests
3. Confirm creation with task URL
RTSP Camera Monitoring
A skill that captures frames from security cameras:
---
name: camsnap
description: Capture frames from RTSP/ONVIF cameras
metadata:
openclaw:
requires:
bins: ["ffmpeg"]
---
# Camera Snapshot
When user asks for camera feed:
1. Use ffmpeg to pull RTSP stream
2. Extract current frame
3. Send image to user
Common Pitfalls
Skill not triggering:
- Description is too vague - be specific about when to use it
- Check
openclaw skills listto verify it loaded - Verify binary dependencies exist
Permission errors:
- Scripts need
chmod +x - Check file paths are absolute or properly resolved
- Verify OpenClaw has access to directories
Environment variables not working:
- Must be defined in
openclaw.jsonunder the skill entry - Use
metadata.openclaw.primaryEnvfor the main API key - Remember they're only injected during agent runs
Sharing Your Skill
Once your skill works, share it with the community:
- Clean up the code:
# Remove hardcoded paths
# Add error handling
# Document required setup
- Add installation instructions:
## Installation
1. Copy to `~/.openclaw/skills/wine-cellar-tracker/`
2. Install dependencies: `pip install -r requirements.txt`
3. Configure in openclaw.json
4. Set CELLAR_DB_PATH environment variable
- Submit to ClawdHub:
# ClawdHub uses npm-style versioning
git tag v1.0.0
git push --tags
Community benefits:
- 700+ skills already available
- Active development and improvements
- Cross-compatible with AgentSkills ecosystem