Bỏ qua để đến nội dung

Một CLAUDE.md thực sự được làm theo

Bài viết được dịch tự động từ bài viết gốc, chưa được kiểm tra lại bởi con người. Chỉ những bài viết có dấu tick xanh cạnh tiêu đề là đã được kiểm tra.

Đây là một cái bẫy bắt gần như ai cũng dính: file CLAUDE.md của bạn cứ phình to dần. Gặp vấn đề, bạn thêm một quy tắc. Gặp vấn đề khác, bạn thêm quy tắc khác. Chẳng mấy chốc bạn có một file khổng lồ, và Claude bắt đầu bỏ qua vài phần trong đó. Đó không phải lỗi của Claude. Đó là cách file này vận hành.

Điều quan trọng cần hiểu: CLAUDE.md không phải là cấu hình bắt buộc thực thi. Nó là chỉ dẫn (guidance). Mỗi dòng đều đang cạnh tranh sự chú ý của Claude với mọi dòng khác. File càng dài, nó càng cạnh tranh với chính nó, và Claude càng khó tuân theo bất kỳ quy tắc riêng lẻ nào một cách nhất quán. Vậy nên mục tiêu không phải là ghi lại mọi thứ. Mục tiêu là giữ file thật gọn. File càng tinh gọn, Claude càng thực sự làm theo được nhiều phần trong đó.

Trước tiên, hỏi xem CLAUDE.md có phải công cụ đúng không

Phần tiêu đề “Trước tiên, hỏi xem CLAUDE.md có phải công cụ đúng không”

Trước khi viết một quy tắc, hãy tự hỏi liệu nó có nên nằm trong CLAUDE.md hay không. Một số quy tắc chỉ là chỉ dẫn, một số khác là ranh giới cứng không bao giờ được vượt qua. Đó là hai việc khác nhau.

Lấy ví dụ quy tắc “không bao giờ push lên main”. Nếu bạn đặt nó trong CLAUDE.md, bạn đang hy vọng Claude đọc và tuân theo. Đa số thời gian nó sẽ làm đúng. Nhưng “đa số thời gian” là không đủ với một điều nguy hiểm như vậy. Một quy tắc cứng như thế nên nằm trong một pre-tool-use hook thay vì CLAUDE.md.

Sự khác biệt nằm ở chỗ: một hook là code chạy trước khi Claude thực hiện một hành động, và nó thực sự có thể chặn hành động đó. Vậy nên dù Claude có cố push lên main, hook sẽ chặn nó lại. Đó là sự thực thi thật sự, không phải một lời đề nghị lịch sự. Hãy chuyển các quy tắc cứng sang hooks, và để CLAUDE.md xử lý các quy ước mềm hơn.

CLAUDE.md không chỉ là một file nằm trong project của bạn. Có bốn nơi nó có thể tồn tại, và Claude nạp tất cả chúng cùng lúc khi khởi động. Không có gì bị bỏ sót, và chúng chồng lên nhau (stack).

Từng loại dùng cho việc gì:

  • Managed policy - file cấp tổ chức do đội platform kiểm soát. Bạn không thể loại trừ nó, nên chính sách tổ chức luôn có hiệu lực.
  • User - sở thích cá nhân của bạn, đi theo bạn qua mọi project trên máy.
  • Project - file dùng chung với team, được check vào repo.
  • Local - bị git bỏ qua (ignored). Ghi chú cá nhân của bạn, chỉ dành cho repo này.

File cuối cùng, local, rất dễ bị bỏ quên nhưng thực sự tiện. Giả sử bạn đang refactor trên một nhánh riêng và muốn Claude ghi nhớ vài quyết định kiến trúc trong lúc làm việc. Điều đó không nên nằm trong file project dùng chung, nơi sẽ ảnh hưởng tới cả team. Nó thuộc về local, nơi chỉ dành riêng cho bạn với repo này.

Khi file project của bạn bắt đầu dài ra, bạn có thể chia nó thành nhiều phần bằng cú pháp import theo đường dẫn file. Thay vì một khối văn bản khổng lồ, bạn trỏ tới các file khác:

@.claude/conventions/code-style.md
@.claude/conventions/testing.md
@.claude/conventions/workflow.md

