Cách tổ chức Skills cho project lớn
Mô hình 4 tầng (global/domain/module/task), CLAUDE.md đa cấp, quy tắc đặt tên, xử lý xung đột skill — đúc kết từ codebase monorepo 80k LOC.
> Khi project vượt mốc 50.000 dòng code, cách bạn tổ chức skills sẽ quyết định AI giúp được bạn hay phá hỏng mọi thứ. Bài này chia sẻ kinh nghiệm thực chiến: chia tầng skill, đặt tên file, viết CLAUDE.md ở nhiều cấp, và xử lý xung đột quy ước giữa các module — đúc kết từ codebase QNifyTech (~80k LOC, monorepo Express + Next.js).
Mục lục nhanh
- Vấn đề khi skill "dồn cục"
- Mô hình 4 tầng: global → domain → module → task
- Cấu trúc thư mục
skill/chuẩn cho monorepo - CLAUDE.md đa cấp: gốc, package, feature
- Quy tắc đặt tên & nguyên tắc "1 skill = 1 trách nhiệm"
- Cross-cutting concerns: auth, logging, error, i18n
- Khi 2 skill mâu thuẫn — ai thắng?
- Versioning skill khi codebase đổi quy ước
- Checklist audit định kỳ
- FAQ
1. Vấn đề khi skill "dồn cục"
Bạn bắt đầu nhỏ với 5-7 file skill: auth.md, database.md, frontend-impl.md... Mọi thứ ổn cho đến khi:
- Codebase có 3 service riêng (web, mobile, admin) dùng chung 1 database nhưng quy ước UI khác nhau
- Module
payments/cần override quy ước REST mặc định vì phải tuân thủ idempotency của VNPay - Team mới vào không biết file nào áp dụng ở đâu — AI lúc thì viết theo
frontend-impl.md, lúc lại theomobile.md - Skill
database.md800 dòng — AI đọc xong quên phần đầu khi áp dụng phần cuối
Triệu chứng cụ thể bạn sẽ thấy:
| Triệu chứng | Nguyên nhân gốc |
|---|---|
| AI viết code không khớp convention của module | Skill quá chung, không có override cấp module |
| AI "quên" skill giữa session dài | 1 file skill quá dài, vượt khả năng giữ trong context active |
| Cùng 1 task nhưng mỗi lần AI làm 1 kiểu | Không có anchor (CLAUDE.md cấp dưới) để cố định lựa chọn |
| Sửa skill chung làm vỡ module khác | Skill chia theo "kỹ năng" thay vì theo "ranh giới ảnh hưởng" |
2. Mô hình 4 tầng: global → domain → module → task
Tôi đề xuất chia skill thành 4 tầng, mỗi tầng có phạm vi ảnh hưởng và tần suất thay đổi khác nhau:
┌─────────────────────────────────────────────────────────────┐
│ TẦNG 1 — GLOBAL (áp dụng toàn project, hiếm khi đổi) │
│ • coding-style.md • git-workflow.md • naming.md │
│ • security-baseline.md • code-review.md │
├─────────────────────────────────────────────────────────────┤
│ TẦNG 2 — DOMAIN (theo lĩnh vực kỹ thuật) │
│ • backend-api.md • frontend-web.md • mobile.md │
│ • database.md • devops.md • testing.md │
├─────────────────────────────────────────────────────────────┤
│ TẦNG 3 — MODULE (theo ranh giới nghiệp vụ) │
│ • modules/auth.md • modules/payment.md │
│ • modules/license.md • modules/affiliate.md │
├─────────────────────────────────────────────────────────────┤
│ TẦNG 4 — TASK (việc lặp lại nhiều lần) │
│ • tasks/add-api-endpoint.md • tasks/migrate-db.md │
│ • tasks/release.md • tasks/incident-response.md │
└─────────────────────────────────────────────────────────────┘
Nguyên tắc đọc: Tầng dưới override tầng trên. Khi AI làm task trong modules/payment/, nó đọc theo thứ tự: Global → Domain (backend-api) → Module (payment) → Task (nếu có). Module thắng nếu có xung đột.
Nguyên tắc viết:
- Tầng 1 (Global): chỉ ghi những thứ KHÔNG BAO GIỜ ngoại lệ. Vd "không commit secret", "luôn typecheck trước khi push".
- Tầng 2 (Domain): mặc định cho 80% trường hợp. Có thể bị override ở tầng 3.
- Tầng 3 (Module): ghi rõ "khác với mặc định ở chỗ nào và tại sao".
- Tầng 4 (Task): quy trình bước-bước cho việc lặp lại — copy/paste vẫn đúng.
3. Cấu trúc thư mục skill/ chuẩn cho monorepo
Với monorepo có nhiều package, đây là layout đã chứng minh hoạt động tốt:
my-project/
├── CLAUDE.md ← entry point, trỏ vào skill/
├── skill/
│ ├── README.md ← index của toàn bộ skill
│ ├── GUIDE.md ← hướng dẫn AI cách CHỌN skill
│ │
│ ├── global/
│ │ ├── coding-style.md
│ │ ├── git-workflow.md
│ │ ├── naming.md
│ │ ├── security-baseline.md
│ │ └── code-review.md
│ │
│ ├── domain/
│ │ ├── backend-api.md
│ │ ├── frontend-web.md
│ │ ├── mobile.md
│ │ ├── database.md
│ │ ├── devops.md
│ │ └── testing.md
│ │
│ ├── modules/
│ │ ├── auth.md
│ │ ├── payment.md
│ │ ├── license.md
│ │ └── affiliate.md
│ │
│ ├── tasks/
│ │ ├── add-api-endpoint.md
│ │ ├── migrate-db.md
│ │ ├── release.md
│ │ └── incident-response.md
│ │
│ └── _archive/ ← skill cũ đã thay thế, giữ lại để truy nguyên
│ └── 2025-03-old-payment.md
│
├── packages/
│ ├── backend/
│ │ └── CLAUDE.md ← override cấp package
│ ├── web/
│ │ └── CLAUDE.md
│ └── mobile/
│ └── CLAUDE.md
│
└── apps/
└── admin/
└── CLAUDE.md
Tại sao tách _archive/? Khi quy ước đổi (vd chuyển từ Redux sang Zustand), đừng xoá skill cũ — chuyển vào archive với ngày. Lý do: PR cũ vẫn cần review theo skill cũ, và bạn có thể truy nguyên "trước đây ta quyết định thế nào".
4. CLAUDE.md đa cấp: gốc, package, feature
CLAUDE.md cấp gốc không nên chứa toàn bộ quy ước. Nó là bản đồ dẫn AI tới đúng file skill.
CLAUDE.md gốc — template
```markdown
Project: <tên project>
Bắt đầu mọi task
- Đọc
skill/GUIDE.mdđể hiểu cách chọn skill phù hợp với task - Đọc các file skill được chỉ định trong GUIDE
- Nếu task ở trong
packages/<x>/, đọc thêmpackages/<x>/CLAUDE.md
Stack tổng quan
- Backend: Node.js + Express + Prisma + Postgres
- Frontend web: Next.js 15 (App Router)
- Mobile: Expo / React Native
- Deploy: Render (BE) + Vercel (FE)
Ranh giới module (KHÔNG ĐƯỢC CHÉO)
packages/backend/src/modules/payment/↔ chỉ team payment sửapackages/backend/src/modules/auth/↔ cần security review trước khi mergepackages/web/src/app/(admin)/↔ chỉ admin role mới truy cập
Khi không chắc — HỎI, đừng đoán
Phase 1 của mọi skill: hỏi user trước khi code. Vi phạm là lỗi nghiêm trọng.
CLAUDE.md cấp package — chỉ override
packages/web — Next.js App
Đè quy ước global tại đây
- Sử dụng TanStack Query thay vì SWR (skill/domain/frontend-web.md có giải thích)
- Mọi route trong
app/(site)/phải có metadata động + JSON-LD - Component dùng shadcn/ui, KHÔNG cài thêm Material UI
File quan trọng
src/lib/api.ts— chỉ dùng client này để gọi BE, đừng dùng fetch trực tiếpsrc/app/(site)/layout.tsx— đã có SEO defaults, đừng override trừ khi cần
CLAUDE.md cấp feature — khi cần
Một số feature có quy ước cực đặc biệt — nên có CLAUDE.md riêng:
packages/backend/src/modules/payment/
├── CLAUDE.md ← quy ước riêng cho payment
├── webhooks/
├── reconciliation/
└── ...
- Quy tắc đặt tên & nguyên tắc "1 skill = 1 trách nhiệm" {#dat-ten}
Đặt tên file
Tốt Tệ
auth.md authentication-and-authorization.md
payment-vnpay.md vnpay-integration-guide-final-v2.md
tasks/add-api-endpoint.md tasks/how-to-add-new-route.md
Quy tắc:
Dùng kebab-case, ngắn gọn
Tầng module: prefix theo domain nếu có ambiguity — payment-vnpay.md thay vì vnpay.md
Tầng task: bắt đầu bằng động từ — add-, migrate-, deploy-, debug-
Không dùng version trong tên (v1, v2, final) — dùng git history hoặc _archive/
Mỗi skill phải có header chuẩn
Để AI biết nhanh skill này dùng làm gì:
scope: module # global | domain | module | task
applies-to: packages/backend//payment/
overrides: domain/backend-api.md
last-reviewed: 2026-04-10
Payment module
Khi nào đọc file này
- Khi viết code trong
packages/backend/src/modules/payment/ - Khi tích hợp gateway mới (VNPay, MoMo, PayOS, Stripe)
- Khi sửa webhook handler
Tóm tắt 3 dòng
- Mọi webhook PHẢI verify chữ ký + idempotent theo gateway event ID
- State machine: pending → awaiting_payment → paid | failed | expired
- Reconciliation job chạy mỗi 15 phút để bắt giao dịch lạc
Chi tiết
...
Lợi ích: AI quét header ⇒ biết có cần đọc tiếp không, không tốn context cho skill không liên quan.
"1 skill = 1 trách nhiệm"
Nếu skill của bạn dài hơn 400 dòng, gần như chắc chắn nó đang ôm 2-3 trách nhiệm. Tách ra:
Trước (1 file 900 dòng) Sau (4 file 200-300 dòng)
payment.md payment-overview.md
payment-vnpay.md
payment-momo.md
payment-reconciliation.md
Sau đó payment-overview.md chỉ làm 1 việc: trỏ vào file con phù hợp.
- Cross-cutting concerns: auth, logging, error, i18n {#cross-cutting}
Có những thứ xuyên suốt mọi module — đừng nhồi vào skill của module:
Auth & permissions: đặt ở global/security-baseline.md + modules/auth.md
Logging: đặt ở global/coding-style.md (format) + domain/devops.md (vận hành)
Error handling: đặt ở global/code-review.md (nguyên tắc) + domain/backend-api.md (response envelope)
i18n: nếu có, tách domain/i18n.md riêng
Quy tắc: Nếu một quy ước áp dụng cho >= 3 module, nó thuộc tầng Domain hoặc Global, không phải Module.
Khi viết skill module, trích dẫn skill cross-cutting thay vì copy:
Validation
Tuân thủ global/security-baseline.md mục "Input validation".
Bổ sung riêng cho module này:
- Số tiền PHẢI là integer (đơn vị VND, không có thập phân)
- Mã đơn hàng tối đa 50 ký tự ASCII
- Khi 2 skill mâu thuẫn — ai thắng? {#mau-thuan}
Đây là tình huống bạn sẽ gặp chắc chắn. Ví dụ:
domain/backend-api.md nói: "Response envelope là { data, meta }"
modules/legacy-license.md nói: "Phải giữ format cũ { license, ok } để không vỡ client v1"
Quy tắc giải quyết, theo thứ tự ưu tiên
Tầng thấp hơn thắng (module > domain > global). Đây là quy tắc mặc định.
Skill ghi rõ overrides: trong header — đó là tuyên bố override chính thức.
Khi cả 2 skill cùng tầng mâu thuẫn, AI PHẢI dừng lại và hỏi user.
Quy ước an toàn (security) không bao giờ bị override — kể cả từ module. Nếu cần, phải có ngoại lệ có document riêng + ngày hết hạn.
Bảo AI áp dụng quy tắc này
Trong CLAUDE.md gốc, thêm:
Khi skill mâu thuẫn
Thứ tự ưu tiên: task > module > domain > global.
Trừ 1 ngoại lệ: quy ước security trong global/security-baseline.md
KHÔNG được override. Nếu phát hiện module cần làm khác, dừng và hỏi user.
- Versioning skill khi codebase đổi quy ước {#versioning}
Project lớn sẽ đổi convention theo thời gian. Đừng "edit in place" thầm lặng — sẽ làm vỡ PR đang mở và làm AI confused khi review code cũ.
Quy trình đổi 1 skill
Tạo nhánh — đừng đổi trên main trực tiếp
Đánh dấu deprecated ở đầu file cũ:
> ⚠️ DEPRECATED từ 2026-05-01. Xem domain/frontend-web-v2.md.
> File này giữ để review PR mở trước ngày đổi.
Tạo file mới với hậu tố hoặc tên mới
Cập nhật skill/GUIDE.md để trỏ vào file mới
Sau 30 ngày không có PR cũ nào tham chiếu, chuyển file cũ vào _archive/
Ghi changelog ở cuối mỗi skill quan trọng
Changelog
- 2026-05-01: Đổi state management Redux → Zustand. Migration guide ở...
- 2026-02-15: Bỏ class component, full function + hooks
- 2025-11-03: Khởi tạo
AI đọc đoạn này hiểu đâu là quy ước hiện hành, không nhầm với code cũ trong repo.
- Checklist audit định kỳ {#checklist}
Mỗi quý làm 1 lần để skill không "thối":
Mọi skill có last-reviewed: cách đây ≤ 6 tháng không?
File nào dài > 400 dòng — có thể tách không?
File nào không có trong skill/GUIDE.md — còn dùng không hay quên xoá?
Quy ước trong skill có khớp với code thực tế trên main không? (chạy 1 vòng đối chiếu)
CLAUDE.md cấp package có còn đúng sau các refactor không?
_archive/ có file nào không còn PR liên quan — có thể xoá hẳn?
Có quy ước mới được lặp lại trong PR review nhiều lần — đã viết thành skill chưa?
AI có hay làm sai 1 chỗ cụ thể không — chỗ đó cần skill mới hoặc làm rõ skill cũ?
Audit này bạn có thể nhờ AI làm hộ:
Đọc toàn bộ thư mục skill/ và checklist trong skill-organization.md
mục 9. Báo cáo cho mình: file nào vi phạm, file nào nên gộp, file nào
nên tách. Đề xuất kế hoạch refactor skill trong 1 tuần.
- FAQ {#faq}
Project nhỏ (< 5k LOC) có cần 4 tầng không?
Không. Project nhỏ giữ flat — 5-10 file skill trong 1 thư mục là đủ. Bắt đầu tách tầng khi: có >= 3 module nghiệp vụ riêng, hoặc có > 2 developer, hoặc có >= 2 quy ước UI khác nhau.
Có nên auto-generate skill từ code không?
Không nên. Skill là ý định + lý do, code là kết quả. Auto-generate ra file mô tả code hiện tại — AI đọc xong vẫn không hiểu "tại sao chọn cách này thay vì cách kia". Viết tay, ngắn gọn, kèm WHY.
Skill có nên versioning theo git tag không?
Không cần tag riêng. Skill thay đổi cùng code trong cùng PR — git history là đủ. Khi cần truy nguyên "ngày X quy ước là gì", git blame skill/<file>.md vẫn hoạt động.
Khi nào dùng CLAUDE.md, khi nào dùng skill/*.md?
CLAUDE.md: bản đồ + những thứ AI cần đọc ngay khi mở project. Giữ ngắn (< 100 dòng).
skill/*.md: chi tiết quy trình, đọc khi làm task cụ thể.
Quy tắc: nếu AI cần biết để tránh disaster ngay từ giây đầu (vd "module X cấm sửa trực tiếp"), đặt ở CLAUDE.md. Còn lại đặt ở skill/.
AI có đọc hết file skill không hay nó "skim"?
Tuỳ cách bạn ra lệnh. Nếu nói "đọc skill X rồi làm task Y", AI thường đọc đầy đủ. Nếu file quá dài, AI có thể chỉ đọc các phần khớp với query → đó là lý do tách file < 400 dòng và đặt header tóm tắt 3 dòng.
Bao nhiêu skill là quá nhiều?
Kinh nghiệm: > 30 file skill mà chưa có GUIDE.md rõ ràng → AI sẽ confused. Mỗi 10 file skill mới, đầu tư 30 phút cập nhật skill/GUIDE.md (bảng "task X → đọc skill nào").
Team mới vào dự án — cần làm gì?
Cho họ đọc theo thứ tự: CLAUDE.md (gốc) → skill/README.md → skill/GUIDE.md → 2-3 file skill liên quan task đầu tiên của họ. Bộ skill tốt thay được 80% onboarding doc.
Kết
Tổ chức skill cho project lớn là một bài toán information architecture, không phải kỹ thuật. Nguyên tắc tóm lại:
Chia theo ranh giới ảnh hưởng, không theo "loại kỹ năng"
Tầng thấp hơn override tầng cao hơn, trừ security
Mỗi file 1 trách nhiệm, < 400 dòng, có header scope rõ ràng
CLAUDE.md là bản đồ, không phải sách giáo khoa
Audit mỗi quý — skill cũng cần bảo trì như code
Khi đã có bộ skill tốt, AI ngừng đoán mò và bắt đầu hỏi đúng câu. Đó là khoảnh khắc vibe coding scale được lên dự án thật.
Liên kết hữu ích: