← All Blog articles
SaaSClaude CodeCodexモノレポ

Which CLAUDE.md and AGENTS.md files load? A measured monorepo

18 min read

Go deeper on this topic

SaaS integrations

Give AI the context to continue the work: source conversations, open tasks, and unresolved details, from adoption decisions to integration code.

Article 3 of 10 in this series.

View topic page

Use the topic hub as a map, then continue to the next article in the series. New here? Start at the home hub →

Claude Code loads ancestor CLAUDE.md files at startup and nested files when work reaches their directory. It also supports AGENTS.md, but its default selection prefers CLAUDE-family files found in or above the launch directory. Neither “every package loads at startup” nor “AGENTS.md is always ignored” is a reliable rule for a monorepo.

Key findings

  • Launching at the root produced no instruction events for packages a or b. Reading a normal file in a added a's CLAUDE.md.
  • A CLAUDE.md above the Git root loaded too. The Git boundary did not isolate instructions.
  • A seven-hop import chain produced events through hop four. Standard output and standard error contained no depth warning.
  • Codex returned canaries from the root through its launch directory. Claude hook events and Codex model replies are different kinds of evidence.

Checked 2026-10-26, Asia/Tokyo. Tested Claude Code 2.1.308 / codex-cli 0.163.0 on macOS. Official sources are unversioned living pages accessed that day. These observations do not establish behavior for every release or setting, or prove instruction compliance.

What did the monorepo fixture measure?

We created a synthetic Git repository beneath /tmp, with a parent directory, packages a and b, and distinct CANARY_ strings per instruction file. On macOS the resolved path was /private/tmp. The ordinary probe file contained no canaries.

fixture/
├── CLAUDE.md                 CANARY_PARENT_CLAUDE
├── AGENTS.md                 CANARY_PARENT_AGENTS
└── repo/                     git init boundary
    ├── CLAUDE.md             CANARY_ROOT_CLAUDE + @imports/1.md
    ├── AGENTS.md             CANARY_ROOT_AGENTS
    ├── CLAUDE.local.md       CANARY_LOCAL_CLAUDE
    ├── .claude/CLAUDE.md     CANARY_DOT_CLAUDE
    ├── imports/1.md → … → 7.md
    └── packages/
        ├── a/CLAUDE.md, AGENTS.md, probe.txt
        └── b/CLAUDE.md, AGENTS.md, AGENTS.override.md

For Claude, an InstructionsLoaded hook recorded only the fixture-relative filename, scope, reason, and import parent. Reasons distinguish startup (session_start), imports (include), and access to a nested directory (nested_traversal). Hooks run asynchronously, so event line order does not establish concatenation order. Official hook reference

We also asked each model to return only canaries already present in its supplied instructions. An omitted canary does not prove a file was absent. In particular, the official docs say native AGENTS.md discovery does not fire this hook. We did not obtain an equivalent injection trace from Codex; its JSONL replies are corroboration of the documented discovery rules, rather than a deterministic loading trace.

Do nested CLAUDE.md files load at startup?

The parent CLAUDE.md, root CLAUDE.md, .claude/CLAUDE.md, and CLAUDE.local.md all produced session_start events in each Claude run.

Claude operation packages/a/CLAUDE.md packages/b/CLAUDE.md Import chain
Root startup, no tools No event No event Hops 1–4: include
packages/a startup, no tools session_start No event No include events
Read a/probe.txt after root startup nested_traversal No event Hops 1–4: include

An absent package instruction at root startup is not sufficient evidence of a configuration failure. The docs describe loading child instructions when Claude accesses files there. Official memory documentation

Starting inside a loaded the ancestor CLAUDE.md files but produced no import events. We did not establish the cause of that difference. The docs require approval for project imports resolving outside the working directory. Record external-import approval state and non-interactive settings when reproducing this case.

Does Claude Code ignore AGENTS.md or read both files?

The current official documentation supports AGENTS.md from Claude Code v2.1.277. Under the default claude-md-or-agents-md selection, a CLAUDE.md, .claude/CLAUDE.md, or CLAUDE.local.md in the launch directory or its ancestors selects the CLAUDE files. The user's ~/.claude/CLAUDE.md does not count toward that selection.

Our mixed layout returned no AGENTS canaries in Claude's replies, consistent with that default. We did not measure an AGENTS-only layout or the setting that loads both. Native AGENTS loading is outside the hook's coverage, so missing hook events alone cannot diagnose it. AGENTS.md selection and settings

The official docs offer Project instructions in /config, or the following configuration passed through --settings, to read both. This plugin option is ignored in project/local settings files. This is a documented example, not the configuration tested here.

{
  "pluginConfigs": {
    "cc-plugin-agents-md@builtin": {
      "options": { "instructionFiles": "claude-md-and-agents-md" }
    }
  }
}

How many @import hops load, and is there a warning?

Counting the root CLAUDE.md as hop zero, we chained @imports/1.md through 7.md. Both runs launched at repo recorded include events for files 1, 2, 3, and 4, with none for 5, 6, or 7. Their canary replies also stopped at four, matching the documented four-hop maximum.

