Skip to content
Loading

The SKILL.md Pattern: Writing AI Agent Skills That Actually Trigger

The SKILL.md Pattern: Writing AI Agent Skills That Actually Trigger hero image

You write a skill. You give it detailed instructions, clear steps, good examples. You open a new session, ask the agent to do exactly what the skill covers, and nothing happens. So you rewrite the instructions. You add more detail. You restructure the steps. Still nothing. You spend an hour on this.

The problem was never the instructions.


The Part Nobody Reads First

For OpenCode, skills live at ~/.agents/skills/<skill-name>/SKILL.md. The format looks simple enough:

---
name: skill-name
description: >
  What the skill does. Use when user says "phrase one", "phrase two", or "trigger phrase".
---
Your skill instructions go here.

The instructions section is where most people spend their time. It is the wrong place to start. The description field at the top is what actually controls whether the skill ever runs at all.


How the Loading System Works

There are three levels, and understanding them changes how you write everything.

Level 1 happens at session start. OpenCode loads only the name and description from every installed skill. Not the body. Just those two fields, roughly 100 tokens per skill. This is the only signal the agent has when deciding whether a skill is relevant to your request.

Level 2 happens when the agent decides a skill matches. It reads the full SKILL.md body into context. This is when your instructions finally get seen.

Level 3 happens inside the skill body itself. If your skill references external files (a reference doc, a script), those are loaded only when the agent needs them.

The practical consequence: you can install many skills without paying a meaningful context cost at session start. The description is cheap to load. The body only enters context when it earns it. But if the description does not match the user's request, the body never loads. The skill does nothing.


The Description Field Is Not Documentation

This is the shift that clicked for me. The description is not there to explain the skill to a human reader. It is the trigger condition the agent evaluates against the current conversation. It needs to answer one question: does what the user said match something in here?

A bad description sounds like this:

description: Helps with documents.

Vague. The agent has no idea when to activate this.

Another common mistake looks more polished but fails the same way:

description: Writes professional README files with advanced formatting and badges.

This describes capability. The agent is not matching against capability. It is matching against what the user typed. If the user says "write a readme for this project", the description above might match. If they say "document this", it will not. You lost the activation on a phrasing variation.

A good description combines what the skill does with the specific phrases a user might actually say:

description: >
  Creates README.md files for software projects. Use when user asks to "write a README",
  "create a readme", "document this project", or "generate project documentation".

Now the agent has concrete anchors. It does not have to infer. It pattern-matches against phrases you explicitly included.


A Real Skill That Earns Its Keep

Here is a minimal SKILL.md I actually use, written for writing git commit messages in a consistent style:

---
name: git-commit-writer
description: >
  Writes conventional git commit messages. Use when user says "write a commit message",
  "commit this", "create a commit", or "generate a commit message for these changes".
---

# Git Commit Writer

You write concise, conventional commit messages based on the staged diff or described changes.

## Format

<type>(<scope>): <short summary>

[optional body: what changed and why, not how]

## Types

- feat: new feature
- fix: bug fix
- refactor: no behavior change
- docs: documentation only
- chore: tooling, deps, config

## Rules

- Summary line: 50 characters max, lowercase, no period.
- Body: wrap at 72 characters. Focus on motivation, not mechanics.
- Do not invent scope if it is not obvious from the diff.

Short body. Concrete format. The description maps directly to what I type when I want it.


Where Things Go

The folder structure under ~/.agents/skills/ is simple:

~/.agents/skills/
  my-skill/
    SKILL.md          # required
    references/       # optional: loaded on demand at Level 3
    scripts/          # optional: executable files, not read into context

The references/ folder is for any file you want the agent to read when the skill runs: API schemas, style guides, checklists. They stay out of context until the skill body explicitly references them. The scripts/ folder is for executables the skill might invoke. They are never read into context passively.

One constraint worth knowing up front: the skill name must be lowercase letters, numbers, and hyphens only, max 64 characters, and cannot start or end with a hyphen. Name it once and name it clearly.


Restricting What the Agent Can Do

There is an allowed-tools field that most skill documentation buries. It lets you lock a skill to a specific set of agent tools:

---
name: log-analyzer
description: >
  Reads and analyzes log files. Use when user says "check the logs" or
  "what errors are in my logs".
allowed-tools: Read, Grep, Glob
---

For read-only skills, this is worth setting. You get a skill that cannot accidentally write files or run shell commands mid-session. It is a guardrail you set once and forget.


Installing Skills vs. Writing Your Own

You do not have to write everything from scratch. The skills.sh ecosystem has a growing catalog of community skills you can install in one command:

npx skills add <owner/repo@skill-name> -g

The -g flag installs globally to ~/.agents/skills/, so the skill is available across all your projects.

Two skills I use constantly: the caveman skill triggers on phrases like "caveman mode" or "less tokens" and switches the agent into ultra-compressed communication. The body is 67 lines of instructions about how to speak efficiently. It cuts token usage around 75% when I am deep in a long session and need to stop burning context on prose. The find-skills skill activates when I say "find a skill for X" or "is there a skill that can..." and wraps npx skills find with quality verification steps. Both were installed in under ten seconds and have been running reliably since day one. The descriptions are precise. They trigger exactly when I intend them to.


What Changed

Once I stopped debugging skill bodies and started writing descriptions with explicit trigger phrases, skills started working the first time. Not every time I tried a new phrasing, but every time I matched one of the phrases I wrote in the description. That is the contract.

The mental model that helped: write the description for the agent, not for yourself. You are not explaining what the skill does. You are writing the match conditions it will be evaluated against. Get that right, and the instructions inside the body finally get a chance to matter.


Pro tip: If a skill is not triggering, open the SKILL.md and read only the description field. Ask yourself: does what I typed in the session closely resemble any phrase in this description? If the answer is no, that is your bug.