0

Cách quản lý context và memory trong Claude Code khi làm việc với dự án lớn

Mình là Tony, hiện làm và vận hành các sản phẩm web, với Claude Code là công cụ phát triển chính trong công việc hằng ngày. Khi một task kéo dài qua nhiều phiên, Claude có thể đề xuất lại phương án đã bị loại bỏ hoặc tiếp tục dựa trên quyết định không còn đúng. Bạn đã thống nhất cách thiết kế API, xử lý một phần migration và sửa frontend, nhưng sang phiên tiếp theo lại phải giải thích những gì đã làm.

Bài này thuộc series Claude Code cho dự án thực tế, gồm sáu bài dành cho developer muốn dùng Claude Code trên codebase thực tế thay vì chỉ thử các tính năng riêng lẻ. Mình viết cho người đang xử lý task kéo dài qua nhiều phiên, đặc biệt khi code và quyết định kiến trúc liên tục thay đổi. Đọc xong, bạn sẽ có cách phân loại context, memory và kiến thức dự án, cùng mẫu handoff và quy trình kiểm tra để tiếp tục công việc mà không phải tin tuyệt đối vào lịch sử hội thoại.

Mình dùng một monorepo TypeScript giả định với apps/admin là ứng dụng quản trị, apps/api phục vụ nhiều tổ chức khách hàng, packages/ui chứa các thành phần giao diện dùng chung và packages/shared chứa những định nghĩa chia sẻ. Dự án dùng pnpm, với lệnh test API là pnpm -F api test. Tình huống xuyên suốt bài là chuyển từ phân quyền tĩnh sang phân quyền theo tổ chức, ảnh hưởng đến database migration, API, frontend và test. API bắt buộc cách ly dữ liệu giữa các tenant, nên một quyết định permission scope sai có thể gây lỗi vượt xa phạm vi giao diện.

1. Context, memory và repository knowledge khác nhau thế nào?

Khi nói Claude Code quên thông tin, developer thường đang gộp nhiều nguồn khác nhau. Có thông tin nằm trong lịch sử hội thoại, có thông tin Claude lưu thành memory và có thông tin được team quản lý trong repository. Ba nhóm này khác nhau về vòng đời, cách được nạp và mức độ có thể kiểm chứng.

Session context là ngữ cảnh Claude đang sử dụng trong phiên, gồm lịch sử hội thoại và nội dung agent nhận khi đọc code, tài liệu hoặc kết quả công cụ. Toàn bộ lịch sử hội thoại được gửi lại trong mỗi request, nên phiên càng dài càng tiêu thụ nhiều context. Lệnh /context cho biết những gì đang chiếm context, còn /usage cho biết lượng token đang dùng.

Memory là những ghi chú Claude có thể giữ để sử dụng lại ở các phiên sau. Auto memory được lưu tại ~/.claude/projects/<project>/memory/, gồm MEMORY.md làm mục lục và các file theo chủ đề. Claude nạp 200 dòng đầu hoặc tối đa 25KB của MEMORY.md khi bắt đầu phiên, còn các file chủ đề được nạp khi cần. Bạn quản lý chế độ memory bằng /memory, nhưng memory không phải bản sao đầy đủ của lịch sử dự án.

Repository knowledge là kiến thức team chủ động quản lý cùng codebase, chẳng hạn CLAUDE.md, tài liệu kiến trúc, quyết định thiết kế và tiến độ task. Claude nạp CLAUDE.md đầu mỗi phiên, còn những tài liệu khác cần được đọc khi công việc yêu cầu. Quyết định được commit vào Git có thể được review và cập nhật cùng code. Auto memory nằm trên máy, không đồng bộ giữa các máy, dù các worktree thuộc cùng repository dùng chung memory.

Ba lớp thông tin khi làm việc với Claude Code

Mình dùng session context cho trao đổi đang diễn ra, memory cho những ghi chú có ích qua nhiều phiên và repository cho quyết định mà team cần chia sẻ. Nếu thay đổi ảnh hưởng đến quyền truy cập dữ liệu khách hàng, mình không chỉ nói với Claude trong hội thoại. Quyết định được ghi vào repository để các phiên sau có nguồn đối chiếu với code.

