Skip to content

docs: make AGENTS.md hierarchical - #3773

Draft
akoumpa wants to merge 1 commit into
NVIDIA-NeMo:mainfrom
akoumpa:akoumparouli/docs_hierarchical_agents_md
Draft

docs: make AGENTS.md hierarchical#3773
akoumpa wants to merge 1 commit into
NVIDIA-NeMo:mainfrom
akoumpa:akoumparouli/docs_hierarchical_agents_md

Conversation

@akoumpa

@akoumpa akoumpa commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

What does this PR do ?

Splits the single 294-line root AGENTS.md into a root file plus 12 subtree files placed next to the code they govern, readable by both Claude Code and Codex, with no symlinks.

Changelog

  • Root AGENTS.md 294 → 199 lines. Keeps only repo-wide rules plus a routing table. The 75-line architecture tour is dropped in favour of docs/repository-structure.mdx, which is already maintained and already correct.
  • 12 subtree AGENTS.md files under nemo_automodel/, _transformers/, components/{models,moe,distributed,checkpoint,datasets}/, recipes/, examples/, tests/, docs/, .github/.
  • A CLAUDE.md beside every AGENTS.md, containing exactly one line: @AGENTS.md.
  • tests/unit_tests/test_agents_md_hierarchy.py — 53 checks enforcing the invariants below.
  • Fixes stale cicd skill guidance that documented a PR title format the CI check rejects.

Why hierarchical

The flat file had drifted, because a fact 250 lines away from its code never appears in the diff that invalidates it. All four items below were live on main:

Claim Reality
_cli/app.py (×2) the directory is nemo_automodel/cli/ — no _cli exists
"27+ model families" 53 directories under components/models/
components/ list, 7 entries 20 subdirectories
recipes/{llm,vlm,diffusion,retrieval} also dllm/, multimodal/

Both agents, one source of truth, no symlinks

AGENTS.md is the real file; Codex reads it natively. Claude Code reads CLAUDE.md and not AGENTS.md, so each directory also holds a CLAUDE.md whose entire contents are the import line @AGENTS.md. An import resolves relative to the file containing it, so each one picks up its own sibling rather than the repository root — verified by loading a file in components/moe/ and confirming the MoE rules (not the root rules) were what got injected.

Deliberately a regular file rather than a symlink. Symlinks need Administrator or Developer Mode on Windows, and any checkout or archive export that does not preserve them writes the literal text AGENTS.md, silently reducing a directory's rules to one meaningless word. This PR adds no symlinks and removes one — the pre-existing root CLAUDE.md symlink is converted to the same import form, so the convention is uniform at every level. The 10 .claude/skills/* directory symlinks already on main are a separate mechanism and are untouched.

Both tools concatenate root-to-leaf, so a nested file is read in addition to the root. The agents.md spec instead says the nearest file wins. Nested files are therefore written additively — each states only what is additionally true in its subtree and never contradicts an ancestor — so all three readings agree. Each opens with Adds to the repository root AGENTS.md, which the test enforces.

The drift guard

test_agents_md_hierarchy.py is the part that makes this pay off rather than multiplying the problem by 13:

  1. every AGENTS.md has a sibling CLAUDE.md containing exactly @AGENTS.md, and is not a symlink;
  2. every backticked path in any instruction file exists on disk — this alone would have caught 3 of the 4 drift items above;
  3. the root routing table matches the files on disk in both directions;
  4. line budgets: root ≤ 200, nested ≤ 80;
  5. every nested file declares itself additive.

It runs in L0 on every PR, so no new workflow.

Note on the pre-existing review-policy test

tests/unit_tests/test_claude_review_policy.py pins ~12 exact strings to the root AGENTS.md (config-owned construction, MODEL_ARCH_MAPPING, _CUSTOM_CONFIG_REGISTRATIONS, …). Those are repo-wide review gates, so they stay at root verbatim and that test is unmodified and passing; the subtree files elaborate rather than relocate them. 144 passed across both files.

Also fixed

.agents/contributor-skills/cicd/SKILL.md documented PR title format: [{areas}] {type}: {description} and branch names like username/feat_add_qwen2_recipe. Validate PR title uses the semantic-PR template, which rejects bracket-prefixed titles — and the root AGENTS.md said so explicitly, so the two files contradicted each other. The skill now matches what CI enforces.

Before your PR is "Ready for review"

Pre checks:

  • Make sure you read and followed Contributor guidelines
  • Did you write any new necessary tests?
  • Did you add or update any necessary documentation?

Additional Information

Docs-only plus one new CPU unit test; no runtime code paths touched. tools/lint_example_yamls.py still lints 519 YAMLs clean.

@copy-pr-bot

copy-pr-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@akoumpa

akoumpa commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 044d3e5

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

The root AGENTS.md had grown to 294 lines and carried subtree-specific rules
far from the code they govern. That distance let it drift: it pointed at
`_cli/app.py` (the directory is `cli/`), claimed "27+ model families" against
53 on disk, listed 7 of 20 `components/` subdirectories, and named recipe
domains that omitted `dllm/` and `multimodal/`.

Split it into one root file plus 12 subtree files, each next to the code it
describes so a rename that invalidates guidance shows up in the same diff.
The root keeps only repo-wide rules and a routing table; the drifted
architecture tour is dropped in favour of `docs/repository-structure.mdx`,
which is already maintained and already correct.

line `@AGENTS.md`, which resolves relative to the file containing it and so
picks up its own sibling. A regular file rather than a symlink: symlinks need
Administrator or Developer Mode on Windows, and checkouts that do not preserve
them write the literal text `AGENTS.md` instead. This also converts the existing

Both tools concatenate root-to-leaf, so nested files are written additively and
never contradict an ancestor; that also satisfies the agents.md spec's
nearest-file-wins reading.

test_agents_md_hierarchy.py enforces the sibling files, the routing table, the
line budgets, and that every path named in an instruction file exists on disk.

Also corrects the cicd skill, which documented a PR title format
(`[model] feat: ...`) and branch naming that the Validate PR title check
rejects.

Signed-off-by: Alexandros Koumparoulis <akoumparouli@nvidia.com>
@akoumpa
akoumpa force-pushed the akoumparouli/docs_hierarchical_agents_md branch from 044d3e5 to 65d45e9 Compare September 1, 2026 03:24
@akoumpa

akoumpa commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 65d45e9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant