The Operator Vault Developer Guide

How to Build Custom OpenClaw Skills

Connect any tool, any API, any workflow. If it has an endpoint, you can build a skill for it.

We've built over a dozen custom skills for our own workflows and published several to ClawHub. This guide walks you through the complete process, from idea to published skill, with real code examples and honest advice about what works.

$ clawhub publish ./my-skill --tags latest

Why build your own?

Your competitive moat.

ClawHub covers the common tools. Thousands of community skills handle standard integrations like Slack, GitHub, Shopify, and Google Sheets. But the skills nobody else has are the ones that give you an edge.

Proprietary integrations

Your internal CRM, custom ERP, or homegrown project management tool. Nobody on ClawHub is going to build a skill for your company's internal API. That is your job, and it gives your automation capabilities that competitors cannot replicate.

Custom data sources

Private databases, internal wikis, proprietary datasets. A skill that connects your agent to your company's knowledge base is worth more than a hundred generic integrations. The data is yours. The automation should be too.

Workflow-specific logic

Generic skills handle generic tasks. Your business has specific workflows with specific rules, edge cases, and requirements. A custom skill encodes your exact process, so the agent follows it perfectly every time.

The bottom line: Community skills are commodities. Custom skills are competitive advantages. Every business that takes AI automation seriously will eventually need skills that do not exist on any marketplace.

What you need

Prerequisites.

Building skills is not hard, but you do need a few things in place before you start.

Working OpenClaw install

You need a running instance to test skills against. Follow our setup guide if you have not installed yet.

Setup Guide

Node.js 22+

OpenClaw runs on Node.js. Skills execute in the same runtime. Older versions may work but are not tested.

Basic TypeScript or JavaScript

You do not need to be an expert. If you can write a function that makes an API call and returns JSON, you have enough.

API credentials for your target service

Whatever you are integrating with, you will need its API key, OAuth token, or authentication credentials.

How skills work

The architecture in 60 seconds.

Understanding how the agent discovers and uses skills will make everything else click. The flow is straightforward.

SKILL.md
Defines capability
Agent Reads
Picks relevant skills
User Request
Triggers invocation
Your Code
Processes inputs
Output
Structured response

Key things to understand

Skills are loaded at session start and cached for the entire session. Changes to SKILL.md are picked up automatically by the skills watcher.

Each skill adds approximately 97 characters plus the length of your field values to the agent's system prompt. Keep descriptions concise to minimize token overhead.

The agent decides when to invoke your skill based on the description field. If the description is vague, the agent may not know when your skill is appropriate.

Environment variables from skills.entries.<name>.env in the config are injected before each agent run and restored afterward. Your code never sees other skills' credentials.

You can reference the skill's directory in your instructions using {baseDir}. This resolves to the actual path at runtime.

The SKILL.md manifest

The file that defines everything.

Every skill starts with a SKILL.md file. It uses YAML frontmatter (single-line keys only) followed by Markdown instructions. The frontmatter tells OpenClaw what the skill is. The Markdown body tells the agent how to use it.

Example SKILL.md
---
name: Shopify Returns Processor
description: Pulls order and return data from a Shopify store. Accepts a date range and store URL. Returns structured JSON with order IDs, amounts, reasons, and resolution status.
version: 1.0.0
skillKey: shopify-returns
emoji: 🛒
homepage: https://github.com/yourname/shopify-returns
os: darwin, linux, win32
install: npm install
metadata: {"openclaw":{"requires":{"env":["SHOPIFY_API_KEY","SHOPIFY_STORE_URL"]}}}
primaryEnv: shopify
always: false
---

# Shopify Returns Processor

Process returns data from any Shopify store.

## Usage

Call this skill with a date range to pull returns:
- Start date (ISO 8601 format)
- End date (ISO 8601 format)
- Optional: filter by return reason

The skill reads credentials from environment variables.
Store URL and API key must be configured in your OpenClaw
config under skills.entries.shopify.env.

## Output Format

Returns a JSON array of return objects with:
- orderId, orderNumber
- returnDate, reason, status
- lineItems (array of products returned)
- refundAmount, currency

Files are saved to {baseDir}/output/ by default.

Field reference

nameRequired

Human-readable skill name displayed in the agent's tool list and on ClawHub.

"Shopify Returns Processor"
descriptionRequired

What the skill does in 1-2 sentences. The agent reads this to decide when to invoke the skill. Be specific about inputs and outputs.

