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?