Chuyện này xảy ra với tôi không chỉ một lần: buổi tối cả nhóm cân nhắc mấy phương án cho một khối, sáng hôm sau có người hỏi tại sao tiêu đề lại ngắn đi. Trong đoạn chat có hàng chục tin nhắn, trong trí nhớ chỉ còn lại kiểu "hình như nền lúc đó sáng màu", còn quyết định chính xác thì tan biến đâu đó giữa các lần sửa.

Vào những lúc như vậy, requests.log là cứu cánh. Đây là một dấu vết bên ngoài ngắn gọn của công việc, có thể mở bằng trình soạn thảo thông thường và đọc từ trên xuống dưới. Tôi coi trọng nó không phải vì số dòng, mà vì khả năng gắn kết một yêu cầu với thứ mà mọi người thật sự quyết định giữ lại.

Vì sao cần một dấu vết bên ngoài

Qua nhiều năm làm việc, tôi đã quen tách riêng bốn thứ: yêu cầu, quyết định, đoạn chat và phiên bản đã lưu của tệp. Chúng trả lời những câu hỏi khác nhau, dù trong một phiên làm việc chúng rất dễ dính chặt vào nhau thành một câu chuyện mơ hồ.

NguồnCó thể biết được gì từ nóNó không chứng minh được điều gì
requests.logĐã yêu cầu gì và khi nào bản ghi xuất hiệnThay đổi đã được thực hiện và chấp nhận
Ghi chú quyết địnhPhương án nào được chọn và ai đã đánh dấuTệp đã lưu hiện trông như thế nào
Lịch sử trò chuyệnBối cảnh trao đổi và các phản hồiCái gì đã lọt vào phiên bản hiện tại của dự án
Hệ thống quản lý phiên bảnNhững tệp và dòng nào đã được lưuVì sao lại chọn đúng phương án này

Nhật ký hoạt động như một biển chỉ đường: đưa bạn quay lại đúng thời điểm và đúng câu chữ. Bản thân mã nguồn thì nó không khôi phục được. Nếu cần xem phiên bản đã lưu của trang, hãy xem tệp và lịch sử phiên bản của dự án.

Claude Code ghi lại điều gì

Ở đây có một ranh giới quan trọng, nơi tôi từng thấy không ít kết luận sai. Hook của sự kiện UserPromptSubmit nhận văn bản trong trường prompt trước khi Claude Code xử lý yêu cầu. Một dòng như vậy chỉ xác nhận văn bản đã được gửi đi, còn kết quả của công việc tại thời điểm đó vẫn chưa biết.

Yêu cầu đi qua sự kiện UserPromptSubmit đến Claude Code, bản ghi tự động lưu lại văn bản đã gửi, còn bản ghi thủ công riêng biệt chỉ xuất hiện sau khi con người kiểm tra kết quảDấu vết bên ngoài trong requests.logYêu cầu của bạnvăn bản đã gửiUserPromptSubmitsự kiện kích hoạtClaude Codeđang xử lýBạn kiểm trađã thấy kết quảBản ghi tự độngyêu cầu đã gửiGhi chú thủ côngquyết định đã chốt
Yêu cầu và quyết định đã chốt xuất hiện trong dấu vết bên ngoài ở hai thời điểm khác nhau

Sơ đồ cho thấy rõ sự khác biệt quan trọng khi phân tích nhật ký. Chuỗi phía trên thể hiện diễn biến công việc, chuỗi phía dưới là những gì còn lại trong nhật ký. Dòng tự động xuất hiện trước khi có kết quả; ghi chú quyết định chỉ xuất hiện sau khi kiểm tra. Cái này không thay thế cho cái kia.

Một bản ghi hữu ích gồm những gì

Tôi sẽ minh họa bằng ba dạng bản ghi. Trong các dự án thực tế, tôi từng gặp cả ba dạng này.

xong

Một dòng như vậy gần như vô dụng: không rõ ai đã làm gì, khi nào, và chữ "xong" này thuộc về việc nào.

