opencode icon indicating copy to clipboard operation
opencode copied to clipboard

Support for "Skills"

Open tobias-walle opened this issue 1 month ago • 28 comments

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.

tobias-walle avatar Oct 17 '25 06:10 tobias-walle

This issue might be a duplicate of existing issues. Please check:

Feel free to ignore if none of these address your specific case.

github-actions[bot] avatar Oct 17 '25 06:10 github-actions[bot]

This issue might be a duplicate of existing issues. Please check:

Feel free to ignore if none of these address your specific case.

  1. 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".

  2. Also not a duplicate

tobias-walle avatar Oct 17 '25 15:10 tobias-walle

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)

rekram1-node avatar Oct 17 '25 15:10 rekram1-node

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.

tobias-walle avatar Oct 17 '25 15:10 tobias-walle

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/

kziemski avatar Oct 17 '25 23:10 kziemski

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

rekram1-node avatar Oct 17 '25 23:10 rekram1-node

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.

kziemski avatar Oct 17 '25 23:10 kziemski

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.mdskills_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

  1. Add plugin to opencode.json (see above)
  2. Restart OpenCode
  3. Create a skill:
mkdir -p .opencode/skills/my-skill
  1. Add a SKILL.md file:
---
name: my-skill
description: A custom skill that helps with specific tasks
---

# My Skill

Your skill instructions here...
  1. 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 avatar Oct 18 '25 02:10 malhashemi

@malhashemi I'll test your solution seems a very straightforward and easy way to integrate Skills into opencode

ihabwahbi avatar Oct 18 '25 02:10 ihabwahbi

@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

rekram1-node avatar Oct 18 '25 05:10 rekram1-node

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 avatar Oct 18 '25 07:10 tobias-walle

@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

kziemski avatar Oct 20 '25 10:10 kziemski

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

rekram1-node avatar Oct 20 '25 13:10 rekram1-node

@malhashemi Can you version-pin the plugin somehow?

ferdinandyb avatar Oct 24 '25 20:10 ferdinandyb

@malhashemi Can you version-pin the plugin somehow?

@ferdinandyb yes you can, inside your opencode.json :

{ "plugin": ["[email protected]"] }

malhashemi avatar Oct 25 '25 02:10 malhashemi

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.

malhashemi avatar Oct 26 '25 14:10 malhashemi

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

numman-ali avatar Oct 31 '25 01:10 numman-ali

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 code discovers all skills in the skills folder automatically and injects them into the system prompt.
    • openskills requires running the CLI (openskills sync) every time I add a skill to get it discovered, and relies on AGENTS.md to make skills discoverable.
    • opencode-skills automatically discovers my skills on startup, just like opencode does 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 on AGENTS.md, it presents an all-or-nothing list to the agent, completely bypassing opencode's native, per-tool permission system.
    • opencode-skills: (This is the key) It follows opencode’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 reason opencode has overtaken claude code as my primary daily driver.
  • Invocation

    • claude code has 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 in opencode.)
    • openskills relies on the agent running a CLI command (openskills read <name>) and parsing stdout.
    • opencode-skills follows the claude code invocation pattern: it's a native tool that injects the SKILL.md content as a noReply (user) message, which is the ideal way to handle persistence.
  • Availability

    • openskills is very helpful if you use other tools in addition to opencode, since it works with anything that reads AGENTS.md.
    • opencode-skills is clearly opencode-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!

ihabwahbi avatar Oct 31 '25 06:10 ihabwahbi

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).

taqtiqa-mark avatar Oct 31 '25 07:10 taqtiqa-mark

@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 avatar Nov 04 '25 14:11 klaudworks

@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 avatar Nov 04 '25 17:11 numman-ali

@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

klaudworks avatar Nov 04 '25 17:11 klaudworks

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.

klaudworks avatar Nov 04 '25 17:11 klaudworks

apologies for jumping in, maybe i didn't read enough but just a note:

plugins allow custom tool definitions so that should be possible

rekram1-node avatar Nov 04 '25 17:11 rekram1-node

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.

klaudworks avatar Nov 04 '25 18:11 klaudworks

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).

malhashemi avatar Nov 04 '25 18:11 malhashemi

@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.

taqtiqa-mark avatar Nov 04 '25 18:11 taqtiqa-mark

@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

taqtiqa-mark avatar Nov 04 '25 18:11 taqtiqa-mark

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.

@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

airtonix avatar Nov 05 '25 23:11 airtonix