Cấu trúc thư mục .claude/ cho dự án Claude Code: từ nhỏ đến lớn

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

Vấn đề: Claude “không nhớ” gì giữa các phiên làm việc

Mình bắt đầu dùng Claude Code cho dự án Python khoảng 3 tháng trước. Ban đầu cứ mỗi lần mở terminal lên là lại phải giải thích lại: “project này dùng FastAPI, database là PostgreSQL, convention đặt tên theo snake_case, đừng tạo file test riêng…” Mệt mỏi thật sự.

Sau vài tuần vật lộn, mình mới nhận ra mình đang bỏ qua hoàn toàn thư mục .claude/ — thứ được thiết kế chính xác để giải quyết bài toán này.

Triệu chứng điển hình khi chưa cấu hình .claude/ đúng cách:

  • Phải nhắc Claude cùng một quy tắc code style mỗi ngày
  • Claude đề xuất cài thêm thư viện mà project đã có sẵn
  • Mỗi thành viên trong team dùng Claude theo cách khác nhau, output không nhất quán
  • Claude không biết test chạy bằng lệnh gì, build ra sao

Nguyên nhân: Claude Code hoạt động theo context, không có “long-term memory” mặc định

Claude Code không tự động ghi nhớ các cuộc hội thoại trước. Mỗi phiên làm việc là trang giấy trắng. Khác với engineer mới vào team — họ có thể đọc README, hỏi đồng nghiệp, dần dần hiểu project. Claude cần được “brief” có cấu trúc ngay từ đầu mỗi phiên.

Khi khởi động trong một thư mục, Claude Code tự động đọc các file cấu hình theo thứ tự ưu tiên: CLAUDE.md ở home → CLAUDE.md ở root project → các file trong .claude/. Toàn bộ “bộ nhớ dài hạn” đó — từ quy tắc code đến lệnh tắt hay dùng — nằm hết ở đây.

Cấu trúc .claude/ từ đơn giản đến phức tạp

Cấp độ 1: Dự án cá nhân (solo)

Với dự án một người, chỉ cần file CLAUDE.md ở root là đủ. Claude đọc file này đầu tiên, tự động, không cần nhắc.

# Cấu trúc tối thiểu
my-project/
├── CLAUDE.md          ← File chính, Claude đọc tự động
├── src/
└── ...

Nội dung CLAUDE.md cho dự án nhỏ:

# Project Context

## Stack
- Python 3.11, FastAPI, SQLAlchemy 2.0
- PostgreSQL (local: localhost:5432/mydb)
- Alembic cho migrations

## Quy ước
- Tên biến/hàm: snake_case
- Tên class: PascalCase
- Không dùng `print()` — dùng `logging` module
- Mọi API endpoint phải có type hint đầy đủ

## Lệnh hay dùng
- Chạy dev server: `uvicorn app.main:app --reload`
- Chạy test: `pytest tests/ -v`
- Tạo migration: `alembic revision --autogenerate -m "mô tả"`

Ngắn gọn nhưng đủ để Claude không đề xuất sai stack hay sinh code ngoài convention.

Cấp độ 2: Dự án vừa (có thêm settings và commands)

Project phức tạp hơn đòi hỏi thêm settings.json để kiểm soát hành vi Claude, và thư mục commands/ để lưu slash command tùy chỉnh.

# Cấu trúc cấp 2
my-project/
├── CLAUDE.md
├── .claude/
│   ├── settings.json      ← Cấu hình permissions, hooks
│   └── commands/
│       ├── review.md      ← /project:review
│       └── deploy.md      ← /project:deploy

File .claude/settings.json cho phép bạn giới hạn những gì Claude được phép thực thi:

{
  "permissions": {
    "allow": [
      "Bash(git:*)",
      "Bash(pytest:*)",
      "Bash(uvicorn:*)"
    ],
    "deny": [
      "Bash(rm -rf:*)",
      "Bash(sudo:*)"
    ]
  }
}

Custom command trong .claude/commands/review.md:

---
description: Review code thay đổi trước khi commit
---

Hãy review các thay đổi trong `git diff HEAD` với các tiêu chí:
1. Có vi phạm convention đặt tên không?
2. Thiếu error handling ở đâu?
3. Có query N+1 nào không?
4. Type hints đầy đủ chưa?

Chỉ báo lỗi thực sự, đừng đề xuất refactor không cần thiết.

Gọi bằng /project:review trong Claude Code — không cần gõ lại toàn bộ yêu cầu mỗi lần.

