The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.
from line 1
1# Creating custom skills
2
3> Learn how to create, structure, and test your own custom skills
4
5Custom skills extend Claude with specialized knowledge and workflows. This guide explains how to create, structure, and test your own skills.
6
7Skills can range from simple instruction sets to multi-file packages with executable code. Effective skills:
8
9* Solve a specific, repeatable task
10* Have clear instructions Claude can follow
11* Include examples when helpful
12* Define when they should be used
13* Focus on one workflow rather than trying to do everything
1# Create custom skills
2
3> Create a custom skill for Claude: write the SKILL.md file, add resources and scripts, package the skill, and test it.
4
5export const Piece = ({id, children}) => <div className="pe-piece" data-piece={id}>{children}</div>;
6
7export const PluginExplorer = ({children, variant}) => {
8 const SKILL_PIECES = [{
9 id: 'skillmd',
10 required: 'Required',
11 name: 'SKILL.md',
12 path: 'brand-guidelines/SKILL.md',
13 lines: [{
14 depth: 0,
15 kind: 'file',
16 text: 'SKILL.md'
17 }],
18 href: '/skills/how-to#create-a-skillmd-file',
19 linkText: 'Go to Create a SKILL.md file'
20 }, {
21 id: 'references',
22 name: 'Reference file',
23 path: 'brand-guidelines/references/voice-and-tone.md',
24 lines: [{
25 depth: 0,
26 kind: 'folder',
27 text: 'references/'
28 }, {
29 depth: 1,
30 kind: 'file',
31 text: 'voice-and-tone.md'
32 }],
33 href: '/skills/how-to#add-resources',
34 linkText: 'Go to Add resources'
35 }, {
36 id: 'assets',
37 name: 'Asset',
38 path: 'brand-guidelines/assets/slide-template.md',
39 lines: [{
40 depth: 0,
41 kind: 'folder',
42 text: 'assets/'
43 }, {
44 depth: 1,
45 kind: 'file',
46 text: 'slide-template.md'
47 }],
48 href: '/skills/how-to#add-resources',
49 linkText: 'Go to Add resources'
50 }, {
51 id: 'scripts',
52 name: 'Script',
53 path: 'brand-guidelines/scripts/check_contrast.py',
54 lines: [{
55 depth: 0,
56 kind: 'folder',
57 text: 'scripts/'
58 }, {
59 depth: 1,
60 kind: 'file',
61 text: 'check_contrast.py'
62 }],
63 href: '/skills/how-to#add-scripts',
64 linkText: 'Go to Add scripts'
65 }];
66 const PLUGIN_PIECES = [{
67 id: 'manifest',
68 required: 'Required',
69 name: 'Manifest',
70 path: '.claude-plugin/plugin.json',
71 lines: [{
72 depth: 0,
73 kind: 'folder',
74 text: '.claude-plugin/'
75 }, {
76 depth: 1,
77 kind: 'file',
78 text: 'plugin.json'
79 }],
80 href: '/plugins/build#write-the-manifest',
81 linkText: 'Go to Write the manifest'
82 }, {
83 id: 'skills',
84 name: 'Skill',
85 path: 'skills/file-expense/SKILL.md',
86 lines: [{
87 depth: 0,
88 kind: 'folder',
89 text: 'skills/'
90 }, {
91 depth: 1,
92 kind: 'folder',
93 text: 'file-expense/'
94 }, {
95 depth: 2,
96 kind: 'file',
97 text: 'SKILL.md'
98 }],
99 href: '/skills/how-to',
100 linkText: 'Go to Create custom skills'
101 }, {
102 id: 'references',
103 name: 'Skill reference file',
104 path: 'skills/file-expense/references/categories.md',
105 lines: [{
106 depth: 2,
107 kind: 'folder',
108 text: 'references/'
109 }, {
110 depth: 3,
111 kind: 'file',
112 text: 'categories.md'
113 }],
114 href: '/skills/how-to#add-resources',
115 linkText: 'Go to Add resources'
116 }, {
117 id: 'scripts',
118 name: 'Skill script',
119 path: 'skills/file-expense/scripts/total.py',
120 lines: [{
121 depth: 2,
122 kind: 'folder',
123 text: 'scripts/'
124 }, {
125 depth: 3,
126 kind: 'file',
127 text: 'total.py'
128 }],
129 href: '/skills/how-to#add-scripts',
130 linkText: 'Go to Add scripts'
131 }, {
132 id: 'commands',
133 name: 'Command',
134 path: 'commands/summarize.md',
135 lines: [{
136 depth: 0,
137 kind: 'folder',
138 text: 'commands/'
139 }, {
140 depth: 1,
141 kind: 'file',
142 text: 'summarize.md'
143 }],
144 href: '/plugins/platform-support#compare-component-support-by-app',
145 linkText: 'Go to component support by app'
146 }, {
147 id: 'mcp',
148 name: 'MCP connector',
149 path: '.mcp.json',
150 lines: [{
151 depth: 0,
152 kind: 'file',
153 text: '.mcp.json'
154 }],
155 href: '/plugins/build#bundle-an-mcp-connector-with-its-skill',
156 linkText: 'Go to Bundle an MCP connector with its skill'
157 }, {
158 id: 'readme',
159 required: 'Required to publish',
160 name: 'README',
161 path: 'README.md',
162 lines: [{
163 depth: 0,
164 kind: 'file',
165 text: 'README.md'
166 }],
167 href: '/plugins/pre-submission-checklist#readme-and-license',
168 linkText: 'Go to README and license checks'
169 }, {
170 id: 'license',
171 required: 'Required to publish',
172 name: 'License',
173 path: 'LICENSE',
174 lines: [{
175 depth: 0,
176 kind: 'file',
177 text: 'LICENSE'
178 }],
179 href: '/plugins/pre-submission-checklist#readme-and-license',
180 linkText: 'Go to README and license checks'
181 }];
182 const isSkill = variant === 'skill';
183 const PIECES = isSkill ? SKILL_PIECES : PLUGIN_PIECES;
184 const rootLabel = isSkill ? 'brand-guidelines/' : 'expense-reports/';
185 const title = isSkill ? 'What goes in the skill folder' : 'What goes in the plugin folder';
186 const treeCaption = isSkill ? 'Skill folder' : 'Plugin folder';
187 const [selectedId, setSelectedId] = useState(isSkill ? 'skillmd' : 'manifest');
188 const [isFullscreen, setIsFullscreen] = useState(false);
189 const rootRef = useRef(null);
190 useEffect(() => {
191 const onFsChange = () => setIsFullscreen(!!document.fullscreenElement);
192 document.addEventListener('fullscreenchange', onFsChange);
193 return () => document.removeEventListener('fullscreenchange', onFsChange);
194 }, []);
195 const toggleFullscreen = () => {
196 if (!rootRef.current) return;
197 if (document.fullscreenElement) document.exitFullscreen(); else rootRef.current.requestFullscreen().catch(() => {});
198 };
199 const selected = PIECES.find(p => p.id === selectedId) || PIECES[0];
200 const onTreeKeyDown = e => {
201 const keys = ['ArrowDown', 'ArrowUp', 'Home', 'End'];
202 if (keys.indexOf(e.key) === -1) return;
203 const i = PIECES.findIndex(p => p.id === selectedId);
204 let next = i;
205 if (e.key === 'ArrowDown') next = Math.min(PIECES.length - 1, i + 1);
206 if (e.key === 'ArrowUp') next = Math.max(0, i - 1);
207 if (e.key === 'Home') next = 0;
208 if (e.key === 'End') next = PIECES.length - 1;
209 e.preventDefault();
210 if (next === i) return;
211 const id = PIECES[next].id;
212 setSelectedId(id);
213 const el = document.getElementById('pe-node-' + id);
214 if (el) el.focus();
215 };
216 const FolderIcon = () => <svg className="pe-icon" width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" aria-hidden="true">
217 <path d="M1.5 4.5a1 1 0 0 1 1-1h3.2l1.3 1.5h6a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1h-10.5a1 1 0 0 1-1-1z" />
218 </svg>;
219 const FileIcon = () => <svg className="pe-icon" width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" aria-hidden="true">
220 <path d="M4 1.5h5.5L13 5v9.5H4z" />
221 <path d="M9.5 1.5V5H13" />
222 </svg>;
223 return <div ref={rootRef} className={isFullscreen ? 'pe-root pe-fullscreen not-prose' : 'pe-root not-prose'} data-selected={selected.id}>
224 <style>{`
225 .pe-root {
226 --pe-mono: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
227 --pe-accent: #D97757;
228 --pe-accent-text: #A8502F;
229 --pe-accent-bg: rgba(217,119,87,0.10);
230 --pe-bg: #FFFFFF;
231 --pe-surface: #FAFAF7;
232 --pe-hover: #F0EEE6;
233 --pe-border: #E8E6DC;
234 --pe-text: #141413;
235 --pe-text-2: #3D3D3A;
236 --pe-text-3: #5E5D59;
237 font-family: inherit;
238 background: var(--pe-bg);
239 color: var(--pe-text);
240 border: 1px solid var(--pe-border);
241 border-radius: 12px;
242 margin: 1.5rem 0;
243 overflow: hidden;
244 box-sizing: border-box;
245 }
246 .dark .pe-root {
247 --pe-accent-text: #EBA98F;
248 --pe-accent-bg: rgba(217,119,87,0.18);
249 --pe-bg: #1A1918;
250 --pe-surface: #232221;
251 --pe-hover: #2E2D2B;
252 --pe-border: #3A3936;
253 --pe-text: #F1EFE9;
254 --pe-text-2: #D6D4CA;
255 --pe-text-3: #B8B5AD;
256 }
257 .pe-root *, .pe-root *::before, .pe-root *::after { box-sizing: border-box; }
258 .pe-head { display: flex; align-items: flex-start; gap: 12px; padding: 18px 24px 16px; border-bottom: 1px solid var(--pe-border); }
259 .pe-head-text { flex: 1; min-width: 0; }
260 .pe-fs-btn { flex-shrink: 0; width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--pe-border); border-radius: 6px; background: var(--pe-surface); color: var(--pe-text-2); font-size: 15px; line-height: 1; cursor: pointer; }
261 .pe-fs-btn:hover { background: var(--pe-hover); }
262 .pe-fs-btn:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: 2px; }
263 .pe-fullscreen { border-radius: 0; height: 100vh; display: flex; flex-direction: column; overflow: auto; }
264 .pe-fullscreen .pe-body { flex: 1; }
265 .pe-title { font-size: 19px; font-weight: 600; line-height: 1.3; color: var(--pe-text); margin: 0; }
266 .pe-sub { font-size: 15px; line-height: 1.5; color: var(--pe-text-3); margin: 4px 0 0; }
267 .pe-sub code { font-family: var(--pe-mono); font-size: 0.88em; padding: 1px 5px; border-radius: 4px; background: var(--pe-surface); border: 1px solid var(--pe-border); }
268 .pe-body { display: flex; align-items: stretch; }
269 .pe-tree-pane { width: 270px; flex-shrink: 0; background: var(--pe-surface); border-right: 1px solid var(--pe-border); padding: 16px 0 12px; }
270 .pe-panel { flex: 1; min-width: 0; padding: 16px 24px 24px; }
271 .pe-caption { font-size: 13px; font-weight: 600; color: var(--pe-text-3); margin: 0 0 10px; }
272 .pe-tree-pane .pe-caption { padding: 0 16px; }
273 .pe-rootline { display: flex; align-items: center; gap: 7px; padding: 3px 16px; font-family: var(--pe-mono); font-size: 13.5px; color: var(--pe-text-3); }
274 .pe-node {
275 display: block; width: 100%; margin: 0; padding: 3px 16px 3px 30px; text-align: left; cursor: pointer;
276 background: transparent; color: var(--pe-text-2);
277 border: none; border-left: 3px solid transparent;
278 font-family: var(--pe-mono); font-size: 13.5px; line-height: 1.4;
279 }
280 .pe-node:hover { background: var(--pe-hover); }
281 .pe-node:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: -2px; }
282 .pe-node[aria-pressed="true"] { background: var(--pe-accent-bg); border-left-color: var(--pe-accent); color: var(--pe-accent-text); font-weight: 600; }
283 .pe-line { display: flex; align-items: center; gap: 7px; padding: 2px 0; }
284 .pe-line span { overflow-wrap: anywhere; }
285 .pe-line > span:not(.pe-req) { white-space: nowrap; flex-shrink: 0; }
286 .pe-req { flex-shrink: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; margin-left: 8px; padding: 0 6px; border-radius: 999px; font-size: 11px; line-height: 18px; font-family: var(--pe-sans, inherit); letter-spacing: .02em; color: var(--pe-accent-text); border: 1px solid var(--pe-border); background: var(--pe-surface); white-space: nowrap; }
287 .pe-piece { display: none; font-size: 16px; line-height: 1.6; color: var(--pe-text-2); }
288 ${PIECES.map(p => '.pe-root[data-selected="' + p.id + '"] .pe-piece[data-piece="' + p.id + '"]').join(',\n ')} { display: block; }
289 .pe-piece p { margin: 0 0 10px; }
290 .pe-piece p:last-child { margin-bottom: 0; }
291 .pe-piece ul { list-style: disc; padding-left: 1.25em; margin: 0 0 10px; }
292 .pe-piece li { margin: 2px 0; }
293 .pe-piece code { font-family: var(--pe-mono); font-size: 0.88em; padding: 1px 5px; border-radius: 4px; background: var(--pe-surface); border: 1px solid var(--pe-border); }
294 .pe-piece .code-block { margin: 12px 0 0; }
295 .pe-piece pre code { padding: 0; border: none; background: none; }
296 .pe-piece a { color: var(--pe-accent-text); }
297 .pe-line-compact { display: none; }
298 .pe-icon { flex-shrink: 0; }
299 .pe-name { font-size: 22px; font-weight: 600; line-height: 1.25; letter-spacing: -0.2px; color: var(--pe-text); margin: 0; }
300 .pe-path { font-family: var(--pe-mono); font-size: 13.5px; color: var(--pe-accent-text); margin: 4px 0 0; overflow-wrap: anywhere; }
301 .pe-block { margin: 20px 0 0; }
302 .pe-link {
303 display: inline-block; margin: 24px 0 0; padding: 8px 14px; border-radius: 8px;
304 font-size: 14.5px; font-weight: 600; text-decoration: none;
305 color: var(--pe-accent-text); background: var(--pe-accent-bg); border: 1px solid var(--pe-accent);
306 }
307 .pe-link:hover { filter: brightness(0.97); }
308 .pe-link:focus-visible { outline: 2px solid var(--pe-accent); outline-offset: 2px; }
309 @media (max-width: 700px) {
310 .pe-head { padding: 16px 16px 14px; }
311 .pe-body { flex-direction: column; }
312 .pe-tree-pane { width: 100%; border-right: none; border-bottom: 1px solid var(--pe-border); }
313 .pe-line-tree { display: none; }
314 .pe-line-compact { display: flex; }
315 .pe-panel { padding: 16px 16px 20px; }
316 }
317 `}</style>
318
319 <div className="pe-head">
320 <div className="pe-head-text">
321 <div className="pe-title">{title}</div>
322 {isSkill ? <div className="pe-sub">This example skill, <code>brand-guidelines</code>, has one of each kind of file a skill can carry. Select a file to read what it's for and see a minimal example.</div> : <div className="pe-sub">This example plugin, <code>expense-reports</code>, has one of each file that chat, Cowork, and Claude Code all load, plus the README and license the directory requires. Select a file to read what it’s for and see a minimal example.</div>}
323 </div>
324 <button type="button" className="pe-fs-btn" onClick={toggleFullscreen} aria-label={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'} title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}>
325 {isFullscreen ? '⤡' : '⛶'}
326 </button>
327 </div>
328
329 <div className="pe-body">
330 <div className="pe-tree-pane">
331 <div className="pe-caption" id="pe-tree-caption">{treeCaption}</div>
332 <div role="group" aria-labelledby="pe-tree-caption" onKeyDown={onTreeKeyDown}>
333 <div className="pe-rootline"><FolderIcon /><span>{rootLabel}</span></div>
334 {PIECES.map(p => <button key={p.id} id={'pe-node-' + p.id} type="button" className="pe-node" aria-pressed={p.id === selected.id} aria-label={p.name + ', ' + p.path} onClick={() => setSelectedId(p.id)}>
335 {p.lines.map((line, i) => <span key={i} className="pe-line pe-line-tree" style={{
336 paddingLeft: line.depth * 18 + 'px'
337 }}>
338 {line.kind === 'folder' ? <FolderIcon /> : <FileIcon />}
339 <span>{line.text}</span>
340 {p.required && i === p.lines.length - 1 ? <span className="pe-req" title={p.required}>Required</span> : null}
341 </span>)}
342 <span className="pe-line pe-line-compact">
343 <FileIcon />
344 <span>{p.path}</span>
345 {p.required ? <span className="pe-req" title={p.required}>Required</span> : null}
346 </span>
347 </button>)}
348 </div>
349 </div>
350
351 <div className="pe-panel" role="region" aria-labelledby="pe-panel-caption" aria-live="polite" aria-atomic="true">
352 <div className="pe-caption" id="pe-panel-caption">Selected file</div>
353 <div className="pe-name">{selected.name}{selected.required ? <span className="pe-req">{selected.required}</span> : null}</div>
354 <div className="pe-path">{selected.path}</div>
355
356 <div className="pe-block">{children}</div>
357
358 <a className="pe-link" href={selected.href}>{selected.linkText}</a>
359 </div>
360 </div>
361 </div>;
362};
363
364A custom skill is a folder with a `SKILL.md` file of instructions, and optionally scripts and reference files, that Claude loads when a task matches the skill's description. This guide is for anyone writing a skill of their own. It explains how to create, structure, and test one.
365
366If you already know what the skill should do, start with the [directory structure](#directory-structure). If you're not sure a skill is the right tool, read [Decide what skill to create](#decide-what-skill-to-create) first.
14367
15368<Note>
16 Skills follow the [Agent Skills specification](https://agentskills.io/specification) — see the specification for more in-depth information.
369 Skills follow the [Agent Skills specification](https://agentskills.io/specification). See the specification for more in-depth information.
17370</Note>
18371
372## Decide what skill to create
373
374A skill pays off when Claude does a task for you repeatedly and you want it done the same way every time. Good candidates are tasks where you find yourself correcting Claude with the same instructions, such as a report format your team uses, a review checklist, a multi-step procedure, or work that needs a reference file or a script to come out right. A skill can also teach Claude how your team uses a tool you've connected, such as which project new issues go in and which labels and template to use in your issue tracker. Write the skill once, and Claude applies it whenever a request matches the skill's description, for you and for anyone you share it with.
375
376A skill isn't the right tool for everything:
377
378* **A one-off task**: describe what you want in the conversation instead
379* **Live data from another service**: that's what an [MCP connector](/docs/connectors/getting-started) provides. A skill can tell Claude how to use a connector, but it can't reach the service itself
380* **Instructions for every conversation**: put those in your [personal preferences or project instructions](https://support.claude.com/en/articles/10185728-understanding-claude-s-personalization-features) rather than a skill, which loads only when a task matches
381
382To start, write down the task in one sentence and what a good result looks like. That sentence becomes the skill's `description`, and the rest becomes the instructions. If you'd rather have Claude draft the skill with you, ask it to use the [skill-creator skill](#measure-whether-the-skill-improves-the-output), then edit what it produces.
383
19384## Directory structure
20385
21A skill is a directory containing at minimum a `SKILL.md` file:
22
23```
24brand-guidelines/
25├── SKILL.md
26├── scripts/ # Optional: executable code
27├── references/ # Optional: additional documentation
28└── assets/ # Optional: templates, images, data files
29```
386A skill is a folder named after the skill. The only required file is `SKILL.md`; the other folders are optional and hold material that `SKILL.md` points Claude to. Select a file in the explorer to see what goes in it and what Claude does with it.
387
388<PluginExplorer variant="skill">
389 <Piece id="skillmd">
390 <p>The one required file. Its frontmatter names and describes the skill, and Claude reads the <code>description</code> to decide when the skill applies. The body holds the instructions Claude follows once it does.</p>
391 <p>In this example, the skill applies Acme's brand guidelines and tells Claude where the supporting files are:</p>
392
393 ```markdown SKILL.md theme={null}
394 ---
395 name: brand-guidelines
396 description: Apply Acme Corp brand guidelines to presentations and documents, including official colors, fonts, and logo usage.
397 ---
398 Use these guidelines whenever you produce a document or deck for Acme.
399
400 1. Use the colors and fonts in the sections below.
401 2. For wording, follow `references/voice-and-tone.md`.
402 3. For slides, start from `assets/slide-template.md`.
403 4. Before you finish, run `python3 ${CLAUDE_SKILL_DIR}/scripts/check_contrast.py` on any color pairs you chose.
404 ```
405 </Piece>
406
407 <Piece id="references">
408 <p>Longer background that Claude reads only when a step calls for it, so it doesn't crowd <code>SKILL.md</code>. Mention the file by path at the step where Claude needs it.</p>
409 <p>In this example, the file holds the writing rules the instructions point to in step 2:</p>
410
411 ```markdown references/voice-and-tone.md theme={null}
412 # Voice and tone
413 - Write in the second person and the present tense.
414 - Prefer short sentences. Avoid exclamation marks.
415 - Product names are always capitalized: Acme Cloud, Acme Sync.
416 ```
417 </Piece>
418
419 <Piece id="assets">
420 <p>Templates, images, and data files that Claude copies or fills in rather than reads for guidance.</p>
421 <p>In this example, the asset is the slide outline that step 3 tells Claude to start from:</p>
422
423 ```markdown assets/slide-template.md theme={null}
424 # [Deck title]
425 ## Agenda
426 ## [Section 1]
427 ## [Section 2]
428 ## Next steps
429 ```
430 </Piece>
431
432 <Piece id="scripts">
433 <p>Code that Claude runs while following the skill, for work that is more reliable as a program than as instructions. Reference it from `SKILL.md` with `${CLAUDE_SKILL_DIR}` so the path resolves wherever the skill is installed.</p>
434 <p>In this example, the script checks that a text and background color pair has enough contrast:</p>
435
436 ```python scripts/check_contrast.py theme={null}
437 import sys
438
439 def luminance(hex_color):
440 r, g, b = (int(hex_color[i:i+2], 16) / 255 for i in (1, 3, 5))
441 f = lambda c: c / 12.92 if c <= 0.03928 else ((c + 0.055) / 1.055) ** 2.4
442 return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b)
443
444 fg, bg = sys.argv[1], sys.argv[2]
445 l1, l2 = sorted((luminance(fg), luminance(bg)), reverse=True)
446 ratio = (l1 + 0.05) / (l2 + 0.05)
447 print(f"{ratio:.2f}", "OK" if ratio >= 4.5 else "LOW")
448 ```
449 </Piece>
450</PluginExplorer>
30451
31452The directory name must match the `name` field in your `SKILL.md`.
32453
33## Creating a `SKILL.md` file
454## Create a `SKILL.md` file
34455
35456The `SKILL.md` file must start with YAML frontmatter containing required metadata, followed by markdown instructions.
36457
37458### Required fields
459
460A `SKILL.md` file starts with YAML frontmatter that names and describes the skill:
38461
39462```markdown SKILL.md theme={null}
40463---
from line 466
43466---
44467```
45468
46**name**: Lowercase letters, numbers, and hyphens only. Maximum 64 characters. Must match the directory name.
47
48**description**: Explains what the skill does and when to use it. Claude uses this to determine when to invoke your skill. Maximum 1,024 characters, the same limit as the [Agent Skills specification](https://agentskills.io/specification).
49
50### Markdown body
51
52After the frontmatter, write markdown instructions for Claude. Include:
469Both frontmatter fields are required:
470
471| Field | Type | Description |
472| :------------ | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
473| `name` | string | Lowercase letters, numbers, and hyphens only, up to 64 characters. Must match the skill's directory name |
474| `description` | string | What the skill does and when to use it. Claude reads this to decide when to load the skill. Up to 1,024 characters, the limit in the [Agent Skills specification](https://agentskills.io/specification) |
475
476### Write the instructions
477
478After the frontmatter, the rest of the file is the instructions Claude follows when the skill loads, written as ordinary text. You can add headings, lists, and bold with Markdown formatting, the lightweight markup many note-taking apps use, but plain paragraphs work too. Useful things to include:
53479
54480* Step-by-step procedures
55481* Examples of inputs and outputs
from line 524
98524See the [assets/](assets/) folder for logo files and font downloads.
99525```
100526
101## Adding resources
102
103For content too detailed for `SKILL.md`, add files to your skill directory:
527## Add resources
528
529Claude reads all of `SKILL.md` every time the skill loads, so anything long that Claude needs only some of the time is better kept in a separate file that `SKILL.md` points to. Claude then opens that file only when a step calls for it, which keeps the skill quick to load and leaves more of the conversation for your actual task. Separate files also let a skill carry things that aren't instructions at all, such as a template to fill in or a table to look values up in. Put them in folders next to `SKILL.md`:
104530
105531* **`references/`**: Additional documentation Claude can read when needed
106532* **`assets/`**: Templates, images, lookup tables, schemas
107* **`scripts/`**: Executable code (see below)
108
109Reference these files in `SKILL.md` so Claude knows when to load them. Keep files focused—smaller files mean less context usage.
110
111## Adding scripts
112
113Skills can include executable code in Python, JavaScript/Node.js, or Bash. Place scripts in the `scripts/` directory.
114
115Claude can install packages from standard repositories (PyPI, npm) when loading skills. Declare dependencies in your frontmatter:
116
117```markdown SKILL.md theme={null}
118---
119name: data-analysis
120description: Analyze CSV files and generate visualizations.
121dependencies: python>=3.8, pandas>=1.5.0, matplotlib
122---
533* **`scripts/`**: Executable code, which [Add scripts](#add-scripts) covers
534
535Mention each file in `SKILL.md` at the step where Claude should use it, for example "Fill in `assets/report-template.md`", so Claude knows when to open it. Keep each file focused on one thing.
536
537## Add scripts
538
539A skill can include scripts that Claude runs while following it, in any language available where the skill runs: in Claude Code that's whatever is installed on your machine, and in chat on claude.ai it's what the code-execution environment provides. Put scripts in a `scripts/` folder inside the skill's own folder, next to `SKILL.md`. In a plugin, that looks like this:
540
541```text theme={null}
542my-plugin/
543└── skills/
544 └── render-chart/
545 ├── SKILL.md
546 └── scripts/
547 └── render.py
123548```
124549
125## Packaging your skill
126
127To upload a skill to Claude:
128
1291. Ensure the directory name matches your skill's `name` field
1302. Create a ZIP file containing the skill directory
131
132**Correct structure:**
550In `SKILL.md`, write the script's path with `${CLAUDE_SKILL_DIR}`, for example `python3 ${CLAUDE_SKILL_DIR}/scripts/render.py`. Claude Code and Cowork replace `${CLAUDE_SKILL_DIR}` with the skill's folder when the skill loads. It's a placeholder in the skill text, not an environment variable. In chat on claude.ai, the skill's whole folder, scripts included, is copied into the code execution sandbox, so also keep the path readable relative to `SKILL.md`, such as `scripts/render.py`.
551
552In Claude Code, running a script is a Bash tool call, so it needs your permission. When you test with [`claude -p`](https://code.claude.com/docs/en/headless), which can't stop to ask, allow the script on the command line, for example `--allowedTools "Bash(python3 /path/to/my-plugin/skills/render-chart/scripts/render.py *)"`, using the script's absolute path. Claude runs the script by its absolute path, and `Bash()` rules match the whole command line, so a rule that names the exact path approves only that script; a wildcard before the path would approve more than you intend.
553
554Don't put API keys, passwords, or other credentials in a script or anywhere else in the skill: everyone you share the skill with receives its files. When a script needs to reach an outside service, have Claude use a [connector](/docs/connectors/getting-started) for that service instead, so each person signs in with their own account.
555
556## Package your skill
557
558You upload a skill to Claude as a ZIP file. The ZIP must contain the skill directory itself as its top level, because Claude looks for `<skill-name>/SKILL.md` inside the archive; a `SKILL.md` sitting at the root of the ZIP isn't recognized as a skill. The packaged file looks like this:
133559
134560```
135561my-skill.zip
from line 564
138564 └── scripts/
139565```
140566
141**Incorrect structure:**
142
143```
144my-skill.zip
145├── SKILL.md # files directly in ZIP root
146└── scripts/
147```
148
149## Testing your skill
567<Steps>
568 <Step title="Check the directory name">
569 Make sure the directory name matches the `name` field in `SKILL.md`.
570 </Step>
571
572 <Step title="Zip the directory from its parent folder">
573 Where the `zip` command is available, such as on macOS and Linux, run it from the folder that contains the skill directory, so the directory becomes the top level of the archive:
574
575 ```bash theme={null}
576 zip -r my-skill.zip my-skill/
577 ```
578
579 If you use another tool to create the ZIP, compress the skill folder itself rather than the files inside it.
580 </Step>
581
582 <Step title="Confirm the structure">
583 List the archive and check that every entry starts with `my-skill/`:
584
585 ```bash theme={null}
586 unzip -l my-skill.zip
587 ```
588
589 If `SKILL.md` appears without the `my-skill/` prefix, you zipped the contents instead of the folder; zip again from the parent folder.
590 </Step>
591</Steps>
592
593To check the skill's contents rather than the archive shape, [validate it before uploading](#before-uploading) with `skills-ref validate` or `claude plugin validate`, or ask Claude to review the folder against the [Agent Skills specification](https://agentskills.io/specification).
594
595## Test your skill
596
597Test the skill's files before you upload it, try it in Claude Code if you have it, confirm that Claude loads it after you upload, and then measure whether it improves Claude's output.
150598
151599### Before uploading
152600
1531. Review `SKILL.md` for clarity
1542. Verify the description accurately reflects when Claude should use the skill
1553. Check that all referenced files exist
1564. Validate using `skills-ref validate ./my-skill` ([validation tool](https://github.com/agentskills/agentskills/tree/main/skills-ref))
601Before you upload the ZIP, check the skill's files:
602
603<Steps>
604 <Step title="Review SKILL.md">
605 Review `SKILL.md` for clarity.
606 </Step>
607
608 <Step title="Check the description">
609 Verify the description accurately reflects when Claude should use the skill.
610 </Step>
611
612 <Step title="Check referenced files">
613 Check that all referenced files exist.
614 </Step>
615
616 <Step title="Validate the skill">
617 Check the frontmatter against the Agent Skills specification with the [`skills-ref` reference tool](https://github.com/agentskills/agentskills/tree/main/skills-ref). It isn't preinstalled: clone that repository and install it into a Python virtual environment as its README describes, which puts `skills-ref` on your `PATH` while the environment is active. Then, from the folder that contains the skill directory, run:
618
619 ```bash theme={null}
620 skills-ref validate ./my-skill
621 ```
622
623 A skill that passes prints `Valid skill: ./my-skill`. Otherwise the command lists each problem, such as a `name` that doesn't match the directory or a frontmatter field the specification doesn't define.
624
625 If the skill is inside a plugin folder, running `claude plugin validate ./my-plugin` in your terminal also parses each skill's frontmatter: it reports a `SKILL.md` whose frontmatter doesn't parse, and prints `✔ Validation passed` when the plugin passes.
626 </Step>
627</Steps>
628
629### In Claude Code
630
631If you use [Claude Code](https://code.claude.com/docs/en/overview), you can try the skill from your terminal without uploading it. Copy the skill folder into `~/.claude/skills/`, so the file sits at `~/.claude/skills/my-skill/SKILL.md`, then start `claude` in any project. Describe a task the skill's `description` covers and check that Claude uses it, or type `/my-skill` to run it directly. If Claude doesn't pick the skill up on its own, revise the description. [Extend Claude with skills](https://code.claude.com/docs/en/skills) covers the other places Claude Code loads skills from, including a project's `.claude/skills/` folder and plugins.
157632
158633### After uploading
159634
1601. Enable the skill in **Customize > Skills**
1612. Try prompts that should trigger it
1623. Review Claude's thinking to confirm it's loading the skill
1634. Iterate on the description if Claude isn't using it when expected
635After you upload, confirm that Claude loads the skill when it should:
636
637<Steps>
638 <Step title="Turn the skill on">
639 Go to [**Customize > Skills**](https://claude.ai/customize/skills) in claude.ai or the desktop app and turn the skill on.
640 </Step>
641
642 <Step title="Try prompts that should trigger it">
643 Send prompts that should trigger the skill, and review Claude's thinking to confirm it's loading the skill.
644 </Step>
645
646 <Step title="Iterate on the description">
647 Iterate on the description if Claude isn't using it when expected.
648 </Step>
649</Steps>
650
651### Measure whether the skill improves the output
652
653Trying a few prompts tells you the skill loads, not whether Claude's answers are better with it. To check that, use [`skill-creator`](https://github.com/anthropics/skills/tree/main/skills/skill-creator), a skill from Anthropic that runs your skill on test prompts you agree on, shows you the results, and helps you revise it. On claude.ai, turn it on under [**Customize > Skills**](https://claude.ai/customize/skills), where it's listed as from Anthropic, then ask Claude to evaluate your skill.
654
655`skill-creator` does more in Cowork and Claude Code than in chat:
656
657* **Chat**: `skill-creator` works through the test prompts one at a time and shows you the results in the conversation
658* **Cowork and Claude Code**: it also runs the same prompts without the skill as a baseline, runs everything in parallel, and adds pass rates, timing, and token counts so you can compare the two. In Claude Code you install it as a plugin, as [Run evals with skill-creator](https://code.claude.com/docs/en/skills#run-evals-with-skill-creator) describes
659
660If the skill is part of a plugin, you can also test the whole plugin from the Claude Code command line with [`claude plugin eval`](https://code.claude.com/docs/en/plugin-evals), which grades eval cases you write and compares against a run without the plugin.
164661
165662## Best practices
166663
167**Keep it focused**: Create separate skills for different workflows. Multiple focused skills compose better than one large skill.
168
169**Write clear descriptions**: Be specific about when the skill applies. Include keywords that help Claude identify relevant tasks.
170
171**Start simple**: Begin with markdown instructions before adding scripts.
172
173**Use examples**: Include example inputs and outputs to help Claude understand what success looks like.
174
175**Test incrementally**: Test after each significant change.
176
177**Leverage composability**: Claude can use multiple skills together automatically.
178
179## Security considerations
180
181* Don't hardcode sensitive information (API keys, passwords)
182* Review any downloaded skills before enabling them
183* Use MCP connections for external service access
664Follow these practices when you write a skill:
665
666* **Keep it focused**: create separate skills for different workflows. Several focused skills combine better than one large skill, and Claude can use more than one in a conversation
667* **Write a specific description**: say when the skill applies and include the words a request for that task would use. The description is the only part Claude reads before deciding to load the skill
668* **Start with instructions**: begin with Markdown instructions and add scripts only when a step needs code
669* **Show the output you expect**: include example inputs and outputs so Claude can match them
670* **Test after each change**: run the skill on a real request after each significant edit, as [Test your skill](#test-your-skill) describes
671
672For more, the Agent Skills site covers [best practices for skill creation](https://agentskills.io/skill-creation/best-practices) and [writing descriptions that trigger reliably](https://agentskills.io/skill-creation/optimizing-descriptions) in depth.
184673
185674## Example skills
186675
187See [github.com/anthropics/skills](https://github.com/anthropics/skills/tree/main/skills) for example skills you can use as templates.
188
189## Related topics
190
191<Columns cols={2}>
192 <Card title="Skills in Claude Code" icon="terminal" href="https://code.claude.com/docs/en/skills">
193 Create and test skills from the Claude Code CLI, including the `/skills` manager.
194 </Card>
195
196 <Card title="Distribute as a plugin" icon="puzzle-piece" href="/docs/plugins/submit">
197 Package your skill for the plugin directory.
198 </Card>
199</Columns>
676Anthropic's [skills repository](https://github.com/anthropics/skills/tree/main/skills) has working skills you can read and copy. These four cover the common shapes, from instructions only to instructions with reference files and scripts:
677
678* **[brand-guidelines](https://github.com/anthropics/skills/tree/main/skills/brand-guidelines)**: a single `SKILL.md` with no scripts or reference files. A good model for a skill that is only instructions, such as a style or formatting rule
679* **[internal-comms](https://github.com/anthropics/skills/tree/main/skills/internal-comms)**: instructions plus an `examples/` folder of sample documents that `SKILL.md` tells Claude to consult, the pattern from [Add resources](#add-resources)
680* **[pdf](https://github.com/anthropics/skills/tree/main/skills/pdf)**: instructions, two reference files for less common tasks, and a `scripts/` folder Claude runs to fill forms and extract tables, the pattern from [Add scripts](#add-scripts)
681* **[skill-creator](https://github.com/anthropics/skills/tree/main/skills/skill-creator)**: the skill that helps you write and test other skills, described in [Measure whether the skill improves the output](#measure-whether-the-skill-improves-the-output)
682
683Copy a skill's structure rather than its contents: keep the folder layout and frontmatter, and replace the instructions with your own.
684
685## Share or package your skill
686
687After your skill works, you can give it to other people on its own or as part of a plugin. People you share it with should be able to read what it does, so keep the instructions and scripts plain enough to review.
688
689* **Share or publish one skill**: on Team and Enterprise plans, open the skill from **Customize > Skills** and use the same **Share** and **Publish to org** controls that a plugin has. They work the way [sharing a plugin with specific people](/docs/plugins/share#share-a-plugin-with-specific-people) and [publishing a plugin to your organization](/docs/plugins/share#publish-a-plugin-to-your-organization) describe
690* **Package skills and connectors together**: when you want several skills, or a skill plus the connector it uses, installed together, [build a plugin](/docs/plugins/build) that contains them
691
692## Next steps
693
694* [Skills in Claude Code](https://code.claude.com/docs/en/skills): create and test skills from the Claude Code CLI, including the `/skills` manager
695* [Plugin structure and testing](/docs/plugins/build): package your skill as a plugin so other people can install it
696* [Submit your plugin](/docs/plugins/submit): submit the plugin to the directory, where Anthropic reviews it before it's listed
200697
No line in this hunk matches that.