Bạn đã cấu hình CLAUDE.md, viết rules, có lẽ đã nghịch hooks. Nhưng settings.json vẫn còn là file bạn chưa thực sự đọc kỹ, chỉ copy từ ví dụ đâu đó rồi để đó. Bài này mổ xẻ các field load-bearing thật sự, field nào có thể crash behavior nếu cấu hình sai, và anti-pattern phổ biến nhất liên quan đến commit secrets.

Ba file settings là ba lớp kiểm soát độc lập. Hiểu thứ tự precedence của chúng là điều kiện để debug “tại sao setting của tôi không ăn”.

Ba mức settings và thứ tự precedence

+----------------------------------------------+
| settings.local.json  (per-machine, gitignored)|
|  overrides                                   |
+----------------------------------------------+
| .claude/settings.json  (project, tracked)    |
|  overrides                                   |
+----------------------------------------------+
| ~/.claude/settings.json  (global)            |
+----------------------------------------------+
FilePhạm viCommit được không?
~/.claude/settings.jsonGlobal, mọi session trên máy nàyCó (private repo riêng)
<project>/.claude/settings.jsonProject, tất cả người dùng clone
<project>/.claude/settings.local.jsonProject, chỉ máy nàyKHÔNG, phải gitignore

Rule đơn giản: local > project > global. Khi cùng một key xuất hiện ở nhiều mức, local thắng. Điều này cho phép mỗi dev override project setting mà không cần sửa file được commit.

settings.local.json là nơi bạn để MCP config nhạy cảm, API key, hoặc toggle thực nghiệm mà bạn không muốn đồng nghiệp kế thừa. Add nó vào .gitignore ngay từ đầu, đừng chờ đến khi commit nhầm.

Field permissions

Đây là field quan trọng nhất cho an toàn và developer experience hàng ngày.

allow: giảm ma sát khi làm việc

"permissions": {
  "allow": [
    "Bash",
    "Edit",
    "Read",
    "Write",
    "WebFetch",
    "WebSearch",
    "Glob",
    "Grep",
    "Task",
    "Monitor"
  ]
}

Mỗi entry trong allow là một pattern tool. Khi CC định gọi một tool khớp pattern trong allow, nó tự động approve mà không hỏi. Điều này tránh màn hình xác nhận liên tục khi đang làm việc.

Pattern có hai dạng:

  • Tool name thuần: "Bash" cho phép mọi bash command.
  • Tool name có argument: "Bash(npm test)" chỉ cho phép lệnh npm test, không mở rộng hơn.
  • Wildcard: "WebFetch(https://docs.anthropic.com/**)" chỉ cho phép fetch từ domain đó.

Ví dụ setup an toàn cho project có test suite:

"allow": [
  "Read",
  "Bash(npm test)",
  "Bash(npm run lint)",
  "Bash(git status)",
  "Bash(git diff *)"
]

Session này CC được đọc file, chạy test, chạy lint, xem git status, nhưng mọi thứ khác đều phải hỏi.

deny: hard block không override được

"deny": [
  "Bash(aws s3 rm *)",
  "Bash(aws s3 rb *)",
  "Bash(aws s3api delete-bucket *)",
  "Bash(aws s3api delete-object *)"
]

deny thắng allow trong mọi tình huống. Kể cả khi user gõ lệnh trực tiếp, kể cả khi agent chạy với bypassPermissions, lệnh match deny vẫn bị chặn.

Đây là sự khác biệt quan trọng: allow chỉ là shortcut để skip prompt. deny là hard wall, không bypass được từ trong session. Xem bài 4 để biết incident cụ thể khiến các rule deny này ra đời.

defaultMode: cấp độ mặc định cho mọi tool

"defaultMode": "default"
Giá trịHành vi
defaultHỏi user trước mỗi tool call không có trong allow.
acceptEditsTự động approve Edit và Write, vẫn hỏi với Bash.
bypassPermissionsAuto-approve tất cả, kể cả Bash. Cực kỳ nguy hiểm.
planChỉ cho phép tool read-only, buộc CC dùng plan mode.

bypassPermissions trong defaultMode là anti-pattern nghiêm trọng. Nếu bạn thấy mình muốn dùng nó để “giảm popup phiền phức”, giải pháp đúng là mở rộng allow list thay vì tắt toàn bộ permission check.