Cấp độ 3: Dự án team (đa môi trường, đa thành viên)

Đây là cấp độ mình thấy nhiều team bỏ qua nhất, dẫn đến Claude cho output không đồng nhất giữa các dev.

# Cấu trúc team-scale
my-project/
├── CLAUDE.md                  ← Context chung cho cả team (commit vào git)
├── .claude/
│   ├── settings.json          ← Permissions shared (commit vào git)
│   ├── settings.local.json    ← Override cá nhân (thêm vào .gitignore)
│   └── commands/
│       ├── review.md
│       ├── test.md
│       ├── migration.md
│       └── deploy-staging.md

Điểm mấu chốt: settings.json commit lên git để cả team dùng chung. settings.local.json cho phép mỗi người override theo máy cá nhân — API key riêng, path riêng — mà không đụng đến người khác.

# Thêm vào .gitignore
.claude/settings.local.json
.claude/memory/    # Nếu dùng auto memory

CLAUDE.md cho team nên có thêm phần onboarding rõ ràng:

# Project: E-commerce Platform

## Kiến trúc tổng quan
- Backend: FastAPI (port 8000)
- Frontend: Next.js (port 3000)  
- Database: PostgreSQL + Redis
- Message queue: RabbitMQ

## Quy tắc QUAN TRỌNG
- KHÔNG tự ý thay đổi schema database — luôn tạo migration
- KHÔNG hardcode credentials — dùng environment variables
- Mọi endpoint mới phải có integration test
- PR phải pass CI trước khi merge

## Môi trường
- Dev: `docker-compose up -d`
- Test: `pytest tests/ --cov=app --cov-report=term`
- Staging deploy: `/project:deploy-staging`

## Liên hệ
- DB schema questions: hỏi @dbteam trên Slack
- Infrastructure: xem docs tại docs/infrastructure.md

Cách tốt nhất: Xây dựng .claude/ theo từng giai đoạn

Setup full structure ngay từ đầu không phải ý hay — vừa mất thời gian vừa không biết mình thật sự cần gì. Tốt hơn là làm theo thứ tự này:

  1. Tuần 1: Tạo CLAUDE.md với stack và 3-5 quy tắc quan trọng nhất. Chỉ vậy thôi.
  2. Sau 2-3 tuần: Chú ý những gì bạn hay nhắc Claude lặp đi lặp lại → thêm vào CLAUDE.md.
  3. Khi có pattern hay dùng: Tạo custom command thay vì gõ tay mỗi lần.
  4. Khi team join: Tách settings.local.json, thêm phần onboarding vào CLAUDE.md.

Một mẹo nhỏ mình hay dùng: sau mỗi sprint, dành 10 phút xem lại những gì Claude làm sai hoặc cần nhắc nhiều lần, rồi update CLAUDE.md luôn. File này nên được coi là “living document” như README — nó cũ đi thì Claude cũng tệ đi theo.

Kiểm tra .claude/ có hoạt động không

# Kiểm tra Claude đọc được CLAUDE.md chưa
# Hỏi thẳng trong Claude Code:
"Dự án này dùng stack gì? Lệnh chạy test là gì?"

# Nếu Claude trả lời đúng → CLAUDE.md đã được đọc
# Nếu Claude không biết → kiểm tra vị trí file và encoding (phải là UTF-8)

Những lỗi thường gặp

  • CLAUDE.md quá dài: File 500+ dòng Claude vẫn đọc được, nhưng context bị loãng — thông tin quan trọng chìm xuống dưới. Ưu tiên đẩy lên đầu.
  • Dùng ngôn ngữ mơ hồ: “Viết code sạch” không có tác dụng. Thay bằng “Tối đa 50 dòng per function, mỗi function chỉ làm 1 việc”.
  • Quên thêm vào .gitignore: settings.local.json chứa thông tin cá nhân — commit lên là lộ.
  • Không version control CLAUDE.md: File này thay đổi theo project. Track history như code bình thường đi.

Kết quả thực tế

Sau khi setup .claude/ đúng cách, thời gian “brief” Claude giảm từ 5-10 phút mỗi phiên xuống còn gần như 0. Output nhất quán hơn hẳn — ít phải sửa lại vì sai convention, Claude cũng ít đề xuất những thứ vô nghĩa với context dự án.

Thư mục .claude/ nhỏ thôi — đôi khi chỉ là 1 file markdown vài chục dòng. Nhưng chính cái file đó quyết định Claude Code là công cụ thật sự hữu ích hay chỉ là chatbot cần canh chừng liên tục.

Share: