Plugin Bundling MCP Servers: Install-and-Launch Implementation and Dynamic userConfig Configuration
Chapter 51: Skill File Format: Markdown-Driven Behavior Definition and Parameter Declaration
51.1 The Nature of a Skill: Natural Language as Code
In traditional software development, behavior is always defined through code. Claude's Skill system challenges that assumption: a single .md file with properly structured YAML frontmatter can define a complete behavioral pattern for Claude.
Why can natural language serve as "code"? The fundamental reason is that Claude is a language model. Its ability to understand and follow natural language instructions far exceeds its ability to execute traditional programming languages. A carefully written Skill file can convey complex behavioral constraints at minimal cost, without requiring developers to learn a new DSL or API.
This does not mean Skills are casual documentation. On the contrary, Skill files have a strict format specification — every field has a precise semantic meaning and purpose. Understanding these specifications is a prerequisite for writing high-quality Skills.
51.2 The Complete Skill File Structure
A complete Skill file consists of two parts:
- YAML frontmatter: machine-readable metadata, enclosed in
---delimiters - Markdown body: human-readable behavioral description
---
# YAML frontmatter (machine-readable)
name: skill-identifier
version: 1.0.0
description: One-sentence summary of what this Skill does
# ... more fields ...
---
## Markdown body (natural language behavior description)
### Trigger Conditions
...
### Execution Steps
...
51.3 YAML Frontmatter Field Reference
Required Fields
name
The unique identifier for the Skill. Used for referencing within Plugins, searching in the marketplace, and invoking in code.
name: sql-query-builder
Naming rules:
- Only lowercase letters, numbers, and hyphens
- Cannot start or end with a hyphen
- Length: 3–64 characters
- Must be unique within a single Plugin
version
A version string following Semantic Versioning.
version: 2.1.0
major: incompatible API changes (modifying required parameters)minor: backward-compatible additions (adding optional parameters)patch: backward-compatible fixes (improving description text)
description
A single sentence. This is the first text users see in the marketplace. Be accurate, specific, and keep it under 120 characters.
description: Generate optimized SQL queries from natural language descriptions, supporting PostgreSQL and MySQL dialects
Parameter Declaration: parameters
The parameters field defines the interface between the Skill and the outside world. It tells Claude what inputs this Skill accepts, and the type and constraints of each input.
parameters:
- name: query_description
type: string
description: Natural language description of the data you want
required: true
- name: dialect
type: string
description: SQL dialect to use
required: false
default: postgresql
enum:
- postgresql
- mysql
- sqlite
- mssql
- name: max_rows
type: number
description: Maximum number of rows to return
required: false
default: 100
minimum: 1
maximum: 10000
- name: include_explanation
type: boolean
description: Whether to include a plain-language explanation of the SQL
required: false
default: true
- name: tables
type: array
description: Specific table names to consider (if known)
required: false
items:
type: string
Type System
| Type | Description | Supported Constraints |
|---|---|---|
string |
String value | enum, minLength, maxLength, pattern |
number |
Numeric (int or float) | minimum, maximum, multipleOf |
integer |
Integer only | minimum, maximum, multipleOf |
boolean |
Boolean value | No additional constraints |
array |
Array | items, minItems, maxItems |
object |
Object | properties, required |
Nested Object Parameter
parameters:
- name: filter
type: object
description: Filter conditions for the query
required: false
properties:
date_range:
type: object
properties:
start:
type: string
description: Start date (ISO 8601)
end:
type: string
description: End date (ISO 8601)
status:
type: array
items:
type: string
enum: [active, inactive, pending]
Metadata Fields
author
author: Jane Doe <[email protected]>
tags
Used for marketplace search. Recommended: 3–8 tags covering functional category, domain, and tech stack.
tags:
- database
- sql
- query-builder
- postgresql
- developer-tools
license
license: MIT
homepage
homepage: https://github.com/yourname/sql-query-builder-skill
Dependency Declarations
requires_tools
Declares which MCP tools this Skill needs. If a required tool is unavailable, Claude warns the user upfront rather than failing mid-execution.
requires_tools:
- execute_sql
- list_tables
- describe_table
requires_plugins
requires_plugins:
- database-plugin@^2.0.0
claude_version
Declares the minimum Claude model version required.
claude_version: ">=claude-3-5-sonnet"
Behavioral Control Fields
max_turns
Limits the maximum number of conversation turns (tool calls) when executing this Skill.
max_turns: 10
timeout_seconds
Execution timeout in seconds. Claude aborts and returns partial results on timeout.
timeout_seconds: 60
confirmation_required
Whether to ask user confirmation before executing. Use for Skills with irreversible operations (sending email, committing code).
confirmation_required: true
confirmation_message: "This will send an email to {recipient}. Proceed?"
output_format
Suggested output format.
output_format: markdown # markdown | plain | json | code
51.4 Markdown Body Structure
The Markdown body is the Skill's behavioral specification. Claude treats it as execution guidance. Body quality directly determines Skill execution quality.
Recommended Section Structure
## Use Cases (What & When)
Describe what problem this Skill solves and when it should be activated.
## Prerequisites
Conditions that must be met before using this Skill
(e.g., database must be connected, input must be in a specific format).
## Execution Steps (How)
Step-by-step guidance for Claude, including:
- What information to gather
- Which tools to call and in what order
- How to process tool return values
## Output Specification
Format, content, and quality standards for the output.
## Edge Cases
Common exception scenarios and how to handle them.
## Examples
Concrete input/output examples.
Principles for High-Quality Behavioral Descriptions
Principle 1: Specific, not vague
# Poor:
Generate SQL based on user requirements.
# Good:
1. Call `list_tables` to get all table names first
2. For entities mentioned in the user's description, call `describe_table`
to retrieve field definitions
3. Generate SQL based on schema and requirements, preferring JOINs over subqueries
4. Verify the generated SQL has no cartesian product risk
(multi-table JOIN without WHERE condition)
Principle 2: Define success criteria
## Quality Standards
Generated SQL must satisfy:
- Syntactically correct and executable on PostgreSQL 14+
- Uses index-friendly patterns (avoids `SELECT *`, uses explicit field names)
- For paginated queries, uses LIMIT/OFFSET or keyset pagination
- All string comparisons use case-insensitive matching (ILIKE or LOWER())
Principle 3: Explicit tool call timing
## Tool Call Strategy
- **Must** call `list_tables` before generating any SQL
- Only call `describe_table` for tables involved in the query — don't
fetch all table schemas at once
- After generating SQL, call `explain_query` to verify no full table scans
Principle 4: Error handling table
## Error Handling
| Situation | Response |
|-----------|----------|
| Entity in description has no matching table | List similar table names, ask user to confirm |
| Generated SQL throws an error | Parse error message, auto-correct and retry (max 3 times) |
| Ambiguous user description | List possible interpretations, ask user to choose |
| Result exceeds max_rows | Auto-add LIMIT clause, inform user results are truncated |
51.5 Complete Production-Grade Skill File
---
name: sql-query-builder
version: 2.0.0
description: Generate optimized SQL queries from natural language with schema awareness
author: Jane Doe <[email protected]>
license: MIT
tags:
- database
- sql
- developer-tools
- postgresql
parameters:
- name: description
type: string
description: Natural language description of the data you want to retrieve
required: true
minLength: 10
maxLength: 2000
- name: dialect
type: string
description: SQL dialect
required: false
default: postgresql
enum: [postgresql, mysql, sqlite, mssql]
- name: max_rows
type: number
description: Maximum rows to return
required: false
default: 100
minimum: 1
maximum: 50000
- name: include_explanation
type: boolean
description: Include a plain-language explanation of the SQL
required: false
default: true
requires_tools:
- list_tables
- describe_table
- execute_sql
max_turns: 15
timeout_seconds: 120
output_format: markdown
---
## Use Cases
Use this Skill when the user needs to query data from a database but is
unfamiliar with the table structure or SQL syntax.
Suitable for:
- Data analysts needing quick data queries
- Backend developers validating query logic
- Operations teams needing ad-hoc reports
## Execution Steps
### Step 1: Understand the Requirements
Carefully read the `description` and identify:
1. Which entities need to be queried (users, orders, products, etc.)
2. What filter conditions apply (time range, status, user attributes)
3. What aggregations are needed (count, sum, average)
4. How results should be ordered and paginated
If requirements are unclear, ask for clarification — do not guess.
### Step 2: Learn the Schema
1. Call `list_tables` to retrieve all table names
2. Identify 1–5 tables likely relevant to the request
3. Call `describe_table` for each relevant table
4. Analyze foreign key relationships to determine JOIN paths
### Step 3: Generate SQL
Generate SQL based on requirements and schema. Follow these standards:
**Query quality standards:**
- Explicitly list SELECT fields — never use `SELECT *`
- Multi-table JOINs must have explicit ON conditions
- Add appropriate WHERE conditions to prevent full table scans
- Use LIMIT for large result sets (not exceeding `max_rows`)
**Dialect-specific rules:**
- postgresql: use ILIKE for case-insensitive string comparison
- mysql: note that `=` is case-insensitive by default; use DATE_FORMAT for dates
- sqlite: no FULL OUTER JOIN support; use UNION instead
### Step 4: Validate and Explain
1. Verify SQL syntax correctness
2. If `include_explanation` is true, explain the SQL logic in plain language
3. Flag potential performance issues (e.g., filtering on unindexed fields)
## Output Format
```sql
SELECT
u.id,
u.email,
COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.created_at >= '2024-01-01'
GROUP BY u.id, u.email
ORDER BY order_count DESC
LIMIT 100;
Explanation (conditional on include_explanation):
This query joins the users table with orders to count the number of orders
per user registered since 2024-01-01, sorted by order count descending,
returning up to 100 records.
Edge Cases
- Table not found: List the most similar table names; ask user to confirm
- Ambiguous field name: When multiple tables share a field name, always use
the
table.fieldprefix form - Complex aggregations: For more than 3 levels of nested subqueries, use CTEs (WITH clauses) for readability
- Permission constraints: Some tables may have row-level security; note this in a SQL comment
Changelog
2.0.0 (2026-03-15)
Breaking: Added 10-character minimum to description parameter.
- Added
dialectparameter for database-specific SQL - Improved multi-table JOIN detection
1.0.0 (2026-01-15)
- Initial release
## 51.6 Skill Versioning Strategy
### Evolution Pattern
```yaml
# v1.0.0: Initial version
parameters:
- name: description
type: string
required: true
# v1.1.0: New optional parameter (backward-compatible)
parameters:
- name: description
type: string
required: true
- name: dialect # new, has default, doesn't affect existing users
type: string
required: false
default: postgresql
# v2.0.0: Modified required parameter constraint (breaking change)
parameters:
- name: description
type: string
required: true
minLength: 10 # new constraint — queries that worked before may now fail
The key rule: any change that could cause a previously working invocation to fail requires a major version bump.
51.7 Testing Skill Files
Skills contain no executable code, but they still need testing. Claude Code provides Skill testing tools:
# Validate frontmatter syntax
claude-plugin skill validate ./skills/sql-query-builder.md
# Simulate Skill execution with given parameters (dry run, no tool calls)
claude-plugin skill test ./skills/sql-query-builder.md \
--param description="Find all users who placed orders in 2024" \
--param dialect=postgresql \
--dry-run
# Full end-to-end test (requires installed MCP tools)
claude-plugin skill test ./skills/sql-query-builder.md \
--param description="Find all users who placed orders in 2024"
51.8 Multi-Language Skill Support
A Skill can provide body text in multiple languages. Claude selects the appropriate version based on the user's language preference:
skills/
├── sql-query-builder.md ← default (English)
├── sql-query-builder.zh.md ← Chinese
└── sql-query-builder.ja.md ← Japanese
Declare multi-language support in plugin.json:
{
"skills": [
{
"default": "./skills/sql-query-builder.md",
"zh": "./skills/sql-query-builder.zh.md",
"ja": "./skills/sql-query-builder.ja.md"
}
]
}
The YAML frontmatter is only required in the default (English) file. Language variants only need to provide the Markdown body.
Summary
A Skill file is a natural language specification of Claude's behavior. The YAML frontmatter provides machine-readable metadata: name, version, parameter type constraints, dependency declarations, and execution controls. The Markdown body provides human-readable behavioral guidance: use cases, execution steps, error handling, and output specifications. The key to a high-quality Skill file is being specific, explicit, and constraint-rich — vague instructions are the single most common root cause of poor Skill quality. The next chapter covers how to publish Skills and Plugins to the clawhub.ai marketplace.