SSD Nodes Learn 🎉 VPS từ $5.50/tháng
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-11

Cách cấu hình AGENTS.md lồng nhau cho monorepo

Tệp AGENTS.md tại root thường bị quá tải và gây lãng phí context khi làm việc với monorepo. Hướng dẫn này giúp bạn chia nhỏ cấu hình theo từng thư mục để tối ưu hiệu suất cho AI.

Ý nghĩa của AGENTS.md lồng nhau trong một monorepo

AGENTS.md lồng nhau trong một monorepo có nghĩa là một tệp nhỏ nằm tại thư mục gốc của repository và thêm một tệp nữa bên trong mỗi thư mục dịch vụ. Tệp ở thư mục gốc chứa một vài quy tắc áp dụng cho mọi nơi, cùng với bản đồ chỉ dẫn vị trí của các tệp khác. Mỗi tệp dịch vụ chứa các lệnh và quy ước riêng cho thư mục đó. Một agent khi chỉnh sửa services/worker/queue.py sẽ đọc tệp gốc và tệp worker, và không tốn bất kỳ context nào cho phần front end mà nó sẽ không bao giờ đụng tới.

Không có gì cần phải cài đặt cả. AGENTS.md là một quy ước, và dự án upstream đã nêu rõ điều này:

AGENTS.md chỉ là Markdown tiêu chuẩn. Bạn có thể sử dụng bất kỳ tiêu đề nào bạn muốn; agent chỉ đơn giản là phân tích văn bản mà bạn cung cấp.

Đó là lý do tại sao kỹ thuật này đáng để học một cách bài bản. Định dạng sẽ không thay đổi dưới chân bạn. Thứ dễ bị hỏng là vị trí đặt tệp và việc bảo trì, và cả hai việc đó đều là trách nhiệm của bạn.

Tại sao một file AGENTS.md lớn ở thư mục root lại ngừng hoạt động?

Một file AGENTS.md dài 600 dòng nằm ở root của repository, chứa thông tin cho web app, background worker và thư mục Terraform, sẽ thất bại theo bốn cách riêng biệt.

Nó trở nên lỗi thời vì không ai quản lý. Kỹ sư đổi tên một script kiểm thử trong apps/web đang chỉnh sửa các file nằm dưới apps/web. File AGENTS.md ở root không nằm trong diff đó, nên không người review nào thấy sự sai lệch. Sáu tuần sau, file này mô tả một bước build không còn tồn tại, và người làm hỏng nó đã quên mất thay đổi đó.

Nó tiêu tốn context cho mọi tác vụ. Các file này được load ngay khi bắt đầu phiên làm việc, trước khi agent biết bạn định hỏi gì. Tài liệu của Claude Code đã đưa ra con số cụ thể: "hãy giữ dưới 200 dòng cho mỗi file CLAUDE.md. Các file dài hơn sẽ tiêu tốn nhiều context hơn và làm giảm độ chính xác." Codex ngừng gộp các file hướng dẫn khi tổng kích thước của chúng đạt 32 KiB, đây là project_doc_max_bytes mặc định. Một file root mô tả bốn dịch vụ sẽ lãng phí ngân sách đó cho ba dịch vụ còn lại trong mọi tác vụ.

Các hướng dẫn bắt đầu mâu thuẫn lẫn nhau. Thư mục web yêu cầu pnpm test. Worker yêu cầu pytest -q. Khi viết chung vào một file, mỗi quy tắc chỉ đúng trong một số trường hợp, khiến agent phải đoán xem quy tắc nào được áp dụng. Tài liệu của Claude Code mô tả kết quả: "nếu hai quy tắc mâu thuẫn nhau, Claude có thể chọn ngẫu nhiên một quy tắc." Một file theo từng thư mục sẽ loại bỏ việc phải đoán, vì chỉ có một trong hai quy tắc xuất hiện trong context tại một thời điểm.

