Chuyển tới nội dung chính

Hướng Dẫn Toàn Diện: Claude Code Skills & Hooks

Mục lục

  1. Bước 0: Thiết Lập Folder .claude (Bắt Buộc)
  2. Phần 1: Viết Skill Chuẩn
  3. Phần 2: Tạo Agent (Subagent)
  4. Phần 3: Hook — Cơ Chế Ép Buộc Tự Động
  5. Phần 4: File CLAUDE.md — Bộ Nhớ Dài Hạn Của Agent
  6. Phần 5: Kiến Trúc Kết Hợp Skill + Hook + Agent + CLAUDE.md

Bước 0: Thiết Lập Folder .claude (Bắt Buộc)

⚠️ Đọc phần này trước khi làm bất cứ điều gì khác. Nếu folder .claude không nằm ở root của dự án, toàn bộ skill, hook, command sẽ không hoạt động — Claude Code đơn giản là không thấy chúng.

Kiểm tra nhanh

Mở Claude Code trong dự án, gõ / rồi nhập tên bất kỳ (ví dụ /my-skill). Nếu:

  • Hiện ra danh sách commands/skills → folder .claude đang hoạt động, bạn có thể bỏ qua phần này.
  • Trống trơn, không hiện gì → folder .claude chưa được thiết lập đúng. Làm theo hướng dẫn bên dưới.

Thiết lập

Cách 1 — Nhờ Claude Code tạo (đơn giản nhất):

Mở Claude Code ở root dự án, gõ:

Hãy thiết lập folder .claude ở root project với cấu trúc chuẩn:
- .claude/settings.json (permissions + hooks)
- .claude/skills/ (folder chứa skills)
- .claude/commands/ (folder chứa custom commands)

Claude sẽ tạo đúng cấu trúc cho bạn.

Cách 2 — Tạo thủ công:

# Chạy ở root dự án
mkdir -p .claude/skills
mkdir -p .claude/commands
mkdir -p .claude/hooks

# Tạo file settings rỗng
echo '{}' > .claude/settings.json

Cấu trúc đúng sau khi thiết lập

my-project/                  ← Root dự án
├── .claude/ ← PHẢI nằm ở đây, cùng cấp với package.json
│ ├── settings.json ← Config: permissions, hooks
│ ├── settings.local.json ← Config cá nhân (gitignore)
│ ├── skills/ ← Chứa các skill folders
│ ├── commands/ ← Chứa custom slash commands
│ └── hooks/ ← Chứa script files cho hooks
├── CLAUDE.md ← Context dự án (xem Phần 3)
├── package.json
└── src/

Lỗi thường gặp

  • Đặt .claude trong subfolder (ví dụ src/.claude/) → không hoạt động. Phải ở root.
  • Đặt .claude trong home directory (~/.claude/) → đây là config user-level (áp dụng mọi project), không phải project-level. Cả hai có thể cùng tồn tại.
  • Quên tạo subfolder → chỉ có settings.json mà không có skills/, commands/ → skill và command không có chỗ để đặt.

Sau khi thiết lập xong, gõ lại / để xác nhận Claude Code đã nhận. Rồi tiếp tục đọc các phần bên dưới.


Phần 1: Viết Skill Chuẩn

1.1. Skill là gì?

Skill là các gói mô-đun (module) mở rộng khả năng của Claude Code bằng kiến thức chuyên môn, quy trình, và công cụ. Mỗi skill là một đơn vị knowledge độc lập mà Claude đọc khi cần — không phải lúc nào cũng load, giúp tiết kiệm context window.

Phân biệt với Agent: Skill cung cấp knowledge (biết làm gì), còn Agent định nghĩa persona + hành vi (làm như thế nào, giao tiếp ra sao). Skill có thể được nhiều agent dùng chung.

Lưu ý quan trọng về độ dài: File SKILL.md nên ngắn gọn, xúc tích — khoảng 300 dòng, tối đa 500 dòng để đạt hiệu quả tốt nhất. SKILL.md dưới 200 dòng đạt tỷ lệ tuân thủ instructions trên 92%, vượt 400 dòng giảm xuống 71% (lost-in-the-middle effect). Trong SKILL.md chỉ nên chứa:

  • Những lưu ý cực kì quan trọng mà agent phải luôn nhớ
  • Hướng dẫn sử dụng, các bước thực thi
  • Bảng Quick Reference link về tài liệu chi tiết

