Skip to content

5.3a Skill Basics ​

A Skill is an on-demand loaded domain knowledge package, defined through SKILL.md, that Agents automatically discover and load based on task semantics.

📝 Course Notes ​

Key concepts from this lesson:

Skill Basics Study Notes

What You'll Learn ​

  • Understand the core design philosophy of Skills
  • Create SKILL.md files that follow conventions
  • Configure Skill permission controls
  • Distinguish between Skill and CLAUDE.md use cases

Why Skills Are Needed ​

Your Current Problem ​

User: Help me query revenue data from the data warehouse

Claude: I suggest using this SQL query...
SELECT * FROM revenue WHERE date > '2024-01-01'

Claude provides a generic SQL pattern, but it doesn't know:

  • What your table structure looks like
  • How "revenue" is defined in your company
  • Test accounts must be excluded
  • Which summary table should be used

Root Cause: Claude starts fresh with every conversation, lacking your team's domain knowledge.

How Skills Solve This ​

User: Help me query revenue data from the data warehouse

Claude: [Automatically loads sql-analysis Skill]
I'll help you query revenue data. Based on your data conventions:
- Use the monthly_revenue summary table
- Exclude test accounts (account != 'Test')
- Revenue is calculated as ARR (monthly * 12)

SELECT ...

Skills encapsulate your domain knowledge into resources that Claude can load on demand.


Core Design Philosophy of Skills ​

Progressive Disclosure ​

Skills don't stuff everything into context; they use layered loading:

┌─────────────────────────────────────────────────────────┐
│ Layer 1: name + description (~100 words)               │
│ → Always visible, used to determine if loading is needed│
├─────────────────────────────────────────────────────────┤
│ Layer 2: SKILL.md body content                         │
│ → Loaded when task matches, contains main instructions  │
├─────────────────────────────────────────────────────────┤
│ Layer 3: Detailed documents in references/ directory    │
│ → Loaded only when specific details are needed          │
└─────────────────────────────────────────────────────────┘

Why This Design?

Context window is a precious resource. Stuffing all domain knowledge causes:

  • Excessive token consumption
  • Distracted model attention
  • Irrelevant content interfering with output

Progressive disclosure lets Claude load only what's needed for the current task.

Skill vs CLAUDE.md ​

FeatureCLAUDE.mdSkill
Loading TimingAlways loaded to contextOnly loaded when task matches
ScopeCurrent projectReusable across projects
Content TypePure MarkdownMarkdown + code + resource files
Platform SupportClaude Code / OpenCode onlyClaude.ai / Code / API
Typical UseProject coding conventions, local commandsDomain knowledge, workflows

Selection Principle:

  • Project-specific conventions (code style, branch naming) → CLAUDE.md
  • Reusable domain knowledge (data analysis workflows, audit standards) → Skill

Skill Directory Structure ​

Basic Structure ​

.opencode/
└── skill/
    └── code-review/
        └── SKILL.md      # Skill definition file (must be uppercase)
.opencode/
└── skill/
    └── sql-analysis/
        ├── SKILL.md              # Main file: workflow and key logic
        └── references/           # Detailed documents (loaded on demand)
            ├── finance.md        # Finance table structures
            ├── product.md        # Product table structures
            └── examples.md       # Query examples

Principle: Keep SKILL.md concise, put detailed content in references/, let Claude read it when needed.

OpenCode Search Locations ​

LocationScopeDescription
.opencode/skill/<name>/SKILL.mdCurrent projectProject-specific skills
~/.config/opencode/skill/<name>/SKILL.mdGlobalAvailable for all projects
.claude/skills/<name>/SKILL.mdCurrent projectClaude compatible format
~/.claude/skills/<name>/SKILL.mdGlobalClaude compatible format

Project paths are traversed from current directory up to git root.

Project References Are Not a Skill's references/ ​

The references/ directory inside a Skill is simply a conventional location for that Skill's own supporting material. The top-level references field in opencode.json is a separate feature: it registers local directories or Git repositories as project context.

jsonc
{
  "references": {
    "backend": {
      "path": "../backend",
      "description": "Backend service source code"
    },
    "design-system": {
      "repository": "https://github.com/example/design-system.git",
      "branch": "main",
      "description": "Components and design standards",
      "hidden": true
    }
  }
}
  • Local entries use path; Git entries use repository and may specify branch.
  • When description is present, the reference is included in the system context; hidden: true only hides it from @ autocomplete in the TUI.
  • Use the plural key references. The singular reference remains compatible in v1.18.22 but is deprecated.

See reference.ts:5-21 for the schema, system.ts:69-92 for system-context injection, and autocomplete.tsx:423-439 for the TUI hiding logic.

Custom Configuration Directory

You can specify additional Skill search paths via the OPENCODE_CONFIG_DIR environment variable:

bash
export OPENCODE_CONFIG_DIR="/path/to/custom/config"

