opencode
opencode copied to clipboard
Support for "Skills"
Yesterday Claude Code released a new feature called "Skills", that basically allows the user to define prompts, that are lazily loaded by the Agent when needed.
https://www.anthropic.com/news/skills
It would be nice to see a similar feature in OpenCode.
This issue might be a duplicate of existing issues. Please check:
- #3195: Dynamic system prompts for custom agents - discusses dynamically generating system prompts that can be lazily loaded, which is conceptually similar to the Skills feature for loading prompts when needed
- #12: Custom system prompt - requests custom system prompt functionality
Feel free to ignore if none of these address your specific case.
This issue might be a duplicate of existing issues. Please check:
- Dynamic system prompts for custom agents #3195: Dynamic system prompts for custom agents - discusses dynamically generating system prompts that can be lazily loaded, which is conceptually similar to the Skills feature for loading prompts when needed
- status messages and logging need work #12: Custom system prompt - requests custom system prompt functionality
Feel free to ignore if none of these address your specific case.
-
Not a duplicate, as this issue is refereeing to handling dynamic content in the system prompt (by running scripts), but these are always included. With skills the agent decides then it wants to include a specific "Skill".
-
Also not a duplicate
Sorry about that @tobias-walle the bot is a little overeager, I think ill make it reword it's comments so that people know they dont need to respond to it.
Every issue opened is seen by someone on the team but the bot helps find duplicates (sometimes haha)
No worries 😄 As I wasn't entirely sure about the first one, I checked and just wanted to share my findings.
Overall, I really like the bot, as it gives me some confidence that my issue is actually unique and that I didn't miss a duplicate.
Adding more to this as this guy has some interesting ideas on extensions to skills: https://github.com/obra/superpowers https://github.com/obra/superpowers-skills https://blog.fsck.com/2025/10/09/superpowers/
I think everything skills offers is already possible right, or at least most of it, just define a custom tool and return markdown from it
I mean that's like 99% of it I think
I think everything skills offers is already possible right, or at least most of it, just define a custom tool and return markdown from it
I mean that's like 99% of it I think
ya that's not surprising i'm just wondering if it could be the starting point for more in opencode. the skill sharing in the superpowers repo could be interesting.
Hey everyone! 👋
I just published an npm plugin that implements Anthropic's Skills Specification for OpenCode!
📦 npm package: https://www.npmjs.com/package/opencode-skills
📄 GitHub repo: https://github.com/malhashemi/opencode-skills
Installation (super simple!)
Add one line to your opencode.json or ~/.config/opencode/opencode.json:
{
"plugin": ["opencode-skills"]
}
That's it! OpenCode will automatically install the plugin from npm on next startup. No npm install needed.
What it does
This plugin provides one-to-one parity with Anthropic's Agent Skills Specification (v1.0), with the added bonus of supporting nested skills (e.g., skills/tools/analyzer/SKILL.md → skills_tools_analyzer) - a feature that Anthropic doesn't support yet.
How it works
The plugin scans your .opencode/skills/ directory (and ~/.opencode/skills/ for global skills), discovers all SKILL.md files, validates them against the spec, and exposes SKILL.md using its meta data as a callable tool (e.g., skills_my_skill). I'm assuming Claude Code implements this similarly, though I could be wrong here and something fancier is running under the hood
Quick Start
- Add plugin to
opencode.json(see above) - Restart OpenCode
- Create a skill:
mkdir -p .opencode/skills/my-skill
- Add a
SKILL.mdfile:
---
name: my-skill
description: A custom skill that helps with specific tasks
---
# My Skill
Your skill instructions here...
- Restart OpenCode again - your skill is now available as
skills_my_skill!
Integration with OpenCode
Since skills are just regular OpenCode tools, they benefit from OpenCode's existing tool management:
- ✅ Can be disabled globally via
opencode.json - ✅ Can be enabled/disabled per-agent in agent frontmatter
- ✅ Inherit all of OpenCode's permission system
Testing
I've tested this with Anthropic's official skills on Claude Sonnet 4.5 with max thinking, and they work beautifully. You may notice that the tool call return some instructions to the LLM about path management, I found that without it the agent gets lost searching for files mentioned in the SKILLS.md.
Note on Tool Restrictions
One difference from Anthropic's implementation: I couldn't find a way to implement skill-level tool restrictions (the allowed-tools field that's available in Claude Code). However, I don't think this is necessary in OpenCode since you'll typically pair skills with specific agents, and agents already have their own fine-grained tool permissions. This actually gives you more control - you can configure which tools are available at the agent level rather than embedding it in the skill itself.
Hope this helps the community! Let me know if anyone has feedback or suggestions. 🎉
For full documentation, check out the GitHub repo.
Feel free to PR if you have some valuable improvements
@thdxr and @rekram1-node , I believe you mentioned you are going to work on revamping the custom tools in the upcoming TUI. Should I expect a breaking change?
@malhashemi I'll test your solution seems a very straightforward and easy way to integrate Skills into opencode
@malhashemi I dont think there should be any breaking changes soon, but if you run into any issues just lmk.
We do version things with specific version bumps if breaking tho
Great idea with the plugin! I think this is already quite a good solution.
I think an official solution would still be valuable to have a common standard, but this doesn't has much priority (considering the big refactoring you are currently working on)
@tobias-walle @malhashemi @rekram1-node I'm wondering if you guys had taken a look at what this guy had done on the CC side https://blog.fsck.com/2025/10/09/superpowers/
i'm wondering if opencode taking the approach of public skills repo or taking the approach of openweb-ui's public search for prompts,functions ie for community sharing would be something that could really bring some adoption for an official version of skills support
i think we are going to watch them play out a little more before doing anything major, we have some higher priority items currently to tackle but thanks for the callout
@malhashemi Can you version-pin the plugin somehow?
@malhashemi Can you version-pin the plugin somehow?
@ferdinandyb yes you can, inside your opencode.json :
{ "plugin": ["[email protected]"] }
Just released v0.1.0 that uses the new noReply parameter from #3433 to deliver SKILL.md as a user message rather than a tool response (This should now survives purging), also followed Anthropic less verbose path resolution style, let me know if this causes any issue in paths resolution. Make sure to update OpenCode to the latest version.
Skills are extremely easy to implement
You can use my lightweight approach which aligns exactly with Anthropics, only difference is instead of a tool, it's a cli bash call - openskills read
Other than that, its injecting into the system prompt the list of skills available
OpenSkills supports .claude globally and also in .agent folders for advanced users
https://github.com/numman-ali/openskills
Give me 50 likes, and approval from OpenCode team, and ill open a native PR
To the opencode maintainers (@rekram1-node): As you consider an official implementation, I'd strongly argue against an approach that just injects all available skills into the system prompt. That would undermine opencode’s core feature of fine-grained, per-agent access control. A native implementation should treat each skill as its own distinct, manageable tool (just like MCPs and custom tools), so we can enable/disable specific skills per agent.
With that in mind, as a heavy user of Skills on cursor, opencode, and claude code, here’s what I’ve found working with both the openskills and opencode-skills plugins. My findings strongly favor one model for the opencode ecosystem.
-
Discovery
claude codediscovers all skills in theskillsfolder automatically and injects them into the system prompt.openskillsrequires running the CLI (openskills sync) every time I add a skill to get it discovered, and relies onAGENTS.mdto make skills discoverable.opencode-skillsautomatically discovers my skills on startup, just likeopencodedoes for MCPs and custom tools.
-
Access Control (The Most Important Point for
opencode)claude code: all skills are automatically exposed to your primary agent as well as all subagents (which I don’t like).openskills: By relying onAGENTS.md, it presents an all-or-nothing list to the agent, completely bypassingopencode's native, per-tool permission system.opencode-skills: (This is the key) It followsopencode’s model perfectly. Each skill becomes a native tool (e.g.,skills_my_skill) that I can control at the agent level. This has become the main reasonopencodehas overtakenclaude codeas my primary daily driver.
-
Invocation
claude codehas a single tool that, when invoked, serves the required skill as a user message. I like this because it has maximum persistence compared to tool responses or file reads that may get purged. (@rekram1-node can you clarify whether file reads get purged? I don’t have a deep understanding of how purging works inopencode.)openskillsrelies on the agent running a CLI command (openskills read <name>) and parsingstdout.opencode-skillsfollows theclaude codeinvocation pattern: it's a native tool that injects theSKILL.mdcontent as anoReply(user) message, which is the ideal way to handle persistence.
-
Availability
openskillsis very helpful if you use other tools in addition toopencode, since it works with anything that readsAGENTS.md.opencode-skillsis clearlyopencode-specific, which is perfect for what it does.
Thanks to both @malhashemi and @numman-ali for giving us access to skills in opencode at such unprecedented speed, literally in less than 48 hours after Anthropic released the feature, we have parity in opencode. Great community!
I'd strongly argue against an approach that just injects all available skills into the system prompt.
claude code: all skills are automatically exposed to your primary agent as well as all subagents (which I don’t like).
@numman-ali your approach is not equivalent to what Anthropic does. This should be functionally equivalent: klaudworks/universal-skills. At least when using it with Claude Code the API requests and reponses are equivalent to native skills.
As @ihabwahbi mentioned: Anthropic injects available tools into each API request instead of into the AGENTS.md. The advantage is that the knowledge about your skills does not decay throughout the conversation.
@klaudworks please read my full write up
https://github.com/numman-ali/openskills/blob/main/README.md
I literally network sniffed the calls and extracted the exact structure
There is system instructions added, and one load skills tool
Thats it
Agents.md is appended as system instructions for every other coding agent out there
Using MCP servers, removes the whole point of progressive disclosure
See their engineering blog
https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills
End of the day, we can trust the OpenCode team to determine the best option - and I'm sure it'll be configurable and take the best of all implementations
@numman-ali I agree that you send the exact same "skill tool description" message provided by Claude Code:
Tool Description: Skill
<!--
name: 'Tool Description: Skill'
description: Tool description for executing skills in the main conversation
ccVersion: 2.0.20
variables:
- AVAILBLE_SKILLS_1
- AVAILBLE_SKILLS_2
-->
Execute a skill within the main conversation
<skills_instructions>
When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
How to use skills:
- Invoke skills using this tool with the skill name only (no arguments)
- When you invoke a skill, you will see <command-message>The "{name}" skill is loading</command-message>
- The skill's prompt will expand and provide detailed instructions on how to complete the task
- Examples:
- \`command: "pdf"\` - invoke the pdf skill
- \`command: "xlsx"\` - invoke the xlsx skill
- \`command: "ms-office-suite:pdf"\` - invoke using fully qualified name
Important:
- Only use skills listed in <available_skills> below
- Do not invoke a skill that is already running
- Do not use this tool for built-in CLI commands (like /help, /clear, etc.)
</skills_instructions>
<available_skills>
${AVAILBLE_SKILLS_1}${AVAILBLE_SKILLS_2}
</available_skills>
What is not correct is that Claude Code sends the "Skill" tool description via the system prompt. The Claude.md is also not sent via a system prompt. At least not in Claude Code. It is sent via the following user input instead:
{
"model": "claude-sonnet-4-5-20250929",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "<system-reminder> ... $CLAUDE.md
The prior message will be part of your conversation history so your approach obviously works. It just has some shortcomings. LLMs have a recency bias so the knowledge of the CLAUDE.md / AGENTS.md fades throughout the conversation. That leads to worse retention of what each tool does and degrading accuracy when invoking tools. It also bypasses the training procedures to make LLMs reliably invoke tool calls.
The approach in openskills boils down to writing into the AGENT.md: "if you want more knowledge about apples, check .agent/skills/apple". That works but in my experience it doesn't work well especially in longer conversations. I'd be happy to hear your experience. You can just start a longer conversation and then try to invoke a skill. I'd strongly assume that it works less reliably. It might still work with direct prompts like "use skill apples" but I'd assume it fails with more implicit skill invocations.
What Claude actually does is to send their skill feature as an available tool in the request to the Anthropic API:
"tools": [
{
"name": "Skill",
"description": "${CONTENT_FROM_TOOL_DESCRIPTION}",
"input_schema": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The skill name (no arguments). E.g., \"pdf\" or \"xlsx\""
}
},
"required": [
"command"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
},
The MCP approach in klaudworks/universal-skills leads to the exact same tool call (with negligible syntactic differences) because each MCP tool is translated into an LLM tool call. It also uses progressive disclosure because the actual SKILL.md is only loaded on demand.
I don't like MCP in general because it provides no native progressive disclosure mechanism and thus bloats the context. However, if you just define a single MCP tool that loads skills on demand then MCP is actually exactly what you want:
- Easy to plug into any agent
- Providing tool call / function call options to the LLM
EDIT: If you would like to understand how skills work in-depth you can read this: https://x.com/klaudworks/status/1982029102925414477
For a native implementation, I'd probably not go with MCP but directly inject a new tool call into the API request. Maybe one would also like to add a little interface decoration for skill invocations.
MCP is just an easy mechanism to plug this skills feature into any agent while preserving all important properties.
apologies for jumping in, maybe i didn't read enough but just a note:
plugins allow custom tool definitions so that should be possible
Then, this may be the way to go for a native implementation. As far as I can judge this looks like a solid approach: https://github.com/malhashemi/opencode-skills. It differs slightly from Claude Codes implementation by creating a tool per skill. That bloats the context a little more than a single tool but that shouldn't matter unless someone plans to use hundreds of tools.
Skills being individual tools allows permission control. Not sure if it's realistic that you would want to access to individual skills though. By design they don't directly interact with external systems anyways. In my current opinion there is not much value in that.
It differs slightly from Claude Codes implementation by creating a tool per skill. That bloats the context a little more than a single tool but that shouldn't matter unless someone plans to use hundreds of tools.
I'd like to argue that if we are using a single tool we still have to pass the name and description of every skill that is available, so single tool vs multiple tool doesn't really blow the context as much as we'd like to believe, if anything with one tool per skill, when you limit certain skills to agents/subagents you would be saving context, why pass skills to a subagent that doesn't need them?
Also another important note to keep in mind is how to invoke a skill, I noticed in longer conversations tool response purging is another issue that you would face, SKILL.md loaded by an MCP or tool response ends up getting forgotten if the skill process starts to drag, Claude Code loads SKILL.md as a user message, thanks to @rekram1-node for approving the noReply addition to the API/SDK which allowed the plugin to load the SKILL.md in a similar fashion.
However, this solution is still not perfect, currently OpenCode default read tool does not allow reading files outside the working directory, so when a skill is residing in ~/.opencode/skills and that skill has reference files to read we are getting read errors, the current solution is to use bash to read the file which I believe not ideal.
@rekram1-node anything can be done in that regard? or do you recommend that I serve a custom read tool (I really don't want to do that, specially that Claude Code default read tool can read files in any absolute path without any issues).
@klaudworks:
That bloats the context a little more than a single tool but that shouldn't matter unless someone plans to use hundreds of tools.
I believe the issue is a workflow using many sessions and subagents, since agents & subagents can configure the tools then tools could be invoked a large number of times.
Skills being individual tools allows permission control. Not sure if it's realistic that you would want to access to individual skills though.
Yes, I believe, and find, these two features are essential.
@malhashemi:
I'd like to argue that if we are using a single tool we still have to pass the name and description of every skill that is available
Given that agents and subagents can configure the set of tools available, such universal lists seems redundant. If there is a use case can this behavior be configurable?
However, this solution is still not perfect, currently OpenCode default read tool does not allow reading files outside the working directory,
I isolate my projects in a container, and git, so a rouge prompt/skill/tool change doesn't affect me.... that said, this does matter for newer/casual users. Since OpenCode does not guard against making changes without source control (discussed in another issue), there is some responsibility to ensure no edits to files outside of the current working directory unless explicitly requested, e.g. using bash (off by default) instead of Read tool
However, this solution is still not perfect, currently OpenCode default read tool does not allow reading files outside the working directory, so when a skill is residing in
~/.opencode/skillsand that skill has reference files to read we are getting read errors, the current solution is to use bash to read the file which I believe not ideal.
@malhashemi Is this what you're referring to in this ticket? https://github.com/malhashemi/opencode-skills/issues/2
I was secretly hoping you wouldn't do something to close off access to the skills original directory.
my current strategy to minimise use of bash to access those files is to frontload all of references into a basicmemory project of the same name as the skill.
Not sure how bullet proof it really is though 😅
I suspect what you might have already thought of is providing a tool that allows reading of skill resources:
> pwd
/mnt/Store/Projects/test
> mythicaltree ~/.config/opencode/skills
speckit/
SKILL.md
planning/
SKILL.md
resources/
...
resources/
templates/
spec.md
plan.md
...
scripts/
get-worktree-id.sh
produces
skill_speckit()
skill_speckit_planning()
skill_resources(skillname: string, path: string)
and you might even address this in the skill description:
use `skill_resources(skillname:string,path:string)` when accessing `resource://<path>` references from a skills SKILL.md