opencode/packages/docs/skills.mdx
2026-07-09 18:01:15 -04:00

227 lines
7.6 KiB
Text

---
title: "Skills"
description: ""
---
Skills are Markdown instructions that OpenCode can advertise to an agent and
load when they are relevant. A skill can include supporting scripts,
references, and other files in the same directory.
## Create a skill
Create one directory per skill with a `SKILL.md` file:
```text
.opencode/skills/
└── git-release/
├── SKILL.md
├── scripts/
│ └── changelog.ts
└── references/
└── release-policy.md
```
```markdown title=".opencode/skills/git-release/SKILL.md"
---
name: Git Release
description: Prepare release notes, version bumps, and GitHub releases
metadata:
opencode/slash: "true"
---
## Workflow
1. Read `references/release-policy.md`.
2. Summarize merged changes since the previous tag.
3. Propose the version bump before changing files.
4. Run `scripts/changelog.ts` only after the user approves the version.
```
Paths in a skill are relative to the directory containing `SKILL.md`.
## Discovery
OpenCode automatically adds the following source directories:
| Scope | Sources |
| --- | --- |
| Global | `~/.config/opencode/skills` |
| Global compatibility | `~/.claude/skills`, `~/.agents/skills` |
| Project | `.opencode/skills` |
| Project compatibility | `.claude/skills`, `.agents/skills` |
For project sources, OpenCode searches from the current directory upward to
the project root and includes matching directories at every level.
Within each source directory, OpenCode discovers:
- Markdown files at the source root, such as `skills/git-release.md`
- `SKILL.md` files at any depth, such as `skills/git-release/SKILL.md`
The directory form is recommended because it gives the skill a private base
directory for supporting files.
## Configure sources
Use the `skills` array in any `opencode.json` or `opencode.jsonc` to add local
directories or HTTP catalogs:
```jsonc title="opencode.jsonc"
{
"$schema": "https://opencode.ai/config.json",
"skills": [
"./team-skills",
"~/shared/opencode-skills",
"/opt/company-skills",
"https://example.com/opencode/skills/"
]
}
```
Relative paths are resolved from the active OpenCode working directory, not
from the directory containing the config file. Paths beginning with `~/` use
the current user's home directory. Only `http://` and `https://` values are
treated as URL sources.
Every discovered config document contributes its `skills` entries; the arrays
are additive rather than replacing one another.
### HTTP catalogs
An HTTP source is a base URL containing an `index.json`:
```json title="index.json"
{
"skills": [
{
"name": "git-release",
"version": "3",
"files": [
"git-release.md",
"references/release-policy.md"
]
}
]
}
```
OpenCode downloads those files from
`<base-url>/git-release/<file>`. File paths must be safe, relative,
same-origin paths. Each entry must include either `SKILL.md` or a Markdown file
named after the index entry, such as `git-release.md`.
Use the named Markdown form for HTTP catalogs. Each downloaded skill directory
is itself a source root, so `git-release.md` produces the ID `git-release`; a
root-level `SKILL.md` produces the literal ID `SKILL` in the current V2
implementation. Increment `version` when files change so OpenCode refreshes
the cached copy.
## Frontmatter
V2 reads these fields:
| Field | Purpose |
| --- | --- |
| `name` | Display name; defaults to the path-derived ID |
| `description` | Summary shown to the model and command catalog |
| `slash` | Set to `false` to hide the skill from the V2 slash-command catalog |
| `metadata.opencode/slash` | Boolean or `"true"`/`"false"`; overrides `slash` |
| `metadata.opencode/autoinvoke` | Set to `false` to omit the skill from model-facing discovery |
Frontmatter, `name`, and `description` are optional at runtime. However, a
clear `description` is strongly recommended: skills without one are not
advertised to the model. `license`, `compatibility`, and other metadata may be
included for portability, but V2 does not interpret them.
`opencode/autoinvoke: false` only removes the skill from the model's available
skills list. The skill remains registered and can still be activated explicitly
by its ID.
## IDs and validation
The skill ID comes from its path, not its frontmatter:
| File | ID |
| --- | --- |
| `<source>/git-release.md` | `git-release` |
| `<source>/git-release/SKILL.md` | `git-release` |
| `<source>/teams/release/SKILL.md` | `release` |
IDs are exact and case-sensitive. V2 currently does not enforce the Agent
Skills name regex, length limits, a match between `name` and the directory, or
a maximum description length. The frontmatter `name` is only a display label.
For portable, predictable skills, use a unique lowercase kebab-case ID of 1-64
characters and keep it aligned with the directory name:
```text
^[a-z0-9]+(-[a-z0-9]+)*$
```
## Precedence
Skills are keyed by ID. If several sources define the same ID, the later source
wins. Sources are registered in this order, from lower to higher precedence:
1. Built-in skills
2. `.claude/skills` sources, global first and then from the current directory upward
3. `.agents/skills` sources, global first and then from the current directory upward
4. `~/.config/opencode/skills`
5. Project `.opencode/skills`, from the project root toward the current directory
6. Explicit `skills` config entries, in config priority and array order
Avoid duplicate IDs unless an override is intentional.
## Runtime loading
At each model step, OpenCode advertises permitted skills that have a
description and do not set `opencode/autoinvoke` to `false`. The advertisement
contains only each skill's ID, name, and description; it does not add every
skill body to the prompt.
When the model calls the `skill` tool with an exact ID, OpenCode:
1. Resolves the current winning definition for that ID
2. Checks the `skill` permission for the selected agent
3. Adds the Markdown body, without frontmatter, to the conversation
4. Provides the skill's base directory and a sample of up to ten supporting file paths
Supporting file contents are not loaded automatically. The agent can read a
referenced file when the skill instructs it to do so. The supporting-file
sample is available for directory-based `SKILL.md` skills; flat Markdown skills
receive no neighboring file list.
In the V2 CLI, skills appear as `/id` commands unless `slash` resolves to
`false`. Selecting one appends the skill body as a skill message and resumes
the session.
## Permissions
Permission rules use the `skill` action and the skill ID as the resource. Rules
are evaluated in order, with the last matching rule winning:
```jsonc title="opencode.jsonc"
{
"permissions": [
{ "action": "skill", "resource": "*", "effect": "allow" },
{ "action": "skill", "resource": "internal-*", "effect": "deny" },
{ "action": "skill", "resource": "experimental-*", "effect": "ask" }
]
}
```
`deny` removes matching skills from model-facing discovery and rejects skill
tool loading. `ask` advertises the skill but requests approval when the model
loads it. The same rules can be placed under an individual
`agents.<id>.permissions` array.
## Troubleshooting
If a skill is missing or loads the wrong content:
1. Confirm the file is either a root-level `*.md` or a nested file named exactly `SKILL.md`.
2. Check the path-derived ID rather than the frontmatter `name`.
3. Add a `description` if the skill should be advertised to the model.
4. Check `opencode/autoinvoke` and the selected agent's `skill` permissions.
5. Look for a later source defining the same ID.
6. For HTTP catalogs, verify `index.json`, same-origin file paths, and a changed `version`.