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 objectchannel: Current channel informationuser: Current user informationabortSignal: 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 startedsession:end— Session endedmessage:receive— New message receivedmessage:send— Message senttool:before— Before tool executiontool:after— After tool executiontool: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
- Least Privilege: Only declare the permissions the extension actually needs
- Graceful Error Handling: All asynchronous operations should include error handling
- Respect Abort Signals: Long-running operations should periodically check the
abortSignal - Thorough Documentation: Write clear descriptions and parameter explanations for tools
- 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.