Building Your Own OpenClaw Skills
Write custom TypeScript skills for OpenClaw β from a simple Hello World to full external API integrations. Step-by-step tutorial with real examples.
February 8, 2026
Note: OpenClaw was previously known as MoltBot and Clawdbot. Skills are modular extensions for OpenClaw. Want a smart home integration? Build a skill. Crypto price tracker? Skill. Any automation can be packaged into one.
Skill Structure
my-skill/
βββ SKILL.md # Instructions for the AI
βββ package.json # Metadata and dependencies
βββ src/
β βββ index.ts # Entry point
βββ scripts/ # Helper scripts (optional)
Quick Start: Hello World
Create the folder
mkdir -p ~/.openclaw/skills/hello-world
cd ~/.openclaw/skills/hello-world
Write SKILL.md
This is the most important file β it tells the AI when and how to use your skill:
# Hello World Skill
Use this skill when the user asks you to say hello
or wants to test that skills are working.
## Commands
### say_hello
Run the script `scripts/hello.sh` with the user's name.
Examples:
- "Say hello" β `./scripts/hello.sh "User"`
- "Greet Sarah" β `./scripts/hello.sh "Sarah"`
Create the script
# scripts/hello.sh
#!/bin/bash
NAME="${1:-World}"
echo "π Hey, $NAME! OpenClaw is up and running!"
chmod +x scripts/hello.sh
Test it
Send your bot:
βSay hello to Alexβ
The bot will execute the script and reply with the output.
Intermediate Example: Weather Skill
Project structure
weather-skill/
βββ SKILL.md
βββ package.json
βββ scripts/
βββ weather.ts
SKILL.md
# Weather Skill
Fetches current weather and forecasts for any city.
## When to Use
- User asks about the weather
- User mentions a city + "weather / temperature / forecast"
## Commands
### get_weather
```bash
npx ts-node scripts/weather.ts "City Name"
Returns JSON with temperature, description, and humidity.
Examples
- βWhatβs the weather in New York?β β get_weather βNew Yorkβ
- βWill it rain in Chicago tomorrow?β β get_weather βChicagoβ
### scripts/weather.ts
```typescript
import https from 'https';
const city = process.argv[2] || 'New York';
const apiKey = process.env.OPENWEATHER_API_KEY || 'demo';
const url = `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(city)}&appid=${apiKey}&units=imperial`;
https.get(url, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => {
try {
const w = JSON.parse(data);
console.log(JSON.stringify({
city: w.name,
temp: Math.round(w.main.temp) + 'Β°F',
feels_like: Math.round(w.main.feels_like) + 'Β°F',
description: w.weather[0].description,
humidity: w.main.humidity + '%',
wind: Math.round(w.wind.speed) + ' mph',
}, null, 2));
} catch (e) {
console.error('Error parsing response:', e);
}
});
});
package.json
{
"name": "weather-skill",
"version": "1.0.0",
"dependencies": {
"typescript": "^5.0.0",
"ts-node": "^10.0.0"
}
}
Advanced: Skill with Persistent State
Skills can store data between sessions using a local JSON file:
// scripts/tracker.ts
import fs from 'fs';
const DATA_FILE = `${process.env.HOME}/.openclaw/skills/tracker/data.json`;
function loadData() {
if (!fs.existsSync(DATA_FILE)) return { items: [] };
return JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
}
function saveData(data: any) {
fs.mkdirSync(path.dirname(DATA_FILE), { recursive: true });
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2));
}
const [action, ...args] = process.argv.slice(2);
const data = loadData();
if (action === 'add') {
data.items.push({ text: args.join(' '), date: new Date().toISOString() });
saveData(data);
console.log(`β
Added: ${args.join(' ')}`);
} else if (action === 'list') {
data.items.forEach((item: any, i: number) => {
console.log(`${i + 1}. ${item.text}`);
});
}
Publishing to ClawHub
Once your skill is ready, you can publish it to the community registry:
# Log in with your GitHub account
clawhub login
# Publish
clawhub publish ./my-skill
Best Practices
- Keep SKILL.md concise β the AI reads it on every interaction. Shorter is better.
- Output JSON β structured output makes it easier for the AI to parse results.
- Handle errors gracefully β print meaningful error messages to help with debugging.
- Use environment variables β never hardcode API keys in your scripts.
- Test edge cases β what happens if the city name has spaces? If the API is down?
Whatβs Next?
- Browse the Skills Catalog for inspiration
- Check out automation examples to see skills in action