---
url: https://docs.nemo12.com/engineering/docs-for-agents.md
description: >-
  Chuẩn để AI agent đọc docs.nemo12.com: llms.txt, bản .md từng trang, trường
  description, trần cỡ trang, thứ tự nội dung và bảng việc G1 tới G10.
---

# Docs cho AI agent

Phần lớn người đọc docs.nemo12.com hôm nay là agent: phiên Claude Code trên repo, agent trên cloud,
agent của đối tác. Agent không lướt thanh bên như người; nó đọc một tệp, quyết định có mở tiếp hay
không, và trả giá bằng token cho mọi chữ nó tải về. Trang này là chuẩn để docs phục vụ được người
đọc ấy mà không làm hỏng trải nghiệm của người đọc là người (SRC-1322, audit ngày 10.10.2026).

## Chuẩn hiện hành

### 1. Lối vào: `/llms.txt`, `/llms-full.txt` và bản `.md` của từng trang

| Địa chỉ | Là gì | Dùng khi |
| --- | --- | --- |
| `https://docs.nemo12.com/llms.txt` | Mục lục theo [llmstxt.org](https://llmstxt.org/): tiêu đề, một đoạn tóm tắt song ngữ Việt/Anh, rồi một mục `##` cho mỗi mảng sản phẩm, mỗi trang một dòng gồm tiêu đề có link tới bản `.md`, dấu hai chấm, rồi `description`. Trang Legacy và trang `status: superseded` dồn xuống `## Optional`. | Agent mới vào, cần biết đọc trang nào. |
| `https://docs.nemo12.com/<trang>.md` | Bản Markdown sạch của đúng trang HTML cùng đường dẫn (bỏ HTML, giữ bảng và code; frontmatter chỉ còn `url` và `description`). Trang `foo/index` thành `foo.md`. | Đã biết cần trang nào. |
| `https://docs.nemo12.com/llms-full.txt` | Toàn bộ docs trong một tệp (khoảng 9 MB). | Chỉ khi cần tìm kiếm toàn văn ngoài repo; trong repo thì đọc thẳng `docs/`. |

Mọi trang HTML còn có thẻ `<link>` trong `<head>` trỏ tới `/llms.txt`, và trang đầu có một dòng ẩn
nói điều tương tự cho agent chỉ đọc chữ.

Cách dựng: plugin [`vitepress-plugin-llms`](https://github.com/okineadev/vitepress-plugin-llms) bản
1.14.0 (ghim số theo [DS-001 §0](../design-system/stack-and-packages.md)), cấu hình ở
`apps/docs/.vitepress/config.mts`. Mục lục của `/llms.txt` không dùng mục lục mặc định của plugin
mà dựng trong `apps/docs/.vitepress/llms.mjs` từ chính `structure.mjs` của thanh bên (SRC-1024), nên
thêm một tài liệu vào đúng mảng là nó tự có chỗ trong `/llms.txt`. Trang con của `curriculum/` (322
unit) không liệt kê trong `/llms.txt`, chỉ trang `index` của từng môn và từng package; mọi unit vẫn
có bản `.md` riêng và nằm trong `llms-full.txt`.

Cloudflare phục vụ các tệp này như tài sản tĩnh: `wrangler.jsonc` của docs chỉ khai thư mục
`.vitepress/dist`, `_redirects` chỉ đổi đường dẫn không đuôi (`/map` về `/`), và `cleanUrls` chỉ bỏ
đuôi `.html`, nên `.md` và `.txt` đi thẳng ra ngoài.

### 2. Trường `description` bắt buộc

Mọi file trong `docs/` có `description:` trong frontmatter: một câu tiếng Việt, tối đa 160 ký tự,
nói trang **trả lời câu hỏi gì**, đặt trong ngoặc kép (YAML đọc sai một chuỗi trần có `: `). Trang
đã bị thay thì câu mở đầu nói điều đó ("Đã gộp vào ..."). Không viết câu rỗng kiểu "Tài liệu này mô
tả ..."; nêu tên sản phẩm, mã SDD, đối tượng đọc khi chúng giúp agent chọn trang.

File dưới `curriculum/` từ nay cũng có frontmatter, nhưng chỉ gồm `title` và `description`: bộ luật
PRD (`id`, `type`, `status`...) vẫn không áp cho chúng, đúng lý do SRC-496 đã ghi trong
`scripts/check-docs.mjs`.

Script sinh docs (`gen-reference.mjs`, `gen-skills-catalog.mjs`, `audit-items.mjs`,
`audit-labs.mjs`, `audit-package-bounds.mjs`) tự ghi `description`; sửa câu thì sửa trong script.

### 3. Cỡ trang: 40 KB mềm, 80 KB cứng

| Ngưỡng | Hệ quả |
| --- | --- |
| Trên 40 KB | Cảnh báo: nên tách. Một agent đọc trang này đã tốn khoảng 10 nghìn token trước khi làm gì. |
| Trên 80 KB | Đỏ: phải tách thành trang tổng quan cộng các trang con. |

Lý do: một trang 600 KB (SDD-038 lúc audit) vượt cửa sổ đọc của mọi công cụ đọc tệp, nên agent đọc
cắt cụt hoặc bỏ qua, và cả hai đều tệ hơn một trang ngắn trỏ sang trang chi tiết. Báo cáo audit dưới
`quality/audits/` được miễn vì chúng đóng băng theo ngày chấm.

### 4. Thứ tự trong một trang: đặc tả hiện hành trước, lịch sử sau

Theo [Diátaxis](https://diataxis.fr/): một trang thuộc MỘT loại (hướng dẫn, cách làm, tham chiếu,
giải thích) và không trộn. Ở Nemo12 điều đó thành ba luật viết:

1. Phần đầu trang là **trạng thái đúng hôm nay**: hệ thống đang làm gì, luật đang áp.
2. Lý do và quyết định đi kèm ngay sau luật mà chúng giải thích, ngắn.
3. **Lịch sử** (đợt sửa, SRC cũ, cách làm đã bỏ) xuống cuối trang dưới một mục `## Lịch sử`, hoặc
   sang trang riêng. Agent đọc từ trên xuống và dừng sớm; lịch sử ở đầu trang là thứ nó mang theo
   làm đặc tả.

### 5. Chỉ dẫn cho agent trong repo: CLAUDE.md, rules, skills

Theo [hướng dẫn memory của Claude Code](https://code.claude.com/docs/en/memory) và
[agents.md](https://agents.md/):

| Tệp | Trần | Vì sao |
| --- | --- | --- |
| `CLAUDE.md` gốc | dưới 200 dòng | Nạp vào MỌI phiên, mọi lượt. Luật chỉ đúng cho một thư mục thì chuyển sang `.claude/rules/*.md` có `paths:` để chỉ nạp khi agent chạm vào thư mục ấy. |
| `.claude/skills/*/SKILL.md` | dưới 500 dòng | Theo [anthropics/skills](https://github.com/anthropics/skills): phần thân skill nạp khi gọi; chi tiết dài để trong tệp tham chiếu cạnh skill và trỏ tới. |
| Trang docs | 80 KB | Mục 3. |

### 6. `sources:` dài trong frontmatter

`sources:` là hợp đồng truy vết: cổng SRC-596 (`scripts/check-src-canonical.mjs`) chỉ đếm một SRC là
"đã có chỗ" khi mã ấy nằm trong FRONTMATTER của một doc. Dời danh sách xuống thân trang hay sang tệp
khác là làm cổng ấy mất dấu hàng trăm SRC, nên **không dời**. Frontmatter cũng không hiện trên trang
HTML, nên người đọc không thấy nó; chỉ agent đọc tệp nguồn mới trả giá. Quyết định: giữ nguyên chỗ,
cảnh báo khi một trang có quá 30 mã (dấu hiệu trang ôm quá nhiều việc, cần tách), không chặn.

## Cổng thi hành

`scripts/check-docs-agents.mjs`, chạy trong `npm run check:docs` (và CI):

* ĐỎ: thiếu `description`, `description` quá 160 ký tự, chưa đặt trong ngoặc kép mà chứa `: `, hay
  kết thúc bằng dấu ba chấm; trang trên 80 KB.
* CẢNH BÁO: trang trên 40 KB; `sources:` quá 30 mã; tên trong allowlist không còn tồn tại.
* Ngưỡng 40 KB VẪN là cảnh báo, chưa thành đỏ (quyết định 10.10.2026): luật là chỉ siết khi số cảnh
  báo về 0, và sau đợt tách thứ ba còn hai trang là sổ mà script đọc hoặc ghi theo dòng
  (`traceability.md`, mảnh intake `intake/src-0550-0574.md`). Tách chúng là đổi định dạng sổ, việc
  riêng; khi cả hai về dưới 40 KB thì đổi cảnh báo thành đỏ kèm một allowlist chỉ co.
* Trang SINH RA thì tách ở bộ sinh, không tách tay: `api.md` (`gen-reference.mjs`, trang con
  `reference/api/`), danh mục skill (`gen-skills-catalog.mjs`, nhóm có trang bộ chỉ còn một dòng mỗi
  skill), bản đồ từ khoá (`apps/web/scripts/keyword-coverage.mjs --docs`, trang con `ops/seo-keywords/`).
* Allowlist TẠM, chỉ được co: `SPLITTING` (rỗng từ 10.10.2026: sáu tệp đã tách xong, cuối cùng
  là bảng REQ §5 của PRD-001 thành mảnh `product/prd-001/req/<area>.md`, bản đồ nhóm → mảnh ở
  `scripts/lib/req-ledger.mjs`) và `OVERSIZE_DEBT` (năm trang quá 80 KB có từ trước, chưa ai nhận tách). PR tách xong thì xoá dòng của mình khỏi allowlist
  trong cùng PR.
* Miễn luật cỡ trang: chỉ báo cáo `quality/audits/` (đóng băng theo ngày chấm). Mảnh sổ
  `intake/src-*.md` KHÔNG còn miễn (SRC-1322): dải 100 số để ba mảnh vượt 80 KB, dải 50 vẫn để
  ba mảnh trên 60 KB, nên sổ chia theo dải **25 số** (mảnh lớn nhất ~41 KB). Đổi cỡ dải: sửa
  `SHARD_SIZE` trong `scripts/lib/intake-ledger.mjs`, chạy `node scripts/intake-reshard.mjs`, cập
  nhật bảng mục lục trong `intake.md` và thêm chuyển hướng URL mảnh cũ vào `docs/public/_redirects`.

## Bảng việc (audit 10.10.2026)

| # | Khoảng trống | Trạng thái |
| --- | --- | --- |
| G1 | Không có `/llms.txt`, `/llms-full.txt`, bản `.md` từng trang | ✅ SRC-1322: plugin trên docs; pearl, compass, playbooks cũng sinh với cấu hình mặc định |
| G2 | Các trang khổng lồ (SDD-038 ~580 KB, SDD-029 ~310 KB, PRD-001 ~270 KB, data dictionary ~440 KB, SDD-023) | ✅ SRC-1322: SDD-038 thành `architecture/sdd-038/` (19 trang), SDD-029, SDD-023 và PRD-001 thành thư mục (bảng REQ §5 thành 8 mảnh `product/prd-001/req/<area>.md`, mỗi mảnh dưới 40 KB), data dictionary chia trang; `SPLITTING` rỗng. Đợt ba (10.10.2026): SDD-002, SDD-010, SDD-027, guided-journey, visitor-state, family-notes-review, emails, course-design-standard, incident-log thành thư mục; user stories 71+ chia hai trang; `api.md`, danh mục skill, bản đồ từ khoá chia ở bộ sinh |
| G3 | `intake.md` (~670 KB) và `knowledge/*.md` quá lớn để agent đọc trọn | ✅ SRC-1322: `intake.md` thành mục lục + mảnh 25 số `intake/src-XXXX-YYYY.md`; `knowledge/<môn>/` thành trang con, mọi trang có `description` |
| G4 | Không trang nào có `description` | ✅ SRC-1322: mọi trang có, kể cả trang sinh ra từ lượt tách; cổng bắt buộc |
| G5 | `sources:` hàng chục mã làm phình đầu trang | ✅ quyết định: giữ chỗ cũ vì cổng SRC-596, cảnh báo trên 30 mã (mục 6) |
| G6 | Trang không có frontmatter (322 trang `curriculum/`; `knowledge/` để lượt tách) | ✅ SRC-1322: thêm `title` + `description`; `map.md` giữ `status: superseded` và chuyển hướng `/map` về `/` |
| G7 | `CLAUDE.md` 218 dòng, chưa có `.claude/rules/` | ✅ SRC-1322 (#569): `CLAUDE.md` 218 xuống 96 dòng, luật theo vùng ra `.claude/rules/*.md` có `paths:`, thêm `AGENTS.md`, gộp trí nhớ trùng trong `.claude/memory/` |
| G8 | Skill dài quá 500 dòng | ✅ đo 10.10.2026: 56 skill, không skill nào quá 500 dòng |
| G9 | Lịch sử đứng trước đặc tả trong nhiều SDD | 🔄 SDD-038 đã áp (đặc tả hiện hành trước, lịch sử quyết định cuối mỗi trang con); các SDD khác áp dần theo mục 4 |
| G10 | Không có trần cỡ trang | ✅ SRC-1322: 40 KB mềm, 80 KB cứng, allowlist chỉ co |

## Nguồn

* [llmstxt.org](https://llmstxt.org/) và [AnswerDotAI/llms-txt](https://github.com/AnswerDotAI/llms-txt): định dạng `llms.txt`, mục `## Optional`.
* [okineadev/vitepress-plugin-llms](https://github.com/okineadev/vitepress-plugin-llms): plugin VitePress, trường `description`.
* [agents.md](https://agents.md/): tệp chỉ dẫn cho agent trong repo.
* [anthropics/skills](https://github.com/anthropics/skills): cấu trúc và độ dài skill.
* [Claude Code memory](https://code.claude.com/docs/en/memory): `CLAUDE.md`, `.claude/rules/` theo đường dẫn.
* [Diátaxis](https://diataxis.fr/): bốn loại tài liệu, không trộn.
