Login
Back to Blog
OpenClaw Skills Development: Building Custom AI Capabilities

OpenClaw Skills Development: Building Custom AI Capabilities

C
Crazyrouter Team
March 7, 2026
9 viewsEnglish
Share:

OpenClaw Skills Development: Building Custom AI Capabilities#

OpenClaw's extensibility through custom skills is one of its most powerful features. Skills allow you to extend the AI assistant's capabilities by integrating external APIs, adding domain-specific knowledge, and creating specialized workflows. This comprehensive guide covers everything from basic skill structure to advanced development patterns.

Understanding OpenClaw Skills Architecture#

Skills in OpenClaw are modular TypeScript functions that extend the assistant's capabilities. Each skill follows a standardized structure that enables seamless integration with the OpenClaw runtime.

Core Skill Components#

Every OpenClaw skill consists of four essential components:

Metadata Definition: Skills declare their purpose, parameters, and requirements through a metadata object. This includes the skill name, description, input schema, and execution context requirements.

Input Validation: Robust skills validate incoming parameters before execution. OpenClaw provides built-in validation utilities that check types, ranges, and required fields automatically.

Execution Logic: The core functionality implements the skill's purpose. This might involve API calls, data processing, or complex workflows. Skills can leverage async/await patterns for handling external services.

Response Formatting: Skills return structured responses that OpenClaw can interpret and present to users. Proper formatting ensures consistent user experience across different skills.

Skills vs Tools: Key Differences#

OpenClaw distinguishes between skills and tools, though they share similarities:

Skills are high-level capabilities that users invoke directly. They often orchestrate multiple operations and provide complete workflows. Examples include "analyze-code", "generate-documentation", or "deploy-application".

Tools are lower-level utilities that skills use internally. They provide specific functions like HTTP requests, file operations, or data transformations. Tools are building blocks that skills compose.

Setting Up Your Skills Development Environment#

Before building custom skills, establish a proper development environment with the necessary tools and dependencies.

Prerequisites and Installation#

Start by cloning the OpenClaw repository and installing dependencies:

bash
git clone https://github.com/openclaw/openclaw.git
cd openclaw
npm install

Install the OpenClaw CLI for skill management:

bash
npm install -g @openclaw/cli
openclaw init --type skill

Project Structure for Skills#

Organize your skills project with this recommended structure:

code
my-openclaw-skills/
├── src/
│   ├── skills/
│   │   ├── my-skill/
│   │   │   ├── index.ts
│   │   │   ├── schema.ts
│   │   │   ├── handlers.ts
│   │   │   └── tests/
│   │   └── another-skill/
│   ├── utils/
│   ├── types/
│   └── index.ts
├── tests/
├── package.json
├── tsconfig.json
└── openclaw.config.ts

This structure separates concerns and makes skills easy to maintain and test.

Building Your First OpenClaw Skill#

Let's create a practical skill that integrates with Crazyrouter to analyze API usage patterns and provide cost optimization recommendations.

Defining Skill Metadata#

Create src/skills/api-analyzer/schema.ts:

typescript
import { SkillSchema } from '@openclaw/types';

export const apiAnalyzerSchema: SkillSchema = {
  name: 'api-analyzer',
  version: '1.0.0',
  description: 'Analyzes API usage patterns and provides cost optimization recommendations',
  category: 'analytics',

  parameters: {
    type: 'object',
    properties: {
      timeRange: {
        type: 'string',
        enum: ['24h', '7d', '30d'],
        description: 'Time range for analysis',
        default: '7d'
      },
      apiKey: {
        type: 'string',
        description: 'Crazyrouter API key for accessing usage data'
      },
      threshold: {
        type: 'number',
        description: 'Cost threshold for recommendations (USD)',
        minimum: 0,
        default: 100
      }
    },
    required: ['apiKey']
  },

  returns: {
    type: 'object',
    properties: {
      totalCost: { type: 'number' },
      recommendations: { type: 'array' },
      usageBreakdown: { type: 'object' }
    }
  }
};