Field hooks

"hooks": {
  "WorktreeCreate": [
    {
      "hooks": [
        {
          "type": "command",
          "command": "$HOME/.claude/hooks/worktree-create.sh",
          "timeout": 30
        }
      ]
    }
  ],
  "Stop": [
    {
      "hooks": [
        {
          "type": "command",
          "command": "$HOME/.claude/hooks/stop-notify-telegram.sh",
          "timeout": 10
        }
      ]
    }
  ]
}

hooks là nơi bạn wire shell script vào các lifecycle event của CC. Mỗi event có thể có nhiều hook, chạy theo thứ tự khai báo.

Các event phổ biến:

EventKhi nào chạy
SessionStartNgay khi session bắt đầu
PreToolUseTrước khi tool được gọi (có thể block tool)
PostToolUseSau khi tool chạy xong
StopKhi CC kết thúc một lượt (assistant done)
SubagentStopKhi subagent kết thúc
WorktreeCreateKhi tạo worktree mới
WorktreeRemoveKhi xóa worktree
PreCompactTrước khi compaction xảy ra

Field timeout (giây) là bắt buộc với mọi hook. Hook chạy quá timeout sẽ bị kill. Nếu hook là PreToolUse và bị kill, tool bị block. Chọn timeout thận trọng, đừng để hook notification làm trì hoãn mọi tool call.

Hook nhận JSON từ stdin (chứa event detail, tool name, input). Hook có thể ghi JSON ra stdout để CC đọc, ví dụ để inject thêm context hoặc block tool với message.

Xem bài 9 để đọc chi tiết về lifecycle event, stdin/stdout schema, và các pattern hook thực tế.

Field env

"env": {
  "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
  "ENABLE_PROMPT_CACHING_1H": "1",
  "CLAUDE_CODE_NO_FLICKER": "1",
  "CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1",
  "CLAUDE_CODE_ENABLE_AWAY_SUMMARY": "1"
}

env set biến môi trường cho mọi session khởi động từ settings file này. Chia nhóm để dễ nhớ:

Nhóm performance và cache

VarTác dụng
ENABLE_PROMPT_CACHING_1H=1Cache L1-L4 prompt với TTL 1 giờ thay vì 5 phút mặc định. Giảm latency và cost đáng kể khi làm việc liên tục. Xem bài 5.
CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCYSố tool được chạy song song. Default 10. Tăng cho agent task nhiều file.
BASH_DEFAULT_TIMEOUT_MSTimeout mặc định của Bash tool (ms). Default 120000 (2 phút).
BASH_MAX_TIMEOUT_MSTimeout tối đa cho lệnh bash dài. Default 600000 (10 phút).

Nhóm experimental và tính năng mới

VarTác dụng
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1Bật team/teammate mode, dùng được TeamCreateSendMessage để spawn agent có tên, liên lạc qua nhau.
CLAUDE_CODE_ENABLE_AWAY_SUMMARY=1Tóm tắt session khi bạn quay lại sau khi tab/terminal bị ẩn.
CLAUDE_CODE_EFFORT_LEVELlow, medium, high, xhigh, max, auto. Ảnh hưởng đến thinking budget.

Nhóm telemetry và privacy

VarTác dụng
DISABLE_TELEMETRY=1Tắt toàn bộ telemetry gửi về Anthropic.
DO_NOT_TRACK=1Honor header Do Not Track, tương đương.
DISABLE_AUTOUPDATER=1Tắt auto-update. Dùng khi cần pin version cho CI/CD.
CLAUDE_CODE_ENABLE_TELEMETRY=1Bật OpenTelemetry để export trace sang hệ thống observability của bạn.

Nhóm debug và logging

VarTác dụng
CLAUDE_CODE_DEBUG_LOGS_DIRPath đến thư mục log debug. Hữu ích khi hook hoặc tool behave unexpected.
CLAUDE_CODE_DEBUG_LOG_LEVELverbose, debug, info, warn, error.
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1Scrub env vars nguy hiểm khi spawn subprocess. Bảo vệ khỏi secret leak qua process tree.

Các field khác

model: chọn model mặc định

Không phải field model trực tiếp mà qua env var:

"env": {
  "ANTHROPIC_MODEL": "claude-opus-4-7"
}

Hoặc dùng lệnh /model trong session để chọn tạm. Thay đổi qua settings.json áp dụng cho mọi session mới từ đó trở đi.

language: ngôn ngữ output

"language": "Vietnamese"

CC sẽ ưu tiên trả lời bằng ngôn ngữ này khi không có chỉ dẫn khác. Giá trị là chuỗi tên ngôn ngữ tiếng Anh: "English", "Vietnamese", "Japanese", v.v.

plugins: bật/tắt từng plugin

"enabledPlugins": {
  "typescript-lsp@claude-plugins-official": true,
  "hookify@claude-plugins-official": true,
  "skill-creator@claude-plugins-official": true,
  "security-guidance@claude-plugins-official": true,
  "frontend-design@claude-plugins-official": true
}

Format: "<plugin-name>@<registry>". Giá trị true bật, false tắt. Plugin tắt sẽ không load tool, không inject context vào session. Nếu một plugin gây ra slowdown hoặc conflict tool name, set false ở đây thay vì uninstall.

Ví dụ: nếu bạn cài plugin telegram cho một mục đích rồi switch sang cơ chế khác, đặt "telegram@claude-plugins-official": false thay vì gỡ cài đặt. Dễ bật lại khi cần.

autoMemoryDirectory: redirect memory folder

"autoMemoryDirectory": "/path/to/shared/memory"

Theo mặc định CC lưu memory vào ~/.claude/projects/<workdir-hash>/memory/. Field này redirect toàn bộ auto-memory sang một path khác. Dùng để chia sẻ memory giữa nhiều project trên cùng một domain (ví dụ nhiều project cùng công ty dùng chung một memory folder).

Xem bài 12bài 14 để hiểu đầy đủ hơn về memory system.

Anti-pattern: commit secrets vào settings.json

Đây là lỗi phổ biến nhất liên quan đến settings.

Nếu bạn nhét ANTHROPIC_API_KEY, database URL, hay token vào env trong settings.json project rồi commit, key đó sẽ tồn tại mãi trong git history dù bạn xóa đi sau đó.

Pattern đúng:

project/
  .claude/
    settings.json        <- commit, env không có secret
    settings.local.json  <- gitignored, chứa secret của máy này
  .gitignore
    .claude/settings.local.json

settings.local.json override settings.json cho máy bạn. Bạn đặt key ở đây, commit lên máy bạn không ảnh hưởng đến repo. Người khác clone repo sẽ không có file đó và phải tự tạo cho máy của họ.

Breadcrumb pattern: đặt file settings.local.json.example trong repo (không chứa giá trị thật) để người clone biết cần tạo file đó với các key gì.

Một settings.json tối thiểu cho project team

Đây là cấu hình tối giản an toàn để bắt đầu với project có nhiều người:

{
  "permissions": {
    "allow": [
      "Read",
      "Bash(npm test)",
      "Bash(npm run lint)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)"
    ],
    "deny": [],
    "defaultMode": "default"
  },
  "language": "English",
  "enableAllProjectMcpServers": false
}

Sau đó từng dev thêm settings.local.json với những gì họ muốn override (model, allow list mở rộng hơn, MCP server riêng, v.v.).

Tóm tắt và bài tiếp theo

  • Ba mức settings: global (~/.claude/settings.json), project (.claude/settings.json), per-machine (.claude/settings.local.json). Thứ tự: local > project > global.
  • permissions.deny là hard wall, permissions.allow chỉ là skip prompt. Deny thắng allow mọi lúc.
  • env trong settings.json set biến môi trường cho mọi session. Chia nhóm: cache, experimental, telemetry, debug.
  • Secrets không bao giờ vào settings.json được commit. Luôn dùng settings.local.json và gitignore nó.
  • hooks wire shell script vào lifecycle event. Xem bài 9 để đọc chi tiết.

Bài 11 sẽ đi vào plugin system: cách CC load plugin, format <name>@<registry>, và cách viết plugin cơ bản để thêm tool hoặc inject context.


Bài thuộc series Claude Code từ zero. Series plan tại bài giới thiệu.