Skill vs CLAUDE.md / subagent / hook / MCP

Hệ sinh tháiTrung cấp20 phút

Đây là câu hỏi nhận được mỗi khi giới thiệu skill với team đã quen Claude Code. Họ có CLAUDE.md, có slash command, một số team tiến xa hơn có subagent, hook, MCP server.

Bạn sẽ học được
  • So sánh skill với 4 cơ chế còn lại trong Claude Code: CLAUDE.md, subagent, hook, MCP server
  • Chọn đúng công cụ cho mỗi use case qua decision tree rõ ràng
  • Thiết kế setup kết hợp nhiều cơ chế — không force mọi thứ vào skill
  • Nhận diện 3 anti-pattern phổ biến khi dev lẫn lộn các cơ chế

5 cơ chế customize Claude Code — overview

Mental model: Claude Code như một "layered system"

Bạn không chọn 1 trong 5. Setup thực tế dùng nhiều cơ chế cùng lúc, mỗi cái một vai trò.

Cơ chếLoad khi nàoAi triggerMục đích chính
CLAUDE.mdMỗi conversationAuto (luôn có mặt)Project standards luôn áp dụng
SkillKhi match requestClaude semantic matchTask-specific expertise on-demand
SubagentKhi bạn delegate taskUser hoặc Claude gọiTask độc lập, isolated context
HookKhi có event (save file, tool call)Event-drivenSide effect tự động
MCP serverKhi Claude cần external dataClaude qua tool callKết nối data/service bên ngoài
┌─────────────────────────────────────────────────────┐
│  MCP Servers          🌐 External data              │
│  (GitHub, Slack,         Connect to outside world   │
│   Postgres, ...)                                    │
├─────────────────────────────────────────────────────┤
│  Subagents            👥 Specialized roles          │
│  (frontend-reviewer,     Delegated work, isolated   │
│   backend-reviewer, ...) contexts                   │
├─────────────────────────────────────────────────────┤
│  Skills               🎓 Task expertise             │
│  (pr-review,             On-demand, triggered       │
│   commit-format, ...)    by request                 │
├─────────────────────────────────────────────────────┤
│  Hooks                ⚙️ Event automation           │
│  (on-save-lint,          Fire on file save, tool    │
│   pre-commit, ...)       call, etc.                 │
├─────────────────────────────────────────────────────┤
│  CLAUDE.md            🏗️ Project foundation        │
│                          Always-on project context  │
└─────────────────────────────────────────────────────┘

Skill vs CLAUDE.md — Load khi nào?

CLAUDE.md: Always-on

File này load vào system prompt mọi conversation. Luôn có mặt. Claude luôn biết "dự án này là Next.js".

Skill: On-demand

Skill pr-description chỉ load khi bạn nói "write PR description". Còn lại, nó ngủ.

Khi nào dùng cái nào?

Ví dụ thực tế — quyết định 5 trường hợp

Anti-pattern: CLAUDE.md phình to

Sai lầm: Nhồi mọi instruction vào CLAUDE.md — review checklist, email template, report format, debug procedure...

Hậu quả: Mỗi conversation ăn 40% context cho content có thể chỉ cần 5%.

Cách đúng: CLAUDE.md chỉ giữ thứ luôn áp dụng. Còn lại → skill.

Otto hỏi ngược: "Look at your current CLAUDE.md file. Is there anything in it that would work better as a skill (loaded only when relevant)?" Answer cho hầu hết team: có.

Hướng dẫnĐể đâu? Tại sao
"Project này dùng Next.js 14"CLAUDE.md — luôn cần biết
"Never modify /migrations/ directly"CLAUDE.md — constraint luôn luôn
"Review PR theo checklist 15 điểm"Skill — chỉ khi review PR
"Format commit theo Conventional Commits"Skill — trigger khi commit
"All API routes live in src/app/api/"CLAUDE.md — structural, always relevant
# CLAUDE.md

