Bạn đang dùng Claude Code và muốn wrap một workflow lặp đi lặp lại thành một lệnh. Bạn nghĩ đến CLAUDE.md, nhưng nhét instruction vào đó có nghĩa là mọi session đều tải nó dù bạn không dùng. Bạn cần thứ gì đó chỉ load khi cần.

Đó chính là lý do skill tồn tại. Skill là một đơn vị instruction được đóng gói, chỉ vào context khi trigger, thay vì luôn nằm trong mọi session. Nếu bài 6 nói về CLAUDE.md và rules như lớp instruction toàn cục, thì bài này nói về lớp instruction có điều kiện.

Skill là gì về mặt vật lý

Không có khái niệm “đăng ký skill” trong Claude Code. Một skill chỉ đơn giản là một thư mục tại ~/.claude/skills/<tên-skill>/ chứa một file bắt buộc: SKILL.md.

~/.claude/skills/
├── nf-direnv/
│   └── SKILL.md
├── nf-memory/
│   └── SKILL.md
│   └── references/
│       └── nf-memory-mappings.md
└── format-date/
    └── SKILL.md

Thư mục phụ là optional. Khi skill phức tạp hơn, bạn có thể thêm:

  • references/: tài liệu Claude đọc khi cần, không nạp vào context ngay từ đầu
  • scripts/: bash script có thể gọi qua Bash tool
  • assets/: template file được copy vào output
  • examples/: ví dụ hoàn chỉnh để người dùng tham khảo

Nguyên tắc: SKILL.md gọn (khoảng 150 dòng, hard cap 5.000 từ), nội dung chi tiết chuyển vào references/. Đây là kỹ thuật progressive disclosure: Claude chỉ đọc references/ khi workflow cần, không đọc trước.

Anatomy của SKILL.md

File SKILL.md có hai phần: frontmatter YAML và body markdown.

Frontmatter

---
name: format-date               # kebab-case, max 64 ký tự. Đây là slug cho slash command.
description: "..."              # quan trọng nhất: quyết định khi nào model trigger
argument-hint: <YYYY-MM-DD>     # optional: hint hiện trong autocomplete
disable-model-invocation: true  # optional: tắt auto-trigger, chỉ trigger qua /slash
user-invokable: false           # optional: ẩn khỏi /menu, chỉ dùng nội bộ
version: 0.1.0                  # optional
---

Các trường KHÔNG hợp lệ: allowed-tools, context, agent, model. Binary sẽ bỏ qua hoặc báo lỗi.

Trường quan trọng nhất là description. Binary đọc description của tất cả skill và nạp vào <system-reminder> ở đầu mỗi turn. Model dùng description đó để tự quyết định khi nào nên trigger skill.

Description tốt trông như thế nào

Một description tốt cần:

  1. Viết theo dạng trigger phrase cụ thể mà người dùng thực sự gõ
  2. Ít nhất 3 ví dụ cụm từ trong dấu ngoặc kép
  3. Bắt đầu bằng “This skill should be used when the user asks to…”
# TỐT
description: "This skill should be used when the user asks to 'set up direnv',
  'add GH_TOKEN to .envrc', 'configure github token for this repo', or mentions
  wanting to avoid hardcoding tokens in environment files."

# XẤU - quá mơ hồ, model không biết khi nào trigger
description: "Helps with direnv setup."

# XẤU - quá rộng, trigger cả lúc không muốn
description: "Use when working with environment variables."

Description xấu theo kiểu quá rộng gây ra vấn đề thực tế: model trigger skill “environment helper” ngay khi bạn chỉ đang hỏi về một export trong bash script. Context bị tốn cho instruction không liên quan.

Body

Body là plain markdown. Viết theo dạng imperative (mệnh lệnh thức), không second person:

# ĐÚNG
Read .envrc before making changes.
Run `direnv allow` after writing the file.

# SAI
You should read .envrc before making changes.
Claude should run `direnv allow` after writing.

Body có thể include file khác bằng cú pháp @path:

@references/patterns.md

File được referenced sẽ được đọc khi skill trigger, không phải khi binary khởi động.

Cách trigger

Có hai cách để skill chạy.

Auto-trigger qua description matching

Khi model đọc message của bạn và nhận ra nó khớp với description của một skill, model tự gọi Skill tool để load SKILL.md vào context, rồi thực thi theo instruction trong đó.

User: "Set up direnv for this repo"
Model: nhận ra khớp với nf-direnv description
-> Gọi Skill("nf-direnv")
-> SKILL.md được load vào context
-> Model chạy workflow theo body

Bạn không gõ gì thêm, không cần biết skill tên gì.

Manual trigger qua slash command

/tên-skill trong REPL. Binary nhận slash command, load skill tương ứng, thực thi.

User: /nf-direnv

Slash command cũng có thể nhận argument:

User: /nf-memory personal

Argument được truyền vào context cùng SKILL.md để model dùng trong workflow.

disable-model-invocation: true

Đây là trường frontmatter quan trọng thứ hai, và nhiều người bỏ qua nó khi mới viết skill.

Khi không có flag này, model có thể auto-trigger skill bất cứ lúc nào nó thấy description khớp. Điều đó tốt cho skill “hỗ trợ” như format-date hay nf-memory. Nhưng không tốt cho skill có side effect.

Ví dụ: skill deploy-production có description “deploy app to production”. Nếu để model auto-trigger, một câu hỏi đại loại “what happens when I deploy to production?” có thể trigger skill và bắt đầu thực sự deploy. Không ai muốn điều đó.

---
name: deploy-production
description: "Deploy the current build to production. Use when user explicitly
  types /deploy-production."
disable-model-invocation: true
---

Với disable-model-invocation: true, skill chỉ chạy khi người dùng gõ /deploy-production. Model không tự gọi dù description khớp.

Khi nào dùng disable-model-invocation:

Loại skillCó dùng flag không
Query / read-only workflowKhông cần
Wrap một task thường dùngKhông cần
Có side effect (deploy, push, send message)Cần
Command có destructive potentialCần
Skill chỉ muốn trigger explicitCần

user-invokable: false

Khác với disable-model-invocation, field này không liên quan đến trigger. Nó ẩn skill khỏi /menu và autocomplete, nhưng model vẫn có thể tự gọi và người dùng vẫn có thể gõ slash command nếu biết tên.

Dùng khi skill là background knowledge mà bạn không muốn người dùng thấy trong danh sách, ví dụ claude-authoring dùng user-invokable: false vì nó là skill nội bộ cho Claude biết cách viết skill/rule đúng chuẩn, không phải workflow người dùng cần chủ động gọi.

Skill khác CLAUDE.md thế nào

Đây là câu hỏi phổ biến nhất.

CLAUDE.md / rulesSkill
Load thời điểmMọi session tự độngChỉ khi trigger
Phù hợp choConvention toàn cục, quy tắc không thay đổiWorkflow cụ thể, có điều kiện
Ảnh hưởng contextTốn token mọi sessionChỉ tốn khi cần
Ví dụGit commit format, ngôn ngữ trả lời, code styleSetup direnv, deploy, format date

Quy tắc ngón tay cái: nếu instruction luôn đúng bất kể đang làm gì, cho vào CLAUDE.md. Nếu instruction chỉ liên quan trong một tình huống cụ thể, đóng gói thành skill.

Skill khác subagent thế nào

Subagent (bài 8) là một session riêng biệt với tool whitelist riêng, chạy độc lập với main session. Skill không tạo session mới, không có tool whitelist riêng, chỉ là instruction markdown được load vào context của session hiện tại.

+----------------------------------+
|  Main session (context window)  |
|                                  |
|  L2: rules + CLAUDE.md           |
|  + skill body khi trigger ---->  |  <- skill load vào đây
|                                  |
+----------------------------------+

vs.