Người dùng: Làm tiêu đề thẻ ngắn lại...
Claude: Được, để tôi xem component trước đã...
Người dùng: Và giảm khoảng đệm luôn...
Claude: Đã sửa...

Còn ở đây thì lại quá nhiều để tìm kiếm nhanh. Toàn bộ luồng hội thoại hợp với lịch sử trò chuyện, nhưng một nhật ký riêng thì nhanh chóng biến thành bản sao bất tiện của nó. Tôi từng thử làm vậy, rồi chính mình lại mất thời gian cuộn lên cuộn xuống.

2026-09-08T14:32:11+03:00 | prompt_submitted | actor=user | ref=card-header | text="Rút gọn tiêu đề thẻ xuống một dòng"
2026-09-08T14:41:06+03:00 | decision_recorded | actor=user | ref=card-header | text="Chấp nhận tiêu đề ngắn, cỡ chữ 24 px"

Dạng thứ ba là dạng tôi thích nhất: nó giữ lại một sự việc ngắn gọn, thời gian kèm múi giờ, người thực hiện và nhãn ref liên kết các dòng với nhau. Tên các trường ở đây được đặt ra cho dự án học tập. Đây là định dạng của tệp chúng ta, không phải một cấu trúc bắt buộc của Claude Code. Trong ví dụ này, nhãn ref được thêm bằng tay vào các dòng liên quan. Hook không tự đoán yêu cầu thuộc về khối nào: sự kiện gốc UserPromptSubmit không mang theo nhãn ngữ nghĩa như vậy. Nếu không có trường liên kết, bạn vẫn có thể tìm trong nhật ký của mình theo đúng cụm từ.

Điều gì đã biết tại thời điểm ghi

Dòng prompt_submitted chỉ nói đúng một điều: phiên đã nhận được yêu cầu này, và hook đã ghi lại. Thường đó là văn bản của bạn, nhưng không phải lúc nào cũng vậy. UserPromptSubmit cũng kích hoạt ở mỗi vòng mới của /loop, ở báo cáo của subagent chạy nền và ở tin nhắn từ một phiên khác, nên actor=user trong định dạng của chúng ta chỉ là một giả định của ví dụ học tập. Từ đó không suy ra được rằng Claude Code đã sửa trang, việc kiểm tra đã đạt, hay mọi người đều hài lòng với kết quả.

Kết quả nên được ghi lại sau khi đã thật sự biết nó. Trong ví dụ của chúng ta, đó là một ghi chú riêng sau khi xem lại trang. Nếu định dạng của bạn có các trường result hoặc error, hãy điền vào đó các sự việc đã quan sát được, chứ không phải một dự đoán về kết quả tương lai của công việc.

Ghi nhận quyết định đã chốt ở đâu

Quyết định chỉ xuất hiện khi có ai đó ghi lại nó một cách rõ ràng. Trong ví dụ trên, người dùng thêm dòng này sau khi xem lại trang. Người thực hiện được ghi trong actor, còn ref=card-header giữ liên kết với yêu cầu.

Ghi chú có thể là thủ công, và điều đó bình thường. Bản ghi tự động lưu lại đầu vào, còn con người xác nhận ý nghĩa của kết quả. Một dòng "xong" không có người thực hiện và không có liên kết thì không nên tin tưởng.

Đọc nhật ký yêu cầu

Hãy cùng phân tích một nhật ký nhỏ gồm năm dòng. Chính từ những đoạn ngắn như thế này mà tôi thường bắt đầu khi cần dựng lại diễn biến của một quyết định.