Cách này rất tốt để tổ chức nội dung. Nhưng hãy hiểu chính xác nó mang lại điều gì, vì rất dễ hiểu lầm. Khi Claude khởi động, nó mở rộng (expand) các file import ngay tại chỗ bạn tham chiếu tới. Vậy nên import giúp bạn giữ mọi thứ gọn gàng, nhưng toàn bộ nội dung vẫn được nạp ngay từ đầu. Chúng không làm giảm lượng ngữ cảnh Claude phải đọc. Hãy dùng import để tổ chức, chứ không phải để giảm tải.

Cách diễn đạt là thứ khiến quy tắc thực sự có hiệu lực

Phần tiêu đề “Cách diễn đạt là thứ khiến quy tắc thực sự có hiệu lực”

Một khi bạn đã quyết định một quy tắc thuộc về CLAUDE.md, việc Claude có thực sự tuân theo hay không phụ thuộc vào cách bạn diễn đạt nó. Đa số quy tắc thất bại vì chúng mơ hồ. Đây là cách khắc phục.

Đừng viết “tuân theo best practice”. Bản thân bạn có biết chính xác điều đó nghĩa là gì không? Nếu bạn không kiểm chứng được liệu nó có được tuân theo hay không, Claude cũng vậy. So sánh hai cách viết:

  • Mơ hồ: “Follow best practices for API routes.”
  • Cụ thể: “Put new API routes in src/api/handlers, one per file.”

Cách thứ hai rõ ràng. Bạn có thể nhìn kết quả và biết ngay nó có được làm đúng hay không. Đó là chuẩn mà mọi quy tắc nên đạt tới.

Khi bảo Claude không được làm gì đó, hãy nói luôn nó nên làm gì thay thế. Nếu không, bạn đang để ngỏ cánh cửa.

  • Bỏ ngỏ: “Don’t use default exports.” Được, nhưng vậy thì dùng gì?
  • Rõ ràng: “Use named exports, not default exports.”

Cách thứ hai nêu rõ cái thay thế, nên không còn gì để hiểu sai.

Những từ như “IMPORTANT” và “YOU MUST” thực sự nâng mức ưu tiên của một quy tắc. Nhưng chỉ nâng tương đối so với mọi thứ nhỏ nhẹ xung quanh nó. Nếu quy tắc nào cũng hét lên, thì không có gì nổi bật cả, và việc nhấn mạnh trở nên vô nghĩa. Vậy nên hãy coi việc nhấn mạnh như một khoản ngân sách. Chi nó cho hai, ba quy tắc thực sự gây đau đớn khi bị phá vỡ, và để phần còn lại ở mức âm lượng bình thường.

File CLAUDE.md của bạn không bao giờ “hoàn thiện”. Hãy đối xử với nó như code đang sống, luôn được chỉnh sửa.

Khi Claude làm sai điều gì đó, đừng chỉ thở dài rồi tự tay sửa. Hãy coi đó như một báo cáo lỗi (bug report) nhắm vào file CLAUDE.md của bạn. Bạn thậm chí có thể nói thẳng với Claude: “add that to the CLAUDE.md file”, và nó sẽ tự viết quy tắc đó cho bạn. Nhờ vậy, file này sẽ tốt hơn mỗi khi có gì đó sai sót.

Hãy đối xử với CLAUDE.md như code sẽ chạy trong production. Nếu bạn không thể biện minh cho một dòng, hãy xóa nó. Để giữ file gọn và dễ tuân theo:

  1. Chuyển các quy tắc cứng sang hooks, nơi chúng thực sự được thực thi.
  2. Tổ chức các file dài bằng import (nhớ rằng chúng không làm giảm ngữ cảnh).
  3. Làm cho mỗi quy tắc cụ thể và kiểm chứng được, và nêu rõ cái thay thế.
  4. Chi “ngân sách nhấn mạnh” của bạn cho vài quy tắc quan trọng nhất.
  5. Luôn cập nhật file mỗi khi Claude làm sai điều gì đó.

Ý tưởng cốt lõi rất đơn giản: file càng tinh gọn, Claude càng làm theo được nhiều hơn.

Xem thêm: Bộ nhớ với CLAUDE.md