Publishing Skills for Clawdbot
Learn how to create, package, and publish skills as npm packages that integrate seamlessly with Clawdbot and other OpenClaw-compatible AI agents.
What is a Clawdbot Skill?
A Clawdbot skill is an npm package that adds new capabilities to AI agents. Skills can:
- Add new commands and functionality
- Integrate with external APIs and services
- Access system resources (with permissions)
- Store and retrieve data
- Interact with other skills
Quick Start
Minimum Viable Skill
Create a basic skill structure:
// index.js
module.exports = {
name: 'my-awesome-skill',
version: '1.0.0',
description: 'Does something awesome',
async init(context) {
// Initialize your skill
console.log('Skill initialized!');
},
commands: {
'do-something': async (args, context) => {
return { success: true, message: 'Did something!' };
}
}
};
// package.json
{
"name": "@yourname/my-awesome-skill",
"version": "1.0.0",
"description": "Does something awesome",
"main": "index.js",
"keywords": ["clawdbot", "skill", "clawget"],
"license": "MIT",
"clawdbot": {
"type": "skill",
"permissions": []
}
}
Skill Anatomy
Every skill needs:
- package.json - npm package configuration with clawdbot metadata
- index.js - Main entry point exporting skill definition
- LICENSE - Open source license (MIT recommended)
- README.md - Documentation for users
Optional but recommended:
- config.schema.json - JSON schema for configuration validation
- tests/ - Unit and integration tests
- examples/ - Usage examples
Skill Manifest
The clawdbot section in package.json defines skill metadata:
{
"clawdbot": {
"type": "skill",
"category": "productivity",
"permissions": [
"network:https",
"fs:read:~/Documents"
],
"dependencies": {
"skills": ["@clawdbot/core-tools"],
"services": ["anthropic"]
},
"config": {
"schema": "./config.schema.json",
"required": ["apiKey"]
}
}
}
Key Properties
type - Always "skill" for skill packages
category - Helps with discovery:
productivitycommunicationdatacreativedev-toolshome-automationentertainment
permissions - Array of permission requests:
network:http/network:https- HTTP requestsfs:read:<path>- File system read accessfs:write:<path>- File system write accessexec:<command>- Execute system commandsclipboard- Access clipboardcamera- Access cameralocation- Access location data
dependencies - Other skills or services required
config - Configuration schema and requirements
Implementing Commands
Commands are the primary way users interact with your skill:
commands: {
'search': async (args, context) => {
const { query, limit = 10 } = args;
// Validate arguments
if (!query) {
throw new Error('Query is required');
}
// Do the work
const results = await searchAPI(query, limit);
// Return structured response
return {
success: true,
data: results,
message: `Found ${results.length} results`
};
}
}
Command Arguments
Arguments come from the user's natural language input, parsed by the agent:
// User says: "search for cats with limit 5"
// Your command receives:
{
query: "cats",
limit: 5
}
Context Object
Every command receives a context object with:
{
agent: {
id: 'agent-123',
name: 'MyBot',
model: 'claude-sonnet-4'
},
user: {
id: 'user-456',
preferences: {...}
},
session: {
id: 'session-789',
history: [...]
},
skills: {
get: (name) => {...}, // Access other skills
call: (name, command, args) => {...} // Call other skills
},
config: {...}, // Your skill's configuration
storage: { // Persistent storage
get: (key) => {...},
set: (key, value) => {...},
delete: (key) => {...}
}
}
License Validation
Integrate Clawget licensing to monetize your skill:
const ClawgetLicense = require('@clawget/license');
module.exports = {
async init(context) {
const license = new ClawgetLicense({
skillId: 'my-awesome-skill',
apiKey: context.config.clawgetApiKey
});
// Validate license on startup
const valid = await license.validate();
if (!valid.success) {
throw new Error(`License invalid: ${valid.error}`);
}
// Store for later checks
context.license = license;
},
commands: {
'premium-feature': async (args, context) => {
// Check license before premium features
const check = await context.license.check('premium');
if (!check.allowed) {
return {
success: false,
error: 'This feature requires a premium license',
upgradeUrl: 'https://clawget.io/skills/my-awesome-skill'
};
}
// Feature code here
}
}
};
License Tiers
Implement different functionality based on license tier:
const features = {
free: ['basic-search'],
personal: ['basic-search', 'advanced-search'],
team: ['basic-search', 'advanced-search', 'bulk-export'],
enterprise: ['basic-search', 'advanced-search', 'bulk-export', 'custom-api']
};
const tierFeatures = features[license.tier] || features.free;
if (!tierFeatures.includes(command)) {
return {
error: `Upgrade to ${license.requiredTier(command)} for this feature`
};
}
Configuration
Allow users to configure your skill:
// config.schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"apiKey": {
"type": "string",
"description": "API key for the service",
"minLength": 20
},
"endpoint": {
"type": "string",
"format": "uri",
"default": "https://api.service.com"
},
"maxResults": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 10
}
},
"required": ["apiKey"]
}
Users configure via ~/.clawdbot/skills/my-awesome-skill/config.json or environment variables.
Testing
Unit Tests
// test/commands.test.js
const skill = require('../index');
describe('search command', () => {
it('should search and return results', async () => {
const context = {
config: { apiKey: 'test-key' },
storage: new Map()
};
await skill.init(context);
const result = await skill.commands.search(
{ query: 'test', limit: 5 },
context
);
expect(result.success).toBe(true);
expect(result.data.length).toBeLessThanOrEqual(5);
});
});
Integration Tests
Test your skill in a real Clawdbot environment:
clawdbot test-skill ./my-skill --verbose
Publishing to npm
Prepare for Publishing
Before publishing:
# Run tests
npm test
# Check package
npm pack --dry-run
# Verify files included
tar -tzf *.tgz
Publish
# Login to npm (one-time)
npm login
# Publish package
npm publish --access public
# Or for scoped packages
npm publish --access public
Versioning
Follow semantic versioning:
1.0.0- Major version (breaking changes)1.1.0- Minor version (new features, backward compatible)1.0.1- Patch version (bug fixes)
Update version before each publish:
npm version patch # 1.0.0 -> 1.0.1
npm version minor # 1.0.1 -> 1.1.0
npm version major # 1.1.0 -> 2.0.0
Listing on Clawget
After publishing to npm, create a marketplace listing:
clawget create-listing \
--package @yourname/my-awesome-skill \
--category productivity \
--price-personal 10 \
--price-team 50
Or use the web interface at clawget.io/creator/new-listing.
Listing Requirements
To list on Clawget marketplace:
- Published to npm registry
- License validation integrated
- Documentation complete (README + examples)
- Passing automated security scan
- Screenshots or demo video
- Support contact provided
Best Practices
Code Quality
- Use TypeScript for better developer experience
- Include comprehensive error handling
- Validate all inputs
- Write unit tests
- Document all functions and commands
User Experience
- Provide clear error messages
- Return structured, consistent responses
- Support natural language arguments
- Include usage examples in README
- Offer sensible defaults
Security
- Never store sensitive data in code
- Use environment variables or secure config
- Validate all external inputs
- Request minimum necessary permissions
- Audit dependencies regularly
Performance
- Cache API responses when appropriate
- Implement rate limiting for external calls
- Use async/await properly
- Clean up resources in cleanup hooks
Example Skills
Check out these example skills for reference:
- @clawdbot/email-assistant - Email management
- @clawdbot/home-control - Smart home integration
- @clawdbot/dev-tools - Developer utilities
Support & Resources
Next Steps
Start building and publishing your skills today! 🚀