Both runs had zero-byte standard error and no depth warning in their normal replies. A depth-related keyword search in the debug logs found no matches either. This does not guarantee silent behavior in every UI or version. Check the files actually observed rather than relying on a deep chain.

Relative @path imports resolve from the containing file. Imports written inside a code span or fenced code block stay literal. Official import rules

How does Codex AGENTS.md discovery compare?

The comparison below distinguishes documentation from observations. “More specific guidance takes precedence” does not mean all ancestor text is discarded. Codex's docs explicitly describe concatenating discovered files and giving later guidance priority. Official Codex discovery rules

Question Claude Code Codex
Filenames CLAUDE.md, .claude/CLAUDE.md, CLAUDE.local.md; AGENTS.md depends on version, settings, and layout AGENTS.override.md, then AGENTS.md, then configured fallbacks; at most one file per directory
Direction and boundary Launch directory and ancestors; child files load on access. We observed a parent above Git root Project/Git root down to cwd; global guidance is separate. The parent canary was not returned
Merge and override Discovered CLAUDE-family files concatenate; a nested file does not erase the entire ancestor Discovered levels concatenate, later guidance takes precedence; override wins over AGENTS.md at the same level
Import depth Documented maximum: four hops; root runs observed 1–4 Equivalent @import behavior was not tested; do not assume shared syntax
Size Docs recommend fewer than 200 lines per file; no hard limit measured here Default project_doc_max_bytes: 32 KiB; boundary behavior not measured here
Verification /context Memory files, InstructionsLoaded, debug; native AGENTS is outside hook coverage Official examples ask the model for loaded sources; our replies are not a direct injection trace

Codex actually returned CANARY_ROOT_AGENTS at root, that plus CANARY_A_AGENTS in a, and root plus CANARY_B_OVERRIDE in b. It did not return b's ordinary AGENTS.md canary. No tool execution was observed. We did not test size boundaries, compliance with conflicting instructions, or changing cwd during a session.

How can both tools share one source, and how can you reproduce this?

If Claude-specific additions are needed, the official docs describe keeping shared text in AGENTS.md and importing it from an adjacent CLAUDE.md. We did not run that sharing layout in this experiment.

# Actual contents of CLAUDE.md
@AGENTS.md

# Add Claude-specific instructions below

Do not include the surrounding Markdown fence in the file. With no Claude-specific additions, the docs also offer ln -s AGENTS.md CLAUDE.md. Consider Windows symlink permissions and Git settings, and edit the target rather than writing through the link. Verify either layout in the next real session.

To reproduce the measurements, save the distributable script on a Mac with existing Claude Code and Codex authentication, Node.js 22 or later, and Git.

claude --version
codex --version
node instruction-discovery.mjs --create-only  # Create synthetic files only
node instruction-discovery.mjs --run          # Measure a separate synthetic fixture
shasum -a 256 instruction-discovery.mjs

Recorded commands, exact extracted replies, and fixture events are available as JSON. Startup metadata and raw debug are omitted from the shared record.

Distributable SHA-256: 7bd46337e5018c96e0ed7770423ecaf099821d52b25e4937ab22b52217a6bfea.

--run makes three Claude and three Codex non-interactive calls. It uses existing authentication and retains the fixture and results. Your authentication's normal usage limits or API charges apply. Claude excludes user settings, outside instruction files, and MCP, and restricts Read to the single synthetic probe. Codex ignores user config, uses read-only mode, and is asked not to use tools. This does not prove complete isolation of global guidance or managed policy.

commands.json records cwd, arguments, and exit codes; *.hooks.jsonl holds fixture-only instruction events; *.stdout.txt and *.stderr.txt retain output. Claude's actual arguments include -p --setting-sources project,local --settings <fixture>/settings.json --debug-file <fixture>/results/<case>.debug.txt. We avoid an empty --setting-sources: a pilot disabled project memory with that setting. Raw debug logs can contain machine configuration, so share only the required fixture records.

For the next session, record CLI version, cwd, instruction settings, observed events, and untested conditions. Use the context handoff guide for task state and revision checks, MCP configuration for connection selection, and hook exit codes for checks that stop an action. Confirm instruction loading separately from enforced controls.

FAQ

Q. Do all package CLAUDE.md files load at startup?
Our root launch produced no events for a or b. Reading an ordinary file in a added its CLAUDE.md with nested_traversal. Launching directly inside packages/a loaded that file at session start.
Q. Does Claude Code support AGENTS.md?
The current official docs support it from v2.1.277. The default prefers CLAUDE-family files when present in the launch directory or its ancestors. Our mixed-layout replies agreed with that description; AGENTS-only and both-files settings were not measured.
Q. How many @import hops were observed?
Both root launches on 2.1.308 recorded include events for hops 1–4 of a seven-hop chain. Standard output and error contained no depth warning. Other versions and UIs were not tested.
Q. Does a nested Codex AGENTS.md replace all ancestor text?
The docs describe concatenating levels with later guidance taking precedence. At one level AGENTS.override.md is selected first. Our b reply contained root and b override canaries, without the ordinary b AGENTS canary. Replies are not direct injection logs.