[KongchangAI]
· 4 min read· 2,045 words

One Set of Rules, Two Use Cases: Nested Codex and Subdirectory AGENTS.md in Claude

One Set of Rules, Two Use Cases: Nested Codex and Subdirectory AGENTS.md in Claude

Explains the rule-loading differences between Codex and Claude Code, offering a complete solution for sharing rule files in monorepos.

Addressing the problem of AI coding agent rule files not taking effect in monorepos, the article compares Codex and Claude Code loading mechanisms: Codex builds an instruction chain once from the root directory to the launch directory, so the launch location determines rule scope; Claude Code loads upper-level CLAUDE.md at startup and loads subdirectory rules on demand during runtime. The solution uses a layered design, with AGENTS.md carrying the actual rules and a single-line @AGENTS.md CLAUDE.md in each directory enabling cross-tool sharing. The article also covers verifying loaded content via codex debug prompt-input, the /context command, and the InstructionsLoaded hook, and emphasizes that rule files are only guidance context—prohibited operations require permission deny rules or PreToolUse hooks to enforce constraints.

Why Aren't Your Rule Files Taking Effect?

In a monorepo, apps/web/AGENTS.md explicitly requires using Vitest and prohibits modifying the generated API client. But when you launch Codex from the repository root and ask it to fix a React component, it still touches src/generated/client.ts. The reason is simple: that file never made it into the prompt.

According to Codex's official documentation, Codex builds the instruction chain only once per run, from the project root down to the directory you launch from; rule files below that are excluded. Claude Code works the opposite way: it loads a subdirectory's CLAUDE.md only when it touches a file in that subdirectory.

This difference in loading logic means the same set of rule files behaves completely differently under the two tools. The solution: build an independent rulebook for each package, and verify what each agent actually loads.

Rule file loading mechanism diagram

Step 1: Layered Design of Root Files and Package-Level Files

Take a monorepo with a React frontend and a Go backend as an example. The recommended directory structure is:

acme/
  AGENTS.md            # Repository-level rules
  CLAUDE.md            # @AGENTS.md
  apps/web/
    AGENTS.md          # Frontend rules
    CLAUDE.md          # @AGENTS.md
  services/api/
    AGENTS.md          # Backend rules
    CLAUDE.md          # @AGENTS.md

AGENTS.md is the shared format defined by agents.md, supported by a variety of tools including Codex, and carries the actual rule content. Each CLAUDE.md contains only a single import line, the reason for which is explained in Step 3.

The root file covers repository-wide common rules, such as commit message prefixes, prohibiting committed secrets, and running scripts inside package directories. The frontend file only contains frontend-related content: testing with npx vitest run, prohibiting edits to src/generated/, and using functional components. The backend file only contains backend rules: using go test ./..., not modifying merged migrations, and wrapping errors with fmt.Errorf.

The Rulebook: marker on the first line of each file is designed for the verification in Step 4. Be careful to control file size: Anthropic's documentation recommends keeping each CLAUDE.md under 200 lines, while Codex stops appending files when the combined size reaches project_doc_max_bytes (default 32 KiB).

The AGENTS.md format was proposed by the agents.md community to provide a unified rule-file interface for different AI coding agents, avoiding the need to maintain separate configurations for each tool. It is written in Markdown and can include project conventions, command examples, directory descriptions, and more. Codex natively supports this format, and Claude Code has also been compatible with reading it since v2.1.277, but with lower priority than CLAUDE.md. The @AGENTS.md import syntax in CLAUDE.md is a file-reference mechanism specific to Claude Code; when parsed, it inlines the target file's content into the current context and does not trigger duplicate loading. This design makes AGENTS.md the single source of truth, while CLAUDE.md serves only as an adaptation layer.

Step 2: How Codex Builds the Instruction Chain

Codex's loading order is as follows:

  1. Global files take priority: AGENTS.override.md under ~/.codex (or $CODEX_HOME); if it doesn't exist or is empty, AGENTS.md is used.
  2. From the project root (usually the git root) down level by level to the current directory, each directory is checked for AGENTS.override.md, AGENTS.md, and the filenames listed in project_doc_fallback_filenames, with at most one file taken per directory.
  3. Files are concatenated with the root directory first; files closer to the current directory appear later in the prompt, and when rules conflict, the later ones override the earlier ones.

