Tôi có một batch viết blog từng làm bằng nhiều worker song song. Worker A sửa bài Kubernetes, worker B sửa bài Kibana, worker C cập nhật tracker. Mọi thứ nghe đơn giản cho đến khi một worker dùng checklist cũ, mark nhầm status, và worker khác dựa vào tracker đó để chọn bài kế tiếp. Không có code bug, nhưng workflow sai. Mất thời gian hơn cả sửa bài.

Sau vụ đó tôi bắt đầu chuẩn bị context pack cho những task dài. Không phải một prompt khổng lồ. Là một gói nhỏ gồm docs, memory, tracker, repo map và trạng thái hiện tại. Mục tiêu là để worker mới vào repo không phải đoán lịch sử, không lặp lại quyết định cũ, và không làm sai thứ tự.

AI coding không chỉ cần code context. Nó cần operational context: hôm qua đã làm gì, rule nào là source of truth, file nào đang do worker khác sở hữu, command nào đã fail, task nào pending. Nếu thiếu lớp này, agent có thể viết code đúng nhưng vận hành sai.

Context pack là gì

Context pack là bộ input có cấu trúc cho một worker trước khi bắt đầu task. Nó thường gồm:

  • Mục tiêu task.
  • Boundary và non-goals.
  • File ownership.
  • Repo map ngắn.
  • Source of truth docs.
  • Tracker hoặc checklist hiện tại.
  • Memory từ các lần làm trước.
  • Validation command.
  • Known issues.

Nó khác README. README phục vụ người mới hiểu project. Context pack phục vụ một task cụ thể tại một thời điểm cụ thể. README có thể ổn trong sáu tháng. Context pack có thể stale sau một giờ nếu nhiều worker chạy song song.

Một context pack tốt không cần nhồi mọi thứ. Nhồi quá nhiều làm agent mất tín hiệu. Chỉ đưa những gì ảnh hưởng đến quyết định của task này.

Repo map: chỉ đường trước khi thả agent vào rừng

Agent có thể tự rg, tự đọc file, tự khám phá. Nhưng nếu repo lớn, để nó tự tìm từ zero sẽ tốn thời gian và dễ đi nhầm. Repo map là đoạn ngắn chỉ các khu vực quan trọng.

Ví dụ cho một task frontend:

Repo map:
- src/features/reports/: report pages, hooks, export logic
- src/api/reports.ts: existing report API client
- src/components/ui/: shared UI components, read-only unless asked
- src/utils/date.ts: shared date helpers, do not change for this task
- tests/features/reports/: targeted tests

Repo map không thay thế search. Nó đặt bias đúng. Agent vẫn phải đọc code thật trước khi sửa, nhưng nó biết bắt đầu ở đâu và nơi nào nguy hiểm.

Điểm quan trọng là ghi cả vùng forbidden. Nếu chỉ liệt kê nơi cần sửa, agent vẫn có thể lạc sang migration, shared middleware, hoặc config vì thấy liên quan.

Docs nào là source of truth

Một lỗi phổ biến là đưa quá nhiều docs nhưng không nói docs nào thắng khi mâu thuẫn. Repo thật hay có README cũ, wiki mới, ticket đang update, comment trong code, và memory từ lần deploy trước. Agent thấy tất cả, rồi chọn cái có vẻ hợp lý.

Context pack nên ghi rõ thứ tự ưu tiên:

Source of truth order:
1. Current code and tests
2. docs/report-export.md
3. Ticket acceptance criteria
4. Older README notes are background only

Nếu một doc stale, nói thẳng:

Known stale:
- README export section still mentions v1 API. Do not use it as source of truth.

Câu này giúp agent không “trung hòa” giữa docs cũ và code mới. Với AI coding, stale docs nguy hiểm hơn thiếu docs. Thiếu docs khiến agent hỏi hoặc search. Stale docs khiến agent tự tin làm sai.

Memory: ghi lại quyết định đã trả giá

Memory khác docs ở chỗ nó lưu quyết định và bài học từ các lần làm trước. Ví dụ:

Memory:
- Do not use global formatDate for CSV export. Audit log depends on UTC rendering.
- Full test suite has one unrelated flaky SearchBox test. Use targeted report tests for this task.
- API hook useReports already handles pagination; do not create a second fetcher.

Những dòng này thường không đáng đưa vào README chính, nhưng cực đáng đưa vào context pack. Chúng là “sẹo” của repo. Không nói ra, agent sẽ dẫm lại.

Tôi thích memory ngắn, có điều kiện áp dụng. Đừng viết:

Always avoid formatDate.

Viết:

For CSV export timezone work, do not change global formatDate because audit log depends on UTC rendering.

Memory quá rộng sẽ trở thành luật giả. Agent có xu hướng áp dụng rule mạnh hơn con người. Nếu rule chỉ đúng trong một feature, ghi feature đó.

Tracker: source of truth cho việc còn lại

Với task một lần, checklist trong prompt là đủ. Với series, migration, audit, hoặc batch edit, cần tracker file. Tracker nên nằm trong repo để mọi worker đọc cùng một trạng thái.

Tracker đơn giản có thể là markdown:

# Migration Tracker

| Item | Status | Owner | Notes |
|---|---|---|---|
| reports API | done | worker-a | tests pass |
| invoices API | in-progress | worker-b | do not touch |
| exports API | pending |  | needs contract check |

Tracker lớn hơn có thể là JSON để script validate:

{
  "items": [
    {
      "file": "src/features/reports/exportCsv.ts",
      "status": "pending",
      "owner": null,
      "notes": "Needs timezone regression test"
    }
  ]
}

Điều quan trọng không phải format. Điều quan trọng là rule cập nhật: worker sửa item nào thì update tracker ngay sau khi xong item đó, không chờ cuối batch. Nếu worker crash giữa chừng, tracker vẫn gần đúng.

Trong batch nhiều worker, tracker cũng là lock mềm. Nếu item có owner: worker-b, worker khác không đụng. Không cần hệ thống distributed lock phức tạp cho mọi việc. Một tracker rõ và thói quen đọc trước khi sửa đã giảm phần lớn conflict.

Evidence pack: đưa lỗi thật, không chỉ mô tả

Khi giao bug cho agent, đừng chỉ nói “login sometimes fails”. Đưa evidence:

Evidence:
- User sees 401 after token refresh.
- Log sample:

```text
POST /auth/refresh 200
GET /me 401
```

- Repro: wait until access token expires, keep refresh token valid, reload dashboard.
- Suspected area: src/auth/session.ts

Trong markdown thật, nếu cần nested code fence, dùng fence dài hơn ở ngoài để tránh vỡ format. Ý chính là evidence phải cụ thể: log, request, screenshot, stack trace, input/output, commit range.

Agent debug tốt hơn khi có bằng chứng hẹp. Nếu không, nó sẽ search rộng và sửa theo pattern quen thuộc. Với auth bug, pattern quen thuộc thường là “refresh token race”. Có thể đúng. Cũng có thể lần này là cookie domain sai ở staging.

Context pack cho worker song song

Khi nhiều worker cùng chạy, context pack phải thêm coordination:

Parallel work rules:
- Other workers are editing unrelated files.
- Do not run repo-wide formatter.
- Do not touch files outside ownership.
- If you need a shared file, stop and report.
- Do not update tracker entries owned by another worker.

Repo-wide formatter có thể tạo conflict cho tất cả. Shared helper change có thể invalidate work của worker khác. Tracker entry sai có thể làm cả batch lệch thứ tự. Tôi cũng thích đặt worker id trong task:

Worker id: blog-series-worker-1
Owned files:
- src/content/blog/ai-coding-thuc-chien-bai-1-setup-repo-cho-agent.md
- src/content/blog/ai-coding-thuc-chien-bai-2-viet-task-brief.md

Nếu tracker có owner field, dùng đúng id đó. Nếu final report có issue, bạn biết worker nào làm phần nào.

Đừng biến context pack thành bãi rác

Context pack dễ phình. Mỗi incident thêm một rule. Mỗi rule thêm một exception. Sau vài tuần, agent nhận 300 dòng instruction và bỏ sót phần quan trọng.

Tôi dọn theo ba câu hỏi: dòng này có ảnh hưởng đến task hiện tại không; nếu bỏ dòng này, agent có khả năng làm sai không; dòng này là rule lâu dài hay trạng thái tạm thời? Rule lâu dài chuyển vào repo instructions. Trạng thái tạm thời nằm trong tracker hoặc task brief. Incident cũ chỉ giữ nếu liên quan trực tiếp.

Template context pack tôi dùng

Đây là bản gọn:

Task:

Worker id:

Goal:

Boundary:
- In scope:
- Out of scope:

File ownership:
- Allowed:
- Read-only:
- Forbidden:

Repo map:

Source of truth:

Memory / prior decisions:

Tracker:
- Path:
- Update rule:

Evidence:

Validation:

Final report:
- Changed files
- Validation run
- Notes / blockers

Không phải lúc nào cũng điền hết. Với task nhỏ, chỉ cần Goal, File ownership, Validation. Với migration nhiều ngày, điền đủ và lưu thành file trong repo.

Khi nào cần lưu context pack vào repo

Nếu task chỉ chạy một lần trong một session, paste context trong chat là đủ. Nếu task kéo dài qua nhiều ngày, nhiều worker, hoặc nhiều lần resume, hãy lưu vào repo, ví dụ docs/<feature>/implementation-plan.md, content-audit/<tracker>.json, hoặc tasks/<ticket-id>.md.

File trong repo là điểm neo để worker mới đọc lại bằng path cụ thể. Đừng lưu secret hoặc token vào context pack. Nếu cần nhắc credential, ghi path gitignored:

Credentials:
- Stored in .local/report-export/README.md
- Do not commit .local/

Chốt lại

AI coding càng mạnh thì context càng quan trọng. Một worker có thể sửa code rất nhanh, nhưng nếu nó bắt đầu từ docs stale, tracker sai, memory thiếu, hoặc file ownership mơ hồ, tốc độ đó chỉ làm lỗi lan nhanh hơn.

Context pack tốt làm ba việc: chỉ nơi cần đọc, nói rõ quyết định đã có, và giữ trạng thái hiện tại đủ mới để worker không đoán. Trước mỗi task đủ lớn, tôi tự hỏi: nếu một dev mới vào team nhận gói context này, họ có biết bắt đầu từ đâu và dừng ở đâu không?