"Pulls order and return data from Shopify. Accepts a date range and returns structured JSON with order IDs, amounts, and return reasons."
versionRequired

Semver version string. Bump this every time you publish an update.

"1.2.0"
skillKeyRequired

Unique identifier for the skill. Used internally by OpenClaw for routing. Use kebab-case.

"shopify-returns"
emojiOptional

A single emoji shown next to the skill name in logs and the agent's tool list.

"🛒"
homepageOptional

URL to the skill's documentation or GitHub repo.

"https://github.com/yourname/shopify-returns"
osOptional

Operating systems the skill supports. Use Node.js process.platform values.

"darwin, linux, win32"
installOptional

Command that runs once during setup. Typically used to install dependencies. Runs from the skill's directory.

"npm install"
metadataOptional

Single-line JSON object for OpenClaw-specific config. Includes requires.env, requires.bins, requires.anyBins, and requires.config for gating.

'{"openclaw":{"requires":{"env":["SHOPIFY_API_KEY","SHOPIFY_STORE_URL"]}}}'
primaryEnvOptional

Links the skill to a named entry in skills.entries.<name>.apiKey in your config. The agent uses this for credential injection.

"shopify"
alwaysOptional

When set to true, the skill is always loaded regardless of relevance scoring. Use sparingly as it adds to token cost.

"false"

Important: The metadata field must be a single-line JSON object. Multi-line YAML values are not supported in SKILL.md frontmatter. All frontmatter keys must be on a single line.

This is the most common mistake we see developers make. If your skill is not loading, check the metadata format first.

The 6-step build process

From idea to published skill.

This is the exact process we follow for every skill we build. Each step has code examples and patterns you can adapt.

01

Define the single capability

Every skill should do one thing well. Use the verb-noun pattern: 'Pull Shopify returns', 'Monitor Reddit trends', 'Generate invoice PDF'. If you need the word 'and' to describe it, you need two skills. The agent picks skills based on their description. A focused skill gets invoked at the right time. A vague one gets ignored or misused.

02

Write the SKILL.md manifest

Start with the frontmatter fields above. The description is the most important field. Write it like you are explaining the skill to a colleague who needs to decide whether to use it. Include what inputs it expects and what output it returns.

Minimal SKILL.md template
---
name: Your Skill Name
description: One to two sentences explaining what this skill does, what inputs it expects, and what it returns.
version: 1.0.0
skillKey: your-skill-name
install: npm install
metadata: {"openclaw":{"requires":{"env":["YOUR_API_KEY"]}}}
primaryEnv: your-service
---

# Your Skill Name

Instructions for the agent on how to use this skill.

## Inputs
- Describe expected inputs here

## Output
- Describe output format here

## Files
Working directory: {baseDir}
03

Design inputs and outputs

Think in TypeScript types, even if you write JavaScript. Define exactly what the agent sends in and what your skill sends back. Structured I/O makes the agent's job easier and your skill more reliable. Never rely on free-form text when a typed object will work.

Type definitions (for your reference)
// Input your skill expects from the agent
interface ShopifyReturnsInput {
  storeUrl: string;
  startDate: string;  // ISO 8601
  endDate: string;    // ISO 8601
  reasonFilter?: string;
}

// Output your skill returns
interface ShopifyReturnsOutput {
  success: boolean;
  totalReturns: number;
  returns: Array<{
    orderId: string;
    orderNumber: string;
    returnDate: string;
    reason: string;
    status: "pending" | "approved" | "rejected";
    refundAmount: number;
    currency: string;
    lineItems: Array<{
      productName: string;
      quantity: number;
      sku: string;
    }>;
  }>;
  errors?: string[];
}
04

Write the handler logic

This is where the actual work happens. Keep it clean: validate inputs, make the API call, handle errors, return structured output. Use environment variables for credentials. Never hardcode API keys, tokens, or URLs.

Handler pattern
// index.ts - main handler
const SHOPIFY_API_KEY = process.env.SHOPIFY_API_KEY;
const SHOPIFY_STORE_URL = process.env.SHOPIFY_STORE_URL;

if (!SHOPIFY_API_KEY || !SHOPIFY_STORE_URL) {
  console.error(JSON.stringify({
    success: false,
    error: "Missing required environment variables: SHOPIFY_API_KEY, SHOPIFY_STORE_URL"
  }));
  process.exit(1);
}