OpenCode will scan both:

  • Default config directory: ~/.config/opencode/skill/
  • Custom config directory: $OPENCODE_CONFIG_DIR/skill/

This is useful for team-shared Skills or using different Skill sets in different environments.

In v1.18.22, OpenCode retrieves every configuration directory from the configuration service, then scans each one for {skill,skills}/**/SKILL.md files. See skill/index.ts:205-208.

Nested Directory Support ​

OpenCode supports nested Skill directories:

.opencode/
└── skill/
    └── audit/
        └── security/
            └── SKILL.md    # Skill name determined by frontmatter name field

Source: skill/index.ts:21-25

typescript
const OPENCODE_SKILL_PATTERN = "{skill,skills}/**/SKILL.md"

The ** means matching subdirectories at any depth.

Built-in customize-opencode Skill ​

v1.18.22 registers customize-opencode by default for modifying OpenCode's own configuration, Agents, Skills, plugins, MCP servers, and permissions. It is registered before Skills found on disk, so a local Skill with the same name can override the built-in version. See skill/index.ts:27-35 and skill/index.ts:276-284.

Scout Is Historical, Not a Current Agent

Scout was introduced briefly within this synchronization range but removed in v1.16.0. Do not continue to depend on Scout in Agent lists or workflows for v1.18.22; use the Agents and tools currently available when exploring a codebase.


SKILL.md Format ​

Required Frontmatter ​

yaml
---
name: "sql-analysis"
description: "Used for analyzing business data: revenue, ARR, customer segmentation, product usage, sales pipeline. Provides table structures, metric definitions, required filters, and query patterns."
---
FieldRequiredDescription
nameYesSkill identifier, used for invocation
descriptionYesTrigger condition description (most important!)
licenseNoLicense information
compatibilityNoCompatibility markers
metadataNoCustom key-value pairs

name Naming Convention ​

