Writing a Skill
Skills extend OpenMotoko with new tools. This guide covers creating a skill from scratch, the manifest format, the defineSkill API, testing, and publishing.
Quick start with CLI
Section titled “Quick start with CLI”npx create-openmotoko-skill my-skillcd my-skillpnpm installThis scaffolds a skill project with the manifest, entry point, and test setup.
Project structure
Section titled “Project structure”my-skill/ manifest.json src/ index.ts test/ index.test.ts package.json tsconfig.jsonManifest format
Section titled “Manifest format”Every skill needs a manifest.json:
{ "id": "my-skill", "name": "My Skill", "version": "1.0.0", "description": "Does something useful", "author": "your-name", "capabilities": { "network": false, "filesystem": { "enabled": false, "paths": [] }, "shell": false, "env": [] }, "tools": [ { "name": "do_thing", "description": "Does the thing with the input", "inputSchema": { "type": "object", "properties": { "query": { "type": "string", "description": "The input to process" } }, "required": ["query"] } } ]}Capability fields
Section titled “Capability fields”| Field | Type | Description |
|---|---|---|
network | boolean | Outbound HTTP access |
filesystem.enabled | boolean | File read/write access |
filesystem.paths | string[] | Allowed directories |
shell | boolean | Shell command execution |
env | string[] | Environment variables the skill can read |
Only declare what you actually need. The security scanner rejects skills that use undeclared capabilities.
defineSkill API
Section titled “defineSkill API”import { defineSkill } from '@openmotoko/skill-sdk'
export default defineSkill( require('./manifest.json'), async (ctx, toolName, input) => { switch (toolName) { case 'do_thing': const result = await processQuery(input.query) return { content: result } default: throw new Error(`Unknown tool: ${toolName}`) } })SkillContext
Section titled “SkillContext”The ctx parameter provides:
| Property | Type | Description |
|---|---|---|
manifest | SkillManifest | The parsed manifest |
env | Record<string, string> | Allowed environment variables |
log | Logger | Structured logger |
Return format
Section titled “Return format”Tool handlers return an object with a content field:
return { content: 'Result text here' }For errors, throw an exception:
throw new Error('Something went wrong')Helper functions
Section titled “Helper functions”The SDK exports utilities:
| Function | Description |
|---|---|
formatToolResult(content) | Wraps content in the expected result format |
formatError(error) | Formats an error for the IPC response |
parseJsonInput(raw) | Safely parses JSON input |
validateInput(input, schema) | Validates input against a JSON schema |
Testing with SkillTestHarness
Section titled “Testing with SkillTestHarness”import { SkillTestHarness } from '@openmotoko/skill-sdk'import skill from '../src/index'
const harness = new SkillTestHarness(skill)
const result = await harness.runTool('do_thing', { query: 'test input',})
console.log(result.result)console.log(result.logs)console.log(result.durationMs)Test result fields
Section titled “Test result fields”| Field | Type | Description |
|---|---|---|
toolName | string | Tool that was called |
input | object | Input that was passed |
result | object | Tool return value |
logs | string[] | Log output during execution |
durationMs | number | Execution time |
Manual creation
Section titled “Manual creation”If you prefer not to use the CLI:
- Create a directory with
manifest.jsonandsrc/index.ts - Add
@openmotoko/skill-sdkas a dependency - Export a
defineSkillcall as the default export - Write tests using
SkillTestHarness
Publishing to the registry
Section titled “Publishing to the registry”npx @openmotoko/cli publish ./my-skillThis uploads your skill to the OpenMotoko registry where it undergoes security scanning before being listed.
Pre-publish checklist
Section titled “Pre-publish checklist”- All capabilities are correctly declared in the manifest
- No
eval()or dynamic code execution - Environment variable usage matches
capabilities.env - Tests pass via
SkillTestHarness - Version follows semver
Installing from registry
Section titled “Installing from registry”Users install published skills via the API:
curl -X POST http://localhost:3457/api/registry/install \ -H "Cookie: session=..." \ -H "Content-Type: application/json" \ -d '{"skillId": "my-skill"}'Or through the web UI’s skill library.