
Claude Code: 5 Tầng Settings Và Hooks, Đừng Đè Nhầm File
Claude Code đọc settings từ 5 tầng theo thứ tự ưu tiên cố định, cộng hooks và MCP để tự động hoá workflow — toàn bộ model, không cần đoán mò.
Bạn set permissions.defaultMode trong ~/.claude/settings.json, restart Claude Code, và một mode khác lại active. Không có gì bị lỗi — chỉ là một file khác đã thắng. Claude Code đọc settings từ 5 nơi khác nhau, và khi cùng một key xuất hiện ở nhiều nơi, một thứ tự ưu tiên cố định sẽ quyết định giá trị nào áp dụng.
Phần lớn báo lỗi "setting của tôi không hoạt động" thực ra là câu hỏi về precedence. Dưới đây là toàn bộ model, cùng với hooks và MCP để bạn dừng việc tự động hoá lại từng bước tay.
5 tầng settings, từ cao xuống thấp
Theo thứ tự ưu tiên giảm dần:
- Managed settings — do tổ chức deploy (server-delivered, MDM/OS policy, hoặc
managed-settings.jsonở cấp hệ thống). Không tầng nào dưới có thể override, trừ vài ngoại lệ security có chủ đích. - Command line — JSON truyền qua
--settings. Chỉ tồn tại trong session đó. - Local project settings —
.claude/settings.local.jsonở root repo. Của riêng bạn, chỉ áp dụng cho repo này. - Shared project settings —
.claude/settings.json, được check vào repo. Của cả team. - User settings —
~/.claude/settings.json. Của riêng bạn, áp dụng cho mọi project.
Với giá trị scalar, quy tắc rất đơn giản: tầng cao hơn thắng, theo từng key. Key nào bạn không set ở tầng cao sẽ rơi xuống tầng thấp hơn — các tầng merge với nhau, không thay thế toàn bộ.
Array không override — chúng gộp lại
Đây là phần khiến nhiều dev bất ngờ: giá trị scalar override, nhưng giá trị array concatenate và dedupe qua các scope. Điều này áp dụng cho đúng những array bạn quan tâm nhất: permissions.allow, permissions.deny, sandbox.filesystem.allowWrite.
Nếu file project (checked-in) cho phép Bash(npm test:*) và file local của bạn cho phép Bash(pnpm test:*), cả hai rule đều active cùng lúc. Tầng thấp hơn có thể thêm entry, nhưng không thể xoá entry mà tầng cao đã thêm — và ngược lại. Hệ quả thực tế: bạn không thể "tắt" một permission rule của team từ file local. Không có negative entry.
Hai array là ngoại lệ, không merge theo kiểu này: fallbackModel là một chain có thứ tự, nên file có precedence cao nhất định nghĩa nó sẽ cung cấp toàn bộ list; và một availableModels allowlist do managed set sẽ áp dụng nguyên trạng — user/project/local không thể extend thêm.
Local settings: hai gotcha hay bị bỏ qua
Auto-gitignore chỉ chạy khi chính Claude Code viết file .claude/settings.local.json. Nếu bạn tự tạo file này bằng tay, bước thêm vào global git excludes không chạy — bạn phải tự thêm vào .gitignore, nếu không sẽ commit nhầm settings cá nhân vào repo chung.
Vị trí file này đã đổi từ bản Claude Code v2.1.211: file thuộc về root repo. Version cũ hơn ghi vào bất kỳ directory nào bạn start Claude Code, và version hiện tại vẫn đọc file cũ ở đó nếu còn tồn tại. Khi cả hai cùng set một key, giá trị ở repo root thắng — trừ permission rule, vẫn theo quy tắc array ở trên, tức rule ở cả hai file đều còn hiệu lực.
Vài key an toàn phá luôn cả luật "tầng cao thắng"
disableClaudeAiConnectors: true áp dụng từ bất kỳ tầng nào, ngay cả khi managed source nói false. Còn crossSessionInbound (cách session nhận message từ session khác) dùng một accept ladder, và giá trị strict hơn ở project hoặc local sẽ thắng managed và user. Một file checked-in không bao giờ có thể làm lỏng cái refuse cá nhân của bạn. Ý tưởng thiết kế nhất quán: một file lạ trong repo vừa clone có thể siết chặt security posture của bạn hơn, nhưng không bao giờ làm lỏng nó ra.
Cách kiểm tra thực tế đã load gì — đừng đoán theo trí nhớ: gõ /status, tab Status có dòng "Setting sources" liệt kê từng tầng đã load trong session này. Một tầng chỉ xuất hiện nếu nó load được ít nhất một key.
Hooks: enforcement không cần platform engineer riêng
Hooks là các shell command chạy tự động tại điểm cố định trong execution cycle của Claude Code: trước khi tool được gọi, sau khi tool hoàn tất, hoặc khi session start/stop. Chúng được cấu hình trong settings.json và chạy background, không cần can thiệp tay. Có 4 loại hook: PreToolUse (trước khi gọi tool), PostToolUse (sau khi tool hoàn tất), Stop (khi session kết thúc), và Notification (khi Claude Code gửi message cho user).
Hook config nằm trong .claude/settings.json ở project root, dạng:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{ "type": "command", "command": "npx prettier --write $CLAUDE_TOOL_INPUT_FILE_PATH" }
]
}
]
}
}
matcher nhắm vào loại tool cụ thể — Write bắt các lệnh write file, bạn cũng có thể match Edit, Bash, hoặc để trống để bắt mọi tool call. Một bài viết trên Dev.to ước tính mỗi lần context-switch tốn team khoảng 23 phút để phục hồi năng suất — đây là con số của riêng tác giả bài đó, không phải benchmark chính thức, nhưng nó giải thích vì sao hook auto-format/auto-test đáng để setup ngay từ đầu thay vì để dev tự nhớ chạy tay.
MCP: bớt tab-switching, không phải build custom integration
MCP (Model Context Protocol) là chuẩn cho phép Claude Code gọi external tool và data source như thể chúng là capability native. Một MCP server expose ra một tập function, Claude Code gọi các function đó trong lúc chạy để lấy data hoặc trigger action — đây là dùng server có sẵn, không phải tự code integration từ đầu. Config nằm trong settings.json, dưới key mcpServers.
Ba loại MCP hay dùng: MCP server cho Jira (đọc ticket trực tiếp trong session, không cần copy description vào prompt), MCP server cho GitHub (check PR status, đọc comment, list issue, lấy file content từ branch), và MCP server cho file system/database (mở rộng ra database nội bộ hoặc log có cấu trúc). Theo bài viết gốc, config hook cơ bản (auto-format, test trigger) tốn dưới một giờ với người đã quen Claude Code, còn mỗi MCP server cộng thêm 30-60 phút tuỳ yêu cầu authentication.
Áp dụng ngay
Nếu bạn đang debug "setting không ăn", đừng đoán — gõ /status trước, rồi mới đọc lại 5 tầng theo thứ tự trên. Nếu team bạn đang tự tay chạy formatter và poll ticket status, bắt đầu bằng một PostToolUse hook cho Prettier/test suite, sau đó thêm một MCP server (GitHub hoặc Jira) khi thấy việc tab-switching thực sự tốn thời gian. Cả hai không cần thay đổi infra — chỉ là JSON đi kèm project.
Không spam, hủy đăng ký bất kỳ lúc nào.


