Documentation Index
Fetch the complete documentation index at: https://mintlify.com/anomalyco/opencode/llms.txt
Use this file to discover all available pages before exploring further.
Agent skills let OpenCode discover reusable instructions from your repo or home directory.
Skills are loaded on-demand via the native skill tool—agents see available skills and can load the full content when needed.
Place files
Create one folder per skill name and put a SKILL.md inside it.
OpenCode searches these locations:
- Project config:
.opencode/skills/<name>/SKILL.md
- Global config:
~/.config/opencode/skills/<name>/SKILL.md
- Project Claude-compatible:
.claude/skills/<name>/SKILL.md
- Global Claude-compatible:
~/.claude/skills/<name>/SKILL.md
- Project agent-compatible:
.agents/skills/<name>/SKILL.md
- Global agent-compatible:
~/.agents/skills/<name>/SKILL.md
Create skill directory
Create a directory for your skill:mkdir -p .opencode/skills/git-release
Create SKILL.md file
Create a SKILL.md file with frontmatter and content:.opencode/skills/git-release/SKILL.md
---
name: git-release
description: Create consistent releases and changelogs
license: MIT
compatibility: opencode
metadata:
audience: maintainers
workflow: github
---
## What I do
- Draft release notes from merged PRs
- Propose a version bump
- Provide a copy-pasteable `gh release create` command
## When to use me
Use this when you are preparing a tagged release.
Ask clarifying questions if the target versioning scheme is unclear.
Use the skill
The agent can now load this skill:Load the git-release skill and help me create a release.
Understand discovery
For project-local paths, OpenCode walks up from your current working directory until it reaches the git worktree.
It loads any matching skills/*/SKILL.md in .opencode/ and any matching .claude/skills/*/SKILL.md or .agents/skills/*/SKILL.md along the way.
Global definitions are also loaded from ~/.config/opencode/skills/*/SKILL.md, ~/.claude/skills/*/SKILL.md, and ~/.agents/skills/*/SKILL.md.
Discovery order
Skills are discovered in this order:
- Global external skills (
.claude/skills/, .agents/skills/ in home directory)
- Project external skills (walking up from current directory to worktree)
- OpenCode skills (
.opencode/skills/ directories)
- Additional paths (from
skills.paths config)
- Remote skills (from
skills.urls config)
Later sources can override earlier ones if they have the same skill name.
Discovery implementation
The skill discovery system:
// From skill/skill.ts
export const state = Instance.state(async () => {
const skills: Record<string, Info> = {}
const dirs = new Set<string>()
// Scan external skill directories (.claude/skills/, .agents/skills/)
if (!Flag.OPENCODE_DISABLE_EXTERNAL_SKILLS) {
// Global skills first
for (const dir of EXTERNAL_DIRS) {
const root = path.join(Global.Path.home, dir)
await scanExternal(root, "global")
}
// Project skills (walking up directory tree)
for await (const root of Filesystem.up({
targets: EXTERNAL_DIRS,
start: Instance.directory,
stop: Instance.worktree,
})) {
await scanExternal(root, "project")
}
}
// Scan .opencode/skill/ directories
for (const dir of await Config.directories()) {
const matches = await Glob.scan(OPENCODE_SKILL_PATTERN, { cwd: dir })
for (const match of matches) await addSkill(match)
}
// Scan additional paths from config
for (const skillPath of config.skills?.paths ?? []) {
const resolved = resolveSkillPath(skillPath)
const matches = await Glob.scan(SKILL_PATTERN, { cwd: resolved })
for (const match of matches) await addSkill(match)
}
// Download and load skills from URLs
for (const url of config.skills?.urls ?? []) {
const list = await Discovery.pull(url)
for (const dir of list) {
const matches = await Glob.scan(SKILL_PATTERN, { cwd: dir })
for (const match of matches) await addSkill(match)
}
}
return { skills, dirs }
})
Write frontmatter
Each SKILL.md must start with YAML frontmatter.
Only these fields are recognized:
name (required)
description (required)
license (optional)
compatibility (optional)
metadata (optional, string-to-string map)
Unknown frontmatter fields are ignored.
---
name: git-release
description: Create consistent releases and changelogs
license: MIT
compatibility: opencode
metadata:
audience: maintainers
workflow: github
version: "1.0"
---
Validate names
name must:
- Be 1–64 characters
- Be lowercase alphanumeric with single hyphen separators
- Not start or end with
-
- Not contain consecutive
--
- Match the directory name that contains
SKILL.md
Equivalent regex:
Valid names:
git-release
code-review
test-generator
api-docs
Invalid names:
Git-Release (uppercase)
-git-release (starts with hyphen)
git--release (consecutive hyphens)
git_release (underscore)
Follow length rules
description must be 1-1024 characters.
Keep it specific enough for the agent to choose correctly.
# Good
description: Create consistent releases and changelogs from merged PRs
# Bad (too vague)
description: Help with releases
# Bad (too long - over 1024 chars)
description: This skill helps you create releases by analyzing...
Use an example
Create .opencode/skills/git-release/SKILL.md like this:
---
name: git-release
description: Create consistent releases and changelogs
license: MIT
compatibility: opencode
metadata:
audience: maintainers
workflow: github
---
## What I do
- Draft release notes from merged PRs
- Propose a version bump
- Provide a copy-pasteable `gh release create` command
## When to use me
Use this when you are preparing a tagged release.
Ask clarifying questions if the target versioning scheme is unclear.
OpenCode lists available skills in the skill tool description.
Each entry includes the skill name and description:
<available_skills>
<skill>
<name>git-release</name>
<description>Create consistent releases and changelogs</description>
</skill>
</available_skills>
The agent loads a skill by calling the tool:
skill({ name: "git-release" })
Control which skills agents can access using pattern-based permissions in opencode.json:
{
"permission": {
"skill": {
"*": "allow",
"pr-review": "allow",
"internal-*": "deny",
"experimental-*": "ask"
}
}
}
| Permission | Behavior |
|---|
allow | Skill loads immediately |
deny | Skill hidden from agent, access rejected |
ask | User prompted for approval before loading |
Patterns support wildcards: internal-* matches internal-docs, internal-tools, etc.
Override per agent
Give specific agents different permissions than the global defaults.
For custom agents (in agent frontmatter):
---
permission:
skill:
"documents-*": "allow"
---
For built-in agents (in opencode.json):
{
"agent": {
"plan": {
"permission": {
"skill": {
"internal-*": "allow"
}
}
}
}
}
Completely disable skills for agents that shouldn’t use them:
For custom agents:
---
tools:
skill: false
---
For built-in agents:
{
"agent": {
"plan": {
"tools": {
"skill": false
}
}
}
}
When disabled, the <available_skills> section is omitted entirely.
Advanced configuration
Additional skill paths
Add custom directories to scan for skills:
{
"skills": {
"paths": [
"~/shared-skills",
"./team-skills",
"/absolute/path/to/skills"
]
}
}
Paths can be:
- Absolute:
/path/to/skills
- Relative to project:
./team-skills
- Home relative:
~/shared-skills
Remote skill repositories
Load skills from remote URLs:
{
"skills": {
"urls": [
"https://example.com/skills"
]
}
}
The remote URL must serve an index.json file:
https://example.com/skills/index.json
{
"skills": [
{
"name": "git-release",
"description": "Create consistent releases",
"files": ["SKILL.md", "template.md"]
},
{
"name": "code-review",
"description": "Review code for issues",
"files": ["SKILL.md", "checklist.md"]
}
]
}
Skills are downloaded to ~/.cache/opencode/skills/ and loaded automatically.
Disable external skills
Disable Claude Code/Agent compatible skill directories:
export OPENCODE_DISABLE_EXTERNAL_SKILLS=1
This disables scanning of .claude/skills/ and .agents/skills/ directories.
Skill content structure
The content of your SKILL.md (after the frontmatter) contains instructions for the agent.
Best practices
Be specific about what the skill does:
## What I do
- Analyze git history between tags
- Extract merged PRs and group by type (features, fixes, breaking)
- Generate semantic version bump recommendation
- Format output as markdown changelog
- Provide `gh release create` command
Explain when to use the skill:
## When to use me
Use this skill when:
- You're ready to create a new release
- You need to generate changelog entries
- You want version bump recommendations
Don't use this skill for:
- Pre-release testing
- Backporting fixes
Provide context and constraints:
## Assumptions
- Project follows semantic versioning
- PRs are labeled with `feature`, `fix`, `breaking-change`
- Release branch is `main`
- GitHub CLI (`gh`) is available
Include examples:
## Example output
```markdown
# Release v1.2.0
## Features
- Add support for remote skills (#123)
- Improve skill discovery performance (#124)
## Fixes
- Fix skill name validation (#125)
## Breaking Changes
- Remove deprecated skill API (#126)
Create release:
gh release create v1.2.0 --title "Release v1.2.0" --notes-file CHANGELOG.md
**Structure complex skills:**
```markdown
## Process
### Step 1: Analyze commits
- Run `git log` to get commits since last tag
- Parse commit messages for conventional commit format
- Extract issue/PR references
### Step 2: Categorize changes
- Group by type: features, fixes, breaking changes
- Sort by significance
- Filter out internal/chore commits
### Step 3: Generate output
- Format as markdown with proper headers
- Include PR links
- Add version bump recommendation
- Generate release command
Examples
Code review skill
.opencode/skills/code-review/SKILL.md
---
name: code-review
description: Comprehensive code review with security and performance checks
license: MIT
---
## What I do
- Review code changes for bugs, security issues, and performance problems
- Check code style and best practices
- Identify potential edge cases
- Suggest specific improvements with code examples
## Review checklist
### Security
- SQL injection vulnerabilities
- XSS vulnerabilities
- Authentication/authorization issues
- Sensitive data exposure
- Input validation
### Performance
- Inefficient algorithms (O(n²) or worse)
- Unnecessary database queries
- Missing indexes
- Memory leaks
- Blocking operations
### Code Quality
- Error handling
- Edge cases
- Code duplication
- Naming clarity
- Test coverage
## Output format
For each issue found, provide:
1. Severity (Critical/High/Medium/Low)
2. Location (file:line)
3. Description of the issue
4. Specific code fix
5. Explanation of why the fix works
Test generator skill
.opencode/skills/test-generator/SKILL.md
---
name: test-generator
description: Generate comprehensive unit tests with edge cases
---
## What I do
- Analyze function/class implementation
- Generate unit tests covering all code paths
- Include edge cases and error scenarios
- Follow project's testing patterns
- Aim for >90% code coverage
## Test generation strategy
### 1. Analyze the code
- Identify all public functions/methods
- Map input parameters and their types
- Identify return values and side effects
- Note error conditions and exceptions
### 2. Generate test cases
- Happy path tests
- Edge cases (empty input, null, undefined, etc.)
- Boundary conditions
- Error scenarios
- Async/Promise handling if applicable
### 3. Follow conventions
- Use existing test framework (Jest, Vitest, etc.)
- Match naming patterns from existing tests
- Use same mocking/stubbing approach
- Follow describe/it structure
## Example output structure
```typescript
describe('FunctionName', () => {
describe('happy path', () => {
it('should handle valid input', () => { })
})
describe('edge cases', () => {
it('should handle empty input', () => { })
it('should handle null input', () => { })
})
describe('error scenarios', () => {
it('should throw on invalid input', () => { })
})
})
### API documentation skill
```markdown title=".opencode/skills/api-docs/SKILL.md"
---
name: api-docs
description: Generate OpenAPI/Swagger documentation from code
metadata:
framework: express
format: openapi-3.0
---
## What I do
- Extract API routes from Express/Fastify/etc. code
- Generate OpenAPI 3.0 specification
- Document request/response schemas
- Include authentication requirements
- Add code examples
## Documentation structure
For each endpoint, document:
### Basic info
- HTTP method and path
- Summary and description
- Tags for grouping
### Request
- Path parameters
- Query parameters
- Request body schema
- Headers (especially auth)
### Response
- Success status codes and schemas
- Error status codes and schemas
- Response headers
### Security
- Authentication method
- Required scopes/permissions
### Examples
- Request example (curl)
- Response example (JSON)
## Output format
Generate valid OpenAPI 3.0 YAML that can be imported into:
- Swagger UI
- Postman
- API documentation generators
Database migration skill
.opencode/skills/db-migration/SKILL.md
---
name: db-migration
description: Generate database migration scripts with rollback support
metadata:
orm: drizzle
database: postgresql
---
## What I do
- Generate migration scripts for schema changes
- Include both up and down migrations
- Handle data transformations safely
- Add validation and safety checks
- Follow project's migration conventions
## Migration strategy
### For schema changes
1. Analyze existing schema
2. Determine required changes
3. Generate migration with:
- DDL statements (CREATE, ALTER, DROP)
- Proper column types and constraints
- Index creation/updates
- Foreign key handling
### For data migrations
1. Add safety checks (row counts, validation)
2. Use transactions
3. Include rollback logic
4. Add logging for tracking
## Safety rules
- Never DROP columns/tables without explicit confirmation
- Always include rollback migration
- Use transactions where possible
- Add validation checks before/after
- Log all operations
- Test migrations on copy of production data
## Example output
```typescript
import { sql } from 'drizzle-orm'
export async function up(db) {
// Add new column
await db.execute(sql`
ALTER TABLE users
ADD COLUMN email_verified BOOLEAN DEFAULT FALSE
`)
// Migrate existing data
await db.execute(sql`
UPDATE users
SET email_verified = TRUE
WHERE email IS NOT NULL
`)
}
export async function down(db) {
// Rollback
await db.execute(sql`
ALTER TABLE users
DROP COLUMN email_verified
`)
}
---
## Skills vs Commands vs Tools
Understanding when to use each:
### Skills
**Use for**: Complex, reusable workflows with detailed instructions
**Characteristics**:
- Loaded on-demand by the agent
- Can contain extensive documentation
- Multiple pages of instructions
- Can include bundled resources
- Shareable across projects
**Example**: Code review methodology with checklists
### Commands
**Use for**: Quick, templated prompts with argument substitution
**Characteristics**:
- Invoked with `/command-name`
- Simple template with placeholders
- Can execute shell commands
- Can reference files
- Lightweight and fast
**Example**: `/test` to run test suite
### Tools
**Use for**: Executable functions the LLM can call
**Characteristics**:
- Execute code when called
- Return results to the LLM
- Can perform actions
- Strongly typed arguments
- Can be written in any language
**Example**: Database query tool, API client
### Decision matrix
| Need | Use |
|------|-----|
| Multi-step process with detailed guidance | **Skill** |
| Quick prompt with argument substitution | **Command** |
| Execute code and return results | **Tool** |
| Share complex workflow across projects | **Skill** |
| Simple one-liner with file/shell refs | **Command** |
| Interact with external systems | **Tool** |
| Extensive documentation and examples | **Skill** |
---
## Troubleshoot loading
If a skill does not show up:
1. **Verify `SKILL.md` is spelled in all caps**
```bash
# Correct
.opencode/skills/my-skill/SKILL.md
# Wrong
.opencode/skills/my-skill/skill.md
.opencode/skills/my-skill/Skill.md
-
Check that frontmatter includes
name and description
---
name: my-skill # Required
description: ... # Required
---
-
Ensure skill names are unique across all locations
- Check for duplicate names in global and project skills
- Later sources override earlier ones
-
Check permissions—skills with
deny are hidden from agents
{
"permission": {
"skill": {
"my-skill": "allow" // Make sure not "deny"
}
}
}
-
Verify directory name matches skill name
# Correct
.opencode/skills/my-skill/SKILL.md # name: my-skill
# Wrong
.opencode/skills/MySkill/SKILL.md # name: my-skill
-
Check skill name format
# Valid
name: my-skill
name: code-review
name: api-docs
# Invalid
name: My-Skill # No uppercase
name: my_skill # No underscores
name: -my-skill # Can't start with hyphen
name: my--skill # No consecutive hyphens