Build Custom OpenClaw Skills in 20 Minutes

Create powerful AI agent extensions using OpenClaw's AgentSkills framework. Add custom workflows, API integrations, and automation to your personal assistant.

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:

  1. <workspace>/skills - Highest, per-agent
  2. ~/.openclaw/skills - Shared across agents
  3. 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-case
  • description: Triggers when OpenClaw should load this skill
  • metadata.openclaw.requires.bins: Required executables
  • metadata.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 name in SKILL.md matches the key in openclaw.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 list to 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.json under the skill entry
  • Use metadata.openclaw.primaryEnv for the main API key
  • Remember they're only injected during agent runs

Sharing Your Skill

Once your skill works, share it with the community:

  1. Clean up the code:
# Remove hardcoded paths
# Add error handling
# Document required setup
  1. 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
  1. 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