Home Tutorials Categories Skills About
ZH EN JA KO
Skills-Plugins

Getting Started with OpenClaw Extension Development

· 15 min read

Overview

OpenClaw's extension system allows developers to add custom capabilities to AI agents. Extensions can register new tools, inject system prompt snippets, handle specific events, and even modify the behavior of the tool pipeline. This article will guide you from scratch through developing, testing, and deploying an OpenClaw extension.

Extension Loading Methods

OpenClaw supports two methods for loading extensions:

Programmatic Loading

Register extensions directly through code, suitable for scenarios with deep OpenClaw integration:

const { OpenClaw } = require('openclaw');

const app = new OpenClaw();

app.registerExtension({
  name: 'my-extension',
  version: '1.0.0',
  description: 'My custom extension',
  setup: async (context) => {
    // Extension initialization logic
  }
});

Disk Path Loading

Place extensions in a designated directory, and OpenClaw will automatically discover and load them on startup:

extensions:
  path: /data/openclaw/extensions
  autoLoad: true
  allowedExtensions:
    - my-extension
    - another-extension

Extension directory structure:

/data/openclaw/extensions/
  my-extension/
    index.js
    package.json
    manifest.yaml

Extension Structure

manifest.yaml

Every extension must include a manifest file that declares the extension's metadata and capabilities:

name: my-extension
version: 1.0.0
description: This is a sample extension
author: Developer Name
minOpenClawVersion: 2.0.0

capabilities:
  tools: true
  prompts: true
  events: true

permissions:
  network: false
  filesystem:
    read: ["/data/openclaw/workspace"]
    write: ["/tmp/openclaw/my-extension"]

config:
  apiEndpoint:
    type: string
    required: true
    description: API endpoint address
  maxRetries:
    type: number
    default: 3
    description: Maximum number of retries

Entry File

The extension's entry file exports a setup function that receives the extension context object:

module.exports = {
  setup: async (ctx) => {
    // Register a tool
    ctx.registerTool({
      name: 'my_custom_tool',
      description: 'Description of the custom tool functionality',
      parameters: {
        type: 'object',
        properties: {
          query: { type: 'string', description: 'Query content' }
        },
        required: ['query']
      },
      execute: async (params, toolCtx) => {
        const result = await doSomething(params.query);
        return { content: result };
      }
    });

    // Inject a prompt
    ctx.registerPrompt({
      position: 'tools',
      content: 'When the user needs a certain feature, please use the my_custom_tool tool.'
    });

    // Listen for events
    ctx.on('session:start', async (session) => {
      console.log(`New session started: ${session.id}`);
    });
  }
};

Tool Registration Details

Tool Definition

When registering a tool, you need to provide parameter definitions that conform to the JSON Schema specification. These definitions are checked during the Schema validation stage of the seven-stage tool pipeline, and non-conforming definitions will be rejected.

Execute Function

The tool's execute function receives two parameters:

  • params: Tool parameters passed by the user, already validated against the Schema
  • toolCtx: Tool context containing the following:
    • session: Current session object
    • channel: Current channel information
    • user: Current user information
    • abortSignal: Abort signal (from stage seven of the pipeline)
    • config: Extension configuration

Return Format

The tool execute function should return an object. Common formats include:

// Text result
return { content: 'Operation completed successfully' };

// Structured data
return { content: JSON.stringify(data), metadata: { type: 'json' } };

// Error result
return { error: 'Operation failed: specific reason' };

// Result with attachments
return {
  content: 'Image generated',
  attachments: [{ path: '/tmp/output.png', type: 'image/png' }]
};

Prompt Injection

Extensions can inject content at different positions within the system prompt:

ctx.registerPrompt({
  position: 'system',    // System-level prompt
  content: 'You have the ability to...',
  priority: 10           // Priority; higher numbers appear first
});

ctx.registerPrompt({
  position: 'tools',     // Tool usage guidance
  content: 'When using xxx tool, please note...'
});

These prompt snippets are collected and integrated into the final system prompt by buildAgentSystemPrompt().

Event System

OpenClaw's event system allows extensions to respond to various system events:

  • session:start — New session started
  • session:end — Session ended
  • message:receive — New message received
  • message:send — Message sent
  • tool:before — Before tool execution
  • tool:after — After tool execution
  • tool:error — Tool execution error
ctx.on('tool:before', async (event) => {
  console.log(`About to execute tool: ${event.toolName}`);
  // Can modify parameters or cancel execution
});

Inter-Extension Communication

Multiple extensions can communicate through a shared context:

// Extension A publishes data
ctx.shared.set('weather:current', weatherData);

// Extension B reads data
const weather = ctx.shared.get('weather:current');

Testing

Unit Testing

OpenClaw provides a testing toolkit for testing extensions in an isolated environment:

const { createTestContext } = require('openclaw/testing');

describe('my-extension', () => {
  it('should execute tool correctly', async () => {
    const ctx = createTestContext();
    await extension.setup(ctx);

    const result = await ctx.executeTool('my_custom_tool', {
      query: 'test'
    });

    expect(result.content).toBeDefined();
  });
});

Integration Testing

Use OpenClaw's development mode to start the service, load the extension, and test its functionality through actual conversations.

Session Persistence

Data produced by extensions can be stored using OpenClaw's session persistence mechanism (JSONL format). When session data undergoes compaction, extensions can participate in the compaction process via the session:compact event to determine which data should be retained.

Publishing and Sharing

Completed extensions can be packaged and published to the OpenClaw Skill Marketplace for other users to install and use. A basic security review and functionality verification are required before publishing.

Best Practices

  1. Least Privilege: Only declare the permissions the extension actually needs
  2. Graceful Error Handling: All asynchronous operations should include error handling
  3. Respect Abort Signals: Long-running operations should periodically check the abortSignal
  4. Thorough Documentation: Write clear descriptions and parameter explanations for tools
  5. Version Compatibility: Declare the minimum OpenClaw version requirement in the manifest

Summary

OpenClaw's extension system provides powerful and flexible customization capabilities. Whether you need to add new tools, modify behavior, or integrate external services, extensions can accomplish it in a modular fashion. Mastering extension development is the key to making OpenClaw adapt to any scenario.

OpenClaw is a free, open-source personal AI assistant that supports WhatsApp, Telegram, Discord, and many more platforms