Implementing Skill Logic#

Create src/skills/api-analyzer/index.ts:

typescript
import { Skill, SkillContext, SkillResult } from '@openclaw/types';
import { apiAnalyzerSchema } from './schema';
import { fetchUsageData, analyzePatterns, generateRecommendations } from './handlers';

export const apiAnalyzer: Skill = {
  schema: apiAnalyzerSchema,

  async execute(params: any, context: SkillContext): Promise<SkillResult> {
    const { timeRange, apiKey, threshold } = params;

    try {
      // Fetch usage data from Crazyrouter
      const usageData = await fetchUsageData(apiKey, timeRange);

      // Analyze patterns
      const analysis = analyzePatterns(usageData);

      // Generate recommendations
      const recommendations = generateRecommendations(analysis, threshold);

      return {
        success: true,
        data: {
          totalCost: analysis.totalCost,
          recommendations,
          usageBreakdown: analysis.breakdown
        },
        message: `Analyzed ${usageData.length} API calls over ${timeRange}`
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
        message: 'Failed to analyze API usage'
      };
    }
  }
};

Handler Implementation#

Create src/skills/api-analyzer/handlers.ts:

typescript
import axios from 'axios';

interface UsageRecord {
  timestamp: string;
  model: string;
  tokens: number;
  cost: number;
}

export async function fetchUsageData(
  apiKey: string,
  timeRange: string
): Promise<UsageRecord[]> {
  const baseUrl = 'https://crazyrouter.com/api';

  const response = await axios.get(`${baseUrl}/log/token`, {
    params: {
      key: apiKey,
      range: timeRange
    },
    headers: {
      'User-Agent': 'OpenClaw-Skill/1.0'
    }
  });

  return response.data.data || [];
}

export function analyzePatterns(usageData: UsageRecord[]) {
  const breakdown: Record<string, { calls: number; cost: number }> = {};
  let totalCost = 0;

  for (const record of usageData) {
    if (!breakdown[record.model]) {
      breakdown[record.model] = { calls: 0, cost: 0 };
    }
    breakdown[record.model].calls++;
    breakdown[record.model].cost += record.cost;
    totalCost += record.cost;
  }

  return { totalCost, breakdown };
}

export function generateRecommendations(
  analysis: any,
  threshold: number
): string[] {
  const recommendations: string[] = [];

  if (analysis.totalCost > threshold) {
    recommendations.push(
      `Total cost ($${analysis.totalCost.toFixed(2)}) exceeds threshold ($${threshold})`
    );
  }

  // Find expensive models
  const sortedModels = Object.entries(analysis.breakdown)
    .sort(([, a]: any, [, b]: any) => b.cost - a.cost);

  if (sortedModels.length > 0) {
    const [topModel, stats]: any = sortedModels[0];
    recommendations.push(
      `Consider optimizing ${topModel} usage (${stats.calls} calls, $${stats.cost.toFixed(2)})`
    );
  }

  return recommendations;
}

Advanced Skill Development Patterns#

As you build more complex skills, leverage these advanced patterns for better maintainability and performance.

Skill Composition and Chaining#

Skills can invoke other skills to create powerful workflows:

typescript
export const complexWorkflow: Skill = {
  schema: workflowSchema,

  async execute(params: any, context: SkillContext): Promise<SkillResult> {
    // Execute first skill
    const analysisResult = await context.invokeSkill('api-analyzer', {
      apiKey: params.apiKey,
      timeRange: '30d'
    });

    // Use results in second skill
    const optimizationResult = await context.invokeSkill('cost-optimizer', {
      analysis: analysisResult.data,
      budget: params.budget
    });

    // Combine results
    return {
      success: true,
      data: {
        analysis: analysisResult.data,
        optimization: optimizationResult.data
      }
    };
  }
};

Error Handling and Retry Logic#

Implement robust error handling for external API calls:

typescript
async function fetchWithRetry(
  url: string,
  options: any,
  maxRetries: number = 3
): Promise<any> {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await axios.get(url, options);
      return response.data;
    } catch (error) {
      if (attempt === maxRetries) throw error;

      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Caching and Performance Optimization#

Cache expensive operations to improve skill performance:

typescript
import { Cache } from '@openclaw/utils';

const cache = new Cache({ ttl: 3600 }); // 1 hour TTL

export async function fetchUsageDataCached(
  apiKey: string,
  timeRange: string
): Promise<UsageRecord[]> {
  const cacheKey = `usage:${apiKey}:${timeRange}`;

  // Check cache first
  const cached = cache.get(cacheKey);
  if (cached) return cached;

  // Fetch and cache
  const data = await fetchUsageData(apiKey, timeRange);
  cache.set(cacheKey, data);

  return data;
}

Integrating External APIs with Crazyrouter#

Crazyrouter provides unified access to 300+ AI models, making it ideal for skills that need multi-model capabilities.

Multi-Model Skill Pattern#

Create skills that leverage multiple AI models through Crazyrouter:

typescript
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.CRAZYROUTER_API_KEY,
  baseURL: 'https://crazyrouter.com/v1'
});

export async function analyzeWithMultipleModels(text: string) {
  // Use GPT-4 for initial analysis
  const gpt4Analysis = await client.chat.completions.create({
    model: 'gpt-4',
    messages: [{ role: 'user', content: `Analyze: ${text}` }]
  });

  // Use Claude for verification
  const claudeVerification = await client.chat.completions.create({
    model: 'claude-3-5-sonnet-20241022',
    messages: [{ role: 'user', content: `Verify: ${gpt4Analysis.choices[0].message.content}` }]
  });

  return {
    primary: gpt4Analysis.choices[0].message.content,
    verification: claudeVerification.choices[0].message.content
  };
}

Handling Rate Limits and Quotas#

Implement intelligent rate limiting when using Crazyrouter:

typescript
import { RateLimiter } from '@openclaw/utils';

const limiter = new RateLimiter({
  maxRequests: 100,
  windowMs: 60000 // 1 minute
});

export async function makeAPICall(params: any) {
  await limiter.acquire();

  try {
    return await client.chat.completions.create(params);
  } finally {
    limiter.release();
  }
}

Cost Optimization Strategies#

Monitor and optimize API costs in your skills:

typescript
export async function selectOptimalModel(task: string, budget: number) {
  const modelCosts = {
    'gpt-4': 0.03,
    'gpt-3.5-turbo': 0.002,
    'claude-3-haiku-20240307': 0.00025
  };

  // Classify task complexity
  const complexity = await classifyTaskComplexity(task);

  // Select model based on budget and complexity
  if (complexity === 'high' && budget >= modelCosts['gpt-4']) {
    return 'gpt-4';
  } else if (complexity === 'medium' && budget >= modelCosts['gpt-3.5-turbo']) {
    return 'gpt-3.5-turbo';
  } else {
    return 'claude-3-haiku-20240307';
  }
}

Testing OpenClaw Skills#

Comprehensive testing ensures your skills work reliably in production environments.

Unit Testing Skills#

Create unit tests using Jest or Vitest:

typescript
import { describe, it, expect, vi } from 'vitest';
import { apiAnalyzer } from '../index';
import * as handlers from '../handlers';

describe('API Analyzer Skill', () => {
  it('should analyze usage data correctly', async () => {
    // Mock handlers
    vi.spyOn(handlers, 'fetchUsageData').mockResolvedValue([
      { timestamp: '2026-03-01', model: 'gpt-4', tokens: 1000, cost: 0.03 },
      { timestamp: '2026-03-02', model: 'gpt-4', tokens: 2000, cost: 0.06 }
    ]);

    const result = await apiAnalyzer.execute(
      { apiKey: 'test-key', timeRange: '7d', threshold: 0.05 },
      {} as any
    );

    expect(result.success).toBe(true);
    expect(result.data.totalCost).toBe(0.09);
    expect(result.data.recommendations).toHaveLength(1);
  });

  it('should handle API errors gracefully', async () => {
    vi.spyOn(handlers, 'fetchUsageData').mockRejectedValue(
      new Error('API unavailable')
    );

    const result = await apiAnalyzer.execute(
      { apiKey: 'test-key', timeRange: '7d' },
      {} as any
    );

    expect(result.success).toBe(false);
    expect(result.error).toBe('API unavailable');
  });
});

Integration Testing#

Test skills against real APIs in a controlled environment:

typescript
describe('API Analyzer Integration', () => {
  it('should fetch real usage data from Crazyrouter', async () => {
    const apiKey = process.env.TEST_API_KEY;

    const result = await apiAnalyzer.execute(
      { apiKey, timeRange: '24h', threshold: 100 },
      {} as any
    );

    expect(result.success).toBe(true);
    expect(typeof result.data.totalCost).toBe('number');
  });
});

End-to-End Testing#

Test complete skill workflows in OpenClaw:

bash
# Use OpenClaw CLI for E2E testing
openclaw test skill api-analyzer --config test-config.json

Publishing and Distributing Skills#

Once your skill is tested and ready, publish it for others to use.

Packaging Skills#

Create an npm package for your skill:

json
{
  "name": "@myorg/openclaw-api-analyzer",
  "version": "1.0.0",
  "description": "API usage analyzer skill for OpenClaw",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "keywords": ["openclaw", "skill", "api", "analytics"],
  "peerDependencies": {
    "@openclaw/types": "^1.0.0"
  }
}

Build and publish:

bash
npm run build
npm publish --access public

Skill Registry Submission#

Submit your skill to the OpenClaw registry:

bash
openclaw publish --skill api-analyzer --registry https://registry.openclaw.dev

Documentation Requirements#

Include comprehensive documentation:

markdown
# API Analyzer Skill

Analyzes API usage patterns and provides cost optimization recommendations.

## Installation

