Skip to content

Skill Development Best Practices

What You'll Learn

After completing this tutorial, you will be able to:

  • Write skill names that follow naming conventions
  • Write descriptions that are easily recognized by automatic recommendations
  • Organize clear skill directory structures
  • Use script features appropriately
  • Avoid common Frontmatter errors
  • Improve skill discoverability and usability

Why Best Practices Matter

The OpenCode Agent Skills plugin doesn't just store skills—it also:

  • Auto-discovery: Scans skill directories from multiple locations
  • Semantic matching: Recommends skills based on description similarity to user messages
  • Namespace management: Supports coexistence of skills from multiple sources
  • Script execution: Automatically scans and executes runnable scripts

Following best practices ensures your skills:

  • ✅ Are correctly recognized and loaded by the plugin
  • ✅ Receive higher recommendation priority in semantic matching
  • ✅ Avoid conflicts with other skills
  • ✅ Are more easily understood and used by team members

Naming Conventions

Skill Name Rules

Skill names must conform to the following specifications:

Naming Rules

  • ✅ Use lowercase letters, numbers, and hyphens
  • ✅ Start with a letter
  • ✅ Use hyphens to separate words
  • ❌ Don't use uppercase letters or underscores
  • ❌ Don't use spaces or special characters

Examples:

✅ Good Examples❌ Bad ExamplesReason
git-helperGitHelperContains uppercase letters
docker-builddocker_buildUses underscores
code-reviewcode reviewContains spaces
test-utils1-testStarts with a number

Source reference: src/skills.ts:106-108

typescript
name: z.string()
  .regex(/^[\p{Ll}\p{N}-]+$/u, { message: "Name must be lowercase alphanumeric with hyphens" })
  .min(1, { message: "Name cannot be empty" }),

Directory Name vs. Frontmatter Relationship

The skill directory name and the name field in frontmatter can be different:

yaml
---
# Directory is my-git-tools, but frontmatter name is git-helper
name: git-helper
description: Git common operations helper
---

Recommended practices:

  • Keep directory name and name field consistent for easier maintenance
  • Use short, memorable identifiers for directory names
  • The name field can be more specific about skill purpose

Source reference: src/skills.ts:155-158


Description Writing Tips

Purpose of Descriptions

Skill descriptions are not just for user guidance—they're also used for:

  1. Semantic matching: The plugin calculates similarity between description and user messages
  2. Skill recommendation: Automatically recommends relevant skills based on similarity
  3. Fuzzy matching: Used to recommend similar skills when skill name is misspelled

Good vs. Bad Descriptions

✅ Good Descriptions❌ Bad DescriptionsReason
"Automate Git branch management and commit workflow, supports auto-generating commit messages""Git tool"Too vague, lacks specific functionality
"Generate type-safe API client code for Node.js projects""A useful tool"Doesn't specify use case
"Translate PDF to Chinese while preserving original formatting""Translation tool"Doesn't mention special capabilities

Description Writing Principles

Description Writing Principles

  1. Be specific: Explain the specific purpose and use cases of the skill
  2. Include keywords: Include keywords users might search for (e.g., "Git", "Docker", "translation")
  3. Highlight unique value: Explain advantages compared to similar skills
  4. Avoid redundancy: Don't repeat the skill name

Examples:

markdown
---
name: pdf-translator
description: Translate English PDF documents to Chinese while preserving original layout, image positions, and table structures. Supports batch translation and custom glossaries.
---

This description includes:

  • ✅ Specific features (PDF translation, format preservation)
  • ✅ Use cases (English documents)
  • ✅ Unique value (format preservation, batch, glossaries)

Source reference: src/skills.ts:109

typescript
description: z.string()
  .min(1, { message: "Description cannot be empty" }),

Directory Organization

Basic Structure

A standard skill directory contains:

my-skill/
├── SKILL.md              # Main skill file (required)
├── README.md             # Detailed documentation (optional)
├── tools/                # Runnable scripts (optional)
│   ├── setup.sh
│   └── run.sh
└── docs/                 # Supporting documentation (optional)
    ├── guide.md
    └── examples.md

Skipped Directories