async function fetchReturns(startDate: string, endDate: string) {
  const url = `${SHOPIFY_STORE_URL}/admin/api/2024-01/orders.json`;

  try {
    const response = await fetch(url, {
      headers: {
        "X-Shopify-Access-Token": SHOPIFY_API_KEY,
        "Content-Type": "application/json",
      },
    });

    if (!response.ok) {
      throw new Error(`Shopify API returned ${response.status}: ${response.statusText}`);
    }

    const data = await response.json();
    // Process and filter returns...

    return {
      success: true,
      totalReturns: data.orders.length,
      returns: data.orders,
    };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

// Parse args and run
const args = process.argv.slice(2);
fetchReturns(args[0], args[1])
  .then(result => console.log(JSON.stringify(result, null, 2)));
05

Test locally

Copy your skill folder into your OpenClaw workspace's skills directory. The skills watcher detects new SKILL.md files automatically and makes the skill available to the agent. Start a new session and ask the agent to use your skill. Check that it invokes correctly, handles edge cases, and returns the expected output format.

Local testing workflow
# Copy skill to your workspace
cp -r ./my-skill ~/openclaw-workspace/skills/my-skill

# The skills watcher auto-detects the new SKILL.md
# Start a chat and test it
# "Use the shopify-returns skill to pull returns for the last 7 days"

# Check output, fix issues, iterate
# Changes to SKILL.md are picked up automatically
06

Publish to ClawHub

Once you are satisfied with the skill, publish it. You need a GitHub account that is at least one week old. Choose a unique slug (lowercase, hyphens only). Set the version and tag it as latest. ClawHub will automatically run VirusTotal scanning on your submission.

Publishing
# First publish
clawhub publish ./my-skill \
  --slug shopify-returns \
  --name "Shopify Returns Processor" \
  --version 1.0.0 \
  --tags latest

# Future updates
clawhub publish ./my-skill \
  --slug shopify-returns \
  --name "Shopify Returns Processor" \
  --version 1.1.0 \
  --tags latest

# Or batch sync all changed skills
clawhub sync --all

Design principles

Six rules for great skills.

After building and reviewing dozens of skills, these principles consistently separate the ones that work reliably from the ones that cause problems.

One capability per skill

A skill that does one thing is easier to test, easier to describe, and easier for the agent to invoke correctly. If your skill does two things, split it into two skills. The agent can chain them.

Structured inputs and outputs

Define clear types for what goes in and what comes out. JSON objects with explicit fields. Never return unstructured text when a typed response will work. The agent handles structured data much better.

Never hardcode credentials

API keys, tokens, and secrets belong in environment variables. Use the metadata.openclaw.requires.env field to declare what your skill needs. OpenClaw injects them at runtime.

Fail loudly

When something goes wrong, return a structured error with a clear message. Never swallow errors silently. The agent needs to know when a skill fails so it can try alternatives or report the issue.

Test every path

Happy path, missing credentials, API errors, malformed inputs, rate limits, timeouts. Test them all locally before publishing. A skill that crashes on bad input erodes trust in your entire workspace.

Version thoughtfully

Use semver properly. Patch for bug fixes. Minor for new features. Major for breaking changes. Your users depend on version numbers to decide whether an update is safe to pull.

The Operator Vault Workshop

Get your dev environment set up right.

Building skills requires a working OpenClaw installation. The $19 workshop covers secure setup, first run, and configuring your workspace for skill development. In under 15 minutes, you will have everything you need to start building.

Start Workshop

Skill ideas by business type

What should YOU build?

Not sure where to start? Here are concrete skill ideas for four common business types. Each of these solves a real problem and would be valuable on ClawHub.

E-Commerce

  • Inventory sync across Shopify, Amazon, and your warehouse system
  • Automated review response generator that matches brand voice
  • Returns fraud detector that flags unusual patterns
  • Competitive price monitor that alerts when competitors change pricing
  • Order fulfillment tracker that sends proactive customer updates

SaaS & Tech

  • Customer churn predictor from usage analytics and support tickets
  • Feature request aggregator that clusters similar requests
  • Bug report triager that assigns priority based on impact
  • Release notes generator from git commit history
  • Onboarding progress tracker that nudges inactive users

Professional Services

  • Client intake form processor that creates CRM entries automatically
  • Invoice generator from time tracking data
  • Contract clause extractor for legal review
  • Meeting summary generator with action item tracking
  • Proposal builder from template + client requirements

Education & Training

  • Quiz generator from course content and learning objectives
  • Student progress report builder from LMS data
  • Content adaptation tool that adjusts reading level
  • Plagiarism pattern detector for submitted work
  • Curriculum mapping tool that identifies coverage gaps

Want to see how production-ready skills are built?

Browse Premium Skills

Common mistakes

What goes wrong (and how to fix it).

We have made every one of these mistakes. Save yourself the debugging time.

Multi-line metadata in SKILL.md frontmatter

Keep the metadata field on a single line. YAML multi-line values are not supported. Use a minified JSON string for the metadata object.

Vague description field: "Handles Shopify stuff"

Be specific about inputs and outputs: "Pulls order and return data from Shopify. Accepts date range, returns JSON with order IDs, amounts, and reasons."

Hardcoded API key in the handler code

Use process.env.YOUR_API_KEY and declare the requirement in metadata.openclaw.requires.env. OpenClaw injects credentials at runtime from config.

Swallowing errors with try/catch that returns nothing

Always return a structured error response: { success: false, error: "Descriptive message" }. The agent needs to know what went wrong to take corrective action.

Building a skill that does five things

Split it into five skills. Each skill does one thing. The agent chains them when needed. Single-purpose skills are more reliable, more testable, and more reusable.

Skipping the install field for skills with dependencies

If your skill uses npm packages, include install: "npm install" in the frontmatter. Without this, the skill will fail on first run because dependencies are missing.

Advanced patterns

Level up your skills.

Once you have the basics down, these patterns will make your skills more robust and professional.

Gating fields

Use gating fields in metadata to prevent skills from loading in environments where they cannot work. This avoids confusing error messages when required tools or credentials are missing.

# Require specific environment variables
metadata: {"openclaw":{"requires":{"env":["API_KEY","API_SECRET"]}}}

# Require specific binaries on PATH
metadata: {"openclaw":{"requires":{"bins":["docker","ffmpeg"]}}}

# Require any ONE of these binaries (OR logic)
metadata: {"openclaw":{"requires":{"anyBins":["npm","pnpm","yarn"]}}}

# Require specific config keys
metadata: {"openclaw":{"requires":{"config":["shopify.storeUrl"]}}}

OS-specific skills

If your skill only works on certain operating systems (e.g., it uses macOS-specific APIs or Linux-only tools), declare it in the os field. OpenClaw uses Node.js process.platform values.

# macOS and Linux only
os: darwin, linux

# All platforms
os: darwin, linux, win32

# Linux only (e.g., uses systemd)
os: linux

Environment injection

When you set primaryEnv, OpenClaw links your skill to a named config entry. Users configure credentials once in their config, and they are injected automatically at runtime. After the agent run, the original environment is restored.

User's OpenClaw config
{
  "skills": {
    "entries": {
      "shopify": {
        "apiKey": "shppa_xxxxxxxxxxxxx",
        "env": {
          "SHOPIFY_API_KEY": "shppa_xxxxxxxxxxxxx",
          "SHOPIFY_STORE_URL": "https://mystore.myshopify.com"
        }
      }
    }
  }
}

Recommended file structure

How to organize your skill.

Typical skill directory
my-skill/
├── SKILL.md          # Manifest (required)
├── package.json      # Dependencies
├── tsconfig.json     # TypeScript config (if using TS)
├── src/
│   ├── index.ts      # Main handler
│   ├── types.ts      # Input/output type definitions
│   └── utils.ts      # Helper functions
├── output/           # Default output directory
└── README.md         # Human-readable docs (for GitHub)

SKILL.md is the only required file. Everything else is convention.

Keep the skill directory self-contained. All dependencies, config, and output should live inside it.

Use {baseDir} in SKILL.md instructions so paths resolve correctly regardless of where the skill is installed.

Include a README.md for humans reading your code on GitHub. SKILL.md is for the agent.

Kevin Jeppesen, Founder of The Operator Vault

Written by

Kevin Jeppesen

Founder, The Operator Vault

Kevin is an early OpenClaw adopter who has saved an estimated 400 to 500 hours through AI automation. He stress-tests new workflows daily, sharing what actually works through step-by-step guides and a security-conscious approach to operating AI with real tools.

Developer FAQ

Questions developers ask us.

See how production
skills are built.

Our premium skill packs demonstrate every pattern in this guide. Built, tested, and maintained by The Operator Vault team.

>_Browse Premium SkillsStart the $19 Workshop
ClawHub GuideSkills GuideSecurity GuideWhat Is OpenClaw?Premium SkillsWorkshop