Nếu tài liệu quá dài, quá nhiều trường hợp — đặt vào references/ chứ đừng nhét hết vào SKILL.md. SKILL.md chỉ là routing + core instructions.

1.2. Cấu Trúc Thư Mục

Mỗi skill luôn nằm trong một folder riêng mang tên skill, dù đơn giản chỉ có 1 file SKILL.md. Đây là chuẩn thống nhất:

skill-name/
├── SKILL.md ← Bắt buộc. File chính, chứa routing + instructions.
├── references/ ← Tùy chọn. Tài liệu chi tiết, agent đọc khi cần.
│ ├── guide-a.md ← SKILL.md link về đây: "Read references/guide-a.md"
│ └── guide-b.md
├── scripts/ ← Tùy chọn. Code thực thi (Python, Bash, Node...).
│ ├── build.py
│ └── validate.js
└── assets/ ← Tùy chọn. Templates, fonts, images cho output.
├── template.html
└── logo.png

Nguyên tắc: Toàn bộ tài liệu hướng dẫn chi tiết đặt trong references/. File SKILL.md chỉ chứa routing — link về các file reference để agent đọc khi cần, thay vì nhồi hết nội dung vào SKILL.md.

Ví dụ thực tế — skill tạo slide (pptx):

pptx/
├── SKILL.md ← Routing: bảng Quick Reference link về references/
├── references/
│ ├── editing.md ← Hướng dẫn edit template có sẵn
│ └── pptxgenjs.md ← Hướng dẫn tạo slide từ đầu
├── scripts/
│ ├── thumbnail.py ← Xem preview slide
│ └── office/unpack.py ← Giải nén XML
└── assets/
├── default-font.ttf
└── logo.png

Trong SKILL.md, routing trỏ về references:

## Quick Reference
| Task | Guide |
|--------------------|------------------------------------------------------------|
| Read/analyze | `python scripts/thumbnail.py presentation.pptx` |
| Edit template | Read [references/editing.md](references/editing.md) |
| Create from scratch| Read [references/pptxgenjs.md](references/pptxgenjs.md) |

Skill đơn giản (chỉ 1 file) vẫn giữ đúng cấu trúc folder:

my-simple-skill/
└── SKILL.md ← Dù chỉ có 1 file, vẫn nằm trong folder

1.3. Anatomy Của SKILL.md

File SKILL.md gồm 2 phần:

a) YAML Frontmatter (Metadata)

---
name: ten-skill
description: >
Mô tả skill làm gì VÀ khi nào nên trigger.
Đây là cơ chế kích hoạt chính — Claude dựa vào đây
để quyết định có đọc skill hay không.
---

Hai trường bắt buộc:

  • name: Tên skill (identifier)
  • description: Mô tả chức năng + điều kiện kích hoạt

Viết description hiệu quả:

Claude có xu hướng "undertrigger" — không dùng skill khi nên dùng. Do đó description cần hơi "pushy":

# ❌ Quá chung chung
description: Tạo PDF files

# ✅ Cụ thể và pushy
description: >
Use this skill whenever the user wants to do anything
with PDF files. This includes reading, extracting text/tables,
combining, splitting, rotating, watermarking, filling forms,
encrypting, OCR. If the user mentions a .pdf file or asks
to produce one, use this skill.

1.3. Ví Dụ Skill Hoàn Chỉnh

Cấu trúc folder:

mongorest-validation/
├── SKILL.md
├── references/
│ ├── ajv-keywords.md
│ ├── type-coercion.md
│ └── test-patterns.md
└── scripts/
└── validate-test.js

⚠️ Lưu ý bắt buộc: File SKILL.md phải bắt đầu bằng YAML frontmatter (khối --- ở đầu file) chứa namedescription. Nếu thiếu phần này, Claude Code sẽ không nhận diện và không trigger skill.

File SKILL.md hoàn chỉnh (frontmatter + body trong cùng 1 file):

---
name: mongorest-validation
description: >
Use this skill when working on MongoREST validation logic,
AJV custom keywords, schema validation, or input sanitization.
Trigger when editing files in src/core/validation/ or when
the user mentions "validation", "schema", "AJV", or "sanitize".
---

# MongoREST Validation Skill

## Quick Reference

| Task | Action |
|--------------------------|-----------------------------------------------------|
| Add validation rule | Read [references/ajv-keywords.md](references/ajv-keywords.md) |
| Create new schema | Follow Schema Pattern below |
| Debug validation error | Run `node scripts/validate-test.js` |

## Core Principle

Validation layer is SEPARATE from policy layer.
Validation = "is this data well-formed?"
Policy = "is this user allowed to do this?"

Never mix authorization checks into validation schemas.

## Schema Pattern

Every schema must follow this structure:
1. Define with `$id` matching the collection name
2. Use `additionalProperties: false` by default
3. Custom keywords go in `references/ajv-keywords.md`

## When to Read References

- Working with custom AJV keywords → read `references/ajv-keywords.md`
- Handling date/ObjectId transforms → read `references/type-coercion.md`
- Writing tests → read `references/test-patterns.md`

1.4. Kiến Trúc Multi-Skill

Khi project phức tạp, tách thành nhiều skill nhỏ thay vì một skill khổng lồ. Mỗi skill vẫn tuân theo chuẩn cấu trúc folder ở mục 1.2 — có folder riêng và file SKILL.md bên trong. Dùng CLAUDE.md làm routing layer:

project/
├── CLAUDE.md ← Router: chỉ agent đọc skill nào
├── .claude/
│ ├── skills/
│ │ ├── validation/ ← Mỗi skill = 1 folder
│ │ │ ├── SKILL.md ← ~50 dòng routing
│ │ │ └── references/
│ │ │ ├── ajv-keywords.md ← Chi tiết AJV custom keywords
│ │ │ └── type-coercion.md ← Date/ObjectId transforms
│ │ ├── authorization/
│ │ │ ├── SKILL.md
│ │ │ └── references/
│ │ │ ├── rbac-patterns.md
│ │ │ └── policy-schema.md
│ │ ├── external-resources/
│ │ │ ├── SKILL.md
│ │ │ └── references/
│ │ │ └── http-config.md
│ │ └── api-endpoints/
│ │ ├── SKILL.md
│ │ └── references/
│ │ └── crud-patterns.md
│ └── settings.json
└── docs/ ← Deep reference khi cần
└── architecture/
# CLAUDE.md (root) — Routing Layer

## Skills Reference
- Validation logic: see .claude/skills/validation/SKILL.md
- Auth policies: see .claude/skills/authorization/SKILL.md
- API design: see .claude/skills/api-endpoints/SKILL.md

## Task → Skill Mapping
- Khi làm feature CRUD mới: đọc api-endpoints + validation
- Khi sửa permission: đọc authorization
- Khi tích hợp API ngoài: đọc external-resources

1.5. Checklist Viết Skill Tốt

  • Mỗi skill nằm trong folder riêng (tên-skill/SKILL.md)
  • SKILL.md dưới 500 dòng (lý tưởng 200-300), chỉ chứa routing
  • Tài liệu chi tiết tách vào references/, SKILL.md link về
  • Description đủ cụ thể và "pushy" để trigger đúng lúc
  • Dùng imperative form, giải thích WHY
  • Quick Reference table ở đầu file, link về references/
  • Có examples/patterns cho các task phổ biến
  • Scripts cho task lặp đi lặp lại (đỡ reinvent the wheel)

Phần 2: Tạo Agent (Subagent)

2.1. Tại sao cần Agent, không chỉ Skill?

Skill cung cấp knowledge — nhưng khi dự án có nhiều skill, một agent duy nhất phải tự quyết định dùng skill nào cho task nào. Giống như một người biết quá nhiều thứ nhưng lại khó chọn đúng công cụ lúc cần. Agent giải quyết vấn đề này bằng cách tạo ra các nhân vật chuyên biệt, mỗi nhân vật chỉ biết và chỉ dùng những skill nhất định.

Hai lý do chính cần tạo Agent:

Lý do 1 — Phân vai khi có quá nhiều skill:

Ví dụ trong dự án có 10+ skill: frontend components, styling, testing, API design, validation, authorization... Nếu để 1 agent tổng xử lý hết, nó sẽ khó chọn đúng skill cho đúng lúc. Thay vào đó, tách thành các agent chuyên biệt:

  • frontend-dev — chỉ dùng skill: react-components, styling, accessibility
  • tester — chỉ dùng skill: testing-frontend, test-patterns, coverage
  • api-designer — chỉ dùng skill: api-endpoints, validation, authorization