Official recommendations (source doesn't enforce, but following ensures compatibility):

✓ code-review
✓ sql-analysis
✓ git-release
✗ Code_Review    ← Don't use uppercase
✗ sql--analysis  ← Don't use consecutive hyphens
✗ -review        ← Don't start with hyphen

Regex reference: ^[a-z0-9]+(-[a-z0-9]+)*$

description Writing (Key to Triggering) ​

description is the sole factor determining whether a Skill triggers. Claude uses semantic understanding (not keyword matching) to judge if a task needs a certain Skill.

Poor Example:

yaml
description: "Help with documents"

Problem: Too vague, AI can't determine when to trigger.

Good Example:

yaml
description: |
  Extract tables from PDFs and convert to CSV format for data analysis workflows.
  Suitable for: filling PDF forms, batch processing PDF documents, extracting embedded PDF data.
  Not suitable for: simple PDF viewing, basic format conversion, PDF editing.

description Writing Template:

yaml
description: |
  [One sentence explaining core capability]
  Provides: [resources this Skill contains, like table structures, formulas, templates]
  Suitable for: [trigger scenario 1], [trigger scenario 2], [trigger scenario 3]
  Not suitable for: [boundary scenario 1], [boundary scenario 2]

description Elements:

  1. Specific Capability: What it can do (extract tables, convert formats)
  2. Provided Resources: What it contains (table structures, formulas, templates)
  3. Trigger Scenarios: When to use (batch processing, form filling)
  4. Boundary Constraints: When not to use (simple viewing)

Complete Example ​

markdown
---
name: "sql-analysis"
description: |
  Used for analyzing business data: revenue trends, ARR calculation, customer segmentation, product usage, sales pipeline.
  Provides: company table structures, metric definition formulas, standard filters, common query templates.
  Suitable for: writing SQL to analyze business data, understanding company metric definitions, querying data warehouse.
  Not suitable for: database administration, DDL operations, performance tuning, general SQL education.
---

# SQL Analysis Skill

## Quick Workflow

When user requests data analysis:

1. **Clarify Requirements**
   - What time range? (Default: current year)
   - Which customer segment?
   - What decision is this analysis for?

2. **Check Existing Dashboards**
   - See if `references/dashboards.md` has ready-made reports
   - If yes, prioritize guiding user to use them

3. **Determine Data Source**
   - Prefer summary tables over raw event data
   - Confirm table has required fields before querying

4. **Execute Analysis**
   - Apply required filters (exclude test accounts, etc.)
   - Validate results against known baselines

## Standard Query Filters

All revenue queries must:
- Exclude test accounts: `WHERE account != 'Test'`
- Use only complete periods: `WHERE month <= DATE_TRUNC(CURRENT_DATE(), MONTH)`

## ARR Calculation Method

- Monthly to ARR: `monthly_revenue * 12`
- 7-day run rate: `rolling_7d * 52`

## Detailed Documentation

When table structures and query patterns are needed, refer to:
- **Revenue & Finance** → `references/finance.md`
- **Product Usage** → `references/product.md`
- **Sales Pipeline** → `references/sales.md`

Note: SKILL.md only contains workflow and key logic; detailed table structures go in the references/ directory.


How Skills Are Discovered and Loaded ​

Discovery Mechanism ​

At startup, OpenCode scans all Skills and aggregates name and description into the skill tool description:

xml
<available_skills>
  <skill>
    <name>sql-analysis</name>
    <description>Used for analyzing business data: revenue, ARR, customer segmentation...</description>
  </skill>
  <skill>
    <name>code-review</name>
    <description>Perform code review, check conventions, bugs, performance and security</description>
  </skill>
</available_skills>

Loading Mechanism ​

When user sends a message, Claude determines whether to load a Skill based on semantics:

User message: Help me analyze last quarter's revenue data

Claude determines: This is a data analysis task, matches sql-analysis Skill

Claude invokes: skill({ name: "sql-analysis" })

Result: SKILL.md content loaded to context

Output After Loading ​

## Skill: sql-analysis

**Base directory**: /path/to/.opencode/skill/sql-analysis

[SKILL.md content]

The Base directory information tells Claude how to access relative path files in references/.


Permission Configuration ​

Global Permissions ​

Configure in opencode.json:

jsonc
{
  "permission": {
    "skill": {
      "pr-review": "allow",        // Load immediately
      "internal-*": "deny",        // Hidden, access denied
      "experimental-*": "ask",     // Ask user before loading
      "*": "allow"                 // Default allow others
    }
  }
}
Permission ValueBehavior
allowSkill loads immediately
denySkill hidden from Agent, access denied
askPrompt user confirmation before loading

Wildcards supported: internal-* matches internal-docs, internal-tools, etc.

Override Permissions per Agent ​

In Markdown Agent:

yaml
---
permission:
  skill:
    "documents-*": "allow"
---

In opencode.json:

jsonc
{
  "agent": {
    "plan": {
      "permission": {
        "skill": {
          "internal-*": "allow"
        }
      }
    }
  }
}

Disable Skill Tool ​

For Agents that don't need Skills, you can completely disable:

Markdown Method:

yaml
---
tools:
  skill: false
---

JSON Method:

jsonc
{
  "agent": {
    "plan": {
      "tools": {
        "skill": false
      }
    }
  }
}

When disabled, <available_skills> section won't appear in that Agent's tool description at all.


Simple Examples ​

Translation Skill ​

markdown
---
name: "translate"
description: "Professional translation, preserving format and terminology. Used for translating technical documentation, API docs, code comments."
---

# Translation Skill

## Translation Standards

1. Preserve original format and paragraph structure
2. Keep proper nouns in original with annotation
3. Check terminology table for technical terms
4. Proofread after translation

## Output Format

Wrap translation result in code block:


For uncertain translations, annotate original in parentheses.

Brand Guidelines Skill ​

markdown
---
name: "brand-guidelines"
description: "Apply official company brand colors and typography standards when creating documents, presentations, or interface designs that require the company's visual style."
---

# Brand Guidelines Skill

## Colors

**Primary Colors**:
- Dark: `#141413` - Main text and dark backgrounds
- Light: `#faf9f5` - Light backgrounds and text on dark
- Medium Gray: `#b0aea5` - Secondary elements

**Accent Colors**:
- Orange: `#d97757` - Primary accent
- Blue: `#6a9bcc` - Secondary accent
- Green: `#788c5d` - Tertiary accent

## Typography

- **Headings**: Poppins (fallback Arial)
- **Body**: Lora (fallback Georgia)

## Application Rules

- Use Poppins for headings (24pt and above)
- Use Lora for body text
- Intelligently select text color based on background

Common Pitfalls ​

IssueCauseSolution
Skill won't loadSKILL.md case incorrectMust be uppercase SKILL.md
Skill not showingMissing frontmatter fieldsMust include name and description
Task matches but doesn't triggerdescription too vagueAdd specific capabilities, scenarios, boundaries
Same-name Skill conflictSame name defined in multiple placesLater loaded overwrites earlier, check log warnings
Access deniedPermission set to denyCheck permission configuration
Skill directory not recognizedDirectory spelling issueBoth skill/ and skills/ supported

Lesson Summary ​

You learned:

  1. Skill Core Concept: Progressive disclosure, on-demand loading
  2. Directory Structure: skill/<name>/SKILL.md + references/
  3. SKILL.md Format: name and description required
  4. description Writing: Specific capability + trigger scenarios + boundary constraints
  5. Permission Control: allow/ask/deny + wildcards
  6. Skill vs CLAUDE.md: On-demand loading vs always loaded

Next Lesson Preview ​

Next lesson dives into advanced Skill usage: progressive disclosure three-layer structure, executable scripts, creation workflow, testing validation, and real-world examples.

Continue Learning: 5.3b Advanced Skills