SKILL.md Reference
Complete reference for the SKILL.md file format, frontmatter fields, and tool permissions
File Format
A SKILL.md file has two parts: YAML frontmatter (metadata) and a markdown body (agent instructions). The frontmatter is enclosed between --- delimiters.
SKILL.md
---
name: code-review
description: Automated code review with best practices
version: 1.0.0
tags:
- review
- quality
allowed-tools: Read, Edit
---
# Code Review
When reviewing code, follow these guidelines...Required Fields
| Field | Type | Description |
|---|---|---|
| name | string | Unique identifier. Must start with a letter or number. Alphanumeric characters, spaces, hyphens, and underscores only. Max 256 characters. |
| description | string | Brief one-line summary of what the skill does. Max 4096 characters. This appears in search results and skill listings. |
Optional Fields
| Field | Type | Description |
|---|---|---|
| version | string | Semantic version (e.g., "1.0.0"). Helps users track updates. |
| author | string | Your name or handle. |
| tags | string[] | Categorization tags for search and discovery. |
| agents | string[] | Compatible agents (e.g., ["claude", "cursor", "codex"]). |
| license | string | License identifier (e.g., "MIT", "Apache-2.0"). |
| compatibility | string | Compatibility notes (e.g., language requirements). Max 500 characters. |
| allowed-tools | string | List of tools the skill needs. Can be a comma-separated string (e.g., "Bash, Read, Edit") or a YAML list. Declaring this helps users understand the skill's security surface area. |
| metadata | object | Arbitrary key-value pairs for custom metadata. |
Content Body
The markdown body after the frontmatter is what the AI agent reads and follows. This is where you write the instructions, examples, and guidelines.
Structure your content with clear headers:
Recommended structure
# Skill Name
Brief overview of what this skill does and when to use it.
## Guidelines
Specific rules and patterns to follow.
## Examples
### Good
```typescript
// Show the desired pattern
```
### Avoid
```typescript
// Show what NOT to do
```
## Edge Cases
Special situations and how to handle them.Agents process markdown natively. Use code blocks, lists, and headers to organize instructions. The more structured your content, the more consistently the agent will follow it.
Declaring Tool Permissions
The allowed-tools field declares which tools your skill needs. This is important for transparency — users can see what a skill will do before installing it. The platform audit also uses this field for security scoring.
| Tool | Risk Level | Description |
|---|---|---|
| Read | Low | Read file contents. Generally safe. |
| Edit | Low | Modify existing files. Cannot create new files. |
| Write | Medium | Create or overwrite files. |
| Bash | High | Run shell commands. Most powerful and most scrutinized. |
Only request tools your skill actually needs. Skills requesting
Bash access receive extra scrutiny during audit and users will be more cautious about installing them.Complete Example
testing-helper/SKILL.md
---
name: testing-helper
description: Generate comprehensive test suites following TDD best practices
version: 1.2.0
author: Jane Developer
tags:
- testing
- tdd
- quality
agents:
- claude
- cursor
license: MIT
allowed-tools: Read, Edit, Write
---
# Testing Helper
When asked to write or improve tests, follow these guidelines.
## Structure
- Group related tests in describe/context blocks
- Use descriptive names: `test_<function>_<scenario>_<expected>`
- Follow Arrange-Act-Assert (AAA) pattern
## Coverage Priorities
1. Happy path — verify the main use case works
2. Edge cases — null, undefined, empty, boundary values
3. Error scenarios — verify error messages and types
4. Integration points — mock external dependencies
## Examples
### Good test
```typescript
describe("UserService.create", () => {
it("returns the created user with generated ID", async () => {
const input = { name: "Alice", email: "alice@example.com" };
const user = await service.create(input);
expect(user.id).toBeDefined();
expect(user.name).toBe("Alice");
});
it("throws ValidationError for duplicate email", async () => {
await service.create({ name: "A", email: "dup@test.com" });
await expect(
service.create({ name: "B", email: "dup@test.com" })
).rejects.toThrow(ValidationError);
});
});
```
### Avoid
```typescript
// Too vague, no assertion context
test("works", async () => {
const result = await service.create({ name: "A", email: "a@b.com" });
expect(result).toBeTruthy();
});
```