Khi cần, gọi đúng nhân vật: "Dùng frontend-dev agent để build component này" thay vì để agent tổng tự đoán.

Lý do 2 — Xử lý song song với luồng custom:

Khi cần xử lý lặp lại nhiều task giống nhau (ví dụ convert 800 file text, review 50 PR, migrate 100 schema), Claude Code sẽ tự spawn subagent để chạy song song. Nhưng subagent tự tạo của Claude chỉ có prompt chung chung. Nếu đã định nghĩa agent trước với luồng xử lý custom đúng ý mình, Claude sẽ dùng agent đó thay vì tự nghĩ ra cách làm — kết quả chính xác và nhất quán hơn nhiều.

2.2. Vị Trí Đặt File Agent

Agent là file Markdown đặt trong .claude/agents/:

.claude/
├── agents/ ← Agent files
│ ├── frontend-dev.md
│ ├── tester.md
│ └── api-designer.md
├── skills/ ← Skills (knowledge)
├── hooks/ ← Hook scripts
└── settings.json

Hai scope:

  • .claude/agents/ — project-level, share với team qua git
  • ~/.claude/agents/ — user-level, dùng cho mọi project

2.3. Cấu Trúc File Agent

Giống skill, agent cũng dùng YAML frontmatter + body. Trong body chỉ cần nêu rõ: nhân vật này có chức năng gì, có những năng lực gì, và liệt kê các trường hợp sử dụng.

---
name: frontend-dev
description: >
Use this agent for building UI components, implementing React pages,
handling state management, styling with Tailwind, and optimizing
frontend performance. Delegate frontend tasks to this agent.
model: sonnet
tools:
- Read
- Write
- Edit
- Bash
- Glob
- Grep
---

You are a senior frontend developer specializing in React + TypeScript.

## Capabilities
- Build React functional components with hooks
- Implement responsive layouts with Tailwind CSS
- Handle state management (useState, useReducer, Zustand)
- Write accessible, semantic HTML
- Optimize rendering performance (memo, useMemo, useCallback)

## Skills to Use
- React components: read .claude/skills/react-components/SKILL.md
- Styling patterns: read .claude/skills/styling-tailwind/SKILL.md
- Accessibility: read .claude/skills/a11y/SKILL.md

## Workflow
1. Read the requirement carefully
2. Check existing components in src/components/ before creating new ones
3. Follow project conventions in CLAUDE.md
4. Always include TypeScript types
5. Test with `npm run test:component`

## When to Use
- "Build a user profile card component"
- "Implement the dashboard page layout"
- "Fix the responsive breakpoint on mobile"
- "Optimize the product list rendering"

2.4. Ví Dụ: Agent Cho Batch Processing

Khi cần xử lý hàng loạt, agent custom đảm bảo mỗi subagent chạy đúng luồng:

---
name: file-converter
description: >
Use this agent for batch file conversion tasks. Converts text files,
markdown, or data files between formats following a strict pipeline.
Invoke when processing multiple files with the same transformation.
model: haiku
tools:
- Read
- Write
- Bash
---

You are a file conversion specialist.

## Capabilities
- Convert Markdown → HTML with custom templates
- Convert CSV → JSON with schema validation
- Convert text files with encoding transformation
- Batch rename and restructure files

## Pipeline (follow exactly)
1. Read source file
2. Validate format and encoding
3. Apply transformation
4. Validate output against expected schema
5. Write to destination with correct naming convention

## Rules
- Never skip validation steps
- If a file fails validation, log error and continue to next file
- Output naming: {original-name}.{target-extension}
- Always report summary: total, success, failed

Khi gõ "Convert 800 file markdown trong docs/ sang HTML", Claude sẽ spawn nhiều file-converter agent chạy song song — mỗi agent đều tuân theo đúng pipeline 5 bước đã định nghĩa, thay vì tự nghĩ ra cách làm khác nhau.

2.5. Agent vs Skill — Khi Nào Dùng Gì?

