What's OpenCode's take on skills and implementation?
what's opencode's take on "skills"? how do they implement them?
Now I have a comprehensive understanding. Here's OpenCode's take on "skills" and how they implement them:
##OpenCode's Take on Skills
Skills in OpenCode are reusable, on-demand instruction sets that agents can discover and load during a conversation. Think of them as specialized knowledge modules or "how-to guides" that an AI agent can pull in when needed for a specific task.
###Core Philosophy
-
Lazy Loading: Skills aren't loaded into the context by default. Agents see a list of available skills (name + description), and only load the full content when they need it. This keeps the context window clean.
-
Convention over Configuration: Skills are discovered automatically from well-known locations using a simple file structure.
-
Claude Code Compatible: OpenCode supports the
.claude/skills/directory structure, making it compatible with Claude Code's skill format.
##Implementation Details
###1. Skill Discovery (packages/opencode/src/skill/skill.ts)
Skills are discovered by scanning specific directories for SKILL.md files:
const OPENCODE_SKILL_GLOB = new Bun.Glob("{skill,skills}/**/SKILL.md")
const CLAUDE_SKILL_GLOB = new Bun.Glob("skills/**/SKILL.md")
Search locations (in order):
.opencode/skill/<name>/SKILL.md(project-level)~/.config/opencode/skill/<name>/SKILL.md(global).claude/skills/<name>/SKILL.md(Claude-compatible, project)~/.claude/skills/<name>/SKILL.md(Claude-compatible, global)
The discovery walks up from the current directory to the git worktree root, collecting skills along the way.
###2. Skill Format
Each SKILL.md must have YAML frontmatter with:
name(required) — lowercase, hyphen-separated, 1-64 charsdescription(required) — 1-1024 chars, used by agents to decide when to use it
Example:
---
name: git-release
description: Create consistent releases and changelogs
---
## What I do
- Draft release notes from merged PRs
- Propose a version bump
...
###3. The Skill Tool (packages/opencode/src/tool/skill.ts)
Skills are exposed to agents via a built-in skill tool. The tool dynamically builds its description to list all available skills:
export const SkillTool = Tool.define("skill", async (ctx) => {
const skills = await Skill.all()
// Filter by agent permissions
const accessibleSkills = agent
? skills.filter((skill) => {
const rule = PermissionNext.evaluate("skill", skill.name, agent.permission)
return rule.action !== "deny"
})
: skills
const description = [
"Load a skill to get detailed instructions for a specific task.",
"<available_skills>",
...accessibleSkills.flatMap((skill) => [
` <skill>`,
` <name>${skill.name}</name>`,
` <description>${skill.description}</description>`,
` </skill>`,
]),
"</available_skills>",
].join(" ")
// ...
})
When an agent calls skill({ name: "git-release" }), the tool:
- Looks up the skill by name
- Asks for user permission (respects
allow/deny/asksettings) - Parses and returns the full
SKILL.mdcontent with its base directory
###4. Permission Control
Skills integrate with OpenCode's permission system. In opencode.json:
{
"permission": {
"skill": {
"*": "allow",
"internal-*": "deny",
"experimental-*": "ask"
}
}
}
allow— skill loads immediatelydeny— skill is hidden from the agent entirelyask— user prompted before loading
###5. Compaction Protection
Skills are protected from context pruning (packages/opencode/src/session/compaction.ts):
const PRUNE_PROTECTED_TOOLS = ["skill"]
This ensures that loaded skills aren't erased when OpenCode compacts the conversation history.
##Summary
OpenCode's skill system is elegant:
- Discovery: Glob-based scanning of convention-driven directories
- Exposure: A dynamic
skilltool that lists available skills in its description - Loading: On-demand via tool call, with permission checks
- Format: Simple markdown with YAML frontmatter
- Compatibility: Works with both OpenCode-native and Claude Code skill directories
END OF POST