Sổ tay kỹ thuật

Claude Code: settings.json, permissions và hooks

how-to#claude-code#agents#json· cập nhật 2026-11-06

Dùng khi cần cho phép/chặn lệnh trong Claude Code bằng permissions allow/deny và chạy script tự động trước/sau khi tool chạy (PreToolUse/PostToolUse).

Sửa trang này
Mục lục

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

.claude/settings.json
{
  "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

.claude/settings.json
{
  "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êm tool_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.
.claude/hooks/guard-bash.sh
#!/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
.claude/hooks/yamllint.sh
#!/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 0
chmod +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=2

Sự 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

Tham khảo