SkillAgent
Bản chấtTài liệu knowledgeNhân vật chuyên biệt
Ai dùngAgent đọc khi cầnClaude spawn khi delegate task
ContextShare context với agent chínhContext riêng, isolated
Chạy song songKhôngCó — mỗi agent có context window riêng
Khi nào tạoCần kiến thức chuyên môn dùng chungCần phân vai hoặc xử lý song song
Ví dụ"Cách viết AJV keyword""Senior frontend dev"

Kết hợp: Agent có thể dùng skill. Ví dụ agent frontend-dev đọc skill react-componentsstyling-tailwind khi thực thi. Skill là kiến thức, agent là người dùng kiến thức đó.


Phần 3: Hook — Cơ Chế Ép Buộc Tự Động

3.1. Hook là gì?

Hook là logic chạy tự động, không cần AI can thiệp. Khi đã cấu hình hook, Claude Code sẽ mặc định thực thi lệnh tại các điểm cụ thể trong workflow — bất kể agent có nhớ hay không, có muốn hay không.

Điểm khác biệt cốt lõi:

  • Skill = knowledge cho agent đọc → agent có thể quên hoặc bỏ qua
  • Hook = lệnh ép buộc mặc định → luôn chạy, agent không có quyền bỏ qua

Ví dụ thực tế: Bạn có skill tạo slide, trong skill ghi "sau khi tạo HTML xong, chạy script export sang PPTX". Nhưng agent có thể quên bước này. Nếu đặt thành hook, thì mỗi lần Write file HTML vào thư mục output, script export sẽ tự động chạy — agent quên cũng không sao, hook không quên.

3.2. Nơi Cấu Hình

Hook config nằm trong file JSON settings (KHÔNG phải folder riêng):

FileScopeGit commit?
~/.claude/settings.jsonMọi project (user-level)Không
.claude/settings.jsonProject (share với team)
.claude/settings.local.jsonProject (cá nhân)Không (gitignored)

Folder .claude/hooks/ chỉ chứa script files mà hook config gọi tới:

.claude/
├── settings.json ← Hook config ở đây
├── settings.local.json ← Hook config cá nhân ở đây
└── hooks/ ← Script files (optional)
└── export-pptx.sh ← Được gọi bởi config

3.3. Các Hook Events

EventKhi nào chạyCó thể chặn?
PreToolUseTrước khi tool được gọi✅ Có thể deny/allow
PostToolUseSau khi tool hoàn thànhKhông
UserPromptSubmitKhi user gửi prompt✅ Có thể modify
PermissionRequestKhi Claude xin permission✅ Approve/deny
StopKhi Claude dừng respondKhông
SubagentStopKhi subagent kết thúc✅ Có thể chặn dừng
SessionStartBắt đầu sessionKhông
SessionEndKết thúc sessionKhông
PreCompactTrước khi compact contextKhông
SetupInit/maintenance repoKhông
NotificationKhi có notificationKhông

PreToolUse là hook duy nhất có thể block action — dùng cho security gates, chặn lệnh nguy hiểm.

3.4. Ví Dụ Xuyên Suốt: HTML → PPTX

Bài toán: Mỗi khi Claude tạo file HTML trong thư mục output/, tự động chạy script chuyển sang PPTX. Agent không cần nhớ gọi script — hook ép buộc chạy.

Bước 1 — Config hook trong settings:

// .claude/settings.local.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/export-to-pptx.sh",
"timeout": 300,
"statusMessage": "Exporting HTML to PPTX..."
}
]
}
]
}
}

Giải thích config:

  • PostToolUse → chạy sau khi tool hoàn thành
  • matcher: "Write" → chỉ khi tool Write được dùng (không phải Edit, Bash...)
  • type: "command" → chạy shell command (logic thuần, không cần AI)
  • timeout: 300 → cho phép tối đa 5 phút (export có thể nặng)

Bước 2 — Script xử lý logic:

#!/bin/bash
# .claude/hooks/export-to-pptx.sh

# Hook nhận data qua stdin (JSON), KHÔNG phải env variable
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')

# Chỉ chạy nếu file là .html trong thư mục output/
if echo "$FILE_PATH" | grep -q '/output/.*\.html$'; then
node scripts/export-to-pptx.js "$FILE_PATH" 2>&1
fi

# exit 0 = cho phép tiếp tục, không can thiệp
exit 0

Tại sao filter trong script mà không filter ở matcher?

