Claude Code từ zero đến thành thạo · Phần 7 — Permission mode và cấu hình quyền
Sáu permission mode và lúc nào dùng cái nào, classifier của auto mode chặn gì, cú pháp allow/ask/deny rule cho Bash, Read, Edit, WebFetch, MCP — cùng protected path và critical path mà không mode nào vượt qua.
Permission mode là thứ quyết định Claude làm được gì mà không hỏi bạn. Đây cũng là chỗ người dùng mới hay chọn sai theo hai hướng ngược nhau: hoặc bực mình vì bị hỏi liên tục rồi bật thẳng bypassPermissions, hoặc sợ tới mức ở lì Manual mode và mất hết lợi ích của agent.
Bài này chỉ ra khoảng giữa: auto mode với classifier duyệt thay bạn, cộng permission rule để tiền phê duyệt đúng thứ bạn tin tưởng.
Sáu mode
| Mode | Chạy mà không hỏi | Hợp với |
|---|---|---|
default (Manual) | Chỉ đọc | Tự review từng hành động, việc nhạy cảm |
acceptEdits | Đọc, sửa file, và lệnh filesystem thông dụng (mkdir, touch, mv, cp…) | Lặp trên code mà bạn đang review |
plan | Đọc, cộng các lệnh được classifier duyệt khi auto mode khả dụng | Khám phá codebase trước khi đổi nó |
auto | Mọi thứ, kèm kiểm tra an toàn ở nền | Task dài, đỡ mệt vì bị hỏi |
dontAsk | Chỉ tool đã tiền phê duyệt | CI và script bị khoá chặt |
bypassPermissions | Mọi thứ | Chỉ container và VM cô lập |
Lưu ý về tên: mode duyệt từng hành động hiển thị là Manual trong CLI và các extension, nhưng giá trị cấu hình của nó là default. CLI chấp nhận manual làm alias ở mọi chỗ bạn gõ giá trị.
Bấm Shift+Tab để xoay vòng giữa các mode trong phiên đang chạy.
Phiên khởi động ở mode nào
Claude Code lấy permission mode từ cái đầu tiên khớp trong ba nguồn:
- Flag
--permission-mode, hoặc--dangerously-skip-permissions permissions.defaultModetrong file settings- Mặc định dựng sẵn
Mặc định dựng sẵn phụ thuộc cách bạn chạy và gói bạn dùng:
| Cách chạy | Mode khởi động |
|---|---|
Có file settings nào đặt disableAutoMode thành "disable" | default |
| Phiên đầu tiên sau khi cài hoặc nâng cấp lên bản thêm mặc định này | default |
claude -p hoặc Agent SDK | default |
| Bedrock, Google Cloud’s Agent Platform, Microsoft Foundry, Claude Platform on AWS, phiên gateway đã đăng nhập | default |
| Gói Pro, Max hoặc Team, trong terminal hoặc VS Code extension | auto |
| Gói Enterprise hoặc Claude Console API key | default |
Một cái bẫy đáng nhớ: đặt
defaultMode: "auto"trong.claude/settings.jsonhoặc.claude/settings.local.jsonkhông có tác dụng. Giá trịautochỉ ăn từ~/.claude/settings.json. Nếu bạn đặt auto ở settings project mà phiên vẫn khởi động ở Manual không kèm lỗi, đây là nguyên nhân.
Auto mode và classifier
Trong auto mode, một model thứ hai — gọi là classifier — duyệt hành động thay cho bạn. Nó chạy ở nền, chặn cái rủi ro và cho qua phần còn lại.
Classifier tin thư mục làm việc của bạn và các git remote đã cấu hình sẵn lúc phiên bắt đầu. Một remote được thêm hoặc trỏ lại giữa phiên bằng git remote add hay git remote set-url không được tin; mọi thứ khác bị coi là bên ngoài cho tới khi bạn cấu hình hạ tầng tin cậy.
Chặn mặc định:
- Tải và chạy code, kiểu
curl | bash - Gửi dữ liệu nhạy cảm ra endpoint bên ngoài
- Deploy và migration lên production
- Xoá hàng loạt trên cloud storage
- Cấp quyền IAM hoặc quyền repo
- Sửa hạ tầng dùng chung
- Phá huỷ không hồi phục các file đã tồn tại trước phiên
- Force push
- Commit hoặc push một thay đổi khiến secret hoặc dữ liệu nhạy cảm bị đưa ra ngoài repository khi nó chạy, hoặc mở rộng thứ mà deploy phơi ra
Classifier cũng duyệt mỗi tin nhắn Claude gửi cho agent khác qua SendMessage, và duyệt các lệnh rm/rmdir nhắm vào critical path.
Auto mode còn thúc Claude làm tiếp mà không dừng lại hỏi câu làm rõ — dù nó vẫn hỏi khi prompt của bạn hoặc một skill yêu cầu rõ như vậy.
Auto mode giảm số lần bị hỏi nhưng không đảm bảo an toàn. Dùng nó cho task mà bạn tin hướng đi chung, đừng coi nó là vật thay thế cho việc review các thao tác nhạy cảm.
Auto mode chỉ khả dụng khi tài khoản của bạn đủ điều kiện về model (trên Anthropic API: Opus 4.6 trở lên, Sonnet 4.6 trở lên, hoặc Fable 5) và tổ chức không tắt nó. Nếu Claude Code báo auto mode không khả dụng, đó là một điều kiện chưa thoả — không phải sự cố tạm thời.
Plan mode
Plan mode bảo Claude nghiên cứu và đề xuất thay đổi mà không thực hiện. Claude đọc file, chạy lệnh shell để khám phá, và viết ra plan — nhưng không sửa source. Thay đổi bị chặn cho tới khi bạn duyệt plan.
Vào plan mode bằng Shift+Tab, hoặc đặt tiền tố /plan cho một prompt đơn lẻ, hoặc khởi động bằng claude --permission-mode plan.
Khi plan xong, Claude trình bày và hỏi bạn muốn làm gì:
- Yes, and use auto mode — duyệt và chuyển sang auto mode
- Yes, manually approve edits — duyệt và review từng thay đổi
- No, keep planning — ở lại plan mode và nói cho Claude biết cần sửa gì
Bấm Ctrl+G để mở plan trong text editor mặc định và sửa trực tiếp trước khi Claude tiếp tục. Duyệt plan cũng tự đặt tên phiên theo nội dung plan, trừ khi bạn đã đặt tên bằng --name hoặc /rename.
Một chi tiết liên quan tới phần 3: nếu bạn dùng thiết lập model opusplan, mỗi lần vào/ra plan mode là một lần đổi model — và đổi model huỷ toàn bộ prompt cache.
acceptEdits
Mode này cho Claude tạo và sửa file trong thư mục làm việc mà không hỏi. Ngoài sửa file, nó còn tự duyệt các lệnh Bash filesystem thông dụng: mkdir, touch, rm, rmdir, mv, cp, và sed.
Việc tự duyệt chỉ áp cho path bên trong thư mục làm việc hoặc additionalDirectories. Path ngoài phạm vi đó, ghi vào protected path, rm/rmdir nhắm critical path, và mọi lệnh Bash khác ngoài tập read-only dựng sẵn — tất cả vẫn hỏi.
Dùng acceptEdits khi bạn muốn review thay đổi sau đó trong editor hoặc qua git diff, thay vì duyệt từng cái inline.
dontAsk và bypassPermissions
dontAsk tự từ chối mọi tool call lẽ ra sẽ hỏi bạn. Claude chỉ chạy hành động khớp permissions.allow, các lệnh Bash read-only, và những gì được PreToolUse hook duyệt. Phiên không bao giờ chờ input — nên đây là mode cho CI pipeline và môi trường hạn chế.
bypassPermissions tắt hết prompt và kiểm tra an toàn. Ba điều cần biết:
- Bạn không vào được mode này từ một phiên đã khởi động mà không bật nó. Phải bật lúc launch.
- Lần đầu chạy tương tác với mode này, Claude Code hiện hộp thoại cảnh báo yêu cầu bạn nhận trách nhiệm. Từ chối thì Claude Code thoát.
- Trên Linux và macOS, Claude Code từ chối khởi động ở mode này khi chạy dưới quyền root hoặc
sudo.
bypassPermissionskhông có bất kỳ lớp bảo vệ nào trước prompt injection hay hành động ngoài ý muốn. Muốn ít bị hỏi mà vẫn có kiểm tra an toàn ở nền thì dùng auto mode. Chỉ dùng bypass trong container, VM, hoặc dev container không có internet.
Hai lằn ranh không mode nào vượt qua
Đây là phần quan trọng nhất của bài, và cũng là phần ít người biết.
Protected path
Ghi vào một nhóm nhỏ các path không bao giờ được tự duyệt, trừ ở bypassPermissions. Điều này ngăn hỏng trạng thái repository và hỏng chính cấu hình của Claude.
| Mode | Ghi vào protected path |
|---|---|
default, acceptEdits | Hỏi |
plan | Chuyển cho classifier nếu auto mode khả dụng; nếu không thì hỏi |
auto | Chuyển cho classifier |
dontAsk | Từ chối |
bypassPermissions | Cho phép |
Thư mục được bảo vệ: .git, .config/git, .vscode, .idea, .husky, .cargo, .devcontainer, .yarn, .mvn, và .claude (trừ .claude/worktrees).
File được bảo vệ: .gitconfig, .gitmodules; các file khởi động shell (.bashrc, .zshrc, .profile, .envrc…); cấu hình package manager (.npmrc, .yarnrc, .pnpmfile.cjs, bunfig.toml…); .pre-commit-config.yaml và các file lefthook; .devcontainer.json; .ripgreprc, pyrightconfig.json; .mcp.json và .claude.json.
Rule
permissions.allowkhông tiền phê duyệt được ghi vào protected path. Kiểm tra an toàn chạy trước khi Claude Code xét allow rule, nên một dòng nhưEdit(.claude/**)trong settings không đổi được kết quả ở bảng trên.
Critical path
Claude Code không bao giờ để một allow rule hay một PreToolUse hook trả "allow" duyệt lệnh rm hoặc rmdir nhắm vào critical path — kể cả ở các mode bỏ qua mọi prompt khác. Đây là cầu dao chống lỗi của model.
Critical path gồm: gốc filesystem; thư mục cấp một dưới gốc như /usr, /etc; thư mục home của bạn; ổ đĩa Windows và thư mục cấp một của chúng như C:\ và C:\Windows; thư mục làm việc của bạn và các thư mục cha của nó.
Ba chi tiết chống lách luật:
- Glob ngay dưới một biến shell, ví dụ
rm -rf "$DIR"/*, cũng bị coi là critical-path removal — vì lệnh trở thành xoá từ gốc filesystem khi biến rỗng. - Giấu lệnh xoá trong command substitution
$(...), backtick, hay process substitution<(...)không né được kiểm tra. - Ở
bypassPermissions, critical-path removal vẫn hỏi bạn.
Permission rule
Mode đặt nền; rule xếp chồng lên trên để tiền phê duyệt hoặc chặn từng thứ cụ thể. Mở /permissions để xem và sửa.
- Allow — cho Claude Code dùng tool đó mà không cần duyệt tay
- Ask — hỏi xác nhận mỗi lần
- Deny — chặn hẳn
Thứ tự xét: deny → ask → allow. Cái khớp đầu tiên theo thứ tự đó quyết định kết quả, và độ cụ thể của rule không đổi được thứ tự này. Một deny rule rộng như Bash(aws *) chặn mọi lệnh khớp, kể cả lệnh cũng khớp một allow rule hẹp hơn như Bash(aws s3 ls) — nên deny rule không mang được ngoại lệ allowlist.
Deny rule hành xử khác nhau tuỳ bạn viết thế nào:
- Tên tool trần như
Bashgỡ hẳn tool khỏi context của Claude — nó không bao giờ thấy tool đó. (Đây cũng là hành động huỷ prompt cache, xem phần 3.) - Rule có phạm vi như
Bash(rm *)giữ tool khả dụng và chỉ chặn các lệnh khớp khi Claude cố gọi.
Permission rule do Claude Code cưỡng chế, không phải model. Chỉ dẫn trong prompt hay
CLAUDE.mdđịnh hình thứ Claude cố làm, nhưng không đổi được thứ Claude Code cho phép.
Cú pháp
Rule có dạng Tool hoặc Tool(specifier).
| Rule | Khớp với |
|---|---|
Bash | Mọi lệnh Bash. Bash(*) tương đương |
Bash(npm run build) | Đúng lệnh npm run build |
Bash(npm run *) | Mọi lệnh bắt đầu bằng npm run |
Read(./.env) | Đọc file .env ở thư mục hiện tại |
WebFetch(domain:example.com) | Request tới example.com |
mcp__puppeteer | Mọi tool của server puppeteer |
mcp__puppeteer__puppeteer_navigate | Đúng một tool của server đó |
Agent(Explore) | Subagent tên Explore |
Hậu tố :* là cách viết tương đương của wildcard cuối, nên Bash(ls:*) khớp đúng như Bash(ls *). Nhưng nó chỉ được nhận ở cuối pattern — trong Bash(git:* push) thì dấu hai chấm bị coi là ký tự thường.
Ví dụ cho phép npm và git commit nhưng chặn git push:
{
"permissions": {
"allow": ["Bash(npm run *)", "Bash(git commit *)"],
"deny": ["Bash(git push *)"]
}
}
Khớp theo tham số đầu vào
Deny và ask rule khớp được một tham số cấp cao nhất của bất kỳ tool nào, dạng Tool(param:value):
| Rule | Khớp với |
|---|---|
Agent(model:opus) | Lời gọi Agent yêu cầu model tier Opus |
Agent(isolation:worktree) | Lời gọi Agent yêu cầu một git worktree |
Bash(run_in_background:true) | Lời gọi Bash chạy ở nền |
Mỗi rule đặt tên một tham số; muốn chặn theo hai tham số thì viết hai rule. Tham số model bỏ trống thì không bao giờ khớp, nên Agent(model:*) không khớp lời gọi không set model.
Không khớp được theo trường nội dung chính của tool: command của Bash, file_path của Read/Edit/Write, path của Grep/Glob, url của WebFetch. Một rule như Bash(command:rm *) sẽ bị lách bằng lệnh ghép, nên Claude Code bỏ qua nó và cảnh báo lúc khởi động.
Rule cho đường dẫn file
Read và Edit rule dùng cú pháp pattern kiểu gitignore, với bốn dạng neo khác nhau:
| Pattern | Nghĩa | Ví dụ |
|---|---|---|
//path | Đường dẫn tuyệt đối từ gốc filesystem | Read(//Users/alice/secrets/**) |
~/path | Từ thư mục home | Read(~/Documents/*.pdf) |
/path | Tương đối so với nguồn settings | Edit(/src/**/*.ts) |
path hoặc ./path | Tương đối so với thư mục hiện tại | Read(*.env) |
Một pattern như
/Users/alice/filekhông phải đường dẫn tuyệt đối. Dấu gạch chéo đơn ở đầu neo vào nguồn settings, không phải gốc filesystem. Dùng//Users/alice/filecho đường dẫn tuyệt đối.
Ba điều dễ sai khác:
Editrule áp cho mọi tool built-in sửa file. Đừng viết rule choWrite,NotebookEdithayMultiEdit— Claude Code nhận rule nhưng không bao giờ tra tới nó, và cảnh báo lúc khởi động. DùngEdit(docs/**)thay choWrite(docs/**).Readdeny rule cũng chặn Edit và Write trên cùng path, gồm cả tạo file mới ở đó. NhưngNotebookEditkhông được phủ, nên thêmEditdeny rule cho path không tool nào được đổi.- Read và Edit deny rule chỉ áp cho tool file built-in và các lệnh file mà Claude Code nhận diện được trong Bash như
cat,head,tail,sed. Chúng không áp cho subprocess bất kỳ đọc/ghi file gián tiếp — ví dụ một script Python tự mở file. Muốn cưỡng chế ở mức hệ điều hành thì bật sandbox.
WebFetch và wildcard tên miền
WebFetch(domain:*.example.com) khớp mọi subdomain ở mọi độ sâu, nhưng không khớp chính example.com. Ở vị trí khác ngoài *. dẫn đầu, wildcard chỉ khớp phần text giữa hai dấu chấm — nên WebFetch(domain:example.*) khớp example.org nhưng không khớp example.evil.com. Thiết kế này ngăn wildcard cuối khớp phải tên miền mà kẻ tấn công đăng ký được.
Thứ tự ưu tiên
Permission rule theo đúng thứ tự ưu tiên settings chung, với managed settings cao nhất — không cấp nào, kể cả command line, ghi đè được một managed permission rule.
Và một quy tắc bao trùm: nếu một tool bị deny ở bất kỳ cấp nào, không cấp nào allow lại được. User settings allow mà project settings deny thì deny thắng; ngược lại cũng vậy.
Chọn thiết lập nào
| Bạn muốn | Bắt đầu với |
|---|---|
| Tự review từng hành động | claude --permission-mode default |
| Ít bị hỏi ở local mà không cần classifier | Manual mode cộng Bash sandbox ở chế độ auto-allow |
| Khám phá trước khi đổi gì | claude --permission-mode plan |
| Làm không cần trông, có classifier duyệt từng hành động | claude --permission-mode auto |
| Chạy trong CI với allowlist chính xác | claude -p "..." --permission-mode dontAsk --allowedTools "Bash(npm test)" "Read" |
| Chạy hoàn toàn tự động trong container | claude -p "..." --dangerously-skip-permissions |
Với người dùng hằng ngày trên gói Pro/Max/Team, câu trả lời gần như luôn là: để auto mode làm mặc định, rồi thêm dần allow rule cho các lệnh bạn tin tưởng và deny rule cho thứ bạn không bao giờ muốn nó chạm vào. Chạy /fewer-permission-prompts (phần 6) sau vài tuần để nó tự đề xuất allowlist từ transcript thật của bạn.
Nguồn
Docs gốc cập nhật thường xuyên; khi có mâu thuẫn, tin bản tiếng Anh.