This project uses Next.js 14 with App Router, TypeScript strict mode,
and Tailwind CSS. We follow conventional commits. Never modify files in
/migrations/ directly — use `pnpm db:migrate` instead.

Skill vs Subagent — Cùng context vs isolated

Skill: Join current context

Khi skill pr-review trigger, nó thêm instructions vào cuộc hội thoại đang chạy. Context hiện tại (code bạn đang xem, conversation history) vẫn ở đó. Skill làm Claude thông minh hơn trong context hiện tại.

Subagent: Separate context

Subagent là Claude khác chạy trong context riêng, isolated. Bạn delegate task cho nó, nó làm xong, trả result về bạn. Nó không thấy conversation history của bạn, không share context.

Khi nào dùng cái nào?

Dùng Skill khi:

Dùng Subagent khi:

Skill ↔ Subagent: Hoạt động cùng nhau

Đây là điểm quan trọng dễ miss: Subagent có thể dùng skill.

Otto giải thích:

Skill là portable expertise — share được giữa subagent. Bạn không build lại expertise cho mỗi subagent.

Setup mẫu:

Chi tiết config subagent với skill ở Bài 15.5.

⚠️ Gotcha quan trọng

Built-in agent (Explorer, Plan, Verify) KHÔNG access skill. Otto: "Built-in agents can't access skills at all. Only custom subagents you define can use them and only when you explicitly list them."

Skill load khi subagent start, không on-demand như main conversation. Nên chỉ list skill luôn relevant cho purpose của subagent.

  • Bạn muốn cùng conversation smarter về task
  • Expertise apply throughout remaining conversation
  • Ví dụ: activate PR review skill → mọi review tiếp theo trong session vẫn có expertise đó
  • Bạn muốn task độc lập — không polute main context
  • Cần tool access khác main conversation (ví dụ subagent có quyền Bash mà main không có)
  • Parallelize: chạy 5 subagent concurrent cho 5 file khác nhau
  • Ví dụ: delegate "phân tích 10 file log" cho subagent — kết quả về main, không bloat main context
.claude/
├── agents/
│   ├── frontend-reviewer.md    ← subagent: skills = [component-patterns, a11y-standard]
│   └── backend-reviewer.md     ← subagent: skills = [api-conventions, a11y-standard]
└── skills/
    ├── component-patterns/     ← riêng frontend
    ├── api-conventions/        ← riêng backend
    └── a11y-standard/          ← SHARED giữa 2 subagent
Main conversation:
  You working on feature A
     ↓ (delegate)
  Subagent frontend-reviewer:
     (fresh context, no memory of your feature A)
     Runs task
     Returns result
     ↓
  Main conversation continues

Skill vs Hook — Request-driven vs Event-driven

Hook: Fire on event

Hook là automation chạy khi có event xảy ra:

Hook không cần Claude "decide". Nó fire automatically khi event match.

Skill: Fire on request

Skill trigger khi user hỏi điều match với description. Claude làm trung gian.

Khi nào dùng cái nào?

Rule of thumb

Case: Lint workflow

Cách tệ (dùng skill):

  • File save → run linter
  • Before bash call → validate input
  • After Edit tool → auto-format
  • Hook = "operation chạy không cần Claude suy nghĩ" — tự động, deterministic
  • Skill = "knowledge để Claude dùng khi reasoning" — Claude vẫn là người quyết định
SituationHookSkill
Auto-format file sau save
Validate input trước khi run bash
Review PR theo standard
Write commit message
Log mỗi tool call ra file
Explain code when asked
// .claude/settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write ${file}"
          }
        ]
      }
    ]
  }
}

Case: Lint workflow

Problem: Skill chỉ trigger khi user nói "commit". Nếu user quên → không lint.

Cách đúng (dùng hook):

Skill lint-before-commit:
  description: "Runs linter before commits. Use when committing."

Skill vs Hook — Request-driven vs Event-driven (tiếp)