\`\`\`bash
npm install @myorg/openclaw-api-analyzer
\`\`\`

## Usage

\`\`\`typescript
import { apiAnalyzer } from '@myorg/openclaw-api-analyzer';

const result = await apiAnalyzer.execute({
  apiKey: 'your-crazyrouter-key',
  timeRange: '7d',
  threshold: 100
}, context);
\`\`\`

## Parameters

- `apiKey` (required): Your Crazyrouter API key
- `timeRange` (optional): Analysis period ('24h', '7d', '30d')
- `threshold` (optional): Cost threshold for recommendations

## Returns

- `totalCost`: Total API cost in USD
- `recommendations`: Array of optimization suggestions
- `usageBreakdown`: Per-model usage statistics

Best Practices for Skill Development#

Follow these best practices to create high-quality, maintainable skills.

Security Considerations#

Never hardcode API keys: Use environment variables or secure configuration:

typescript
const apiKey = process.env.CRAZYROUTER_API_KEY || context.getSecret('crazyrouter_key');

Validate all inputs: Prevent injection attacks and invalid data:

typescript
function validateApiKey(key: string): boolean {
  return /^[a-zA-Z0-9_-]{32,}$/.test(key);
}

Sanitize outputs: Remove sensitive information from responses:

typescript
function sanitizeResponse(data: any): any {
  const { apiKey, internalId, ...safe } = data;
  return safe;
}

Performance Guidelines#

Minimize API calls: Batch requests when possible:

typescript
async function batchAnalyze(items: string[]) {
  const batchSize = 10;
  const results = [];

  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    const batchResults = await Promise.all(
      batch.map(item => analyzeItem(item))
    );
    results.push(...batchResults);
  }

  return results;
}

Use streaming for large responses: Improve perceived performance:

typescript
export async function* streamAnalysis(data: any[]) {
  for (const item of data) {
    const result = await analyzeItem(item);
    yield result;
  }
}

Maintainability Tips#

Use TypeScript strictly: Enable strict mode for better type safety:

json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true
  }
}

Document complex logic: Add JSDoc comments for clarity:

typescript
/**
 * Analyzes API usage patterns and generates cost optimization recommendations.
 *
 * @param usageData - Array of usage records from Crazyrouter
 * @param threshold - Cost threshold in USD for triggering recommendations
 * @returns Analysis results with recommendations
 *
 * @example
 * ```typescript
 * const analysis = analyzePatterns(usageData, 100);
 * console.log(analysis.recommendations);
 * ```
 */
export function analyzePatterns(usageData: UsageRecord[], threshold: number) {
  // Implementation
}

Real-World Skill Examples#

Learn from these practical skill implementations.

Content Generation Skill#

A skill that generates blog content using multiple AI models through Crazyrouter:

typescript
export const contentGenerator: Skill = {
  schema: {
    name: 'content-generator',
    description: 'Generates high-quality blog content using AI',
    parameters: {
      type: 'object',
      properties: {
        topic: { type: 'string' },
        length: { type: 'number', default: 1000 },
        tone: { type: 'string', enum: ['professional', 'casual', 'technical'] }
      },
      required: ['topic']
    }
  },

  async execute(params, context) {
    const { topic, length, tone } = params;

    // Generate outline with GPT-4
    const outline = await generateOutline(topic, tone);

    // Generate sections with Claude
    const sections = await Promise.all(
      outline.sections.map(section =>
        generateSection(section, length / outline.sections.length, tone)
      )
    );

    // Polish with GPT-4
    const polished = await polishContent(sections.join('\n\n'));

    return {
      success: true,
      data: {
        content: polished,
        wordCount: polished.split(' ').length,
        outline
      }
    };
  }
};

Code Review Skill#

A skill that performs automated code reviews:

typescript
export const codeReviewer: Skill = {
  schema: {
    name: 'code-reviewer',
    description: 'Performs automated code review with AI',
    parameters: {
      type: 'object',
      properties: {
        code: { type: 'string' },
        language: { type: 'string' },
        focus: { type: 'array', items: { type: 'string' } }
      },
      required: ['code', 'language']
    }
  },

  async execute(params, context) {
    const { code, language, focus = ['security', 'performance', 'style'] } = params;

    const reviews = await Promise.all(
      focus.map(aspect => reviewAspect(code, language, aspect))
    );

    return {
      success: true,
      data: {
        reviews,
        summary: generateSummary(reviews),
        score: calculateScore(reviews)
      }
    };
  }
};

Troubleshooting Common Issues#

Resolve common problems encountered during skill development.

Skill Not Loading#

Problem: Skill doesn't appear in OpenClaw

Solutions:

  • Verify skill is properly exported in index.ts
  • Check openclaw.config.ts includes skill directory
  • Ensure skill schema is valid
  • Run openclaw validate skill <name>

API Authentication Failures#

Problem: External API calls fail with 401/403 errors

Solutions:

  • Verify API key is correctly configured
  • Check API key has required permissions
  • Ensure User-Agent header is set for Crazyrouter
  • Test API key independently with curl

Performance Issues#

Problem: Skill executes slowly

Solutions:

  • Profile skill execution with openclaw profile skill <name>
  • Implement caching for repeated operations
  • Use parallel execution for independent operations
  • Reduce API call frequency with batching

Conclusion#

OpenClaw skills development opens endless possibilities for extending AI assistant capabilities. By following the patterns and best practices in this guide, you can create robust, performant skills that integrate seamlessly with OpenClaw and Crazyrouter.

Key takeaways:

  • Skills follow a standardized structure with metadata, validation, execution, and response formatting
  • Leverage Crazyrouter for multi-model AI capabilities and cost optimization
  • Implement comprehensive testing at unit, integration, and E2E levels
  • Follow security best practices and never hardcode sensitive data
  • Optimize performance through caching, batching, and parallel execution
  • Document thoroughly and publish to the OpenClaw registry

Start building your first skill today and join the growing OpenClaw developer community!


Ready to integrate OpenClaw with custom AI models? Continue with OpenClaw Custom Model Integration to learn advanced model configuration and deployment strategies.

Need help with OpenClaw skills? Visit Crazyrouter for API access and support.

Related Articles