opencode plugin with skills setup - continuation of this blog https://mitzen.blogspot.com/2026/04/opencode-creating-plugin-and.html
In the previous post, we learned how to setup plugin so we can call it from opencode. In this post, we are going to add a skill - bragging skills - as I find it really important arsenal to have especially in an interview.
So we only need to update our config object for opencode. Let's see an example of how to do it with skills
config: async (config: any) => {
config.skills = config.skills || {};
config.skills.paths = config.skills.paths || [];
if (!config.skills.paths.includes(skillsDir)) {
config.skills.paths.push(skillsDir);
}
And that's it. Once you have restart opencode, it will load my new skills.
The full code is here and the repo here: https://github.com/kepungnzai/appcoreopc-num-mastery.git
import { type Plugin } from "@opencode-ai/plugin"
import { tool } from "@opencode-ai/plugin/tool"
import path from 'path';
import fs from 'fs';
import os from 'os';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const normalizePath = (p: string, homeDir: string) => {
if (!p || typeof p !== 'string') return null;
let normalized = p.trim();
if (!normalized) return null;
if (normalized.startsWith('~/')) {
normalized = path.join(homeDir, normalized.slice(2));
} else if (normalized === '~') {
normalized = homeDir;
}
return path.resolve(normalized);
};
export const AppcoreopcNumMastery: Plugin = async () => {
const homeDir = os.homedir();
const skillsDir = path.resolve(__dirname, '../skills');
const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR as string, homeDir);
const configDir = envConfigDir || path.join(homeDir, '.config/opencode');
const myTool = tool({
description: "A simple plugin.",
args: {
query: tool.schema.string().describe("Question or topic to submit to Google AI Mode"),
timeout: tool.schema.number().min(5).max(120).optional().describe("Timeout in seconds (default: 30, max: 120)"),
followUp: tool.schema.boolean().optional().describe("Treat the query as a follow-up in the same session"),
},
async execute(args, _ctx) {
return `Hello ${args.query} winner!`
},
})
return {
tool: {
"appcoreopc-num-mastery": myTool,
},
config: async (config: any) => {
config.skills = config.skills || {};
config.skills.paths = config.skills.paths || [];
if (!config.skills.paths.includes(skillsDir)) {
config.skills.paths.push(skillsDir);
}
}
}
}
And your opencode has new skills. Abit more complicated that what we would have liked.
Comments