+----------------------------------+       +---------------------------+
|  Main session                   |       |  Subagent session         |
|                                  | spawn |  (riêng biệt)             |
|  Agent tool call ---------------+-----> |  tools: [Read, Grep only] |
|                                  |       |  context riêng            |
+----------------------------------+       +---------------------------+

Dùng skill khi: bạn muốn thêm instruction có điều kiện cho model hiện tại. Dùng subagent khi: bạn muốn một process riêng chạy song song hoặc bị giới hạn tool.

Ví dụ minimal: skill 20 dòng

Skill nhỏ nhất hoạt động được trông như thế này:

---
name: format-date
description: "This skill should be used when the user asks to 'format a date',
  'convert date to ISO', 'format timestamp', or 'parse date string'."
---

# Date Formatter

Convert a date string to ISO 8601 format (YYYY-MM-DD).

## Workflow

1. Read the date string from user input.
2. Identify the input format (DD/MM/YYYY, MM-DD-YYYY, natural language, etc.).
3. Output the converted date in YYYY-MM-DD format.
4. If input is ambiguous (e.g. 01/02/03), ask which format the user intended before converting.

## Output format

Always output the result in a code block:

2026-05-17


Include a one-line note if you changed interpretation (e.g. "Treated 01 as day, not month").

Skill này không cần disable-model-invocation vì format date là read-only, không side effect. Người dùng hỏi “convert 17/05/2026 to ISO” và model trigger skill tự nhiên.

Anti-pattern thường gặp

Skill quá generic. Tên /helper với description “helps with various tasks” không có giá trị. Model không biết khi nào nên trigger, và khi trigger thì instruction quá mơ hồ để có ích.

Description dùng phrasing mà người dùng không bao giờ gõ. Nếu description là “use when optimizing computational throughput”, nhưng người dùng thực tế hay hỏi “make this code faster”, skill sẽ không bao giờ auto-trigger.

Nhét quá nhiều vào một SKILL.md. Khi body vượt 300 dòng, nó chiếm context lớn mỗi lần trigger. Di chuyển data và chi tiết vào references/ để body chỉ giữ workflow chính.

Thiếu disable-model-invocation cho destructive skill. Đây là lỗi phổ biến nhất và nguy hiểm nhất.

Naming convention

Skill folder và name field follow prefix convention:

  • nf-*: portable, cá nhân (ví dụ nf-direnv, nf-memory)
  • claude-*: tooling cho Claude Code bản thân (ví dụ claude-authoring, claude-docs)
  • server-*: SSH/access knowledge cho server cụ thể (ví dụ server-homelab)
  • Tên standalone cho skill project-agnostic (ví dụ format-date, init, review)

Nếu bạn làm cho nhiều client/project, prefix theo context giúp skill list không bị lẫn lộn và dễ audit hơn.

Tóm tắt và bài tiếp theo

  • Skill là thư mục ~/.claude/skills/<name>/ với file SKILL.md. Không cần đăng ký thêm gì.
  • Frontmatter: name (slug cho slash command), description (quyết định auto-trigger), disable-model-invocation (tắt auto-trigger cho destructive skill), user-invokable: false (ẩn khỏi menu).
  • Body: instruction markdown theo imperative form. File phụ trong references/ chỉ đọc khi cần (progressive disclosure).
  • Khác CLAUDE.md: CLAUDE.md load mọi session, skill chỉ load khi trigger. Dùng skill khi instruction có điều kiện.
  • Khác subagent: skill thêm instruction vào session hiện tại, subagent tạo session riêng với tool whitelist riêng.
  • Anti-pattern chính: description quá mơ hồ, thiếu disable-model-invocation cho destructive command, body quá dài không dùng references/.

Bài 8 sẽ đi vào subagent: cách spawn một session riêng với tool whitelist riêng, khi nào nên dùng agent thay vì skill, và cách truyền context từ main session sang subagent. Nếu bạn muốn đi sâu hơn vào cách xây dựng skill production-grade với references/, scripts/, và progressive disclosure, xem thêm bài 24.


Bài thuộc series Claude Code từ zero. Series plan tại bài giới thiệu.