Claude Code là agent lập trình (coding agent) của Anthropic. Nó chạy cùng các mô hình Claude như ứng dụng Claude, nhưng chạy ngay trên máy của bạn, nơi nó có thể đọc tệp, chạy lệnh shell và sửa code của bạn, và nó đi kèm các gói Claude trả phí. Tôi dùng nó trong terminal chứ không dùng extension VS Code hay ứng dụng desktop: năm session nằm trong một session tmux trên laptop, gần như session nào cũng được khởi động với các lời hỏi xin quyền đã tắt, và tôi truy cập được chúng từ điện thoại qua tính năng Remote Control của ứng dụng Claude, qua SSH, hoặc qua một bot chat.
Phần dưới đây kể chi tiết cách thiết lập đó, với số liệu lấy từ chính máy của tôi chứ không phải từ trí nhớ: các tệp cài đặt (settings), bản ghi các session (transcript) mà Claude Code lưu dưới ~/.claude/projects (của tôi có từ ngày 28/8), và lịch sử prompt của nó, có từ tháng 2 và chứa 7,323 prompt.
Claude và Claude Code là hai thứ khác nhau#
Claude là họ mô hình, đồng thời là ứng dụng chat tại claude.ai, trên máy tính và trên điện thoại, nơi bạn trò chuyện với các mô hình đó. Claude Code là một agent được xây trên chính các mô hình ấy. Bạn khởi động nó trong một thư mục dự án, và nó làm việc ở đó theo một vòng lặp: đọc tệp, chạy lệnh, sửa code và chạy kiểm thử, cho đến khi xong việc hoặc cần đến bạn. Hỏi Claude cách sửa một lỗi thì bạn nhận được câu trả lời. Hỏi Claude Code thì bạn nhận được bản sửa, kèm một diff để đọc.
Tôi dùng cả hai. Từ ngày 18/10, một ứng dụng chợ kiêm cộng đồng mà tôi đang làm gửi việc dịch nội dung thẳng tới Claude API từ backend Django, và thay đổi chuyển nó sang cách đó được thực hiện trong một session Claude Code. Trong các transcript của tôi, 94% câu trả lời đến từ Opus 5.5, và trong cài đặt tôi để mức effort ở high.
Trình cài đặt native chỉ cần một dòng lệnh và tự cập nhật:
curl -fsSL https://claude.ai/install.sh | bashNó tạo một symlink claude trong ~/.local/bin trỏ vào ~/.local/share/claude/versions/; bản của tôi tự lên từ 2.1.305 lên 2.1.306 vào ngày 21/10. Claude Code cần một gói Claude trả phí (Pro, Max, Team hoặc Enterprise) hoặc một tài khoản API. Giá thay đổi thường xuyên nên tôi xin nhường phần đó cho trang bảng giá của Anthropic.
Một session tmux, bảy cửa sổ#
Lúc tôi viết bài này, tmux list-panes -a cho thấy trên laptop có một session tên main với bảy cửa sổ. Năm cửa sổ là Claude Code, mỗi dự án một cái: ứng dụng chợ mà tôi đang làm và ứng dụng ước tính chi phí của tôi (cả hai đều được kể trong bài về bộ công nghệ tôi đang dùng), blog này và hai dự án nhỏ hơn. Profile terminal của tôi mở mọi cửa sổ bằng một login shell tự gắn vào main. Nhờ vậy, mở một tab mới trên laptop hay đăng nhập SSH từ điện thoại thì đều vào đúng những session đó.
Tôi đã thử một trình ghép kênh (multiplexer) khác từ ngày 17/9 đến ngày 8/10 rồi quay lại tmux vì một lý do thực tế: ứng dụng SSH trên điện thoại của tôi ghép kênh bằng tmux, và các nút tắt của nó gửi đúng các phím mặc định của tmux. Những dòng như thế này trong ~/.tmux.conf có mặt là vì điện thoại:
set -g prefix C-a # Ctrl-a prefix
set -g prefix2 C-b # stock Ctrl-b too, for apps that send it
# Size each window to the client that used it last, not the smallest one,
# so a phone attached to the same session doesn't shrink it.
setw -g window-size latest
# Copy to the clipboard of whichever terminal is attached (OSC 52),
# so over SSH it lands on the phone's clipboard too.
set -g set-clipboard onKhi chạy trong tmux, có hai thứ thay đổi. Claude Code chuyển một lệnh đang chạy xuống chạy nền bằng Ctrl+B, mà giờ tổ hợp đó lại là prefix tmux thứ hai của tôi, nên ~/.claude/keybindings.json tắt nó đi và dùng Meta+B thay thế:
{
"bindings": [
{ "context": "Global", "bindings": { "ctrl+b": null } },
{ "context": "Task", "bindings": { "ctrl+b": null, "meta+b": "task:background" } }
]
}Thứ còn lại là xuống dòng. Enter sẽ gửi prompt đi. Tài liệu nêu \ rồi Enter, và Ctrl+J, là hai cách dùng được trong mọi terminal; Option+Enter dùng được khi terminal gửi Option dưới dạng Meta; còn Shift+Enter chạy sẵn trong một số terminal, nhưng tmux chỉ chuyển tiếp nó khi bật extended-keys. Máy tôi không bật, nên trong các session của tôi, Shift+Enter sẽ gửi prompt đi. Mà tôi cũng hiếm khi cần đến cách nào trong số đó: chỉ 84 trong 7,323 prompt của tôi có dấu xuống dòng do tôi tự gõ, trong khi 279 prompt có nội dung dán vào, thứ mà Claude Code thu gọn thành một placeholder kiểu [Pasted text #1 +34 lines] nhưng vẫn gửi đi đầy đủ.
Terminal, extension VS Code hay ứng dụng desktop?#
Cùng một agent nhưng có nhiều lớp vỏ, và các lớp vỏ này đọc chung các tệp cài đặt. Dựa vào điểm khởi chạy (entry point) mà Claude Code ghi lại trong mỗi transcript, các session của tôi chia ra như sau:
| Giao diện | Là gì | Tôi dùng, từ 28/8 đến 21/10 |
|---|---|---|
| CLI trong terminal | claude trong một terminal, bên trong tmux | 128 session |
| Ứng dụng desktop, tab Code | Claude Code bên trong ứng dụng Claude, có phần xem diff và các khung (pane) | 2 session |
| Extension VS Code | một khung chat trong trình soạn thảo | không dùng; hiện không còn cài, chỉ sót lại phần cài đặt của nó |
| Ứng dụng Claude và claude.ai/code | điều khiển một session đang chạy trên laptop của tôi, hoặc chạy một session trên cloud | phần lớn các session kể từ tháng 10, qua Remote Control |
Với tôi thì là terminal, và không phải vì trung thành gì. tmux, thứ mà điện thoại của tôi kết nối vào, cần có terminal, và channels cũng vậy: đây là tính năng đẩy các sự kiện từ bên ngoài vào một session, và tài liệu xếp nó vào nhóm tính năng của CLI.
Nhiều người cũng hỏi Claude Code có cần git không. CLI thì không: thư mục home của tôi không phải là repository, và 208 prompt của tôi được gửi tới các session khởi động ở đó. Tài liệu của ứng dụng desktop nói git là bắt buộc cho cơ chế cô lập session (session isolation), trong đó mỗi session có worktree riêng, còn muốn kéo một session trên cloud về terminal thì cần một bản checkout của cùng repository đó. Bản thân tôi chưa bao giờ gặp thông báo “Git is required for local sessions”. Session desktop gần nhất của tôi, vào ngày 20/10, chạy trong một thư mục hoàn toàn không phải repository.
Các chế độ cấp quyền, và chế độ tôi thật sự dùng#
Chế độ cấp quyền (permission mode) quyết định Claude Code dừng lại hỏi bạn thường xuyên đến đâu, và Shift+Tab chuyển vòng qua các chế độ. Manual (default) hỏi trước hầu hết các thao tác sửa tệp, chạy lệnh hoặc truy cập mạng. acceptEdits cho các thao tác sửa tệp và các lệnh hệ thống tệp thông dụng đi qua. plan chỉ đọc và đề xuất, không sửa gì. auto dùng một mô hình thứ hai, một bộ phân loại (classifier), để chặn các thao tác rủi ro thay vì hỏi bạn. bypassPermissions gần như không hỏi gì cả. Từ phiên bản 2.1.283, một session trong terminal sẽ khởi động ở chế độ auto trừ khi bạn chỉ định khác.
Vậy nên câu trả lời thật lòng của tôi cho câu hỏi “làm sao để chạy Claude Code mà nó không xin quyền” là tôi khởi động nó như thế này:
claude --dangerously-skip-permissions62 trong số 69 lệnh claude trong lịch sử shell của tôi có cờ đó, và cả năm session đang chạy lúc này cũng vậy. Trong 1,266 prompt tôi gõ từ ngày 28/8 đến 21/10, 1,179 prompt đi vào các session ở chế độ bypass, 82 prompt ở chế độ auto và năm prompt ở chế độ Manual hoặc accept-edits.
Tài liệu nói rõ chế độ bypass dành cho “các môi trường được cô lập như container, máy ảo (VM) hoặc dev container không có kết nối internet, nơi Claude Code không thể gây hại cho hệ thống host của bạn”. Laptop của tôi không thuộc loại nào trong số đó, và cài đặt của tôi còn ghi lại việc tôi đã bấm cho qua cảnh báo ấy ("skipDangerousModePermissionPrompt": true). Nếu bạn cũng làm vậy, hãy biết rằng các quy tắc allow không có tác dụng gì trong chế độ bypass, nên trong các session hằng ngày của tôi, 378 quy tắc allow rải rác trên 19 tệp cài đặt hoàn toàn chẳng làm gì cả. Các quy tắc deny và ask thì vẫn có hiệu lực, và tôi không có quy tắc nào thuộc hai loại đó.
Ngoại lệ là session phải đọc những gì người khác viết. Launcher của nó không truyền cờ đó, nên nó khởi động ở chế độ auto. Toàn bộ 27 sự kiện production và 42 trong 43 tin nhắn chat tới được một session trong khoảng từ ngày 12 đến 20/10 đều đến khi session đang ở chế độ auto, không cái nào đến lúc ở chế độ bypass.
Thứ thật sự giữ cho chế độ bypass không quay lại cắn tôi là vài thói quen, được ghi vào bộ nhớ (memory) của Claude sau khi mọi chuyện đã hỏng. Ngày 10/9, khi nhiều session cùng làm việc trên cùng một bản checkout của ứng dụng chợ, một bản sửa chỉ một dòng sống sót qua bốn lần build thất bại rồi biến mất trước khi kịp commit: một session khác đã ghi đè lên tệp đó, và git không có bản ghi nào về nó. Cũng hôm đó, một lần triển khai (deploy) suýt nữa đưa lên production phần việc chưa commit của một session, vì script triển khai build từ working tree chứ không phải từ HEAD. Các quy tắc từ đó đến giờ: commit một bản sửa nhỏ ngay khi nó chạy được, stage tệp theo tên và không bao giờ dùng git add -A, xem git status để tìm những thay đổi không phải do mình làm, và khi main đang chứa phần việc chưa triển khai của các session khác thì triển khai từ một worktree đặt ở đúng commit đang chạy thật.
Truy cập từ điện thoại#
Có ba lối vào, và mỗi lối dẫn tới một thứ khác nhau.
| Lối vào | Những gì tôi có trên điện thoại | Chạy nhờ vào đâu |
|---|---|---|
| Remote Control, trong ứng dụng Claude | cuộc hội thoại của một session: gõ prompt, trả lời câu hỏi của nó, đính kèm ảnh | remoteControlAtStartup: true, cộng thông báo đẩy (push notification) |
SSH vào main, từ một ứng dụng SSH trên điện thoại | chính terminal, mọi cửa sổ | một mạng riêng, một sshd chạy dưới user của tôi, và một alias ngắn để attach |
| Một bot chat | một session nghe các lỗi production và trả lời tin nhắn | một plugin channel chính thức của Claude Code và một event channel do tôi tự viết |
Remote Control kết nối ứng dụng Claude trên điện thoại, hoặc claude.ai/code trên trình duyệt, tới một session vẫn tiếp tục chạy trên laptop, kèm đầy đủ tệp, công cụ và các MCP server. Tôi đã gõ /rc 26 lần từ ngày 13/9 đến 20/10. Giờ thì remoteControlAtStartup đã bật và các session mới tự kết nối: từ đầu tháng 10, 67 trong 77 session tôi khởi động có link Remote Control, so với 3 trên 52 trong nửa cuối tháng 9. Khi bật agentPushNotifEnabled, Claude có thể gửi thông báo đẩy khi nó thấy cần, mà theo tài liệu thì thường là khi một tác vụ dài đã xong hoặc khi nó cần bạn ra quyết định. Tính năng này cần gói đăng ký claude.ai chứ không phải API key, và vì session chạy trên laptop nên laptop phải luôn thức. Từ ngày 15/10, máy tôi không ngủ kể cả khi gập nắp (sudo pmset -a disablesleep 1).
Chiều ngược lại cũng được. /teleport, hoặc claude --teleport, kéo một session trên cloud đã được khởi động trên web hoặc trong ứng dụng về terminal, kèm theo branch và cuộc hội thoại của nó. Tôi đã làm vậy hai lần, cả hai đều vào tháng 7.
SSH là để dùng khi tôi muốn chính cái terminal. Điện thoại truy cập laptop qua mạng riêng trong bài về mạng riêng của tôi, và một alias gắn nó vào main, nên tôi có thể vuốt qua lại giữa các cửa sổ đã để sẵn trên laptop. Để chiếc Mac trả lời đúng cách cho các ứng dụng trên điện thoại, tôi đã phải sửa bốn chỗ riêng biệt, và chỗ quan trọng với Claude Code là tmux tuyệt đối không được tự khởi động: một ứng dụng mở session để chạy docker ps đã nhận về 72 KB dữ liệu vẽ lại màn hình thay vì kết quả lệnh.
Bot chat dành cho session mà tôi không muốn ngồi canh. Từ ngày 12/10, một session chạy cùng một channel nhỏ do tôi viết, cứ mỗi phút kiểm tra máy chủ của ứng dụng một lần để tìm lỗi production mới và hoạt động mới trên bảng quản lý dự án rồi chuyển chúng cho session, cộng thêm một trong các plugin chat chính thức, để hai người chúng tôi có tên trong danh sách cho phép (allowlist) của nó có thể nhắn tin cho nó. Lệnh khởi động trông như thế này, với các tên đã được đổi thành tên chung chung:
exec claude \
--channels plugin:<chat-plugin>@claude-plugins-official \
--dangerously-load-development-channels server:my-events "$@"Một script giám sát (supervisor) giữ cho nó chạy liên tục bên trong tmux. Sau mỗi lần khởi động lại, nó tiếp tục đúng cuộc hội thoại cũ, nên session làm tiếp chứ không tỉnh dậy với đầu óc trống trơn, và script báo mọi lần khởi động lại lên kênh chat. Session này sửa lỗi trong working tree và dừng ở đó, với một ngoại lệ tôi thêm vào ngày 13/10: một lỗi đang thật sự ảnh hưởng tới người dùng trên production thì nó được phép sửa, kiểm thử, commit và triển khai, rồi báo cho chúng tôi biết nó đã làm gì.
Skill, memory và /goal#
Không có khóa hooks nào trong các tệp cài đặt của tôi. Thứ gần nhất là /goal, tôi đã dùng 279 lần kể từ ngày 11/7. Nó nhận một điều kiện và thiết lập một Stop hook cho session, mà theo lời Claude Code là “sẽ chặn việc dừng lại cho đến khi điều kiện được thỏa mãn”. Các goal của tôi viết y như cách tôi nói thành lời. Một goal thật từ tháng 7, giữ nguyên cả lỗi chính tả, bảo nó rằng bản build “still broken, try a deeper fix and dont stop until” (vẫn hỏng, thử sửa sâu hơn và đừng dừng cho tới khi) nó tới tay người kiểm thử. Muốn kiểm tra một lượt chạy dài mà không làm nó chệch hướng thì có /btw, một câu hỏi bên lề không lọt vào cuộc hội thoại chính. Câu của tôi phần lớn là một biến thể nào đó của “hows it going?” (sao rồi?).
Skill chứa những thứ mà nếu không có thì lần nào tôi cũng phải giải thích lại. Một skill ở cấp người dùng (user-level) đọc báo cáo từ khóa hằng tuần cho các trang web tôi đang lo, trong đó có blog này, rồi áp dụng vào tiêu đề, mô tả và tag. Những câu hỏi mà bài này trả lời đến từ báo cáo của nó cho blog này, ngày 18/10, và tệp skill được quản lý phiên bản trong một repo, nằm cạnh phần code của nó. Repo của ứng dụng chợ có skill riêng: một skill khởi động API trong Docker và chạy smoke test, một skill làm việc với bảng quản lý dự án, và một skill kê khai chi phí cho công ty. Hai plugin tôi đang cài là một plugin language server cho Swift và plugin chat kia.
Memory là nơi lưu các bài học. Tôi có 160 tệp memory trên 17 dự án, 83 tệp trong số đó dành cho ứng dụng chợ, và nhiều tệp kể về một thứ từng bị hỏng. CLAUDE.md của ứng dụng giờ dài gấp khoảng sáu lần so với hồi tháng 6. CLAUDE.md của blog này là một tệp rỗng; còn một bài viết nên có giọng văn thế nào thì nằm trong một tệp memory.
Với những việc lớn hơn, Claude khởi động các subagent, 120 lần trong các session chính của tôi, 40 lần trong số đó là bản fork của cuộc hội thoại. Đó là cách blog này có các phiên bản tiếng Nhật, tiếng Hàn, tiếng Trung và tiếng Việt. Ngày 19 và 20/10, đợt thiết kế lại phần cộng đồng của ứng dụng đã đi qua công cụ Workflow bốn lần: một lượt rà soát (audit) qua bảy góc nhìn cùng một người phản biện (critic), xác nhận khoảng 58 phát hiện; các bản sửa do năm nhóm thực hiện, mỗi nhóm phụ trách các tệp riêng của mình và đều được review; một lượt xử lý những phần còn sót; và một lần kiểm tra độc lập rằng mọi phát hiện đều đã được sửa. Bản thiết kế mới được phát hành vào ngày 20.
devbox nằm ở đâu trong chuyện này#
Bài về mạng riêng của tôi kể về việc dồn phần việc nặng sang devbox, máy trạm có GPU ở văn phòng, và truy cập nó từ bất cứ đâu. Phần lớn việc truy cập đó là do Claude Code làm. Từ ngày 24/9 đến 19/10, 21 session trên laptop đã chạy 1,470 lệnh trên devbox qua ssh thông thường: kubectl vào cụm Kubernetes chạy trên đó, psql bên trong một pod cơ sở dữ liệu, tmux capture-pane để xem một tác vụ dài đang tiến triển ra sao. Vì ssh devbox tự chuyển sang một tunnel khi không ở trong mạng văn phòng, cùng một session chạy được ở văn phòng, ở nhà hay ở quán cà phê. Và vì laptop không còn ngủ nữa, một session có thể tiếp tục điều khiển devbox trong khi tôi xem nó từ điện thoại.
Claude Code hay Codex?#
Dựa trên trải nghiệm của chính mình, tôi không thể nói với bạn Claude Code có tốt hơn Codex hay không, và bảng dưới đây cho thấy lý do:
| Codex | Claude Code | |
|---|---|---|
| Thời gian | từ 29/11 đến 4/12/2025 | ít nhất từ tháng 11/2025; lịch sử prompt từ tháng 2/2026 |
| Ở đâu | extension VS Code | terminal (128 session), ứng dụng desktop (2) |
| Mô hình và effort | gpt-5.1-codex, medium | Opus 5.5, high |
| Phê duyệt | sandbox workspace-write, tắt mạng, hỏi theo yêu cầu (on request) | bypass trong 93% số prompt, auto cho session chat |
| Mức độ sử dụng | 4 thread | 7,323 prompt kể từ tháng 2 |
| Ghi chú dự án | đọc AGENTS.md | đọc CLAUDE.md, cộng các tệp memory |
Bốn thread trong một tuần, về một câu hỏi liên quan đến hình ảnh, hai thay đổi cho một website và một cảnh 3D, là một lần dùng thử, không phải một phép so sánh. Nhưng có một chi tiết từ đó áp dụng được cho mọi lần chuyển giữa các agent. Dự án 3D giữ các quy tắc của nó trong một tệp claude.md, và câu đầu tiên tôi hỏi Codex ở đó là nó có đọc các tệp của Claude trước khi bắt đầu cuộc hội thoại không. Nó nói là không, và nó chỉ nắm được quy tắc của dự án khi tôi bảo nó đọc tệp đó. Dù bạn chuyển sang agent nào, tệp hướng dẫn sẽ bị bỏ lại phía sau trừ khi bạn tự mang nó theo. Từ đó đến nay tôi chưa mở thread Codex nào. Extension vẫn được nạp trong VS Code vào vài ngày trong khoảng từ 24/9 đến 4/10 mà tôi không hề bắt đầu thread nào, và giờ nó đã được gỡ cài đặt.
Vậy nên kết luận mà tôi dám đứng ra bảo đảm khá hẹp. Claude Code là thứ mà toàn bộ cách thiết lập của tôi xoay quanh, và tôi chưa quay lại xem bây giờ Codex xử lý những việc tương tự ra sao.
Một con số cuối cùng nói về cách tôi dùng nó nhiều hơn mọi thứ ở trên. Trong các session chính trên laptop kể từ cuối tháng 8, Claude Code đã chạy 18,311 lệnh shell và đọc, ghi hoặc sửa tệp 2,331 lần. Tính theo số lượng, phần lớn công việc của nó là chạy những lệnh mà lẽ ra tôi phải tự gõ, trên laptop và qua SSH, từ bất cứ nơi nào tôi đang ở. Còn khi nó thật sự viết code, thứ code đó không phải ở đâu cũng được chào đón, và đó là một câu chuyện riêng trong bài về pyhtml2text.