This means the launch location determines which rules Codex gets. When doing frontend work, launch from apps/web:

codex --cd apps/web

In this case the instruction chain is the root AGENTS.md plus apps/web/AGENTS.md, and the backend file is not read at all. Launching from the root directory only picks up the global and root-level files. The instruction chain is built only once per run, so changes to AGENTS.md take effect only in the next session.

AGENTS.override.md replaces rather than appends: it completely replaces the AGENTS.md in the same directory, and you need to manually copy over any base rules you still need. It's suitable for temporary scenarios such as release freezes; deleting it restores the original file.

project_doc_max_bytes is a Codex configuration option that limits the total byte count of the merged instruction chain, defaulting to 32 KiB. When appending files would cause the total size to exceed this threshold, Codex stops loading subsequent files and may indicate truncation in the logs. This means that in a large monorepo, if the root-level AGENTS.md is too large, it may crowd out space for subdirectory rules. It's recommended to keep the root file under 10 KiB and to use AGENTS.override.md for temporary replacement rather than appending. This option can be adjusted in ~/.codex/config.toml or in project-level configuration.

Step 3: Claude Code's On-Demand Loading Mechanism

Claude Code loads at two moments:

  • At startup, it loads CLAUDE.md and CLAUDE.local.md from the working directory and all its parent directories.
  • During runtime, when Claude reads, writes, or edits a file in a subdirectory, it loads that subdirectory's CLAUDE.md.

So launching Claude from the root directory is fine too: frontend rules arrive automatically when Claude opens a frontend file. If work always stays within one package, Anthropic's monorepo guide recommends launching directly in apps/web, so that both the root file and the frontend file are loaded at startup.

Since v2.1.277, Claude Code can also read AGENTS.md, but by default this only takes effect when no CLAUDE.md, .claude/CLAUDE.md, or CLAUDE.local.md exists in the working directory or its parent directories. As soon as any CLAUDE.md appears on the path (even a personal CLAUDE.local.md), Claude switches to reading CLAUDE.md and ignores AGENTS.md.

This is why every directory needs a CLAUDE.md containing only @AGENTS.md. The @ import is resolved relative to the file it appears in, so apps/web/CLAUDE.md imports apps/web/AGENTS.md. The documentation explicitly states that this import does not cause duplicate reads and remains effective in sessions that do not support reading AGENTS.md directly. Claude-specific notes can be written below the import line.

There is one file Claude never reads: AGENTS.override.md. Codex's temporary overrides do not carry over to Claude Code; if frozen rules need to be obeyed by both agents, they must be written into the shared AGENTS.md.

CLAUDE.local.md is Claude Code's personal local configuration file, usually added to .gitignore, used to store developer-private rules or temporary notes. Its load priority is higher than the CLAUDE.md in the same directory, but lower than the import chain of AGENTS.md. In team collaboration, CLAUDE.local.md should not contain mandatory project rules, lest other members miss key constraints. If rules need to be shared, they should be written into CLAUDE.md or AGENTS.md. At startup, Claude Code checks for CLAUDE.local.md in the working directory and all parent directories, but its content is not passed to other tools.

Step 4: Verify What Each Agent Actually Loads

The way to verify Codex is codex debug prompt-input, which renders the complete prompt input the model sees as JSON; the command reference documentation recommends using it to debug instruction discovery. Run it in the target directory and search for the marker:

cd apps/web
codex debug prompt-input | grep -o 'Rulebook: [a-z]*'

The expected output is Rulebook: root and Rulebook: web, in that order, with no api. Note that the arguments for this command may change between versions, so check --help first.

For Claude Code, run /context within the session and look at the list under Memory files. This list only shows files loaded at startup; the subdirectory's CLAUDE.md does not yet appear because it is loaded on demand. When it loads, a Loaded line with the path appears in the terminal. The documentation's suggested testing method is: manually create the file from the shell rather than having Claude write it, then have Claude read a file in that directory.