The plugin automatically skips the following directories (doesn't scan for scripts):

Automatically Skipped Directories

  • node_modules - Node.js dependencies
  • __pycache__ - Python bytecode cache
  • .git - Git version control
  • .venv, venv - Python virtual environments
  • .tox, .nox - Python testing environments
  • Any hidden directory starting with .

Source reference: src/skills.ts:61

typescript
const skipDirs = new Set(['node_modules', '__pycache__', '.git', '.venv', 'venv', '.tox', '.nox']);
PurposeRecommended Directory NameDescription
Script filestools/ or scripts/Store runnable scripts
Documentationdocs/ or examples/Store supporting documentation
Configurationconfig/Store configuration files
Templatestemplates/Store template files

Script Usage

Script Discovery Rules

The plugin automatically scans for executable files in skill directories:

Script Discovery Rules

  • ✅ Scripts must have executable permissions (chmod +x script.sh)
  • ✅ Maximum recursion depth is 10 levels
  • ✅ Skips hidden directories and dependency directories
  • ❌ Non-executable files are not recognized as scripts

Source reference: src/skills.ts:86

typescript
if (stats.mode & 0o111) {
  scripts.push({
    relativePath: newRelPath,
    absolutePath: fullPath
  });
}

Setting Script Permissions

Bash scripts:

bash
chmod +x tools/setup.sh
chmod +x tools/run.sh

Python scripts:

bash
chmod +x tools/scan.py

And add shebang at the beginning of the file:

python
#!/usr/bin/env python3
import sys
# ...

Script Invocation Examples

When a skill is loaded, AI sees the available script list:

Available scripts:
- tools/setup.sh: Initialize development environment
- tools/build.sh: Build project
- tools/deploy.sh: Deploy to production

AI can call these scripts using the run_skill_script tool:

javascript
run_skill_script({
  skill: "project-builder",
  script: "tools/build.sh",
  arguments: ["--release", "--verbose"]
})

Frontmatter Best Practices

Required Fields

name: Skill unique identifier

  • Lowercase letters, numbers, and hyphens
  • Short but descriptive
  • Avoid generic names (like helper, tool)

description: Skill description

  • Specifically explain functionality
  • Include use cases
  • Appropriate length (1-2 sentences)

Optional Fields

license: License information

yaml
license: MIT

allowed-tools: Restrict tools available to the skill

yaml
allowed-tools:
  - read
  - write
  - bash

metadata: Custom metadata

yaml
metadata:
  author: "Your Name"
  version: "1.0.0"
  category: "development"

Source reference: src/skills.ts:105-114

typescript
const SkillFrontmatterSchema = z.object({
  name: z.string()
    .regex(/^[\p{Ll}\p{N}-]+$/u, { message: "Name must be lowercase alphanumeric with hyphens" })
    .min(1, { message: "Name cannot be empty" }),
  description: z.string()
    .min(1, { message: "Description cannot be empty" }),
  license: z.string().optional(),
  "allowed-tools": z.array(z.string()).optional(),
  metadata: z.record(z.string(), z.string()).optional()
});

Complete Example

markdown
---
name: docker-deploy
description: Automate Docker image building and deployment process, supports multi-environment configuration, health checks, and rollbacks
license: MIT
allowed-tools:
  - read
  - write
  - bash
metadata:
  version: "2.1.0"
  author: "DevOps Team"
  category: "deployment"
---

# Docker Auto-Deployment

This skill helps you automate the Docker image build, push, and deployment process.

## Usage

...

Avoiding Common Mistakes

Mistake 1: Name Doesn't Follow Conventions

Bad example:

yaml
name: MyAwesomeSkill  # ❌ Uppercase letters

Fix:

yaml
name: my-awesome-skill  # ✅ Lowercase + hyphens

Mistake 2: Description Too Vague

Bad example:

yaml
description: "A useful tool"  # ❌ Too vague

Fix:

yaml
description: "Automate Git commit workflow, auto-generate standard-compliant commit messages"  # ✅ Specific and clear

Mistake 3: Scripts Without Execution Permissions

Problem: Scripts aren't recognized as executable

Solution:

bash
chmod +x tools/setup.sh

Verify:

bash
ls -l tools/setup.sh
# Should show: -rwxr-xr-x (has x permission)

Mistake 4: Directory Name Conflicts

Problem: Multiple skills use the same name

Solution:

  • Use namespaces (via plugin config or directory structure)
  • Or use more descriptive names

Source reference: src/skills.ts:258-259

typescript
// Only keep the first skill with the same name, subsequent ones are ignored
if (skillsByName.has(skill.name)) {
  continue;
}

Improving Discoverability

1. Optimize Description Keywords

Include keywords users might search for in your description:

yaml
---
name: code-reviewer
description: Automated code review tool that checks code quality, potential bugs, security vulnerabilities, and performance issues. Supports multiple languages including JavaScript, TypeScript, Python, and more.
---

Keywords: code review, code quality, bugs, security vulnerabilities, performance issues, JavaScript, TypeScript, Python

2. Use Standard Skill Locations

The plugin discovers skills in the following priority order:

  1. .opencode/skills/ - Project-level (highest priority)
  2. .claude/skills/ - Project-level Claude
  3. ~/.config/opencode/skills/ - User-level
  4. ~/.claude/skills/ - User-level Claude

Recommended practices:

  • Project-specific skills → Place at project-level
  • General-purpose skills → Place at user-level

3. Provide Detailed Documentation

Beyond SKILL.md, you can also provide:

  • README.md - Detailed instructions and usage examples
  • docs/guide.md - Complete usage guide
  • docs/examples.md - Real-world examples

Summary

This tutorial covered best practices for skill development:

  • Naming conventions: Use lowercase letters, numbers, and hyphens
  • Description writing: Be specific, include keywords, highlight unique value
  • Directory organization: Clear structure, skip unnecessary directories
  • Script usage: Set executable permissions, note depth limits
  • Frontmatter conventions: Correctly fill required and optional fields
  • Avoid mistakes: Common problems and solutions

Following these best practices ensures your skills:

  • ✅ Are correctly recognized and loaded by the plugin
  • ✅ Receive higher recommendation priority in semantic matching
  • ✅ Avoid conflicts with other skills
  • ✅ Are more easily understood and used by team members

Next Up

In the next lesson, we'll learn about API Tool Reference.

You'll see:

  • Detailed parameter descriptions for all available tools
  • Tool invocation examples and return value formats
  • Advanced usage and important considerations

Appendix: Source Reference

Click to expand source code locations

Last updated: 2026-01-24

FeatureFile PathLine Numbers
Skill name validationsrc/skills.ts106-108
Skill description validationsrc/skills.ts109-110
Frontmatter Schema definitionsrc/skills.ts105-114
Skipped directories listsrc/skills.ts61
Script executable permission checksrc/skills.ts86
Duplicate skill deduplication logicsrc/skills.ts258-259

Key constants:

  • Skipped directories: ['node_modules', '__pycache__', '.git', '.venv', 'venv', '.tox', '.nox']

Key functions:

  • findScripts(skillPath: string, maxDepth: number = 10): Recursively find executable scripts in skill directory
  • parseSkillFile(skillPath: string): Parse SKILL.md and validate frontmatter