Nó chứa đầy những thông tin mà agent có thể tự đọc từ code. Cây thư mục, danh sách dependency, tóm tắt chức năng của từng package. Kiểm tra /doctor của Claude Code tồn tại để loại bỏ chính xác những thứ này. Nó "cắt bỏ nội dung mà Claude có thể tự suy luận từ codebase, như cấu trúc thư mục, danh sách dependency và tổng quan kiến trúc" và giữ lại "các cạm bẫy, lý do kỹ thuật và quy ước khác với mặc định của công cụ." Câu đó là bài kiểm tra tốt nhất mà tôi biết để xác định xem một dòng có thực sự thuộc về file đó hay không.

Agent đọc file ở root hay chỉ file gần nhất?

Đây là điểm mà hầu hết mọi người hiểu sai về model, vì vậy thay vì diễn giải lại, hãy trích dẫn quy ước từ phía upstream:

Đặt một file AGENTS.md khác bên trong mỗi package. Các agent tự động đọc file gần nhất trong cây thư mục, vì vậy file gần nhất sẽ được ưu tiên và mỗi subproject có thể ship các hướng dẫn riêng biệt.

Và về các xung đột:

File AGENTS.md gần nhất với file đang chỉnh sửa sẽ thắng; các prompt chat cụ thể của người dùng sẽ ghi đè lên tất cả.

"Được ưu tiên" khiến nhiều người hiểu nhầm là "file ở root bị bỏ qua". Thực tế không phải vậy. Trong các công cụ triển khai quy ước này, mọi file trên đường dẫn từ root của repository xuống đến thư mục làm việc đều được đọc và nối lại với nhau. File gần nhất chỉ thắng ở những điểm mà hai file có chỉ dẫn khác nhau về cùng một chủ đề.

Codex giải thích rõ về cơ chế này: "Codex nối các file từ root xuống, kết hợp chúng bằng các dòng trống. Các file gần thư mục hiện tại của bạn hơn sẽ ghi đè lên các hướng dẫn trước đó." Claude Code cũng đi theo lộ trình tương tự cho tên file của riêng nó. Các file trong hệ thống phân cấp thư mục phía trên thư mục làm việc "được load toàn bộ khi khởi chạy", và "Tất cả các file được tìm thấy đều được nối vào context thay vì ghi đè lẫn nhau." Các thư mục bên dưới thư mục làm việc hoạt động khác đi: Claude Code load các file đó theo yêu cầu, "khi Claude đọc file trong các thư mục đó."

Có hai hệ quả thực tế rút ra từ đây. File ở root là tiền tố cho mọi phiên làm việc trong repository, vì vậy hãy coi mỗi dòng trong đó là một dòng bạn phải trả phí hàng trăm lần mỗi tuần. Một file theo từng thư mục sẽ không tốn phí khi agent đang làm việc ở nơi khác, điều này có nghĩa là các chi tiết cụ thể ở đó rất rẻ và nên được đặt ở đó.

Hành vi này đã được kiểm tra đối chiếu với tài liệu của Codex và Claude Code vào tháng 8 năm 2026. Các công cụ triển khai quy ước này có đôi chút khác biệt và chúng thường xuyên thay đổi, vì vậy hãy xác nhận các quy tắc load cho bất kỳ agent nào mà team của bạn đang chạy.

Bố cục mẫu cho một repository với ba service

repo/
  AGENTS.md                   rules true everywhere, plus the map
  apps/web/AGENTS.md          TypeScript client, Vite, Vitest
  services/worker/AGENTS.md   Python queue consumer, pytest
  infra/AGENTS.md             Terraform and the deploy scripts

File root được cố tình viết ngắn gọn. Nó chỉ định vị trí cần tìm kiếm và chỉ chứa các quy tắc áp dụng cho mọi thư mục.

# AGENTS.md

This is a monorepo. Each top-level directory ships its own AGENTS.md.
Read this file and the AGENTS.md nearest the code you are editing
before you change anything.

- `apps/web` browser client
- `services/worker` queue consumer
- `infra` Terraform and deploy scripts

## Rules for the whole repository

- The package manager is `pnpm`. `npm install` writes a second lockfile
  that CI ignores, so the install you tested is not the install that ships.
- Any `generated/` directory is build output. Edit the schema in
  `schemas/` and run `pnpm codegen` instead.
- `.env.local` holds real credentials. Do not read it and do not print it.
- If you change code in a directory, update that directory's AGENTS.md
  in the same commit.

