--- 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 `/git-release/`. 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 | | --- | --- | | `/git-release.md` | `git-release` | | `/git-release/SKILL.md` | `git-release` | | `/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..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`.