2026-09-08T14:32:11+03:00 | prompt_submitted | actor=user | ref=card-header | text="Rút gọn tiêu đề thẻ xuống một dòng"
2026-09-08T14:36:20+03:00 | prompt_submitted | actor=user | ref=card-header | text="Cho tôi xem hai phương án: 24 px và 28 px"
2026-09-08T14:41:06+03:00 | decision_recorded | actor=user | ref=card-header | text="Chấp nhận tiêu đề ngắn, cỡ chữ 24 px"
2026-09-08T15:03:44+03:00 | prompt_submitted | actor=user | ref=card-shadow | text="Làm bóng đổ của thẻ mềm hơn"
2026-09-08T15:08:17+03:00 | prompt_submitted | actor=user | ref=card-header | text="Thử màu tiêu đề tối hơn"

Hãy hình dung bạn cần tìm quyết định cuối cùng đã chốt về định dạng tiêu đề. Bắt đầu bằng cách tìm theo card-header trong trình soạn thảo. Bạn sẽ có bốn dòng. Dòng cuối cùng chứa một mong muốn mới về màu sắc, nhưng không phải là quyết định. Vì vậy kết luận dựa vào dòng ở thời điểm 14:41:06: tiêu đề ngắn, cỡ chữ 24 px, đã được chấp nhận.

Trình tự đọc trong công việc của tôi khá đơn giản:

  1. Trước tiên tôi đặt câu hỏi thành lời: tôi đang tìm một yêu cầu, một quyết định, hay một lỗi đã quan sát được.
  2. Sau đó tìm nhãn chung, tên component, hoặc một cụm từ chính xác.
  3. Chỉ giữ lại các bản ghi đúng loại và đọc chúng theo thứ tự thời gian.
  4. Nêu tên các dòng làm bằng chứng cho kết luận. Mọi thứ còn lại tôi thẳng thắn ghi là chưa biết.

Kiểu phân tích này hoàn toàn có thể làm mà không cần chạy Claude Code. Đây là một thói quen hữu ích: tự mình đối chiếu kết luận với tệp trước, rồi mới giao chính công việc đó cho agent.

Khi nhật ký không có quyết định

Bây giờ hãy bỏ dòng ở thời điểm 14:41:06 đi. Còn lại là yêu cầu xem hai kích thước và một mong muốn đổi màu xuất hiện sau đó. Kích thước nào đã được chấp nhận? Nhật ký không trả lời.

Ở những chỗ như thế này, người ta rất muốn chọn 24 px, vì đó là phương án được đề xuất đầu tiên. Đừng làm vậy. Yêu cầu chỉ cho thấy ý định kiểm tra các phương án, chứ không phải kết quả của lựa chọn. Kết luận trung thực duy nhất ở đây là: nhật ký không ghi nhận quyết định nào về kích thước.

Sau khi tìm các bản ghi liên quan, có ghi chú quyết định rõ ràng thì dẫn đến kết luận đã xác nhận, còn chỉ có yêu cầu thì để quyết định ở trạng thái chưa biếtĐã tìm thấy bản ghi liên quanđọc chúng theo thời gianCó ghi chú rõ ràngvề quyết định?Có, kết luận đã xác nhậnnêu bản ghi và thời gianKhông, quyết định chưa biếtđừng biến yêu cầu thành sự thật
Yêu cầu cuối cùng không tự động trở thành quyết định chỉ vì nó là yêu cầu cuối

Nhánh rẽ không phụ thuộc vào thứ tự các mong muốn, mà phụ thuộc vào loại bản ghi tìm thấy. Có ghi chú quyết định rõ ràng - kết luận có thể xác nhận. Chỉ còn lại các yêu cầu - ta ghi nhận là chưa biết và không lấp khoảng trống bằng phỏng đoán. Sự kiềm chế này rốt cuộc tiết kiệm được rất nhiều thời gian.

Yêu cầu bằng chứng

Khi Claude Code phân tích một nhật ký, tôi yêu cầu nó nêu chính xác những bản ghi mà kết luận dựa vào. Nếu không có dòng xác nhận, điều đó phải rơi vào danh sách chưa biết, không được phỏng đoán về một kết quả thành công.

Những gì nên để ngoài nhật ký

Tôi không cố biến một nhật ký hữu ích thành kho chứa mọi thứ. Nội dung của một bản ghi nên được chọn theo câu hỏi mà sau này sẽ phải giải quyết. Để tìm quyết định, thường thời gian, loại sự kiện, người thực hiện, nhãn liên kết và một đoạn văn bản ngắn là đủ.

  • Đừng sao chép khóa, token, nội dung của .env và dữ liệu cá nhân.
  • Đừng chuyển nguyên vẹn phản hồi của dịch vụ bên ngoài nếu chỉ cần trạng thái hay id của thao tác.
  • Chỉ giữ nguyên toàn bộ prompt ở những chỗ thật sự cần thiết. Trong bài viết này nó đầy đủ chỉ vì ví dụ là hư cấu và ngắn gọn.
  • Định kỳ kiểm tra kích thước tệp và giá trị của các bản ghi cũ. Không có một khoảng thời gian lưu trữ chung cho mọi dự án.

Cắt bớt dòng xuống còn một trăm ký tự giúp dễ đọc hơn, nhưng không tự động xóa bí mật. Một token ngắn hoàn toàn vừa vặn trong một trăm ký tự đầu tiên. Trước hết hãy quyết định những dữ liệu nào được phép ghi lại. Nên bắt đầu chính từ quy tắc này, chứ không phải từ độ dài dòng.

Cách phân tích nhật ký cùng Claude Code

Claude Code giỏi trong việc dựng lại trình tự thời gian và nhanh chóng tìm các dòng liên quan. Nhưng để làm được điều đó, nó cần đọc tệp một cách tường minh: việc requests.log có trong dự án tự nó không có nghĩa là nội dung của tệp đã nằm trong ngữ cảnh.

Hãy giao cho agent một nhiệm vụ cụ thể:

Hãy đọc requests.log. Tìm quyết định cuối cùng đã được chấp nhận rõ ràng
về kích thước tiêu đề thẻ (card-header). Nêu các bản ghi mà bạn dựa vào.
Nếu trong nhật ký chỉ có mong muốn, hãy nói rõ như vậy.
Liệt kê riêng những gì còn chưa biết.

Một câu trả lời tốt sẽ tách bạch sự việc khỏi kết luận: trích dẫn thời gian, loại sự kiện và nội dung quyết định, rồi liệt kê các câu hỏi chưa có xác nhận. Hãy đối chiếu các tham chiếu đó với các dòng gốc. Lỗi đặc biệt dễ nhận thấy khi agent gọi yêu cầu cuối cùng là "phương án đã được chấp nhận".

Với nhật ký học tập hiện tại, câu trả lời sẽ như sau: quyết định về kích thước được xác nhận bởi bản ghi 2026-09-08T14:41:06+03:00; sau đó có xuất hiện yêu cầu về màu tối hơn, nhưng quyết định về màu sắc thì chưa biết. Đó chính là kiểu câu trả lời tôi coi là đáng tin cậy: nó không hứa hẹn nhiều hơn những gì thật sự có trong tệp.

  • Hook lưu lại yêu cầu trước khi nó được xử lý, vì vậy bản ghi này không xác nhận kết quả.
  • Một ghi chú riêng liên kết quyết định đã chốt với yêu cầu theo thời gian hoặc theo nhãn.
  • Việc tìm kiếm bắt đầu từ một câu hỏi cụ thể và kết thúc bằng tham chiếu đến các dòng gốc.
  • Nếu không có xác nhận, nhật ký để lại một khoảng trống. Không cần tự suy diễn để lấp đầy nó.

Cứ như vậy, requests.log vẫn là một dấu vết làm việc nhỏ gọn: giúp tìm lại đúng bước ngoặt trong cuộc trao đổi, nhưng không giả vờ là bản sao lưu của dự án, cũng không giả làm bằng chứng rằng nhiệm vụ đã hoàn thành. Khi một nhật ký được duy trì trung thực, người ta thật sự muốn quay lại xem nó.