2. Tại sao phiên dài dễ mất tính nhất quán?

Một task lớn tạo ra nhiều thông tin trung gian: code được đọc, log test, phương án thử nghiệm và các lần sửa lỗi. Phần lớn thông tin chỉ hữu ích tại một thời điểm, nhưng vẫn nằm trong lịch sử hội thoại. Khi context gần chạm giới hạn, Claude Code có thể tự tóm tắt phần lịch sử cũ bằng auto-compaction.

Bạn cũng có thể gọi /compact, kèm chỉ dẫn như /compact Focus on code samples and API usage để định hướng nội dung cần giữ. Tuy nhiên, tóm tắt có thể bỏ qua chi tiết quan trọng hoặc giữ một quyết định đã lỗi thời. Ngay cả khi bản tóm tắt chứa đúng từ khóa, Claude vẫn có thể không biết quyết định nào đã thay thế quyết định nào.

Giả sử team ban đầu chọn permission scope theo role của người dùng. Sau đó, team phát hiện cùng một người có thể giữ role khác nhau ở hai tổ chức và chuyển sang kiểm tra quyền dựa trên organizationId cùng membership tương ứng. Nếu bản tóm tắt vẫn giữ phương án cũ, Claude có thể viết API kiểm tra role mà không ràng buộc organization. Khi đó, người dùng có nguy cơ truy cập dữ liệu ngoài phạm vi tenant được phép.

Để giảm context tiêu thụ, Claude Code mặc định chỉ nạp tên MCP tool và chỉ dẫn server cho tới khi sử dụng tool. Skill được nạp khi gọi, nên mình có thể chuyển hướng dẫn chuyên biệt từ CLAUDE.md sang skill thay vì giữ tất cả trong context nền. Những công việc tạo nhiều output như chạy test, đọc tài liệu hoặc xử lý log có thể giao cho subagent, chỉ đưa bản tóm tắt về phiên chính. Hooks cũng có thể lọc output trước khi Claude nhìn thấy, chẳng hạn chỉ giữ dòng lỗi của test.

Mình còn thêm mục Compact instructions trong CLAUDE.md khi cần Claude ưu tiên giữ một số thông tin lúc nén. Khi compaction diễn ra, Claude đọc lại CLAUDE.md ở gốc dự án từ đĩa, nhưng chỉ dẫn chỉ xuất hiện trong hội thoại có thể mất. Nén một context lớn cũng là một request lớn, nên mình không kéo dài phiên chỉ để compact vào cuối.

3. Phân loại thông tin theo thời hạn sử dụng

Quy ước đặt tên biến có thể tồn tại qua nhiều task, quyết định permission có thể ảnh hưởng đến nhiều phiên bản sản phẩm, còn kết quả test chỉ phản ánh một trạng thái code. Mình tách những thông tin này theo thời hạn sử dụng và người chịu trách nhiệm cập nhật. Cách phân loại dưới đây giúp agent biết nơi cần đọc khi bắt đầu một task.

Loại thông tin Ví dụ trong monorepo Nơi nên lưu
Quy ước lâu dài Dùng pnpm, vị trí package, nguyên tắc cách ly tenant CLAUDE.md
Quyết định kiến trúc Permission được đánh giá theo organization membership docs/architecture/decisions/
Yêu cầu task Chuyển hệ thống sang phân quyền theo tổ chức docs/tasks/reporting-export/brief.md
Tiến độ đang làm Migration xong, API đang sửa, frontend chưa hoàn tất progress.md
Bằng chứng kiểm tra Lệnh đã chạy, kết quả test, trường hợp chưa xác minh verification.md
Ghi nhớ cá nhân của agent Vị trí các module thường cần đọc Auto memory

Với quy ước lâu dài, CLAUDE.md phù hợp vì Claude đọc nó đầu mỗi phiên và tài liệu này nên giữ dưới 200 dòng. Mình ghi cách tổ chức monorepo, lệnh test chính và nguyên tắc cách ly tenant, nhưng không đưa nhật ký từng task vào đây. Hướng dẫn chuyên biệt có thể chuyển sang skill để tránh làm context nền phình ra. Bài Hướng dẫn viết CLAUDE.md để Claude Code hiểu đúng dự án của bạn giải thích kỹ hơn phần này.

