Back to Docs
Developer Guide

How to Build a Skill

Skills are Python or JavaScript packages that give AI agents new capabilities. This guide walks through building, testing, and publishing one to CrustyClaws.

1

File Structure

Every skill is a directory with three files. Agents care most about SKILL.md — write it first.

Directory layout
my-weather-skill/
ā”œā”€ā”€ SKILL.md       # Documentation (what it does, inputs, outputs, examples)
ā”œā”€ā”€ plugin.json    # Metadata and tool definitions
└── index.js       # Implementation (or index.py for Python)
2

Write SKILL.md

SKILL.md is what AI agents read to understand your skill. Be explicit about inputs, outputs, and any API keys or environment variables required.

SKILL.md
---
name: my-weather-skill
version: 1.0.0
---

# My Weather Skill

Fetches current weather data for any city using the OpenWeather API.

## Inputs
- `city` (string, required) — the city name to look up

## Outputs
Returns a JSON object with `temperature`, `condition`, and `humidity`.

## Notes
Requires `OPENWEATHER_API_KEY` set in your environment.
3

Define plugin.json

plugin.json declares your skill's metadata and tools. The tools array uses the same JSON Schema format as tool-calling LLMs.

plugin.json
{
  "name": "my-weather-skill",
  "version": "1.0.0",
  "description": "Fetch current weather for any city",
  "author": "your-github-username",
  "entrypoint": "index.js",
  "tools": [
    {
      "name": "get_weather",
      "description": "Get current weather for a city",
      "parameters": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string",
            "description": "The city name"
          }
        },
        "required": ["city"]
      }
    }
  ]
}
nameUnique slug — lowercase, hyphens only. Becomes the openclaw install <name> command.
entrypointindex.js for JavaScript, index.py for Python.
toolsTool definitions — each needs a name, description, and JSON Schema parameters block.
4

Write the Implementation

Export one function per tool. Function names must match the name field in plugin.json.

JavaScript (index.js)

index.js
export async function get_weather({ city }) {
  const apiKey = process.env.OPENWEATHER_API_KEY
  const res = await fetch(
    `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`
  )
  if (!res.ok) throw new Error(`Weather API error: ${res.status}`)
  const data = await res.json()
  return {
    temperature: data.main.temp,
    condition: data.weather[0].description,
    humidity: data.main.humidity,
  }
}

Python (index.py)

index.py
import os
import httpx

async def get_weather(city: str) -> dict:
    """Get current weather for a city."""
    api_key = os.environ["OPENWEATHER_API_KEY"]
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.openweathermap.org/data/2.5/weather",
            params={"q": city, "appid": api_key, "units": "metric"},
        )
        res.raise_for_status()
        data = res.json()
    return {
        "temperature": data["main"]["temp"],
        "condition": data["weather"][0]["description"],
        "humidity": data["main"]["humidity"],
    }
5

Test Locally

Install from a local path before publishing to catch any issues:

Terminal
openclaw install ./my-weather-skill
openclaw run get_weather --city "London"
6

Publish to CrustyClaws

Two options — pick whichever fits your workflow:

Option A — Upload via the web

Go to /upload, fill in title, description, price, and paste your GitHub file URL.

Option B — Publish via the openclaw/skills repo

Open a PR to the openclaw/skills GitHub repo. CrustyClaws auto-syncs from that repo hourly.

Terminal
# Fork openclaw/skills, add your skill directory, open a PR
git clone https://github.com/openclaw/skills
cp -r ./my-weather-skill skills/your-username/my-weather-skill
git add . && git commit -m "add my-weather-skill"
git push && gh pr create

Ready to publish?

Upload a skill and start earning.