If you're already using MCP to connect models to databases, file systems, and third-party APIs, you'll likely run into the next, trickier problem: the tools are all connected, but the model still doesn't know in what order or by what standards to complete a task. This is exactly the layer that Agent Skills fills in. It was proposed by Anthropic in October 2025, subsequently established as an open standard at agentskills.io, and by 2026 has been made compatible in the same format by platforms such as Codex, GitHub Copilot, and Microsoft Agent Framework. This article is the first half of the "Complete Guide to Agent Skills." Let's lay the foundation first: the hard constraints on SKILL.md fields, the folder directory conventions, the three-tier progressive disclosure loading sequence, the ledger mindset for Token budgets, and that most easily overlooked core principle—anything that can be determined with code should never be begged from the model with words.
From MCP to Agent Skills: Anthropic's Second Layer of Abstraction and the October 2025 Starting Point
To understand where Skills fit, it's best to view them alongside MCP. MCP (Model Context Protocol) solves "how to connect to external tools and data sources." It cares about the channel problem: can the model call a search interface, can it read a database, can it access some SaaS API. But opening a channel doesn't mean the task is done. A real business action often involves a whole chain of procedural decisions—judgment, sequencing, formatting, boundary validation, failure retries—and MCP itself is not responsible for these decisions.
So Anthropic proposed Agent Skills in October 2025, defining it as the second layer of abstraction after MCP: MCP answers "where the tools are and how to call them," while Skills answer "once you have the tools, how exactly should this be done to count as done well." One is responsible for bringing ingredients into the kitchen, the other for providing the recipe and the heat level. The two are complementary, not substitutes—the official Skills documentation also explicitly notes that for code execution security, stability, and sandbox isolation, MCP's server-hosted execution approach still holds an advantage; Skills are better suited to lightweight scripts and simple logic.
Worth noting is the pace: about two months after proposing it, Anthropic released this specification as an open standard, rather than locking it inside its own product. Any Agent platform, as long as it parses according to this format, can be compatible with Skills written by others. This decision directly determined the cross-platform landscape to be discussed later.
Open Standard Landing: agentskills.io and the Compatibility Landscape of Codex, Copilot, and Microsoft Agent Framework
By 2026, the positioning of Agent Skills has evolved from "a feature of Claude" into a cross-platform open standard, with the official specification site being agentskills.io. Platforms currently supporting Skills in the same format include: Claude Code, OpenAI Codex, GitHub Copilot, Microsoft Agent Framework, and others. This means that a Skill folder you write for Claude Code can theoretically be dropped directly into the skills directory of Codex or Copilot for reuse, as long as it doesn't depend on some platform-specific metadata extension.
Among these, the design of Microsoft Agent Framework deserves separate mention. It splits Skill capabilities into two explicit actions: read_skill_resource and run_skill_script. This dichotomy is not a casually chosen name; it is precisely the core mechanism we will repeatedly emphasize later—"reading" pours content into the context and consumes Tokens; "running" only executes and only takes the result, occupying almost no context. By elevating this distinction to a first-class citizen, the framework essentially forces you to think at runtime: does this step need the Agent to know, or does it need the Agent to execute?
| Comparison Dimension | MCP | Agent Skills |
|---|---|---|
| Question answered | How to connect to external tools and data sources | Once you have the tools, how to do things right and well |
| Level of abstraction | First layer (connection layer) | Second layer (procedural knowledge layer) |
| Typical carrier | Protocol + server-side process | Folder + SKILL.md |
| Execution security | Stronger, can be hosted by a server-side sandbox | Weaker, scripts execute in the local context |
| Applicable complexity | Heavy logic, tasks requiring strong isolation | Lightweight scripts and simple logic |
| Context overhead | Tool schema always resident | Metadata always resident at about 100 tokens/skill |
The Essence of a Skill: A Folder Plus a SKILL.md, Encapsulating Procedural Knowledge
To explain the physical form of a Skill clearly, it really comes down to one sentence: a folder + a Markdown file (SKILL.md). What this folder contains is procedural knowledge, that is, "how to do it"; it deliberately does not contain declarative knowledge, that is, "what it is."
This distinction is crucial because it determines the criteria for trade-offs when writing a Skill. Declarative knowledge—a company's product parameters, the field usage of an API, background concepts in some domain—should be placed in retrieval systems, documentation sites, or references/ for on-demand access; what a Skill should contain is processes, steps, judgment rules, and common pitfalls. For example, "our refund policy is 7 days, no questions asked" is declarative knowledge, suitable for documentation; "when handling a refund dispute, first check the order time; if more than 7 days, require an unboxing video to be uploaded, otherwise approve directly" is procedural knowledge, and this is what a Skill should carry.
Furthermore: within procedural knowledge, anything that can be expressed with deterministic code should not be expressed in natural language. This is the most counterintuitive and most valuable principle in this entire article, and a dedicated section will expand on it later.
Directory Convention Breakdown: SKILL.md Is Required; scripts/, references/, and assets/ Are Optional
The officially agreed directory structure contains four types of content in total, but only the first is strictly required:
- SKILL.md (required): The entry point of the Skill. Without it, this folder is not a Skill. It bears two responsibilities: metadata declaration and main instructions.
- scripts/ (optional): Executable code. Typical scenarios are validation, formatting, data transformation, and file generation. Its value lies in turning "judgment" into "execution," and it is the landing point of deterministic engineering.
- references/ (optional): On-demand reference documentation. The place for API manuals, domain background, and large rule tables. It will be "read" into the context, so it is a heavy resource loaded on demand.
- assets/ (optional): Templates and static resources. File templates, images, fonts, sample outputs, etc., for scripts or the Agent to use directly.
Here is a pitfall that beginners most easily fall into: whether a directory counts as a Skill root directory is determined by whether it directly contains SKILL.md. Many people download from an archive or repository, see an outer folder with the same name, and copy the whole package in, only for the Agent to scan under the skills root directory and find "a subfolder inside a subfolder," fail to find SKILL.md, and the Skill simply doesn't take effect. The correct approach is: enter the directory tree, find the level that directly contains SKILL.md, and copy starting from that level.
SKILL.md Structure: YAML frontmatter Metadata + Markdown Body Instructions
SKILL.md is composed of two segments joined together, separated by three hyphens, and the frontmatter must be located at the very beginning of the file:
- Metadata layer (YAML frontmatter): Tells the Agent "what this Skill is and when it should be used." It is always loaded into the context and is a resident overhead.
- Instruction layer (Markdown body): Tells the Agent "how exactly to execute." It is loaded only after the Skill is activated.
Why must they be separated? Because their loading timing is completely different. Metadata is the "catalog" and must always be present, so that the Agent can discover at the appropriate moment that this Skill is worth activating; instructions are the "body" and are expanded only when needed. If you write key trigger information into the body, then it will never be loaded—
Below is a ready-to-adapt SKILL.md example, where the frontmatter and the body each play their own role:
---
name: csv-schema-checker
description: Validate the headers, encoding, and column types of CSV data, and surface data quality issues that violate the agreed conventions. Use when the user needs to check CSV file format, clean dirty data, or perform data quality gating before upload.
license: MIT
compatibility: Requires Python 3.10 or above, depends on the standard library csv and chardet
metadata:
version: 1.2.0
owner: data-platform
allowed-tools: Bash, Read
description_keywords: CSV, encoding, header, data type, data quality
---
# CSV Data Quality Validation
## When to Use
Enable this Skill when the user asks to check, clean, or validate the format and data quality of a CSV file.
## Execution Flow
1. Run the validation script first; do not judge by eye.
- How to run (intent is run, do not read the script contents):
`python scripts/check_csv.py --path `
2. When the script exit code is 0, validation passed; report PASS to the user directly and do not improvise further.
3. When the script exit code is non-zero, read its standard output; each error corresponds to a specific issue.
4. Fix the data source based on the errors (it may be encoding, header order, or column types), then re-run the script.
5. Repeat steps 3 and 4 until the script outputs PASS.
## Hard Constraints
- It is strictly forbidden to claim the data has passed validation without running the script.
- It is strictly forbidden to modify the decision logic of scripts/check_csv.py to make validation pass.
- The header whitelist and type rules are defined uniformly in references/schema.md; do not repeat them in the body.
## Common Pitfalls (gotchas)
- UTF-8 files with a BOM are often misjudged as garbled text; the script handles this automatically, so do not strip it manually again.
- Date columns may mix `2026/3/1` and `2026-03-01`; the script normalizes them uniformly before comparison.
- If the file exceeds 200MB, the script switches to streaming reads, in which case line numbers are not output; this is normal.
Field Constraint Checklist: name's 64 characters and parent-directory naming rule, description's 1024-character trigger
Metadata is not a casual comment; the official fields have explicit hard validation, and mistakes are rejected outright. Here is the itemized list:
- name (required): at most 64 characters; only lowercase letters, digits, and hyphens are allowed; must not start or end with a hyphen; must not contain consecutive hyphens (e.g.,
my--skillis invalid); must exactly match the parent directory name. This last rule is the easiest to overlook—if you name the foldercsv-checkerbut write the name inside ascsv_schema_checker, it is invalid. - description (required): at most 1024 characters. It is not a summary but a trigger. It must include trigger keywords that let the Agent recognize the task, covering the various ways the user might phrase it.
- compatibility (optional): at most 500 characters, used to declare the runtime environment, dependencies, and platform requirements.
- license (optional): license declaration.
- metadata (optional): custom key-value pairs for version, owner, team, and other information.
- allowed-tools (optional): a whitelist of tools this Skill is allowed to call.
On how to write description, a useful contrast is: do not write "This is a Skill for processing CSV", but rather "Validate the headers, encoding, and column types of CSV... Use when the user needs to check CSV format, clean dirty data, or perform data quality gating before upload." The former is self-introduction; the latter is a trigger signal. The 1024-character budget is actually quite generous, entirely enough to lay out the trigger scenarios.
| Field | Required | Limit | Key Constraint |
|---|---|---|---|
| name | Yes | 64 characters | Lowercase letters/digits/hyphens; no leading or trailing hyphen; no consecutive hyphens; same as parent directory name |
| description | Yes | 1024 characters | Must contain trigger keywords; write it as a trigger, not a summary |
| compatibility | No | 500 characters | Declare environment and dependency requirements |
| license | No | No hard limit | License declaration |
| metadata | No | As needed | Custom key-values such as version and owner |
| allowed-tools | No | As needed | Tool whitelist, used to narrow permissions |
Progressive Disclosure in Three Layers: the loading sequence of always-on metadata, activated instructions, and on-demand resources
Progressive Disclosure is the soul of the Skills architecture. It divides information into three layers by "when it is actually needed" and unfolds them layer by layer:
- Layer 1: Metadata. Always loaded, about 100 tokens/skill. It is like a book's table of contents—the Agent can see the name and description of every installed Skill in each conversation turn, and thereby judge whether to activate it. Because it is only about 100 tokens, even with dozens of Skills installed, the always-on overhead stays within a controllable range.
- Layer 2: Instructions. Loaded only when a Skill is activated, i.e., the Markdown body of SKILL.md. The official recommendation is to keep it within 5k tokens. This layer is the main body of flows and rules.
- Layer 3: Resources. references/ and scripts/, the "on-demand within on-demand". Even if a Skill is activated, it does not mean all these resources must be used; they are fetched only when the flow actually reaches a certain step.
This design solves a fundamental contradiction: the Agent needs to know "what capabilities exist", but cannot carry all the details of every capability in its context. The table of contents is always-on, the body is on-demand, and the resources are further on-demand—equivalent to transforming the context from "full loading" into "lazy loading".
And within Layer 3 there is another key fork that must be made clear:
- references/ is "read": the content is read into the context and genuinely consumes Tokens. So it is suitable for material "the Agent needs to understand", such as rule tables, field definitions, and domain background.
- scripts/ is "run": it is only executed, not read, and barely occupies context. The Agent only needs to know how to call it, not how it is implemented internally. A validation script of several hundred lines may cost only that one command line in the instructions in terms of context.
The only exception is: if SKILL.md does not clearly state how to run the script, the Agent may proactively read the code to figure out how to run it, at which point it degrades into "read" and the context overhead immediately spikes. So explicitly writing the run command and intent (run or read) in the instructions is not optional, but the key to saving money.
Token Ledger: Treat context as a budget to spend, keep SKILL.md within 500 lines
With the three-layer model, we can do the math. Suppose you have 30 Skills installed: the always-on metadata alone costs about 3000 tokens. If 5 of them are activated in a conversation, each body at the 5k tokens upper limit, that is another 25000 tokens. At this point, if references/ is also read in full indiscriminately, the context will quickly run out, and the model's attention will be diluted.
This is exactly the engineering meaning of the official recommendation to keep SKILL.md within 500 lines—it is not typographic fastidiousness, but a budget red line. From the perspective of treating context as a budget to spend, the longer the file, the less it is "more complete information" and the more it is "less attention allocated to each rule". This is the so-called attention decay
The fundamental way to address this problem is to take the power of judgment away from text and give it back to code. Prompts are probabilistic; code is deterministic. Instead of writing in the body, "Please carefully check whether the data format conforms to the specification," write, "Run python scripts/check_csv.py; if the exit code is non-zero, fix it and rerun until PASS." The former pins correctness on the model's self-discipline; the latter anchors correctness to a reproducible execution result.
#!/usr/bin/env python3
"""scripts/check_csv.py — Example of a deterministic CSV validation script.
Design principles: the exit code is the conclusion, and standard output is the repair checklist.
- Exit code 0: all passed; the last line prints PASS.
- Exit code 1: data quality problems exist; print each problem description.
- Exit code 2: the script itself has an argument or environment error (this is not a data problem; do not retry).
"""
import csv
import sys
import argparse
import unicodedata
from pathlib import Path
REQUIRED_HEADERS = ["order_id", "user_id", "amount", "created_at"]
ALLOWED_AMOUNT_CHARS = set("0123456789.-\u00a5\uffe5")
STREAM_THRESHOLD_BYTES = 200 * 1024 * 1024
def normalize_header(name: str) -> str:
"""Remove BOM, full-width whitespace, and zero-width characters; normalize to lowercase and strip leading/trailing whitespace."""
cleaned = unicodedata.normalize("NFKC", name)
cleaned = cleaned.replace("\ufeff", "").replace("\u200b", "")
return cleaned.strip().lower()
def check_headers(fieldnames):
problems = []
actual = [normalize_header(f) for f in (fieldnames or [])]
if actual != REQUIRED_HEADERS:
problems.append(
f"Header mismatch: expected {REQUIRED_HEADERS}, actual {actual}"
)
return problems
def check_amount(raw: str, line_no: int):
value = (raw or "").strip().replace(",", "").lstrip("\u00a5\uffe5")
if not value:
return [f"Line {line_no} amount is empty"]
if not set(value) <= ALLOWED_AMOUNT_CHARS:
return [f"Line {line_no} amount contains illegal characters: {raw!r}"]
try:
amount = float(value)
except ValueError:
return [f"Line {line_no} amount cannot be parsed as a number: {raw!r}"]
if amount < 0:
return [f"Line {line_no} amount is negative: {amount}"]
return []
def check_file(path: Path):
problems = []
size = path.stat().st_size
stream_mode = size > STREAM_THRESHOLD_BYTES
with path.open("r", encoding="utf-8-sig", newline="") as fh:
reader = csv.DictReader(fh)
problems.extend(check_headers(reader.fieldnames))
for offset, row in enumerate(reader):
line_no = offset + 2 # The header occupies one line, and line numbers start at 1.
problems.extend(check_amount(row.get("amount", ""), line_no))
if stream_mode and len(problems) >= 20:
problems.append("Problem limit reached; no further line numbers will be output in streaming mode")
break
return problems
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--path", required=True, help="Path to the CSV file to validate")
args = parser.parse_args()
target = Path(args.path)
if not target.is_file():
print(f"[Environment error] File does not exist: {target}", file=sys.stderr)
return 2
try:
problems = check_file(target)
except UnicodeDecodeError as exc:
print(f"[Environment error] File encoding cannot be parsed: {exc}", file=sys.stderr)
return 2
if problems:
print("Validation failed; please fix each item and rerun:")
for item in problems:
print(f"- {item}")
return 1
print("PASS")
return 0
if __name__ == "__main__":
sys.exit(main())
This script embodies exactly the closed loop of "script FAIL → fix → rerun → until PASS." Note its exit code semantics: 0 means business validation passed, 1 means there are data problems that need fixing, and 2 means an environment or argument error that should not be retried. Separating 2 from 1 is an important engineering detail—otherwise the Agent will repeatedly retry a call with a wrong path, wasting turns for nothing.
Incidentally, back to a security reminder in the installation step: obtaining a Skill from the internet is essentially equivalent to running software written by a stranger on your own machine. A Skill can carry scripts/, and therefore may also carry destructive commands or unauthorized access. In the official repository github.com/anthropics/skills, under the skills directory, each subdirectory is a Skill; the community site skillsmp.com and the open-source collection github.com/ComposioHQ/awesome-claude-skills are also common sources. No matter where it comes from, reading through SKILL.md and the contents of scripts/ before installation is a bottom line that cannot be skipped. The installation action itself is very simple—just put the entire Skill folder into the skills directory agreed upon by the Agent, for example Claude Code's .claude/skills, the skills under the Codex installation directory, or .opencode/skills within an OpenCode project—but which directory to copy it to and at which level depends on whether you have found the root directory that directly contains SKILL.md.
The first half has covered the positioning of Skills, the format and field constraints of SKILL.md, and the loading sequence and budget model of progressive disclosure. But one sharper question has not been directly answered: if the description is not written well, even a perfect Skill will not be activated; if the intent of the body and scripts is not clearly written, determinism will degrade into probability. Next we enter the place that truly determines whether a Skill is usable—how resources are divided, where the boundary between text and code lies, and what you must do before installation.
references are for "reading," scripts are for "running": the division of labor between the two resource types and the context cost
Back to the directory convention: SKILL.md is required, scripts/
references/ is for "reading". When the Agent determines that it needs to consult a document, it uses a file-reading action to pull the content in, and that content enters the context window and consumes Tokens billed by the character. This means that what you put in references and what you write in the body of SKILL.md are the same category of thing in terms of the cost model—only the loading timing is deferred to "on demand". So the value of references is not "saving Tokens", but "not spending Tokens when they aren't needed".
scripts/ is for "running". The Agent invokes an execution action to run the script, and the content of the script itself does not enter the context—only its standard output, error messages, and exit code come back into the conversation. A 300-line validation script and a 3-line script, if both output the same single line PASS, occupy almost the same amount of context. This is the most underrated lever in a Skill: lock the complexity inside the script.
But here is a very common engineering pitfall: if SKILL.md doesn't clearly state how the script should be run and what parameters it needs, the Agent will very likely first "read" the script's source code, trying to figure it out on its own. Once that happens, all of scripts' context advantage vanishes on the spot, degrading into a references file read in full. So the correct approach is: the way to invoke the script must be written in the body of SKILL.md as a command line that can be copied directly, including the interpreter, argument order, input/output conventions, and what to do on failure.
Another category of pitfall is writing the script as an interactive program that "needs a human watching it run"—waiting for input, printing progress bars, depending on the current working directory. When the Agent executes a script, it is non-interactive; such scripts either hang or fail silently. The convention is: a script must be one-shot, idempotent, non-interactive, and have a determinable exit code.
| Dimension | references/ (read) | scripts/ (run) |
|---|---|---|
| Agent action | Read file content | Execute code |
| Enters context? | Yes, the full text enters | No, only stdout / stderr / exit code are returned |
| Token cost | Proportional to document length | Proportional to output length, unrelated to code length |
| Determinism | Low, it is reference information given to the model | High, same input same result |
| What it's suited for | API references, field dictionaries, long specifications, domain background | Format validation, data transformation, calling external interfaces, generating artifacts |
| Common misuse | Stuffing in core rules that are used every time | Forgetting to write the run command, causing the Agent to read the source code |
To summarize the division of labor between the two in one sentence: references influence "how the model thinks", scripts determine "how the system moves". Anything that requires the model to understand, weigh, and express goes into references; anything whose answer is unique and whose correctness is determinable goes into scripts.
From Prompt to Deterministic Script: Take out of the text everything that can be judged by code
To understand the engineering value of a Skill, you must first accept a premise: prompts are probabilistic, code is deterministic. You write "please ensure the JSON fields are complete", and the model may check, may not check, or may check but miss some nested level. You write "please check carefully", and the expected return of this sentence is close to zero—it neither defines what "carefully" means nor what "pass" means.
A deterministic script turns this into a mechanical process: the script FAIL → fix → rerun → until PASS. The reason this closed loop is far stronger than a reminder comes down to three things:
- It has a clear success criterion. A non-zero exit code means it's not done; there is no "I think it should be fine now". The model's self-assessment is naturally optimistic, but the exit code is not.
- It shifts attention from "checking" to "fixing". The model doesn't need to stay vigilant continuously across a long context; it only needs to see the specific error line, fix it, and run again. Every step is short feedback.
- It is reproducible. Running the same input twice yields the same result, which means when something goes wrong you can locate it, rather than restarting once and praying it gets better.
So the core principle of a good Skill can be condensed into one sentence: take out of the text everything that can be judged by code and hand it to a script. The criterion for judging "whether it can be judged by code" is simple—if two engineers would reach the same conclusion about whether the same output is correct, then it should be code's job.
Below is a usable SKILL.md example. It encapsulates the skill of "organizing external data into canonical JSON and validating it"; note how it leaves "judgment" to the script and "explanation" to the text.
---
name: json-schema-guard
description: Validate and repair JSON data files so they conform to the project schema. Use when the user asks to check JSON format, fix missing fields, unify output structure, or mentions schema validation, field alignment, or data cleaning.
license: MIT
compatibility: Requires Python 3.10+ and the jsonschema package
metadata:
author: platform-team
version: 1.1.0
allowed-tools: read_file, write_file, run_skill_script
---
# JSON Schema Guard
Normalize arbitrary JSON data into a structure conforming to `assets/schema.json`, and validate it with a script until it passes.
## When to use
Use this skill when the task is "the data format is wrong", "fields are missing", or "the output structure must align with the schema".
If you are only reading JSON content for display, this skill is not needed.
## Execution flow
1. Run the validation script to see the current failures:
`python scripts/validate.py --input data.json --schema assets/schema.json`
2. The script exits with a non-zero exit code and prints errors line by line in the form `PATH: reason`.
3. Modify `data.json` item by item according to the error lines, changing only the indicated paths, and do not rewrite the entire file.
4. Rerun the same command until the exit code is 0 and it outputs `PASS`.
5. Only after the script PASSes, report completion to the user.
## Script conventions
- `scripts/validate.py` is an idempotent read-only validation and will not modify the input file.
- Do not read the source code of `scripts/validate.py` to infer the rules; the rules are based on `assets/schema.json`.
- When you need to check the meaning of a field, read `references/fields.md`, do not guess.
## Boundaries
- Do not modify the schema itself. If the schema conflicts with the data, confirm with the user first.
- Do not process non-UTF-8 encoded files; report directly and stop.
## Gotchas
- `additionalProperties` in `assets/schema.json` is false, so even one extra field will fail; deleting is safer than adding.
- An empty array and a missing field are two different errors; do not use `null` as a fallback.
- The script is sensitive to relative paths; always execute from the Skill root directory.
Note several design choices in this file: the body does not explain the principles of JSON Schema (that's references' job), and does not list the meaning of each field (that's placed in references/fields.md), but it nails down "which command to run", "what failure looks like", "when it counts as complete", and "which pitfalls must not be stepped in again". The gotchas section is often the most valuable part of the entire SKILL.md, because it comes from real pitfalls, not from restating documentation.
The second example is a truly deterministic validation script. Its value lies not in complex logic, but in that its output is directly actionable for both humans and the Agent:
#!/usr/bin/env python3
"""Idempotent read-only validation: check whether data.json conforms to schema.json.
Exit codes: 0 = pass; 1 = validation failed; 2 = usage or environment error.
"""
import argparse
import json
import sys
from pathlib import Path
try:
from jsonschema import Draft202012Validator
except ImportError:
print("ERROR: missing jsonschema, please pip install jsonschema
There are three easily overlooked but critical details in this script: exit codes are split into three tiers, letting the Agent distinguish between "the data is wrong, go fix the data" and "the environment is wrong, don't blindly change things"; errors are output sorted by path, letting the model reliably start fixing from the first one; non-UTF-8 input is explicitly rejected, avoiding the situation where "the model fiddles for ages, but it was actually an encoding problem." None of these are algorithmic difficulties—they are engineering habits that nail down uncertainty.
Attention decay and rule failure: a pure-text Skill is just a big Prompt with two ceilings
If you write all the logic into the body of SKILL.md, what you actually get is just a big Prompt. It won't gain extra capabilities just because the file format changed; instead, it will hit two ceilings.
The first is attention decay. The more content there is in the context, the weaker the attention each rule receives. This isn't the model being lazy—it's a mechanical inevitability: ten rules each have their own place, but among a hundred rules, the ones in the middle are easily ignored. The symptom is this—the rules are written in SKILL.md, the model "sees" them, but during execution it only follows the few at the beginning and the end. This is why the official guidance recommends keeping SKILL.md under 500 lines and second-layer instructions under 5k tokens. This isn't an aesthetic requirement; it's to ensure each rule can still receive enough attention.
The second is rule failure. When the model's judgment conflicts with a rule, it will weigh things and may choose to violate the rule—because to the model, a rule is a suggestion, not a command. "Don't modify this file" is a suggestion; a constraint that is validated in a script and exits non-zero on failure is a command. This is also why writing rules into code is more reliable than writing them into text: text is understood, code is executed.
The result of these two ceilings stacking is the old problem of long Prompts: more rules ≠ more reliable, and may in fact be less reliable. The engineering response is not to "write more clearly," but to layer—put the "core principles that must be followed every time" into a concise body, move "details only used in specific scenarios" into references, and move "checks with determinable right and wrong" into scripts. This also echoes the earlier point about treating context as a budget.
The boundary with MCP: MCP provides ingredients, Skill gives the recipe—complementary, not a replacement
After Skills appeared, the most common confusion is "is it going to replace MCP?" The answer is clear: no. The two manage different things at the abstraction layer.
MCP solves "connecting external tools and data sources"—bringing databases, APIs, file systems, and SaaS services into the range the Agent can call. To use an analogy, MCP provides ingredients: it lets the Agent obtain data and call remote capabilities, with the focus on "being able to connect and call."
Skill solves "how to process this data"—once you have the ingredients, how to cut them, in what order to put them in the pot, and what the finished product should look like. Skill gives the recipe: procedural knowledge, with the focus on "doing it right and doing it reliably."
| Comparison dimension | MCP | Agent Skills |
|---|---|---|
| Problem solved | Connecting external tools and data sources | How to process data, how to complete tasks |
| Analogy | Provides ingredients | Provides the recipe |
| Carrier | Protocol and server | Folder + SKILL.md |
| Good at | Standardized access, authentication, remote calls | Lightweight scripts, simple logic, process orchestration |
| Weakness | Carrying complex business processes requires extra design | Security and stability of code execution are inferior to MCP |
| Relationship | Complementary rather than a replacement. A typical form is a Skill calling MCP tools within a process | |
We should look honestly at Skill's shortcomings: it is essentially a lightweight convention of "files + scripts," and it is inferior to MCP in the security, isolation, and stability of code execution. An MCP server can centrally handle authentication, rate limiting, auditing, and sandboxing, whereas a Skill's scripts run in your environment. So the reasonable boundary is: leave lightweight, local, one-off processing to Skill; leave capabilities requiring authentication, multi-tenancy, strong isolation, and centralized governance to MCP. In a mature system, the two are usually nested: a Skill defines the process, and key steps in the process call MCP tools to complete them.
Three common pitfalls: the longer SKILL.md the better, stuffing all materials into the body, ignoring description
After seeing enough Skills, the problems basically cluster into three categories.
Pitfall one: the longer SKILL.md the better. Many people instinctively feel that the more detailed the writing, the better the model performs, so they write SKILL.md as a several-thousand-line encyclopedia. The result is that it dilutes the key points and wastes Tokens for nothing—because the body is the second layer, and once the Skill is activated, the entire thing is loaded. The more rules there are, the weaker each one becomes, and the core steps get drowned out instead. The correct approach is: keep only the execution flow, script invocation methods, boundaries, and gotchas in the body, and move everything else out. The official recommended 500-line limit should be treated as a hard constraint, not a reference value.
Pitfall two: stuffing all materials into SKILL.md. A typical symptom is writing the full API field table, historical background, and terminology explanations all into the body. The characteristic of such content is that it is "only used in specific scenarios," so it naturally belongs in references/. The criterion is: if this content is not needed for every execution, it should not appear in the body. Similarly, anything that can be written as a check should not be written as an explanation.
Pitfall three: ignoring description. This is the most hidden and also the most fatal one. Many authors treat description as an "introduction" and write it like a summary: "A useful skill for data processing." But description is not an introduction; it is a trigger. It is the part that is always loaded at the first layer (about 100 tokens/skill), and the model relies on it to judge "whether this task should activate this Skill." Therefore, the description must contain trigger keywords that help the Agent identify the task: how the user might say it, which nouns are involved, which scenarios should use it, and which scenarios should not. Writing a summary is equivalent to ensuring this Skill is never selected, even if its internals are written perfectly. By specification, it is at most 1024 characters, and this quota is for you to write trigger conditions—not using it is a waste.
Acquisition, installation, and root directory determination: from the official repository to .claude/skills, .opencode/skills
There are mainly three channels for obtaining Skills: the official repository github.com/anthropics/skills, where each subdirectory under the skills directory is a Skill; the community aggregation site skillsmp.com; and the open-source collection repository github.com/ComposioHQ/awesome-claude-skills. Since Agent Skills is already a cross-platform open standard (the specification site is agentskills.io), the same Skill can be recognized on platforms such as Claude Code, OpenAI Codex, GitHub Copilot, and Microsoft Agent Framework—for example, Microsoft Agent Framework explicitly splits capabilities into two actions, "read resources read_skill_resource" and "execute scripts run_skill_script," which is the same model as the "read / run" division described earlier.
The installation method is so simple it's almost counterintuitive: just put the entire Skill folder as-is into the skills directory agreed upon by the Agent—no build, no registration required. Common locations include Claude Code's .claude/skills, the skills under the Codex installation directory, and .opencode/skills within an OpenCode project.
Here is a very practical question that is often glossed over in a single sentence in the documentation: when copying from a compressed archive or repository, which level of folder should actually be copied? There is only one way to determine it—see which directory directly contains SKILL.md; that directory is the true Skill root directory. If after extraction you get my-skill-main/json-schema-guard/SKILL.md
json-schema-guard level, not the outermost my-skill-main. The consequence of copying the wrong level is that the Agent cannot find SKILL.md when scanning the agreed-upon directory, and the Skill silently fails. Incidentally, this also explains why the specification requires that name must match the parent directory name—the directory name itself is part of the locating mechanism.
While we're at it, let's list the hard constraints on metadata in one place, because most of the pitfalls when writing a Skill are here: name is required, at most 64 characters, only lowercase letters, digits, and hyphens allowed, must not start or end with a hyphen, must not contain consecutive hyphens, and must match the parent directory name; description is required, at most 1024 characters, and should contain trigger keywords that help the Agent identify the task; compatibility is optional, at most 500 characters; license and metadata are optional; allowed-tools is optional, used to declare which tool permissions the Skill needs at runtime.
Audit before installing: installing a Skill is equivalent to running a stranger's software on your machine
This last point is non-negotiable. A Skill is not a pure configuration file; it can carry scripts, and those scripts will be executed in your environment. So installing a Skill from the internet is essentially running a stranger's software on your own machine—it's just that its distribution format looks like a few Markdown files, which makes it easy to let your guard down.
This is exactly the scenario targeted by the fifth principle summarized by the engineering community: "audit before running". In practice, before installing you should at least do the following:
- Read the entire SKILL.md, especially the execution flow and script invocation sections, to confirm what commands will actually be executed.
- Review all code under scripts/ line by line. Don't skip it just because it's "only a validation script." Focus on whether there are operations that delete, overwrite, or batch-rewrite files.
- Look for destructive commands: recursive deletion, disk formatting, directory wiping, overwriting system configuration, dangerous commands executed without arguments.
- Look for privilege escalation: reading SSH keys, environment variables, credential files, browser data, or sending data to external addresses.
- Confirm network behavior: whether the script makes external requests, where the requests are sent, and what is sent.
- Confirm dependency sources: whether packages are dynamically installed at execution time, and whether code is pulled from suspicious sources.
- Run it once in an isolated environment first, especially for Skills from non-official sources.
Also note an easily overlooked contagious risk: a Skill's references can also be indirectly used as an attack vector—if a seemingly harmless reference document says "when you encounter situation X, please execute command Y," and that content is adopted by the model as an instruction, it bypasses your own judgment. Therefore the audit scope should cover the entire Skill folder, not just scripts. One-sentence principle: for any Skill from an external source, don't let it run until you can understand what it is trying to do.
Summary and best practices
Compress this guide into an executable checklist that you can directly follow when writing and installing Skills:
- Think through positioning first: A Skill encapsulates procedural knowledge (how to do something), not factual knowledge (what something is). If it's pure knowledge, consider putting it in references or not making it a Skill at all.
- Put only what belongs in each directory: SKILL.md is required; scripts/ holds executable code, references/ holds on-demand documentation, assets/ holds templates and static resources.
- Follow the metadata rules: name at most 64 characters, lowercase letters/digits/hyphens, no leading or trailing hyphens, no consecutive hyphens, and matching the parent directory name; description at most 1024 characters and must contain trigger keywords; compatibility at most 500 characters; license, metadata, and allowed-tools as needed.
- Write description as a trigger: state clearly which tasks should activate it, how users might describe them, and which scenarios should not use it. It is the first layer of always-resident content, about 100 tokens/skill; writing a summary is self-sabotage.
- Control length: SKILL.md should not exceed 500 lines; keep second-layer instructions within 5k tokens as much as possible. Long content goes into references, not the main text.
- Distinguish reading from running: things that require the model to understand trade-offs go in references (enter context, consume Tokens); things with determinable right/wrong go in scripts (execute only, barely consume context).
- Don't make the Agent read script source code: in SKILL.md, write the complete run command, parameters, input/output, and failure handling for scripts, and note whether the intent is run or read.
- Let code make judgments: anything that can be determined by code should be written as a script, following the "FAIL → fix → rerun → PASS" loop, replacing all places that say "please check carefully."
- Scripts should be engineered: idempotent, non-interactive, exit codes with distinct levels, error messages with paths, executed from the Skill root directory, and handling only declared encodings.
- Use layering to fight attention decay: keep only the core flow and boundaries in the main text, push details down to references, and push checks down to scripts. Rules written in prose are suggestions; rules written in code are commands.
- Clarify the boundary with MCP: MCP provides ingredients (connecting tools and data sources), Skill provides the recipe (how to process them). Use Skill for lightweight scripts; use MCP when you need authentication, isolation, auditing, and centralized governance. The two are complementary and often nested.
- Write gotchas seriously: the most valuable section in the main text is the pitfall record; it comes from real experience, not documentation paraphrase.
- Spend context like a budget: every paragraph you add and every reference you read consumes that limited attention quota. Before adding, ask: is this really needed every time?
- Install the whole package in the right place: the official repository github.com/anthropics/skills, the community site skillsmp.com, and the open-source collection github.com/ComposioHQ/awesome-claude-skills are the main sources; put the entire folder into .claude/skills, Codex's skills directory, or .opencode/skills.
- Use SKILL.md to determine the root directory: whichever directory directly contains SKILL.md is the Skill root directory; when unzipping, copy only that layer. Copy the wrong layer and the Skill will silently fail.
- Audit before running: read through all of SKILL.md and scripts/, look for destructive commands and privilege escalation, confirm network behavior and dependency sources, and run suspicious sources in an isolated environment first.
To sum it up in one sentence: the competitiveness of a Skill is not how many words you write, but how many uncertain things you nail down into certain things. Let description be responsible for being selected, let the main text be responsible for explaining the flow, let references be responsible for on-demand supplementation, and let scripts be responsible for giving conclusions that don't lie—and finally, before installing a Skill written by someone else, review it like code.