File tại mỗi thư mục là nơi chứa chi tiết, và nó có thể dài tùy theo yêu cầu của thư mục đó.

# apps/web

Browser client. Vite and React, TypeScript with `strict` on.

## Commands

- `pnpm dev` serves on port 5173.
- `pnpm test` runs Vitest once and exits.
- `pnpm typecheck` runs `tsc --noEmit`.

## Conventions

- One component per file under `src/components/`.
- All HTTP goes through `src/api/client.ts`. Do not call `fetch` directly,
  because the client attaches the auth header and retries on 429.

## Traps

- `pnpm build` does not type check. Vite strips the types instead of
  checking them, so a broken type still produces a green build.
  Run `pnpm typecheck` as a separate step.

File worker có cấu trúc tương tự nhưng nội dung khác biệt: lệnh cài đặt, pytest -q, lý do tại sao consumer phải đảm bảo tính idempotent, và migration cần chạy trước khi các bài test pass. File infra là nơi bạn viết các quy tắc ngăn chặn agent gây ra thiệt hại. Không bao giờ chạy terraform apply. Hãy chạy terraform plan rồi dừng lại, đồng thời chỉ định state backend đã được cấu hình sẵn để agent không cố gắng khởi tạo một backend mới.

Hãy chú ý những gì không có trong các file này: mô tả mục đích của từng service. Điều đó dành cho con người. Upstream cũng vạch ra ranh giới tương tự, cho rằng "các file README.md dành cho con người: hướng dẫn nhanh, mô tả dự án và hướng dẫn đóng góp", trong khi AGENTS.md chứa "ngữ cảnh bổ sung, đôi khi rất chi tiết mà các coding agent cần: các bước build, test và quy ước". Sự phân tách giữa AGENTS.md và README dành cho con người đi sâu vào từng câu qua ranh giới đó, và một file DESIGN.md ghi lại lý do tại sao code được định hình như vậy bao hàm file thứ ba, file giải thích các quyết định thay vì các lệnh.

Ai cập nhật file khi code thay đổi?

Có một quy tắc duy nhất và nó nằm trong file root: bất kỳ ai thay đổi code trong một thư mục đều phải cập nhật file AGENTS.md của thư mục đó trong cùng một commit.

Cách này hiệu quả vì lý do kỹ thuật, không phải vì văn hóa. File của từng thư mục nằm trong cùng một diff với code, nên người review pull request sẽ thấy cả hai cùng lúc. File root thuộc về tất cả mọi người, nghĩa là nó không thuộc về ai cả, và nó không bao giờ nằm trong diff mà người khác đang đọc.

Hãy hỗ trợ quy tắc này bằng một bước kiểm tra trên pull request. Nó sẽ tìm file AGENTS.md gần nhất phía trên mỗi file bị thay đổi, sau đó báo cáo nếu file đó không được chỉnh sửa.

#!/usr/bin/env bash
# Warn when code changed but the nearest AGENTS.md above it did not.
changed=$(git diff --name-only origin/main...HEAD)

nearest_doc() {
  d=$(dirname "$1")
  while [ "$d" != "." ]; do
    if [ -f "$d/AGENTS.md" ]; then echo "$d/AGENTS.md"; return; fi
    d=$(dirname "$d")
  done
  echo "AGENTS.md"
}

printf '%s\n' "$changed" | while read -r f; do
  [ -n "$f" ] || continue
  case "$f" in AGENTS.md|*/AGENTS.md) continue ;; esac
  doc=$(nearest_doc "$f")
  printf '%s\n' "$changed" | grep -Fqx "$doc" && continue
  echo "note: $f changed but $doc was not updated"
done

Trên một nhánh đã sửa lại API client mà không cập nhật tài liệu, kết quả sẽ trông như thế này:

note: apps/web/src/api/client.ts changed but apps/web/AGENTS.md was not updated

Hãy giữ nó ở mức cảnh báo thay vì chặn hoàn toàn. Một rào cản cứng nhắc sẽ khiến mọi người chỉ thêm một dòng trống vào file để CI báo xanh, và một file được chỉnh sửa chỉ để đối phó với robot thì không có giá trị gì cả. Cảnh báo sẽ đặt ra một câu hỏi để người review trao đổi, đó mới là phần thực sự hiệu quả.

Làm sao để phát hiện file AGENTS.md đã cũ?

Bạn có thể thực hiện hai bước kiểm tra ngay hôm nay, cùng với một triệu chứng sẽ xuất hiện trong phiên làm việc.

So sánh tuổi của từng file với tuổi của mã nguồn mà nó mô tả. %cs in ra ngày commit dưới dạng YYYY-MM-DD.

for f in $(git ls-files '*AGENTS.md'); do
  d=$(dirname "$f")
  printf '%s  doc:%s  code:%s\n' "$f" \
    "$(git log -1 --format=%cs -- "$f")" \
    "$(git log -1 --format=%cs -- "$d")"
done
apps/web/AGENTS.md          doc:2026-02-11  code:2026-08-07
services/worker/AGENTS.md   doc:2026-07-29  code:2026-08-09
infra/AGENTS.md             doc:2026-08-01  code:2026-08-01

Một ngày tháng trong tài liệu cũ hơn mã nguồn 6 tháng không chứng minh file đó sai. Nó chỉ cho bạn biết file nào cần đọc trước, và đó là tất cả những gì bạn cần từ một bước kiểm tra chỉ mất một giây.

Tìm các đường dẫn không còn tồn tại. Tài liệu bị lỗi thời theo một cách rất cụ thể: nó tiếp tục mô tả mã nguồn đã bị xóa. Mọi đường dẫn trong các file này đều được viết trong dấu backtick, nên rất dễ để trích xuất và kiểm tra.

grep -o '`[^`]*`' apps/web/AGENTS.md | tr -d '`' | grep '/' | while read -r p; do
  [ -e "$p" ] || [ -e "apps/web/$p" ] || echo "missing: $p"
done

Hãy đọc kết quả đầu ra thay vì tích hợp lệnh này vào CI. Nó cũng sẽ gắn cờ các glob như src/**/*.ts và bất kỳ URL nào bạn đã trích dẫn, vì cả hai đều chứa dấu gạch chéo và không phải là file trên đĩa.

Triệu chứng trong một phiên làm việc. Agent đọc file, cố gắng mở src/api/client.ts vì file yêu cầu như vậy, và công cụ trả về:

No such file or directory

Vì vậy, nó thực hiện hành động hợp lý là tự viết một wrapper fetch của riêng nó. Đó chính là cái giá thực sự của một file cũ. Agent không phớt lờ tài liệu của bạn. Nó tuân theo tài liệu, đi đến một đường dẫn đã bị xóa từ ba tháng trước, và xây dựng lại mã nguồn mà bạn đã có. Một kỹ năng như Ponytail, giúp giữ agent ở mức thay đổi nhỏ nhất có hiệu quả, làm cho bản năng xây dựng lại đó trở nên hiếm gặp hơn, nhưng nó không thể tìm thấy một helper mà file của bạn đã trỏ sai vị trí.

Claude Code có đọc file AGENTS.md không?

Không, và điều này cần được làm rõ vì cấu trúc lồng nhau phụ thuộc vào nó. Tính đến tháng 8 năm 2026, tài liệu ghi rõ: "Claude Code đọc CLAUDE.md, không phải AGENTS.md." Mô hình này vẫn hoạt động, bạn chỉ cần một CLAUDE.md bên cạnh mỗi AGENTS.md.

Dạng import là lựa chọn đúng khi bạn muốn thêm các dòng lệnh cụ thể cho công cụ lên trên các dòng lệnh dùng chung. Hãy đặt nội dung này vào services/worker/CLAUDE.md:

@AGENTS.md

## Claude Code

Use plan mode for changes under `services/worker/migrations/`.

Dạng symlink là lựa chọn đúng khi không có nội dung cụ thể nào cần thêm cho công cụ.

git ls-files '*AGENTS.md' | while read -r f; do
  ln -s AGENTS.md "$(dirname "$f")/CLAUDE.md"
done
ls -l apps/web/CLAUDE.md

ln không in ra gì khi thành công, vì vậy hãy kiểm tra danh sách bằng: apps/web/CLAUDE.md -> AGENTS.md. Sau đó bắt đầu một phiên làm việc và chạy /context, nơi các file đã load sẽ xuất hiện dưới mục Memory files. Trên Windows, symlink yêu cầu quyền Administrator hoặc Developer Mode, vì vậy hãy sử dụng lệnh import @AGENTS.md ở đó.

Có một bẫy cần lưu ý. Sau /compact, file gốc (root file) được đọc lại từ ổ đĩa, nhưng các file lồng nhau trong thư mục con thì không được nạp lại. Chúng sẽ quay lại vào lần tiếp theo agent đọc một file trong thư mục đó. Nếu một quy tắc theo thư mục có vẻ ngừng áp dụng giữa chừng trong một phiên làm việc dài, đó thường là lý do, và việc touch bất kỳ file nào trong thư mục đó sẽ kích hoạt lại nó.

Các cài đặt trỏ các agent khác tới AGENTS.md

Codex đọc AGENTS.md một cách tự nhiên. Tại mỗi cấp độ, nó kiểm tra AGENTS.override.md trước, cho phép một thư mục có ghi đè cục bộ mà không cần chỉnh sửa file dùng chung. Nó ngừng gộp khi tổng kích thước đạt 32 KiB, đây là project_doc_max_bytes mặc định, và đó là một lý do nữa để giữ cho file gốc có kích thước nhỏ.

Aider nhận file này thông qua .aider.conf.yml với dòng read: AGENTS.md.

Gemini CLI nhận file này thông qua .gemini/settings.json với { "context": { "fileName": "AGENTS.md" } }.

Tài liệu upstream có ghi chú về việc đổi tên để tương thích ngược cho các repository vẫn đang sử dụng tên số ít cũ: mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md.

Trong một monorepo rất lớn, cài đặt claudeMdExcludes của Claude Code sẽ bỏ qua các file tổ tiên theo đường dẫn hoặc glob, điều này hữu ích khi thư mục của một team khác nằm phía trên thư mục của bạn.

Điều này khác gì với bộ nhớ của agent, hoặc một kỹ năng (skill)?

Các cơ chế này trông có vẻ giống nhau nhưng lại thất bại theo những cách hoàn toàn khác biệt, vì vậy cần phải xác định chính xác bạn đang muốn sử dụng cái nào.

AGENTS.md do bạn viết, được commit vào git, được review trong pull request và giống hệt nhau đối với bất kỳ ai clone repository. Bộ nhớ của agent do agent tự viết, được lưu trữ bên ngoài repository và chỉ cục bộ trên một máy. Tài liệu của Claude Code cũng vạch ra ranh giới tương tự: CLAUDE.md chứa "Hướng dẫn và quy tắc" do bạn viết, bộ nhớ tự động chứa "Những điều đã học và các mẫu hình" do Claude viết, và thư mục bộ nhớ không được chia sẻ giữa các máy. Bài kiểm tra rất đơn giản. Nếu một dữ kiện bắt buộc phải đúng với một đồng nghiệp trên một bản clone mới, nó không được phép nằm trong bộ nhớ. Cách bộ nhớ của agent duy trì giữa các phiên làm việc bao quát phần đó của vấn đề.

Kỹ năng (skill) là yếu tố thứ ba. AGENTS.md là ngữ cảnh được tải trong mọi phiên làm việc; kỹ năng là một quy trình được tải khi cần thiết. Tài liệu của Claude Code đưa ra một quy tắc hữu ích: "Nếu một mục là quy trình gồm nhiều bước hoặc chỉ quan trọng đối với một phần của codebase, hãy chuyển nó sang kỹ năng hoặc quy tắc theo đường dẫn (path-scoped rule)." Vế sau của câu đó chính xác là những gì mà AGENTS.md lồng nhau giải quyết. Vế đầu là mục đích của các kỹ năng của agent, và khi cùng một quy trình cần thiết ở nhiều repository, hãy chia sẻ kỹ năng giữa các repo thay vì dán cùng một đoạn văn vào mười file AGENTS.md khác nhau.

Upstream lưu ý rằng "tại thời điểm viết bài, repository chính của OpenAI có 88 file AGENTS.md". Con số đó là toàn bộ lập luận. Một repository lớn không cần một file lớn hơn. Nó cần nhiều file nhỏ hơn, mỗi file nằm cạnh đoạn code mà nó mô tả, và mỗi file được sở hữu bởi người cuối cùng đã thay đổi đoạn code đó.

FAQ

File AGENTS.md lồng nhau thay thế file ở root hay bổ sung vào đó?

Nó bổ sung vào đó. Upstream cho biết "file gần nhất sẽ được ưu tiên", điều này mô tả những gì xảy ra khi có xung đột, chứ không phải những gì được load. Codex "nối các file từ root xuống, ngăn cách bằng các dòng trống", và Claude Code nối mọi file mà nó tìm thấy khi duyệt từ thư mục làm việc lên thay vì ghi đè chúng. File gần nhất chỉ thắng khi hai file đưa ra các chỉ dẫn khác nhau về cùng một chủ đề. Hãy viết các quy tắc chung tại root một lần và đừng lặp lại chúng trong mọi thư mục.

File AGENTS.md ở root nên lớn bao nhiêu?

Đủ nhỏ để bạn không thấy phiền khi nó bị dán vào đầu mọi request bạn thực hiện trong repository đó, vì đó chính xác là những gì sẽ xảy ra. Tài liệu của Claude Code gợi ý nên giữ dưới 200 dòng mỗi file và cảnh báo rằng các file dài hơn sẽ "làm giảm độ tuân thủ". Codex mặc định dừng việc gộp các file chỉ dẫn ở mức 32 KiB tổng cộng. Nếu file root của bạn mô tả bốn dịch vụ, phần lớn nội dung đó là dữ liệu thừa cho bất kỳ tác vụ đơn lẻ nào. Hãy chuyển các chi tiết xuống các file theo thư mục và để lại một bản đồ chỉ dẫn.

Làm thế nào để các file này không bị lỗi thời?

Đặt một quy tắc trong file root: bất kỳ ai thay đổi code trong một thư mục phải cập nhật file AGENTS.md của thư mục đó trong cùng một commit. Việc đặt file cạnh code giúp quy tắc này hiệu quả hơn, vì thay đổi đó sẽ nằm trong cùng một pull request diff mà con người đang đọc. Thêm một cảnh báo CI để ánh xạ mỗi đường dẫn đã thay đổi tới file AGENTS.md gần nhất phía trên nó, và thỉnh thoảng hãy so sánh git log -1 --format=%cs trên mỗi file với cùng lệnh đó chạy trên thư mục mà nó mô tả.

Claude Code có đọc các file AGENTS.md không?

Không. Tính đến tháng 8 năm 2026, tài liệu nêu rõ "Claude Code đọc CLAUDE.md, không phải AGENTS.md." Hãy tạo một CLAUDE.md trong cùng thư mục với @AGENTS.md ở dòng đầu tiên, lệnh này sẽ load file dùng chung và cho phép bạn thêm các chỉ dẫn cụ thể cho Claude ở bên dưới. Một symlink được tạo bằng ln -s AGENTS.md CLAUDE.md sẽ hoạt động khi không có gì cần thêm, mặc dù trên Windows nó cần quyền Administrator hoặc Developer Mode. Chạy /context trong một phiên làm việc và xác nhận file xuất hiện trong Memory files.

Tôi nên đặt một quy tắc chỉ quan trọng đôi khi ở đâu?

Không phải trong AGENTS.md. File đó được load trong mọi phiên làm việc, vì vậy mọi dòng trong đó đều cạnh tranh sự chú ý với request mà bạn thực sự đã nhập. Một quy trình gồm nhiều bước chỉ cần thiết thỉnh thoảng nên thuộc về một skill, thứ được load theo yêu cầu. Một quy tắc áp dụng cho một thư mục nên nằm trong file AGENTS.md của thư mục đó. Một sự thật mà agent có thể đọc trực tiếp từ code, chẳng hạn như cây thư mục hoặc danh sách dependency, thì không thuộc về cả hai nơi trên.