Custom Plugins
Create custom plugins to hook into OpenCode events and add automatic behaviors.
Create a Custom Plugin
aikit plugins create my-plugin
This creates .aikit/plugins/my-plugin.ts.
Plugin Format
import { Plugin } from 'aikit';
export const MyPlugin: Plugin = async ({ project, config, emit }) => {
return {
event: async ({ event }) => {
if (event.type === 'session.idle') {
console.log('Session idle');
}
},
'tool.execute.before': async (input) => {
// Modify input before tool execution
return input;
},
'tool.execute.after': async (input, output) => {
// Modify output after tool execution
return output;
},
};
};
export default MyPlugin;
Plugin Events
session.idle
Session completed:
event: async ({ event }) => {
if (event.type === 'session.idle') {
console.log('Session completed at:', event.timestamp);
}
}
session.created
New session started:
event: async ({ event }) => {
if (event.type === 'session.created') {
console.log('New session started');
}
}
session.error
Session error occurred:
event: async ({ event }) => {
if (event.type === 'session.error') {
console.log('Session error:', event.error);
}
}
tool.execute.before
Before tool execution:
'tool.execute.before': async (input) => {
// Log tool call
console.log('Executing tool:', input.tool);
// Modify input
return input;
}
tool.execute.after
After tool execution:
'tool.execute.after': async (input, output) => {
// Log result
console.log('Tool result:', output);
// Modify output
return output;
}
file.edited
File was edited:
'file.edited': async ({ event }) => {
if (event.type === 'file.edited') {
console.log('File edited:', event.path);
}
}
Plugin Options
Parameters
export const MyPlugin: Plugin = async ({
project, // Project configuration
config, // AIKit configuration
emit, // Emit events
}) => {
// Plugin implementation
};
Returns
return {
event: async ({ event }) => { },
'tool.execute.before': async (input) => { },
'tool.execute.after': async (input, output) => { },
'file.edited': async ({ event }) => { },
// ... more events
};
Examples
Auto-Save Plugin
import { Plugin } from 'aikit';
export const AutoSavePlugin: Plugin = async () => {
return {
'file.edited': async ({ event }) => {
if (event.type === 'file.edited') {
console.log(`Auto-saving: ${event.path}`);
// Trigger save logic
}
},
};
};
export default AutoSavePlugin;
Analytics Plugin
import { Plugin } from 'aikit';
export const AnalyticsPlugin: Plugin = async () => {
const events: any[] = [];
return {
event: async ({ event }) => {
events.push({
type: event.type,
timestamp: Date.now(),
});
},
'tool.execute.after': async ({ event }) => {
console.log('Total tool calls:', events.filter(e => e.type.startsWith('tool.')).length);
},
};
};
export default AnalyticsPlugin;
Custom Validation Plugin
import { Plugin } from 'aikit';
export const ValidationPlugin: Plugin = async () => {
return {
'tool.execute.after': async ({ event, input, output }) => {
if (event.type === 'tool.execute.after') {
if (input.tool === 'memory-update') {
// Validate memory updates
if (output.includes('secret')) {
return 'Error: Cannot store secrets in memory';
}
}
}
},
};
};
export default ValidationPlugin;
Enable Custom Plugins
In .aikit/aikit.json:
{
"plugins": {
"enabled": true,
"autoload": ["my-plugin", "enforcer", "compactor"]
}
}
Best Practices
- Keep plugins focused - One responsibility per plugin
- Handle errors - Don't let plugin errors break AIKit
- Be async - Always use async for event handlers
- Log actions - Provide feedback for debugging
- Test thoroughly - Test plugin doesn't break workflows
List All Plugins
aikit plugins list
Next Steps
- Plugins Guide - Built-in plugins
- Custom Skills - Create custom skills
- Custom Tools - Create custom tools