Note: Core tools (filesystem, command, web operations) have been successfully migrated to plugins. See
PLUGIN_MIGRATION.mdin the project root for migration details.
The CortexAI plugin system allows you to extend the agent's capabilities by adding custom tools. Plugins are dynamically loaded at startup from the plugins/ directory.
Each plugin must be in its own directory under plugins/ with the following structure:
plugins/
└── my-plugin/
├── plugin.json (required - plugin manifest)
├── index.js (required - main plugin file)
└── ... other files
Every plugin must include a plugin.json file with the following structure:
{
"name": "my-plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "Brief description of what your plugin does",
"main": "index.js",
"tools": [
"tool_name_1",
"tool_name_2"
]
}- name (required): Unique identifier for your plugin
- version (required): Semver version number (e.g., "1.0.0")
- author (required): Plugin author name or organization
- description (required): Brief description of plugin functionality
- main (optional): Entry point file, defaults to "index.js"
- tools (required): Array of tool names this plugin provides
Your plugin's main file must export an init() function that receives the toolRegistry:
/**
* Initialize the plugin
* @param {ToolRegistry} toolRegistry - The tool registry to register tools with
*/
export async function init(toolRegistry) {
// Register your tools here
toolRegistry.register(myToolDefinition, myToolHandler);
}Tools use the OpenAI function calling format:
const myToolDefinition = {
type: "function",
function: {
name: "my_tool",
description: "What this tool does",
parameters: {
type: "object",
properties: {
param1: {
type: "string",
description: "Description of parameter"
},
param2: {
type: "number",
description: "Another parameter"
}
},
required: ["param1"]
}
}
};The handler is an async function that implements the tool's logic:
async function myToolHandler(args) {
// args contains the parameters passed by the AI
const { param1, param2 } = args;
try {
// Your tool logic here
const result = await doSomething(param1, param2);
// Return JSON string with results
return JSON.stringify({
success: true,
data: result
});
} catch (error) {
return JSON.stringify({
success: false,
error: error.message
});
}
}{
"name": "example-plugin",
"version": "1.0.0",
"author": "CortexAI Team",
"description": "Example plugin demonstrating the plugin system",
"main": "index.js",
"tools": [
"greet_user",
"calculate_fibonacci"
]
}// Tool 1: Greet User
const greetUserDefinition = {
type: "function",
function: {
name: "greet_user",
description: "Greets a user with a personalized message",
parameters: {
type: "object",
properties: {
name: {
type: "string",
description: "Name of the user to greet"
},
language: {
type: "string",
enum: ["en", "es", "fr"],
description: "Language for greeting (default: en)"
}
},
required: ["name"]
}
}
};
async function greetUserHandler(args) {
const { name, language = "en" } = args;
const greetings = {
en: `Hello, ${name}!`,
es: `¡Hola, ${name}!`,
fr: `Bonjour, ${name}!`
};
return JSON.stringify({
success: true,
greeting: greetings[language] || greetings.en
});
}
// Tool 2: Calculate Fibonacci
const fibonacciDefinition = {
type: "function",
function: {
name: "calculate_fibonacci",
description: "Calculate the nth Fibonacci number",
parameters: {
type: "object",
properties: {
n: {
type: "number",
description: "Position in Fibonacci sequence (0-based)"
}
},
required: ["n"]
}
}
};
async function fibonacciHandler(args) {
const { n } = args;
if (n < 0 || n > 100) {
return JSON.stringify({
success: false,
error: "n must be between 0 and 100"
});
}
function fib(num) {
if (num <= 1) return num;
return fib(num - 1) + fib(num - 2);
}
const result = fib(Math.floor(n));
return JSON.stringify({
success: true,
n: n,
result: result
});
}
// Plugin initialization
export async function init(toolRegistry) {
toolRegistry.register(greetUserDefinition, greetUserHandler);
toolRegistry.register(fibonacciDefinition, fibonacciHandler);
console.log(" 🎉 Example plugin tools registered");
}- Always return JSON strings from your tool handlers
- Include success/error status in your responses
- Validate input parameters before processing
- Handle errors gracefully and return meaningful error messages
- Keep tool names descriptive and use snake_case
- Document your parameters with clear descriptions
- Use async/await for asynchronous operations
- Follow semver for version numbers
- Place your plugin directory in
plugins/ - Restart the agent - it will automatically load your plugin
- Check the console output for successful loading
- Test your tools by asking the AI to use them
- Plugin not loading: Check console for error messages
- Missing plugin.json: Ensure manifest file exists in plugin root
- Tool not found: Verify tool names in manifest match registration
- Invalid manifest: Validate JSON syntax and required fields
- Handler errors: Check that handler function is async and returns JSON string