# Skills

Create a skill to give an agent reusable instructions for a specific task. Put a `SKILL.md` file in `.opencode/skills/<skill-id>` and describe when to use it in `description`.

```markdown title=".opencode/skills/git-release/SKILL.md"
---
name: Git Release
description: Prepare release notes, version bumps, and GitHub releases
---

## 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.
```

OpenCode advertises this skill when it is relevant. The agent can then load its instructions with the `skill` tool instead of adding every skill to every prompt.

## Create

Keep related scripts, references, and templates beside `SKILL.md`:

```text
.opencode/skills/
└── git-release/
    ├── SKILL.md
    ├── scripts/
    │   └── changelog.ts
    └── references/
        └── release-policy.md
```

Paths written inside the skill are relative to the directory containing `SKILL.md`. The directory form is recommended because it gives supporting files a private base directory.

## Discovery

OpenCode automatically searches these locations:

| 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 up to the project root and includes matching directories at every level.

Each source can contain either form:

```text
skills/
├── review.md
└── git-release/
    └── SKILL.md
```

- Markdown files must be at the source root, such as `skills/review.md`.
- Files named exactly `SKILL.md` can be nested in grouping directories, such as `skills/git-release/SKILL.md` or `skills/teams/release/SKILL.md`.
- A directory containing `SKILL.md` is one skill. OpenCode does not search inside it for more skills.
- Hidden files and directories and `node_modules` are skipped.
- Search stops six directories below the source root.

## Sources

Add more local directories or HTTP catalogs with the `skills` array in any `opencode.json` or `opencode.jsonc`:

```jsonc title="opencode.jsonc"
{
  "$schema": "https://opencode.ai/config.json",
  "skills": [
    "./team-skills",
    "~/shared/opencode-skills",
    "/opt/company-skills",
    "https://example.com/opencode/skills/",
  ],
}
```

| Value | Resolution |
| ----- | ---------- |
| Relative path | From the active OpenCode working directory, not the config file |
| `~/` path | From the current user's home directory |
| Absolute path | Used as written |
| `http://` or `https://` URL | Loaded as an HTTP catalog |

Every discovered config file contributes its entries. `skills` arrays are combined rather than replaced.

A connected [OpenCode Console](/console) workspace can also share skills.

## Catalogs

An HTTP catalog is a base URL with an `index.json` file:

```json title="index.json"
{
  "skills": [
    {
      "name": "git-release",
      "version": "3",
      "files": ["git-release.md", "references/release-policy.md"]
    }
  ]
}
```

For that entry, OpenCode downloads each file from `<base-url>/git-release/<file>`.

| Rule | Requirement |
| ---- | ----------- |
| Paths | Must be safe, relative, and same-origin |
| Entry file | Include `SKILL.md` or `<name>.md`, such as `git-release.md` |
| Updates | Increment `version` when files change so OpenCode refreshes its cache |

Each downloaded skill directory becomes a source root named after the entry, so both `git-release.md` and `SKILL.md` have the ID `git-release`.

## Frontmatter

Use frontmatter to name the skill and control where it appears:

```markdown title="SKILL.md"
---
name: Git Release
description: Prepare a repository release
metadata:
  opencode/autoinvoke: false
---

Prepare the changelog, version bump, tag, and release notes.
```

| Field                          | Behavior                                                          |
| ------------------------------ | ----------------------------------------------------------------- |
| `name`                         | Display name; defaults to the path-derived ID                     |
| `description`                  | Summary used to show the skill to the model                       |
| `metadata.opencode/autoinvoke` | Set to `false` to omit the skill from the model's available list  |
| `disable-model-invocation`     | Set to `true` for the same effect as `opencode/autoinvoke: false` |

All frontmatter is optional at runtime. Add a clear `description` when the model should discover the skill; skills without one are not advertised.

`opencode/autoinvoke: false` only hides the skill from the model's available list. The skill remains registered and can still be loaded explicitly by ID. When both `disable-model-invocation` and `opencode/autoinvoke` are set, `opencode/autoinvoke` wins. V2 accepts portability fields such as `license` and `compatibility` but does not interpret them.

## IDs

The file path determines the skill ID. The frontmatter `name` is only a display label.

| 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. For portable 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]+)*$
```

V2 currently does not enforce this pattern, the 1–64 character recommendation, a match between `name` and the directory, or a maximum description length.

## Precedence

Skills are selected by ID. If two sources define `git-release`, the source registered later supplies the skill that OpenCode loads:

```text
~/.config/opencode/skills/git-release/SKILL.md  ← lower precedence
.opencode/skills/git-release/SKILL.md           ← loaded
```

Sources are registered from lower to higher precedence:

1. Built-in skills
2. `.claude/skills`, global first and then from the farthest ancestor toward the current directory
3. `.agents/skills`, global first and then from the farthest ancestor toward the current directory
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 you intend to override an earlier skill.

## Loading

At each model step, OpenCode lists permitted skills that have a description and do not set `opencode/autoinvoke` to `false`. The list includes only the ID, name, and description, not the full Markdown body.

The model loads a skill by calling the `skill` tool with its exact ID:

```json title="skill tool input"
{
  "id": "git-release"
}
```

OpenCode then:

1. Selects the current definition for that ID.
2. Checks the selected agent's `skill` permission.
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.

To load a skill yourself, mention it in your prompt as `@skill-id`.

Supporting file contents are not loaded automatically. The agent reads them when the skill directs it to do so. The file sample is available for directory-based `SKILL.md` skills; flat Markdown skills do not receive a neighboring file list.

## Permissions

Use the `skill` action and the skill ID as the resource. Rules run in order, and the last matching rule wins:

```jsonc title="opencode.jsonc"
{
  "permissions": [
    { "action": "skill", "resource": "*", "effect": "allow" },
    { "action": "skill", "resource": "internal-*", "effect": "deny" },
    { "action": "skill", "resource": "experimental-*", "effect": "ask" },
  ],
}
```

| Effect | Behavior |
| ------ | -------- |
| `allow` | Advertises and loads matching skills without approval |
| `ask` | Advertises matching skills and asks before loading them |
| `deny` | Hides matching skills from the model and rejects loading |

Place the same rules under `agents.<id>.permissions` to apply them only to one agent.

## Troubleshooting

For example, this skill's ID is `release`, not its frontmatter name `Git Release`:

```text
.opencode/skills/release/SKILL.md
                      └─ ID: release
```

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, case-sensitive ID rather than the frontmatter `name`.
3. Add a `description` if the model should discover the skill.
4. Check `opencode/autoinvoke` and the selected agent's `skill` permissions.
5. Look for a later source that defines the same ID.
6. For HTTP catalogs, verify `index.json`, same-origin file paths, and a changed `version`.