If you need a retainable record, you can register an InstructionsLoaded hook. It fires when CLAUDE.md or a rule file enters the context, and receives JSON details via stdin. The following script uses jq to append a line to the log each time it loads:

#!/bin/sh
# .claude/hooks/loads.sh  (chmod +x it)
jq -c '{load_reason, file_path,
        trigger_file_path, parent_file_path}' \
  >> "$CLAUDE_PROJECT_DIR/.claude/loads.log"

Register it in the root .claude/settings.json:

{
  "hooks": {
    "InstructionsLoaded": [{
      "matcher": "",
      "hooks": [{
        "type": "command",
        "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/loads.sh"
      }]
    }]
  }
}

Launch Claude from the root directory to run this test, have it read a file in apps/web, and add loads.log to .gitignore. According to the hooks reference documentation, load_reason of session_start indicates startup loading, nested_traversal indicates an on-demand loaded subdirectory CLAUDE.md, and trigger_file_path points to the file Claude touched. Files brought in via @ imports show up as include, and parent_file_path points to the file that imported them. Reading a frontend file should record apps/web/CLAUDE.md as nested_traversal and apps/web/AGENTS.md as include.

Rule Files Are Not Locks: Add Enforcement Constraints

Both instruction files are essentially guidance content. Claude Code's documentation states plainly: it treats CLAUDE.md as context rather than enforced configuration; to block an operation, use a PreToolUse hook or a permission deny rule.

Therefore "prohibit editing src/generated/" should appear in both places: in the rulebook to explain why, and in the deny rule to enforce the block. In the root .claude/settings.json:

{
  "permissions": {
    "deny": ["Edit(./**/generated/**/*)"]
  }
}

This rule covers Claude's built-in file tools, but scripts that Claude runs (such as npm run codegen) open files themselves and can still write to them—which is exactly the desired behavior. Relative path patterns are anchored to the directory where Claude was launched, so this covers all generated/ folders below that point. Project settings are not inherited from parent directories like CLAUDE.md is; a session launched from apps/web reads apps/web/.claude/settings.json, so a copy needs to be added separately. On the Codex side, you can use /status to view the session's approval policy and writable roots, and configure restrictions there.

The PreToolUse hook is a hook mechanism provided by Claude Code that allows intercepting and inspecting an operation before a tool executes. Unlike permission deny rules, the PreToolUse hook can run custom scripts to dynamically decide whether to allow based on file paths, command contents, and so on, and can block operations via exit codes or JSON output. For example, you can write a script that checks whether the target path of the Edit tool matches the generated/ pattern and, if so, returns a non-zero exit code and outputs the reason for denial. This mechanism is more flexible than static permission rules, but be mindful of the performance overhead of hook scripts and avoid introducing noticeable latency during frequent operations.

Multi-Source Verification and the Tool Ecosystem Perspective

The mechanism descriptions in this article are cross-verified against two official documentation sources, Codex and Claude Code: Codex's instruction chain is built once from the root to the current directory, while Claude Code uses a hybrid model of upward loading at startup plus on-demand loading during runtime. This difference is the root cause of the many "rules not taking effect" reports in the community.

According to consistent observations from the agents.md community and multiple developer blogs, AGENTS.md as a cross-tool shared format has been adopted by most AI coding tools, but the strategies each tool uses for handling nested files are not uniform. In the author's own Hermes IDE project practice, the working tree contains only git-tracked files, so ignored CLAUDE.local.md or AGENTS.override.md will not appear in a new working tree; they can be copied in via the copy key of a worktree recipe.

Interestingly, the loading rules change across versions, and the documentation already lists several version breakpoints. Whenever you add a rule file, move a file's location, or upgrade an agent version, you should repeat the verification in Step 4.

Key Takeaways

The key to sharing rule files across tools lies in understanding the difference between the two loading models: Codex depends on the launch location, while Claude Code depends on when files are touched. Use AGENTS.md to carry the real rules, use a single-line CLAUDE.md as the import adapter, then use verification to confirm the loading results, and finally use permission rules to enforce constraints as a backstop. This combination can significantly reduce the frustration of "I wrote the rules but they didn't take effect" in monorepos.

#Codex#Claude Code#AGENTS.md#monorepo#rule files#instruction chain
Share:

Related articles