Hook fire luôn luôn khi có bash command match git commit. Không dựa vào user.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "[[ \"$TOOL_INPUT\" == *\"git commit\"* ]] && pnpm lint"
          }
        ]
      }
    ]
  }
}

Skill vs MCP Server — Expertise vs Data connection

Đây là phần gây confuse nhất. Vì cả skill và MCP đều "extend Claude".

MCP (Model Context Protocol): Connection tới external world

MCP là open protocol cho phép Claude truy cập data/service bên ngoài:

MCP server expose tools để Claude gọi. Ví dụ:

Claude dùng các tool này khi cần data đó.

Skill: Expertise về cách làm gì với data

Skill không fetch data. Skill chứa instructions.

Otto's killer one-liner

Clean nhất trong tất cả explanation. Memorize đi.

Ví dụ cụ thể — MCP + Skill hoạt động cùng nhau

Setup:

  • MCP server cho GitHub → Claude đọc/write issue, PR, code
  • MCP server cho Postgres → Claude query database
  • MCP server cho Slack → Claude đọc tin nhắn
MCP server github/ expose tools:
  - list_issues
  - create_pr
  - get_file_content
  - ...

MCP server postgres/ expose tools:
  - execute_query
  - list_tables
  - describe_schema

Ví dụ cụ thể — MCP + Skill hoạt động cùng nhau

User: "Review PR #142"

Claude:

MCP cho access tới GitHub. Skill dạy Claude quy trình review. Không cái nào đủ một mình:

Setup cho team thực tế

Litton (AI University) cho workflow mẫu:

Skill orchestrate. MCP cung cấp tool. 2 thứ complement, không compete.

Decision:

  • Match skill pr-review → load instructions (Bài 15.2)
  • Instructions nói: gh pr view 142 hoặc dùng MCP github.get_pr(142) lấy diff
  • Instructions nói: check X, Y, Z theo checklist
  • Instructions nói: comment review qua MCP github.comment_pr(142, ...)
  • Chỉ MCP không skill → Claude có thể đọc PR nhưng review không theo style team
  • Chỉ skill không MCP → Claude biết cách review nhưng không access được PR
Câu hỏiTrả lờiDùng cái gì
Bạn cần Claude access data ở external system?YESMCP server
Bạn cần dạy Claude quy trình theo style của team?YESSkill
Cả 2YESSkill + MCP cùng lúc
MCP server: github-mcp (list PRs, read code, comment)
Skill: pr-review (checklist + style + tone)

Decision Tree — Chọn cơ chế nào?

Flowchart dạng checklist

  • Cần fetch data từ GitHub/Slack/DB/API? → MCP server
  • Cần side-effect tự động khi save/call tool? → Hook
  • Instruction luôn luôn áp dụng trong mọi conversation của project? → CLAUDE.md
  • Muốn task chạy isolated, không polute main context? → Subagent
  • Instruction chỉ áp dụng khi user hỏi về task đó, Claude tự nhận? → Skill
┌─────────────────────────────────────────────────────────┐
│  Bắt đầu: Bạn muốn customize Claude Code làm gì?        │
└─────────────────────────────────────────────────────────┘
                        ↓
        ┌───────────────┴───────────────┐
        ↓                               ↓
┌─────────────────┐             ┌─────────────────┐
│ Cần external    │             │ Cần automation  │
│ data/service?   │             │ trên event      │
│                 │             │ (save, tool     │
│ (GitHub,        │             │  call)?         │
│  Postgres...)   │             │                 │
└─────────────────┘             └─────────────────┘
        │                               │
       YES                             YES
        ↓                               ↓
   ┌─────────┐                    ┌──────────┐
   │   MCP   │                    │   Hook   │
   │  server │                    │          │
   └─────────┘                    └──────────┘

                         ↓ (không cần 2 cái trên)
                         
        ┌────────────────┴────────────────┐
        ↓                                 ↓
┌──────────────────┐               ┌────────────────┐
│ Instruction này  │               │ Muốn task chạy │
│ có LUÔN áp dụng  │               │ trong context  │
│ mọi conversation?│               │ ISOLATED khỏi  │
│                  │               │ main?          │
└──────────────────┘               └────────────────┘
        │                                 │
       YES                                YES
        ↓                                 ↓
   ┌─────────┐                      ┌──────────┐
   │CLAUDE.md│                      │ Subagent │
   └─────────┘                      └──────────┘

                         ↓ (không cần những cái trên)
                         
                  ┌──────────────────┐
                  │ Instruction cần  │
                  │ Claude tự kích   │
                  │ hoạt khi relevant│
                  │                  │
                  │ → SKILL          │
                  └──────────────────┘

Setup hoàn chỉnh: Case study team engineering

Để thấy 5 cơ chế sống chung thế nào, hãy xem setup của 1 team engineering giả lập nhưng realistic:

Team 12 người, làm SaaS trên Next.js 14 + TypeScript + Postgres. Ship code hàng tuần. Yêu cầu: code quality, security, consistency.

Tầng 1: CLAUDE.md — Foundation

Vai trò: Foundation context. Claude luôn biết stack + constraint.

Tầng 2: MCP servers — Data connections

# CLAUDE.md

This project uses Next.js 14 (App Router), TypeScript strict mode,
and Tailwind CSS. Database: Postgres 16 with Drizzle ORM.

Conventions:
- Conventional commits (feat, fix, chore, refactor, docs, test)
- PR target main, squash merge
- Never modify /migrations/ directly (use `pnpm db:migrate`)
- All API routes in src/app/api/
- Test coverage must stay ≥ 80%

Tools available: pnpm, gh (GitHub CLI), docker, drizzle-kit.

Tầng 2: MCP servers — Data connections

Vai trò: Access external data. Skill gọi MCP tool khi cần.

Tầng 3: Skills — Expertise

Vai trò: Task-specific expertise. Trigger on-demand khi team member làm task đó.

Tầng 4: Subagents — Specialized roles

Vai trò: Isolated task delegation. Khi tech lead gõ "ask frontend-reviewer to check PR #142" → subagent chạy riêng.

Tầng 5: Hooks — Automation

.claude/agents/
├── frontend-reviewer.md
│   └── skills: [pr-review, a11y-audit, design-system-check]
├── backend-reviewer.md
│   └── skills: [pr-review, api-conventions, sql-perf-check]
└── security-auditor.md
    └── skills: [security-scan, owasp-checklist]
Configured MCP servers:
- github (list issues, read PRs, create reviews)
- linear (track tickets)
- postgres (query read-only to staging DB)
- sentry (error analytics)

Tầng 5: Hooks — Automation

Vai trò: Auto-format sau mỗi edit, chạy lint+test trước push.

Kết quả

Workflow điển hình của 1 dev:

5 tầng, mỗi tầng 1 vai trò. Không cơ chế nào làm việc của cơ chế khác.

  • Dev mở task "thêm API endpoint". CLAUDE.md đã cho Claude biết stack + convention.
  • Dev gõ "tạo API route cho POST /api/users". Skill api-route-generator trigger (đúng convention team).
  • Claude generate code qua MCP file system + pnpm tool.
  • Dev edit code → Hook prettier --write auto format.
  • Dev commit. Skill commit-format trigger khi nói "viết commit message".
  • Dev push → Hook pnpm lint && pnpm test chạy.
  • Dev mở PR qua MCP github. Skill pr-review bảo subagent backend-reviewer review → subagent dùng skills pr-review, api-conventions, sql-perf-check cho review toàn diện.
{
  "hooks": {
    "PostToolUse": [
      { "matcher": "Edit.*\\.ts$", "hooks": [{ "command": "pnpm prettier --write ${file}" }] }
    ],
    "PreToolUse": [
      { "matcher": "Bash.*git push.*", "hooks": [{ "command": "pnpm lint && pnpm test" }] }
    ]
  }
}

