Ai Coding 6 min read

How to Create Your First Agent Skill

A step-by-step guide to writing an agent skill from scratch: directory structure, SKILL.md format, effective descriptions, common patterns, and a complete working example.

Agent skills are easy to use and easy to create. The entire format is a folder with a markdown file. No build step, no SDK, no configuration beyond the file itself. Here’s how to write one from scratch.

The Directory Structure

Create a folder inside .cursor/skills/ (for a project-level skill) or ~/.cursor/skills/ (for a personal skill that works across all your projects). The folder name should match your skill name: lowercase, hyphens, no spaces.

.cursor/skills/
  commit-messages/
    SKILL.md

That’s the minimum. One folder, one file. For more complex skills, you can add supporting files:

.cursor/skills/
  deploy-checklist/
    SKILL.md
    reference.md
    scripts/
      validate.sh

The agent reads SKILL.md first. It only loads reference files and scripts when the instructions tell it to.

Writing the SKILL.md

Every SKILL.md has two parts: YAML frontmatter and a markdown body.

Frontmatter

Two fields are required:

---
name: commit-messages
description: Generate commit messages following the project's conventional commits format. Use when the user asks for help with commit messages or is committing code.
---

The name must be lowercase letters, numbers, and hyphens. Max 64 characters. It should match the folder name.

The description is critical. It’s what the agent uses to decide whether this skill is relevant to the current task. A bad description means the skill never gets loaded. A good description triggers reliably.

Writing Effective Descriptions

Follow the WHAT and WHEN pattern:

  • WHAT: What the skill does (specific capabilities)
  • WHEN: When the agent should use it (trigger scenarios)

Here are examples of the difference:

# Bad: vague, no trigger terms
description: Helps with git stuff

# Good: specific capabilities, clear triggers
description: Generate commit messages using conventional commits format (feat, fix, chore, refactor). Use when the user asks to commit, write a commit message, or review staged changes.

Write the description in third person. It gets injected into the agent’s system prompt, so “I can help you” reads strangely in that context.

The Markdown Body

This is where you write the actual instructions. The agent is already capable. You’re providing context it doesn’t have: your conventions, your preferences, your workflows.

# Commit Messages

## Format

Use conventional commits:

\`\`\`
type(scope): description

Optional body explaining why, not what.
\`\`\`

## Types

- `feat`: new feature
- `fix`: bug fix
- `refactor`: code change that doesn't fix a bug or add a feature
- `chore`: maintenance tasks
- `docs`: documentation only

## Rules

- Keep the subject line under 72 characters
- Use imperative mood: "add feature" not "added feature"
- Don't end the subject with a period
- Include scope when the change is limited to a specific module

Notice what’s not in there: no explanation of what git is, no tutorial on how commits work, no preamble about why good commit messages matter. The agent already knows all of that. You’re only providing the information it doesn’t have: your project’s specific conventions.

Common Patterns

Template Pattern

Give the agent an output format to follow:

## PR Description Template

\`\`\`markdown
## Summary
[1-3 bullet points describing the change]

## Test Plan
[How to verify this works]

## Breaking Changes
[List any breaking changes, or "None"]
\`\`\`

Workflow Pattern

Break multi-step processes into clear sequences:

## Deployment Process

1. Run the test suite: `npm test`
2. Build the production bundle: `npm run build`
3. Run the staging smoke tests: `npm run test:staging`
4. Deploy to production: `npm run deploy`
5. Verify the health check: `curl https://api.example.com/health`

Conditional Pattern

Guide the agent through decision points:

## Database Changes

**Adding a new column?**
→ Create a migration file in `db/migrations/`
→ Column must have a default value
→ Run `npm run db:migrate` to apply

**Modifying an existing column?**
→ Never rename directly; create a new column, migrate data, drop the old one
→ This requires two separate deployments

Feedback Loop Pattern

For quality-critical tasks, build validation into the workflow:

## After generating tests

1. Run the tests: `npm test`
2. If any test fails, fix the test (not the source code)
3. Run coverage: `npm run test:coverage`
4. If coverage dropped, add missing test cases
5. Only proceed when all tests pass and coverage is stable

Progressive Disclosure

Keep SKILL.md under 500 lines. If you have extensive reference material, put it in a separate file and link to it:

## API Conventions

Follow the patterns in [API_STANDARDS.md](API_STANDARDS.md) for endpoint naming, error responses, and pagination.

The agent will read API_STANDARDS.md only when it needs to, keeping the context window clean during unrelated tasks. Keep references one level deep. Don’t chain references to references.

Using Your Skill

Once the file is in place, the agent picks it up in three ways:

Automatic discovery. Start a new chat and work on a relevant task. The agent matches the task against your skill description and loads it automatically. No invocation needed.

Slash command. Type /commit-messages to explicitly invoke the skill.

Context attachment. Type @commit-messages to attach the skill as context without invoking it.

A Complete Example

Here’s a full skill for scaffolding React components in a project that uses a specific structure:

.cursor/skills/
  react-components/
    SKILL.md
---
name: react-components
description: Scaffold React components following project conventions. Use when creating new components, refactoring existing ones, or when the user asks about component structure.
---

# React Components

## File Structure

Every component gets its own directory:

\`\`\`
src/components/
  Button/
    Button.tsx        # Component
    Button.test.tsx   # Tests
    index.ts          # Re-export
\`\`\`

## Component Template

\`\`\`tsx
interface ButtonProps {
  children: React.ReactNode;
  variant?: 'primary' | 'secondary';
  onClick?: () => void;
}

export function Button({ children, variant = 'primary', onClick }: ButtonProps) {
  return (
    <button className={styles[variant]} onClick={onClick}>
      {children}
    </button>
  );
}
\`\`\`

## Conventions

- Named exports only, no default exports
- Props interface named `ComponentNameProps`
- Functional components only
- Co-locate tests with the component
- Re-export from index.ts for clean imports

Security: Vet Before You Install

Community skill registries are growing fast. As of early 2026, roughly 10% of published skills on public hubs have been flagged as potentially malicious. Before installing a skill from an external source:

  • Read the SKILL.md in full
  • Inspect any scripts in the scripts/ directory
  • Check if the skill requests network access, file system writes, or environment variable reads that don’t match its purpose
  • Treat it like installing an npm package from an unknown publisher

The safest skills are the ones you write yourself. Start there, and expand to community skills once you’re comfortable reading and auditing them.

Get Insanely Good at AI

Get Insanely Good at AI

The book for developers who want to understand how AI actually works. LLMs, prompt engineering, RAG, AI agents, and production systems.

Keep Reading