Plugin Development
OMP plugins extend the harness with new commands, skills, agent tools, and UI panels. A plugin is a directory with a manifest and one or more entry-point modules.
Plugin Structure
my-plugin/
plugin.json # manifest — id, version, hooks, skills
src/
index.ts # main entry — exports activate() + deactivate()
skills/
my-skill.md # skill instruction file
tools/
my-tool.ts # agent tool definition
tests/
my-plugin.test.ts # integration tests
README.md The manifest plugin.json is the only required file. Entry point defaults to src/index.ts.
Manifest Reference
{
"id": "my-plugin",
"name": "My Plugin",
"version": "1.0.0",
"description": "What this plugin does",
"author": "you@example.com",
"entry": "src/index.ts",
"hooks": ["session:start", "tool:before", "tool:after"],
"skills": ["src/skills/my-skill.md"],
"tools": ["src/tools/my-tool.ts"],
"permissions": ["fs:read", "network"]
} Lifecycle Hooks
session:start Runs when an OMP session initialises. Use for setup, env checks, or injecting system prompts.
session:end Runs after the session completes. Ideal for cleanup, logging, or flushing telemetry.
tool:before Intercepts a tool call before execution. Return false to abort; mutate args to override inputs.
tool:after Receives the tool result. Can mutate the result or trigger side-effects.
agent:spawn Fires when a sub-agent is created. Inject context or constraints before the agent runs.
message:output Intercepts every assistant turn. Use for streaming logging or output post-processing.
Writing a Skill
Skills are Markdown instruction files discovered via the skills field in plugin.json. The frontmatter sets the trigger and metadata:
---
name: my-skill
trigger: "my keyword"
description: "What this skill does"
---
# My Skill
Instructions for the model go here. Use imperative tone.
Reference other skills with `skill://other-skill`. Registering a Tool
// src/tools/my-tool.ts
import type { ToolDefinition } from '@omp/sdk';
export const myTool: ToolDefinition = {
name: 'my_tool',
description: 'Does a specific task',
inputSchema: {
type: 'object',
properties: {
target: { type: 'string', description: 'The target resource' },
},
required: ['target'],
},
async execute({ target }) {
// implementation
return { result: `processed ${target}` };
},
}; Testing Plugins
- Use
@omp/test-utilsto spin up a sandboxed harness session. - Call
createTestSession({ plugins: [myPlugin] })to mount your plugin. - Assert hook calls with the built-in spy helpers; assert tool results directly.
- Run
bun test— OMP tests run in an isolated Bun subprocess to avoid state leakage. - E2E tests should cover at least one full session lifecycle (start → tool call → end).
Publishing
Open a PR to oh-my-pi/plugins registry with your plugin directory. Include a README.md with install instructions, a changelog, and test evidence. The registry bot will run CI and add the plugin to the discovery index on merge.