Can I create TypeScript-based skills?
can i create typescript-based skills?
Based on my exploration of the codebase, I can give you a clear answer:
No, you cannot create TypeScript-based skills. Skills in OpenCode are Markdown-based only.
##How Skills Work
Skills are defined as SKILL.md files (Markdown with YAML frontmatter). They're essentially prompt/instruction documents that agents can load on-demand—not executable code.
###Skill Locations
.opencode/skill/<name>/SKILL.md(project)~/.config/opencode/skill/<name>/SKILL.md(global).claude/skills/<name>/SKILL.md(Claude-compatible, project)~/.claude/skills/<name>/SKILL.md(Claude-compatible, global)
###Skill Structure
---
name: my-skill
description: What this skill does
---
## Instructions for the agent
Step-by-step guidance goes here...
##What Skills Are For
Skills are reusable instructions/prompts that agents can dynamically load when needed. They're designed to give the AI detailed guidance on how to perform specific tasks (like "git-release" or "code-review")—not to execute code.
If you're looking to extend OpenCode with actual TypeScript code/logic, you'd want to look at tools instead (see packages/opencode/src/tool/), though those aren't user-definable in the same plug-and-play way that skills are.
tools are fine, but what's nice about skills is that they're discovered on-demand. how would i make that a thing? like a mix between tools and skills.
Now I have a complete picture. Let me explain what you could do:
##You Can Already Create TypeScript-Based Tools!
OpenCode already supports custom TypeScript tools that are discovered automatically. They go in:
.opencode/tool/<name>.ts(project-local)~/.config/opencode/tool/<name>.ts(global)
From packages/opencode/src/tool/registry.ts:
const glob = new Bun.Glob("{tool,tools}/*.{js,ts}")
for (const dir of await Config.directories()) {
for await (const match of glob.scan({ cwd: dir, ... })) {
const namespace = path.basename(match, path.extname(match))
const mod = await import(match)
// ... registers tools from the module
}
}
##But They're Not "On-Demand" Like Skills
You're right that skills have a nice pattern where:
- The agent sees a list of available skills with descriptions
- The agent chooses which skill to load when relevant
- The full content is loaded lazily
Custom tools, by contrast, are always loaded and always visible to the agent.
##How You Could Build "Discoverable Tools"
To get the skill-like discovery pattern for executable code, you'd essentially need to create a meta-tool similar to SkillTool. Here's a conceptual approach:
###Option 1: Create a "Dynamic Tool Loader" Tool
You could create a custom tool that:
- Scans a directory for tool definitions (with metadata frontmatter)
- Shows available tools in its description
- When called, dynamically imports and executes the chosen tool
import { tool } from "@opencode-ai/plugin"
import { Glob } from "bun"
// Scan for discoverable tools at init time
const discoverableTools = await scanTools()
export default tool({
description: `Load and execute a dynamic tool.
<available_tools>
${discoverableTools.map(t => ` <tool><name>${t.name}</name><description>${t.description}</description></tool>`).join('\n')}
</available_tools>`,
args: {
name: tool.schema.string().describe("Tool name to execute"),
args: tool.schema.record(tool.schema.any()).describe("Arguments for the tool"),
},
async execute({ name, args }) {
const toolPath = discoverableTools.find(t => t.name === name)?.path
if (!toolPath) throw new Error(`Tool ${name} not found`)
const mod = await import(toolPath)
return mod.default.execute(args)
},
})
###Option 2: Fork/Extend the Skill System
You could modify the skill system to support a type: executable frontmatter field, where instead of returning markdown, it imports and runs a .ts file referenced in the skill.
The first option is something you can do today without modifying OpenCode's core. The second would require contributing to the codebase. Would either of these directions work for what you're trying to build?
END OF POST