Quyết định kiến trúc cần có bối cảnh, phương án được chấp nhận, ảnh hưởng lên các module và lý do thay thế phương án cũ. Nếu chỉ ghi “permission theo organization”, người đọc chưa biết các API đang dùng role tĩnh có cần migration hay không. Khi team đổi thiết kế, tài liệu phải thể hiện rõ quyết định nào còn hiệu lực.

Tiến độ task có thời hạn sử dụng ngắn hơn. Dòng “API tests passed” có thể đúng trước khi sửa middleware nhưng không còn giá trị sau thay đổi đó. Mình ghi trạng thái Git, phần chưa kiểm tra và bằng chứng test riêng để phiên tiếp theo không suy diễn từ kết quả cũ.

4. Thiết kế bản bàn giao giữa các phiên

Một task kéo dài cần bản bàn giao đủ để người tiếp nhận biết mục tiêu, trạng thái hiện tại, quyết định đang áp dụng và bước kiểm tra kế tiếp. Mình không chép toàn bộ hội thoại vì phần lớn nội dung là phân tích trung gian. Thay vào đó, handoff dẫn tới các file và bằng chứng có thể đối chiếu trong repository.

Mình đề xuất cấu trúc dưới đây cho task nhiều phiên. Đây là cách tổ chức tài liệu tham khảo, không phải cấu trúc mặc định của Claude Code. Claude không tự động đọc mọi file trong docs/, nên prompt đầu phiên cần chỉ rõ đường dẫn hoặc CLAUDE.md phải có hướng dẫn tương ứng.

docs/
  architecture/
    decisions/
      001-permission-scope.md
      002-organization-membership.md
  tasks/
    reporting-export/
      brief.md
      progress.md
      verification.md

Ở đây, reporting-export là task xuất báo cáo đang được triển khai cùng thay đổi phân quyền. API phải kiểm tra tenant trước khi truy vấn dữ liệu, kể cả khi frontend đã ẩn nút export với người không có quyền. Mình đặt quyết định kiến trúc ở thư mục chung để các task tham chiếu cùng một nguồn.

Trong brief.md, team ghi yêu cầu, phạm vi, điều kiện nghiệm thu và ràng buộc không được vi phạm. progress.md theo dõi những thay đổi đã thực hiện, quyết định hiện hành và phần còn dở. verification.md lưu lệnh kiểm tra, kết quả thực tế và những trường hợp chưa xác minh.

Mẫu progress.md:

# Handoff: Reporting Export

## Mục tiêu
Cho phép export báo cáo theo tổ chức.
API phải kiểm tra membership và permission
trong phạm vi organization của request.

## Trạng thái hiện tại
- Database migration: đã viết, chưa xác minh
  với dữ liệu migration từ schema cũ.
- API: đang sửa permission middleware.
- Admin: chưa cập nhật luồng hiển thị quyền.
- Tests: chưa chạy lại sau thay đổi middleware.

## Quyết định đang áp dụng
- Permission scope dựa trên organization membership.
- Quyết định hiện hành:
  docs/architecture/decisions/
  002-organization-membership.md
- Quyết định 001 đã bị thay thế.

## Các thay đổi đã thực hiện
- apps/api: thêm kiểm tra membership.
- packages/shared: cập nhật permission types.
- apps/admin: chưa sửa.

## Phần cần đối chiếu
- Git diff của middleware và permission types.
- Migration với dữ liệu role cũ.
- Tenant isolation cho API export.

## Bước tiếp theo
1. Đọc quyết định 002.
2. Đối chiếu code API với quyết định.
3. Kiểm tra migration.
4. Chạy pnpm -F api test.
5. Cập nhật verification.md.

## Trạng thái Git
- Commit nền: ghi SHA khi bàn giao.
- Thay đổi chưa commit: kiểm tra bằng git status.
- Kết quả test: xem verification.md.

Một bản handoff để phiên sau làm tiếp

Mẫu này phân biệt rõ “đã viết migration” với “đã xác minh migration”. Mình cũng giữ đường dẫn ADR hiện hành ngay trong handoff để Claude không phải đoán quyết định nào đang áp dụng. Những khẳng định về test và quyền truy cập vẫn cần được kiểm tra trước khi coi task hoàn thành.

Prompt bàn giao có thể dùng như sau:

Đọc task tại docs/tasks/reporting-export/.

Cập nhật progress.md dựa trên code hiện tại
và những thay đổi trong phiên này.

Ghi rõ:
- Mục tiêu còn lại.
- File đã thay đổi.
- Quyết định kiến trúc đang áp dụng.
- Test đã chạy và kết quả thực tế.
- Test chưa chạy.
- Rủi ro về tenant isolation.
- Các bước cần làm trong phiên tiếp theo.

Không đánh dấu hoàn thành nếu chưa có bằng chứng.
Không sửa code trong bước bàn giao này.

Mình chỉ định task directory và các module liên quan thay vì yêu cầu agent quét toàn bộ repository. Với thay đổi phức tạp, plan mode giúp thống nhất phạm vi trước khi sửa code. Quy trình handoff này sẽ được đặt trong bối cảnh phát triển tính năng đầy đủ ở bài về workflow trong series.

5. Khi nào dùng compact, clear hoặc phiên mới?

/compact giải quyết dung lượng context, nhưng không tự sửa những quyết định đã lỗi thời. Mình chọn cách xử lý dựa trên câu hỏi: còn cần lịch sử hiện tại để làm tiếp hay đã có đủ tài liệu để khởi động lại? Không có một ngưỡng token cố định phù hợp với mọi task.

Tình huống Cách xử lý
Đang làm cùng task, lịch sử vẫn hữu ích nhưng quá dài /compact
Chuyển sang công việc không liên quan /clear
Muốn tiếp tục phiên đã có /resume
Muốn tiếp tục phiên gần nhất claude --continue
Muốn chọn phiên để quay lại claude --resume
Cần quay về checkpoint trước /rewind
Task kéo dài, đã có handoff được kiểm tra Bắt đầu phiên mới và đọc handoff

Nếu task export đang dở và lịch sử phân tích API vẫn hữu ích, mình dùng /compact với chỉ dẫn giữ quyết định permission, file đã sửa và test chưa đạt. Khi chuyển sang task UI độc lập, /clear hợp lý hơn vì lịch sử middleware không còn cần thiết. Có thể /rename phiên trước khi clear rồi dùng /resume để quay lại khi cần.

claude --continue và claude --resume hỗ trợ tiếp tục hội thoại qua nhiều phiên, nhưng không bảo đảm code vẫn giống lúc hội thoại kết thúc. /rewind khác với compact và clear vì đưa hội thoại cùng code trở về checkpoint trước. Nếu agent bắt đầu sửa sai phạm vi, mình dùng Escape để dừng sớm rồi xác định lại những file cần xử lý.

Trường hợp quyết định kiến trúc đã thay đổi phức tạp hơn. Resume có thể đưa Claude trở lại lịch sử chứa giả định cũ, còn compact có thể tiếp tục giữ giả định đó. Khi tài liệu kiến trúc và handoff đã được cập nhật, mình thường chọn phiên mới rồi đối chiếu với code hiện tại.

6. Khôi phục trạng thái mà không tin tuyệt đối vào bản tóm tắt

Handoff vẫn có thể bỏ sót thay đổi chưa commit, nhầm kết quả test hoặc dẫn tới quyết định lỗi thời. Vì vậy, mình bắt đầu phiên tiếp theo bằng bước đối chiếu tài liệu với repository. Agent chưa sửa code cho tới khi xác định được trạng thái thực tế và những điểm mâu thuẫn.

Trước tiên, Claude đọc brief.md, progress.md, verification.md cùng các ADR được dẫn chiếu. Agent cần phân biệt yêu cầu phải đạt, trạng thái được ghi nhận và bằng chứng đã có. Nếu progress ghi API hoàn thành nhưng verification chưa có test tenant isolation, trạng thái đó vẫn chưa được xác minh.

Tiếp theo là kiểm tra Git để xác định branch, thay đổi chưa commit và lịch sử commit. SHA trong handoff giúp xác định điểm tham chiếu, còn diff cho biết code thực tế đã thay đổi ra sao. Với nhiều branch hoặc worktree, bước này tránh đối chiếu tài liệu của một trạng thái với code thuộc trạng thái khác.

git status
git diff
git diff --cached
git log -5 --oneline

pnpm -F api test

Sau khi đọc kết quả, Claude so sánh các file đã sửa với progress.md. Nếu có thay đổi không được ghi trong handoff, mình xác định chúng thuộc task nào trước khi tiếp tục. Nếu test thất bại, verification.md cần ghi lại lỗi và phân biệt lỗi mới với lỗi đã tồn tại ở trạng thái nền.

Prompt khôi phục phiên:

Task: docs/tasks/reporting-export/

Đọc:
- brief.md
- progress.md
- verification.md
- Quyết định kiến trúc được progress.md dẫn chiếu

Sau đó:
1. Kiểm tra git status và git diff.
2. Đọc code liên quan trong apps/api và packages/shared.
3. So sánh code với quyết định hiện hành.
4. Chạy pnpm -F api test.
5. Báo lại:
   - Điều đã được xác minh.
   - Điều handoff ghi nhưng chưa có bằng chứng.
   - Điều đang mâu thuẫn.
   - Rủi ro tenant isolation chưa xử lý.

Chưa sửa code. Chỉ đề xuất bước tiếp theo.

Với permission scope, mình kiểm tra API có dùng membership thuộc organization của request hay không. Test phải bao gồm trường hợp người dùng có quyền export ở tổ chức A nhưng không có quyền tương ứng ở tổ chức B, cùng trường hợp không có membership phù hợp. API trả đúng dữ liệu ở luồng thông thường chưa chứng minh được tenant isolation.

Nếu test tạo quá nhiều output, Claude có thể giao cho subagent chạy rồi nhận bản tóm tắt trong phiên chính. Tuy nhiên, subagent không nhận auto memory của phiên chính, nên prompt giao task phải nêu rõ tài liệu và ràng buộc cần tuân thủ. Bản tóm tắt trả về vẫn phải cho biết lệnh đã chạy, test thất bại và nơi có thể kiểm tra kết quả.

Khi đã đối chiếu xong, mình mới cho agent lập kế hoạch sửa phần chưa hoàn thành. Với thay đổi ảnh hưởng đến database, API và frontend, plan mode giúp xem tác động trước khi triển khai. Nhờ vậy, phiên mới tiếp tục từ trạng thái đã kiểm chứng thay vì chỉ dựa vào lời kể của phiên trước.

7. Dọn dẹp kiến thức đã lỗi thời

Thông tin cũ đôi khi nguy hiểm hơn thông tin bị thiếu. Khi Claude không biết một quyết định, agent còn có thể đọc tài liệu để tìm hiểu; nhưng nếu memory khẳng định chắc chắn một quy tắc đã hết hiệu lực, Claude có thể tiếp tục xây code trên giả định sai. Mình cập nhật kiến thức cùng lúc với thay đổi kiến trúc để hạn chế tình trạng này.

Giả sử 001-permission-scope.md mô tả phân quyền theo role tĩnh, còn team đã chuyển sang organization membership. Mình giữ ADR cũ để giải thích lịch sử migration, nhưng đánh dấu nó đã được thay thế và dẫn tới 002-organization-membership.md. ADR mới ghi rõ lý do thay đổi, phạm vi ảnh hưởng và những phần cần xác minh.

Vòng đời một quyết định kiến trúc

# ADR 002: Permission theo organization membership

## Trạng thái
Được chấp nhận.
Thay thế: ADR 001.

## Bối cảnh
Một người dùng có thể thuộc nhiều tổ chức
và giữ role khác nhau ở mỗi tổ chức.

## Quyết định
API xác định permission dựa trên membership
của người dùng trong organization được yêu cầu.

## Ảnh hưởng
- apps/api: authorization middleware.
- apps/admin: hiển thị quyền theo tổ chức.
- packages/shared: permission types.
- Database: migration membership và role.
- Tests: kiểm tra cách ly giữa các tenant.

## Cần xác minh
- Không suy quyền từ membership ở tổ chức khác.
- API export áp dụng đúng permission scope.
- Migration giữ đúng quan hệ role hiện có.

Sau khi cập nhật ADR, mình rà những nơi còn dẫn chiếu quyết định cũ. Nếu CLAUDE.md chứa quy tắc role tĩnh đã lỗi thời, nó phải được sửa, còn progress.md cần chuyển sang ADR hiện hành. Các test viết theo cơ chế cũ cũng phải được đánh giá lại thay vì mặc nhiên coi kết quả xanh là đủ.

Auto memory cần được kiểm tra theo cùng nguyên tắc. Claude có thể lưu ghi chú kiến trúc trong MEMORY.md hoặc file chủ đề, nhưng ghi chú đó không phải quyết định chính thức của team. Vì memory nằm trên máy, không đồng bộ giữa các máy và dùng chung giữa những worktree cùng repo, mình không đặt quy tắc bảo mật quan trọng chỉ ở đây.

Sau auto-compaction, skill đã gọi được gắn lại với giới hạn 5.000 token đầu mỗi skill và tổng 25.000 token, còn CLAUDE.md ở gốc được đọc lại từ đĩa. Mình giữ hướng dẫn nền ngắn, đặt kiến thức chuyên biệt trong tài liệu hoặc skill phù hợp và loại bỏ những quy tắc đã lỗi thời. Nhân bản cùng một quyết định ở quá nhiều nơi chỉ khiến team phải cập nhật nhiều bản khi kiến trúc đổi.

Checklist trước khi tiếp tục một phiên Claude Code

Mình dùng checklist dưới đây trước khi tiếp tục task có migration, authorization hoặc API phục vụ nhiều tenant. Với thay đổi nhỏ, không nhất thiết phải thực hiện toàn bộ. Nhưng khi một giả định sai có thể ảnh hưởng đến dữ liệu khách hàng, những bước đối chiếu này đáng để giữ thành quy trình của team.

  • [ ] Đã xác định đúng task, branch và trạng thái Git.
  • [ ] Đã đọc brief và handoff của task.
  • [ ] Đã mở quyết định kiến trúc hiện hành.
  • [ ] Đã kiểm tra các quyết định cũ có bị thay thế hay không.
  • [ ] Đã so sánh handoff với code đang có.
  • [ ] Đã xác định các thay đổi chưa commit.
  • [ ] Đã phân biệt test đã chạy và test chưa chạy.
  • [ ] Đã kiểm tra các ràng buộc bảo mật và tenant isolation.
  • [ ] Đã xác định bước tiếp theo cùng tiêu chí hoàn thành.
  • [ ] Đã yêu cầu Claude báo lại mâu thuẫn trước khi sửa code.

Checklist có thể nằm trong tài liệu task hoặc hướng dẫn bàn giao của team. Mình ưu tiên prompt cụ thể về file và hàm cần xử lý, dùng plan mode khi thay đổi phức tạp và dừng bằng Escape nếu agent bắt đầu đi sai hướng. Những quyết định có ảnh hưởng lâu dài được ghi vào repository, còn handoff giữ trạng thái cần thiết để tiếp tục task.

Memory giúp Claude giữ một phần thông tin qua các phiên, còn context phục vụ công việc đang diễn ra. Khi codebase thay đổi, cả hai vẫn cần được đối chiếu với tài liệu, Git và test. Mục tiêu của mình không phải làm Claude nhớ mọi cuộc trao đổi, mà giúp phiên tiếp theo tìm đúng nguồn, nhận ra thông tin đã lỗi thời và tiếp tục từ trạng thái có bằng chứng.


Các bài trong series

Series Claude Code cho dự án thực tế, mỗi bài trả lời một câu hỏi dev hay gặp khi đưa Claude Code vào dự án thật:

Bài tiếp theo trong series: Hướng dẫn cấu hình quyền cho Claude Code bằng settings.json.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.