Matcher chỉ filter theo tên tool (Write, Bash, Edit...), không filter được file path. Nên hook sẽ fire mỗi lần Claude dùng Write, nhưng script kiểm tra path rồi exit 0 ngay nếu không match — overhead gần bằng 0. Dù sau này có thêm nhiều skill khác cũng dùng Write, hook chỉ thực sự chạy export khi đúng file HTML trong output/.

Luồng hoạt động:

Claude tạo file slide.html vào output/

Write tool hoàn thành

Hook PostToolUse fire (matcher: "Write" ✅)

Script nhận JSON qua stdin

Kiểm tra: "/output/slide.html" match pattern? ✅

node scripts/export-to-pptx.js chạy tự động

File .pptx được tạo — agent không cần làm gì thêm

3.5. Lưu Ý Kỹ Thuật Quan Trọng

Data chảy qua stdin, không phải env variable — sai ở đây = hook im lặng fail:

INPUT=$(cat)                    # ✅ Đọc stdin
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command') # ✅ Parse JSON

# ❌ SAI — không có env variable nào tên như vậy
# echo $CLAUDE_TOOL_INPUT

Exit codes:

  • 0 = cho phép tiếp tục (không can thiệp)
  • 2 = block action (chỉ PreToolUse) + hiện lý do
  • Khác = lỗi, hiện stderr cho user

Luôn exit 0 khi không match — nếu quên, hook có thể block agent vô tình.


Phần 4: File CLAUDE.md — Bộ Nhớ Dài Hạn Của Agent

4.1. CLAUDE.md là gì?

CLAUDE.md là file markdown mà Claude Code tự động đọc mỗi khi mở session mới. Mục đích chính: chú thích cho agent biết dự án hoặc folder đó làm gì, để không phải nhắc lại mỗi khi mở cửa sổ prompt mới. Nếu viết tốt, agent đỡ phải đọc lại code mỗi lần bắt đầu làm việc.

Điểm khác biệt với Skill và Hook:

  • Skill = knowledge chuyên môn, load khi cần
  • Hook = logic ép buộc, chạy tự động
  • CLAUDE.md = context dự án, luôn được đọc khi agent vào folder đó

Đặc tính quan trọng: CLAUDE.md survive /compact. Khi context bị nén (compact), conversation history có thể mất, nhưng Claude Code sẽ đọc lại CLAUDE.md từ disk — nên thông tin trong đây không bao giờ bị mất giữa session.

4.2. Vị Trí Đặt File

CLAUDE.md có thể đặt ở nhiều vị trí trong dự án, mỗi vị trí phục vụ một mục đích:

my-project/
├── CLAUDE.md ← Root: overview toàn bộ dự án
├── src/
│ ├── CLAUDE.md ← Chú thích folder src/
│ ├── core/
│ │ ├── CLAUDE.md ← Chú thích core logic
│ │ ├── validation/
│ │ │ └── CLAUDE.md ← Chú thích module validation
│ │ └── auth/
│ │ └── CLAUDE.md ← Chú thích module auth
│ └── api/
│ └── CLAUDE.md ← Chú thích API layer
├── scripts/
│ └── CLAUDE.md ← Chú thích các script tiện ích
└── docs/
└── CLAUDE.md ← Chú thích cấu trúc tài liệu

Thứ tự đọc: Claude Code đọc theo hierarchy — root trước, rồi folder con khi navigate vào. Nên:

  • Root CLAUDE.md chứa overview tổng (stack, convention, project structure)
  • Folder con chứa chi tiết cục bộ (module này làm gì, file nào quan trọng)
  • Không lặp lại thông tin giữa các tầng

4.3. Root CLAUDE.md — Overview Dự Án

Giữ dưới 200 dòng (compliance >92%). Dùng imperative + bullet list — agent tuân thủ dạng list tốt hơn 60% so với paragraph.

# MongoREST

## Overview
MongoDB REST API framework with RBAC/ABAC authorization.

## Stack
- Runtime: Node.js 20, TypeScript 5.4
- Framework: Fastify 4
- Database: MongoDB 7 (Atlas)
- Tests: Vitest
- Linter: ESLint + Prettier

## Project Structure
- src/core/validation/ — AJV schema validation
- src/core/auth/ — Authorization engine (RBAC/ABAC)
- src/api/ — REST endpoint definitions
- src/shared/ — Shared utilities, error classes
- scripts/ — Build, deploy, seed scripts

## Key Commands
- `npm run dev` — Start dev server
- `npm test` — Run all tests
- `npm run build` — TypeScript compilation

## Conventions
- Use functional style, avoid classes where possible
- All API responses follow { data, error, meta } format
- Validation layer is SEPARATE from authorization layer
- Respond in Vietnamese, use tôi/bạn

## Task → Skill
- Validation/AJV: read .claude/skills/validation/SKILL.md
- Auth/RBAC: read .claude/skills/authorization/SKILL.md
- API design: read .claude/skills/api-endpoints/SKILL.md

4.4. Folder Con CLAUDE.md — Chi Tiết Cục Bộ

Ngắn hơn root — khoảng 20-50 dòng là đủ. Mục đích: agent vào folder này biết ngay module làm gì, file nào quan trọng, pattern nào đang dùng.

# src/core/validation/

## Purpose
AJV-based input validation for all API endpoints.
Validates data shape — NOT authorization (that's in auth/).

## Key Files
- schemas/ — JSON Schema definitions per collection
- keywords/ — Custom AJV keywords (objectId, dateRange, etc.)
- index.ts — Main validator factory, export validateInput()

## Patterns
- Every schema has $id matching collection name
- Use additionalProperties: false by default
- Custom keywords registered in keywords/register.ts

## Recent Changes
- 2026-03-15: Added dateRange keyword for date filtering
- 2026-03-10: Refactored schema loading to lazy init

4.5. Một Dự Án Nên Có Bao Nhiêu CLAUDE.md?

Không có con số cố định — phụ thuộc vào độ phức tạp:

  • Dự án nhỏ (1-2 dev, <20 files): 1 file ở root là đủ
  • Dự án trung bình (vài module): Root + mỗi module chính 1 file (3-5 file)
  • Dự án lớn (nhiều team, microservices): Mỗi folder quan trọng đều nên có (10+ file)

Nếu agent thường xuyên hỏi lại "folder này làm gì?" hoặc đọc sai file — đó là tín hiệu cần thêm CLAUDE.md cho folder đó.

4.6. Cập Nhật CLAUDE.md

Lưu ý quan trọng: CLAUDE.md chỉ hữu ích khi được cập nhật. Có 2 cách:

Cách 1 — Nhờ agent cập nhật (khuyến nghị):

Thêm dòng này vào root CLAUDE.md:

## Maintenance
After significant changes to any module, update the CLAUDE.md
in that folder to reflect new files, patterns, or conventions.

Agent sẽ tự cập nhật CLAUDE.md khi refactor hoặc thêm module mới.

Cách 2 — Dev tự review định kỳ:

Agent có thể cập nhật không chính xác hoặc thêm thông tin thừa. Nên review CLAUDE.md mỗi 1-2 tuần, đặc biệt khi:

  • Thêm module/folder mới
  • Đổi convention hoặc stack
  • Thấy agent liên tục hiểu sai context

4.7. Phân Biệt CLAUDE.md vs Skill vs .claude/rules/

CLAUDE.mdSkill (SKILL.md).claude/rules/
Chứa gìProject context: dự án làm gì, stack, cấu trúcDomain knowledge: hướng dẫn chuyên mônCoding rules: format, naming, test
Khi nào đọcLuôn đọc khi vào folderChỉ khi trigger bởi descriptionLuôn đọc (global rules)
Ai viếtDev + agent cùng maintainDev viết, agent đọcDev viết, agent tuân thủ
Ví dụ"Dự án dùng Fastify + MongoDB""Cách viết AJV custom keyword""Dùng single quotes, 2-space indent"

Phần 5: Kiến Trúc Kết Hợp Skill + Hook + Agent + CLAUDE.md

5.1. Nguyên Tắc Vàng

Skill     = Knowledge chuyên môn (tài liệu agent đọc khi cần)
Agent = Nhân vật chuyên biệt (dùng skill, chạy song song, context riêng)
Hook = Enforcement tự động (chạy mặc định, không cần AI)
CLAUDE.md = Context dự án (agent luôn đọc khi vào folder)

Không nhầm lẫn vai trò: Skill không enforce, hook không truyền knowledge, agent không thay thế skill (agent dùng skill), CLAUDE.md không chứa hướng dẫn chuyên môn dài.

5.2. Kiến Trúc Đề Xuất Cho Project Thực Tế

project/
├── CLAUDE.md ← Router (~100-200 dòng)

├── .claude/
│ ├── settings.json ← Hooks + permissions (shared)
│ ├── settings.local.json ← Hooks cá nhân (gitignored)
│ ├── agents/ ← Nhân vật chuyên biệt
│ │ ├── frontend-dev.md
│ │ ├── tester.md
│ │ └── api-designer.md
│ ├── hooks/ ← Script files cho hooks
│ │ ├── auto-format.sh
│ │ ├── block-dangerous.sh
│ │ └── export-pptx.sh
│ ├── skills/ ← Mỗi skill = 1 folder + SKILL.md
│ │ ├── validation/
│ │ │ ├── SKILL.md
│ │ │ └── references/
│ │ │ └── ajv-keywords.md
│ │ ├── authorization/
│ │ │ ├── SKILL.md
│ │ │ └── references/
│ │ │ └── rbac-patterns.md
│ │ └── api-endpoints/
│ │ ├── SKILL.md
│ │ └── references/
│ │ └── crud-patterns.md
│ ├── rules/ ← Coding conventions
│ │ ├── typescript.md
│ │ └── testing.md
│ └── commands/ ← Custom slash commands
│ ├── deploy.md
│ └── review.md

└── docs/ ← Deep reference
├── architecture/
└── glossary.md

5.3. Ví Dụ: Workflow MongoREST Với Skill + Hook

CLAUDE.md (router):

# MongoREST Project

## Stack
Node.js, TypeScript, Fastify, MongoDB. Tests: Vitest.

## Task → Skill
- CRUD endpoints: .claude/skills/api-endpoints/SKILL.md
- Validation/AJV: .claude/skills/validation/SKILL.md
- Auth/RBAC: .claude/skills/authorization/SKILL.md

## After editing .ts files
Hook tự động chạy prettier + eslint (không cần nhớ).

Hook (enforcement):

// .claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/auto-format.sh",
"timeout": 30,
"statusMessage": "Formatting TypeScript..."
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block-dangerous.sh"
}
]
}
]
}
}

Skill (knowledge):

# .claude/skills/validation/SKILL.md
## Quick Reference
| Task | Action |
|---------------------|----------------------------------------------------------------|
| New validation rule | Read [references/ajv-keywords.md](references/ajv-keywords.md) |
| Custom keyword | Read docs/architecture/ajv-custom.md |

## Core Principle
Validation ≠ Authorization. Keep them separate.
...

5.4. Best Practices Tổng Hợp

Skill:

  • Mỗi skill = 1 folder riêng + SKILL.md bên trong (dù chỉ 1 file)
  • SKILL.md dưới 500 dòng, lý tưởng 200-300
  • Description đủ cụ thể và "pushy" để trigger đúng lúc
  • Dùng imperative form, giải thích WHY
  • Quick Reference table ở đầu, link về references/
  • Tài liệu chi tiết tách vào references/, SKILL.md chỉ routing
  • Giải thích WHY, không chỉ MUST

Agent:

  • Tạo khi có nhiều skill cần phân vai, hoặc cần xử lý song song
  • Giới hạn 3-4 agent chính — quá nhiều thì tốn thời gian chọn agent
  • Nêu rõ: chức năng, năng lực, skill nào được dùng, workflow
  • Dùng model phù hợp: sonnet cho task phức tạp, haiku cho batch processing
  • Agent dùng skill, không thay thế skill

Hook:

  • Dùng cho enforcement (format, lint, security), KHÔNG cho knowledge
  • Filter path trong script (matcher chỉ filter tool name)
  • Tách script phức tạp ra file riêng trong .claude/hooks/
  • Luôn exit 0 khi không match — tránh block agent vô tình
  • Timeout hợp lý (30s cho format, 300s cho export nặng)

CLAUDE.md:

  • Root dưới 200 dòng, folder con 20-50 dòng
  • Dùng imperative + bullet list
  • Root chứa overview, folder con chứa chi tiết cục bộ — không lặp lại
  • Nhờ agent cập nhật khi refactor, dev review định kỳ
  • Survive /compact — Claude đọc lại từ disk sau compact

Tài liệu tổng hợp từ Anthropic official docs, skill-creator skill, và kinh nghiệm thực tế.