Anti-patterns — Khi dev lẫn lộn các cơ chế

❌ Anti-pattern 1: Nhồi review checklist vào CLAUDE.md

Triệu chứng: CLAUDE.md 800 dòng, nửa là review checklist không ai cần khi đang viết feature mới.

Tại sao tệ: Overhead mỗi conversation. Claude confused (quá nhiều context).

Cách đúng: Review checklist → skill pr-review. CLAUDE.md giữ foundation (stack, convention luôn áp dụng).

❌ Anti-pattern 2: Dùng skill thay cho hook

Triệu chứng: Skill auto-format-on-save description "Formats code after save. Use whenever editing."

Tại sao tệ: Skill chỉ fire khi user nói gì đó match. Save file không phải là "user request" → skill không trigger. Format không happen.

Cách đúng: Hook PostToolUse fire on Edit tool. Skill dành cho "expertise Claude cần suy nghĩ để apply", không phải automation mechanical.

❌ Anti-pattern 3: MCP cho mọi thứ

Triệu chứng: Build MCP server cho "team coding standards" — trả về rules.

Tại sao tệ: MCP thiết kế cho data/service external. Coding standard là expertise, không phải data cần fetch. Overhead, slow, complex.

Cách đúng: Coding standard → skill với instructions. Dùng MCP cho data thực sự ở external system.

❌ Anti-pattern 4: Subagent thay vì skill

Triệu chứng: Tạo subagent pr-reviewer thay vì skill pr-review.

Tại sao tệ: Subagent chạy isolated context → mất context PR bạn đang xem. Phải pass lại toàn bộ context. Overhead.

Cách đúng: Skill pr-review join main context, review với full context sẵn có. Chỉ dùng subagent khi cần isolation thực sự (parallelization, different tool access, large delegated task).

Áp dụng ngay

Bài tập 1: Audit CLAUDE.md của bạn (~10 phút)

Mở CLAUDE.md của project hiện tại. Đọc từng section, trả lời cho mỗi section:

Ghi ra:

Bài tập 2: Thiết kế setup cho use case của bạn (~10 phút)

Pick 1 workflow bạn làm thường xuyên (ví dụ: "review PR", "ship feature", "on-call response"). Điền bảng:

Nếu trả lời có 5 cơ chế khác nhau — bạn đã hiểu rồi.

  • Section cần giữ ở CLAUDE.md: _____
  • Section cần move thành skill: _____
  • Ước tính % giảm size CLAUDE.md: _____
Aspect của workflowDùng cơ chế nàoGiải thích
Luôn-luôn biết stack + convention_____
Fetch data (CRM, DB, Slack...)_____
Automation khi save / commit_____
Expertise theo task_____
Delegate task lớn isolated_____

Tóm tắt bài học

🎯 5 cơ chế, 5 vai trò. CLAUDE.md = foundation. MCP = external data. Subagent = isolated roles. Skill = on-demand expertise. Hook = event automation.

🎯 Otto's one-liner: "MCP connects to data, Skills teach Claude what to do with it." — Memorize.

🎯 Decision tree quick check: Cần external data? → MCP. Event-driven? → Hook. Luôn áp dụng? → CLAUDE.md. Isolated? → Subagent. On-demand task expertise? → Skill.

🎯 Combine, không compete. Setup hoàn chỉnh dùng cả 5 cơ chế. Skill gọi MCP, subagent dùng skill, hook complement skill.

🎯 Skill là đúng khi: (1) task-specific, (2) Claude tự nhận qua semantic, (3) join current context, (4) portable qua project (personal) hoặc share team (project).

Tài liệu tham khảo
  • Anthropic Academy — "Skills vs. other Claude Code features"
  • Video — "Choosing the right feature"
  • Model Context Protocol — MCP spec
  • Otto, "Claude Agent Skills Explained" — quote sources
Nội dung này có hữu ích không?