Viết CLAUDE.md như một bản hiến pháp: cấm kỵ, quy tắc hành vi, quyết định mặc định. 92 commits trong 5 ngày, không lệch hướng.
Trong 5 ngày tôi đã đẩy 92 commit và đưa một sản phẩm lên production (github.com/defi-io/smarts). Không sự cố, không rollback, không refactor lớn. Lý do không phải là Claude thiên tài. Lý do là tệp CLAUDE.md 565 dòng nằm ở thư mục gốc của dự án.
Bài này nói về cách viết một CLAUDE.md hoạt động như một bản hiến pháp, và chuyện gì xảy ra sau đó.
Nhiều người viết CLAUDE.md giống README — dự án là gì, chạy thế nào. Đó là lãng phí.
README dành cho con người. CLAUDE.md dành cho Claude. Claude tự động nạp nó ở đầu mỗi session. Nghĩa là từng dòng bạn viết trong đó trở thành điều kiện tiên quyết cho mọi quyết định Claude đưa ra sau đó.
Viết kiểu README, bạn có: Claude biết đại khái dự án là gì, biết chạy test, nhưng mọi quyết định kỹ thuật đều bắt đầu từ con số 0.
Viết kiểu hiến pháp, bạn có: Claude biết những con đường nào bị chặn, quy ước nào bắt buộc, ngã rẽ nào nên mặc định đi đường nào, khi nào phải dừng và hỏi.
Khác biệt: kiểu thứ nhất sẽ "nhân tiện" kéo thêm một dependency mới, thêm một lớp trừu tượng, sửa Gemfile. Kiểu thứ hai thì không.
Dự án tôi đang làm gần đây tên là smarts.md — một nền tảng tạo live docs và máy chủ MCP cho smart contract. CLAUDE.md của nó dài 565 dòng, chia thành các phần:
1. Định danh dự án (5 dòng)
2. Cốt lõi sản phẩm (định nghĩa một câu + khác biệt cấu trúc với đối thủ)
3. Tech stack (ràng buộc cứng, định dạng YAML)
4. Danh sách cấm (mục ❌ rõ ràng)
5. Phạm vi hỗ trợ (biên cứng của MVP)
6. Kiến trúc (kèm sơ đồ ASCII)
7. Cấu trúc thư mục (trách nhiệm từng tệp)
8. Quy ước code Ruby (kèm đoạn nên/không nên)
9. Chiến lược cache (dạng bảng)
10. Yêu cầu test
11. Chi tiết deploy
12. Quy trình Git
13. Quy ước dùng Claude Code (chỉ thị hành vi)
14. Cột mốc 90 ngày
15. Nguyên tắc cốt lõi
Không phần nào là trang trí. Dưới đây tôi chọn vài phần và giải thích vì sao viết như vậy.
Của tôi trông như thế này:
❌ Không thêm dịch vụ TypeScript / Node.js
❌ Không thêm ethers.js / web3.js
❌ Không thêm Sidekiq (dùng Solid Queue)
❌ Không thêm React / Vue / Svelte (dùng Hotwire)
❌ Không thêm Redis (Solid Cache / Solid Queue / Solid Cable bao trọn)
❌ Không xử lý hợp đồng chưa verified (chỉ nhận đã verified trên Etherscan)
❌ Không xử lý Solana / Bitcoin / Move (chỉ EVM)
Đây là dự án Web3. Mặc định của giới Web3 là TypeScript + ethers.js + Redis + React. Tôi đi ngược lại. Tôi có lý do của mình, nhưng Claude không biết. Thiếu danh sách cấm, Claude sẽ đề xuất dựa trên "cảm thức ngành" chôn trong dữ liệu huấn luyện — gần như chắc chắn là hướng TypeScript.
Có danh sách cấm rồi, Claude không còn hỏi "thêm một service Node để chạy web3.js nhé?". Con đường đó đã đóng theo mặc định.
Mấu chốt: từng mục phải rõ ràng và tuyệt đối. Đừng viết "cố gắng tránh TypeScript". Hãy viết "không thêm TypeScript". Mọi thứ mơ hồ Claude sẽ đọc là có thể thương lượng.
Khối lớn cuối của CLAUDE.md là "Quy ước dùng Claude Code":
### Khi tôi nói "bắt đầu làm X"
1. Trước tiên kiểm tra xem ràng buộc CLAUDE.md có cho phép cách này không
2. Sau đó kiểm tra trong code đã có triển khai liên quan chưa (đừng phát minh lại)
3. Trước khi viết code, mở một branch mới
4. Sau khi triển khai xong, chạy test
5. Không tự động commit — khi code đã viết và test xanh, hãy dừng và báo cáo.
Đợi tôi nói rõ "commit" mới commit
### Khi tôi nói "tôi có một ý tưởng"
Đừng viết code ngay. Trước tiên:
1. Xác nhận hiểu đúng (paraphrase lại)
2. Đánh giá so với ràng buộc CLAUDE.md
3. Chỉ ra vấn đề tiềm ẩn hoặc phương án tốt hơn
4. Đợi tôi xác nhận rồi mới hành động
### Khi gặp ngã rẽ kỹ thuật
Khi CLAUDE.md không quy định rõ:
1. Mặc định chọn phương án "Rails-native hơn"
2. Mặc định chọn phương án "ít dependency hơn"
3. Mặc định chọn phương án "giúp solo dev iterate nhanh hơn"
4. Phân vân thì dừng và hỏi
Phần này quan trọng gấp mười lần "đặt tên kiểu snake_case".
Phong cách code Claude đọc code là học được. Nhưng "khi nào dừng và hỏi", "nghe 'tôi có ý tưởng' thì paraphrase trước khi viết code" — đây là khuôn mẫu hành vi. Chỉ đọc code không học được.
Dòng quan trọng nhất: ngã rẽ thì mặc định đi hướng nào. Quy tắc duy nhất đó quyết định Claude làm gì khi bạn không có mặt (khi bạn chỉ nói "bắt đầu làm X" rồi đi). Viết rõ điều này, bạn mới dám buông tay cho nó làm.
Đầu CLAUDE.md có dòng:
Tài liệu này là "nguồn gốc" của dự án. Tự động nạp ở đầu mỗi session Claude Code. Khi đổi quyết định kỹ thuật, đổi tệp này trước; code đi theo sau.
Đây là một thỏa thuận quy trình. Khi tôi quyết đổi một lựa chọn kỹ thuật — ví dụ nâng model AI chính từ gpt-5-mini lên gpt-5 — bước đầu không phải sửa initializer. Bước đầu là sửa đoạn này trong CLAUDE.md:
ai:
fast: gpt-5-mini # trước
fast: gpt-5 # sau
Sau đó để Claude đọc lại CLAUDE.md và sửa code khớp.
Tại sao? Vì nếu bạn đổi giá trị trong code mà CLAUDE.md không theo kịp, lần sau Claude đọc CLAUDE.md thấy giá trị cũ và "tốt bụng" revert code của bạn. Gốc rễ xung đột là điểm thất bại đơn — CLAUDE.md lỗi nhịp. Hiến pháp lạc hậu so với hiện thực là cách nội chiến nổ ra.
Coi CLAUDE.md là hiến pháp nghĩa là: nó luôn chạy trước code.
smarts.md, 5 ngày, 92 commit:
Tuổi thọ trung bình mỗi PR: 30 phút. Không refactor lớn. Không "khoan, hướng đó sai, rollback".
Không phải vì Claude là phép thuật. Vì mỗi session nó đều chạy trên đường ray 565 dòng. Nó biết không được kéo TypeScript vào, biết Solid Queue là queue mặc định, biết hàm view cache 60 giây, biết mỗi service phải triển khai class method call, biết phải đợi tôi xác nhận trước khi commit.
Bóc đi một nửa số ràng buộc đó, bạn sẽ có: 30 phút mỗi ngày giải thích "sao mình không dùng X", 5 phút review dependency mà nó "tiện tay" thêm, và một Gemfile từ từ vỡ vụn.
Đừng bắt đầu từ tệp trắng. Bắt đầu từ quyết định gần nhất khiến bạn đau.
Nếu gần đây Claude "luôn kéo dependency mới", hãy viết danh sách cấm.
Nếu là "động tí là đổi kiến trúc", hãy viết sơ đồ kiến trúc + "thêm microservice, đổi DB, v.v. cần xác nhận".
Nếu là "không viết test", hãy viết "phần nào bắt buộc unit test".
Nếu là "commit quá hung hăng", hãy viết "không tự động git commit, đợi chỉ thị rõ ràng".
Mỗi lần đau, thêm một dòng. Phần khác tạm chưa viết.
Ba tháng sau bạn sẽ có một CLAUDE.md 500 dòng, mỗi dòng đứng sau là một "tôi không muốn nó làm thế nữa" cụ thể. Tài liệu đó hơn mọi template, vì nó được hiệu chỉnh chính xác cho dự án của bạn, quy trình của bạn, đội ngũ của bạn (dù chỉ một người).
Hiến pháp không được viết một lần. Nó kết tinh từ những xung đột cụ thể, lần lượt từng cái một.
Mã nguồn: github.com/defi-io/smarts