Tóm tắt: Rule permissions.allow/ask/deny quyết định tool nào chạy không cần hỏi, phải hỏi, hay bị chặn. Hook là lệnh shell do harness chạy ở các sự kiện (PreToolUse, PostToolUse...), nhận JSON qua stdin; exit 2 ở PreToolUse sẽ chặn tool và gửi stderr cho Claude. Lệnh nhanh xem Claude Code cheatsheet.
Luồng hoạt động
flowchart LR A[Claude muốn gọi tool] --> B{"permissions deny/ask/allow"} B -->|deny| X[Bị chặn] B -->|"allow / user đồng ý"| C[Hook PreToolUse] C -->|"exit 2"| X C -->|"exit 0"| D[Tool chạy] D --> E[Hook PostToolUse] E --> F[Kết quả về Claude]
Cấu hình
Vị trí file settings
| File | Phạm vi | Commit? |
|---|---|---|
~/.claude/settings.json |
User, mọi project | Không |
.claude/settings.json |
Project, cả team | Có |
.claude/settings.local.json |
Project, riêng bạn | Không (gitignore) |
--settings <file> |
Một phiên (CI) | Tuỳ |
Managed settings (do admin cài) luôn thắng. Giữa project và user, cấu hình cụ thể hơn được ưu tiên; rule permission từ các file được gộp lại.
Permissions
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git diff *)",
"Bash(ansible-lint *)",
"Read(./inventory/**)",
"mcp__netops__ping",
"mcp__netops__list_devices"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Read(./**/vault.yml)",
"Bash(rm -rf *)",
"Bash(ssh *)",
"WebFetch"
],
"defaultMode": "acceptEdits"
}
}| Cú pháp rule | Ý nghĩa |
|---|---|
Bash |
Mọi lệnh Bash |
Bash(git diff *) |
Lệnh bắt đầu bằng git diff (wildcard *) |
Read(./secrets/**) / Edit(./roles/**) |
Đường dẫn theo pattern kiểu gitignore (** = mọi cấp thư mục) |
WebFetch(domain:example.com) |
Chỉ một domain |
mcp__<server>__<tool> |
Một tool MCP; mcp__<server> là mọi tool của server |
Thứ tự ưu tiên: deny > ask > allow. Rule Bash so khớp theo tiền tố lệnh, có thể bị lách (bash -c ..., biến môi trường); muốn chặn chắc thì thêm hook hoặc chạy trong sandbox.
Hooks
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guard-bash.sh" }
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/yamllint.sh", "timeout": 60 }
]
}
]
}
}matcher: tên tool, hỗ trợ regex (Edit|Write,mcp__netops__.*). Bỏ trống hoặc*= mọi tool.- Hook nhận JSON qua stdin:
session_id,cwd,hook_event_name,tool_name,tool_input(Bash:tool_input.command; Edit/Write:tool_input.file_path). PostToolUse có thêmtool_response. - Exit code:
0= tiếp tục;2= chặn (PreToolUse) / báo lại cho Claude (PostToolUse), nội dung stderr được gửi cho Claude; mã khác = lỗi không chặn, chỉ hiện cho người dùng.
#!/usr/bin/env bash
# Chặn lệnh đẩy cấu hình lên router production
cmd=$(jq -r '.tool_input.command // ""')
if grep -Eq 'ansible-playbook' <<<"$cmd" && grep -Eq -- '-l +prod|--limit +prod' <<<"$cmd" && ! grep -q -- '--check' <<<"$cmd"; then
echo "Chặn: playbook trên prod phải chạy --check trước. Hãy thêm --check --diff." >&2
exit 2
fi
exit 0#!/usr/bin/env bash
f=$(jq -r '.tool_input.file_path // ""')
case "$f" in
*.yml|*.yaml) yamllint -f parsable "$f" >&2 || exit 2 ;;
esac
exit 0chmod +x .claude/hooks/*.sh
echo '{"tool_name":"Bash","tool_input":{"command":"ansible-playbook site.yml -l prod"}}' \
| .claude/hooks/guard-bash.sh; echo "exit=$?" # mong đợi exit=2Sự kiện hook hay dùng khác: UserPromptSubmit, Stop, SessionStart, Notification, PreCompact. Trong phiên, /hooks hiển thị hook đang nạp.
Hook chạy lệnh shell với quyền của bạn, không qua permission. Review hook trong repo người khác trước khi mở Claude Code ở đó.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
| Rule allow không có tác dụng, vẫn bị hỏi | Sai cú pháp (Bash(git diff) chỉ khớp đúng lệnh đó) |
Dùng Bash(git diff *), kiểm tra trong /permissions |
| Hook không chạy | JSON sai cấu trúc (thiếu mảng hooks lồng trong matcher) |
Đối chiếu mẫu trên, xem /hooks |
| Hook chạy nhưng không chặn | Dùng exit 1 thay vì exit 2 |
PreToolUse muốn chặn phải exit 2 |
Permission denied khi chạy hook |
Script chưa chmod +x |
chmod +x .claude/hooks/*.sh |
jq: command not found |
Thiếu jq trên máy | apt install jq hoặc viết hook bằng Python đọc sys.stdin |
Settings bị bỏ qua khi chạy -p |
File không hợp lệ, ở chế độ -p không báo lỗi |
python3 -m json.tool .claude/settings.json, chạy claude doctor |