DEV Community

Cover image for One Repo, Two Rulebooks: Nested AGENTS.md for Codex, Subfolder CLAUDE.md for Claude Code
Gabriel Anhaia
Gabriel Anhaia

Posted on AI-assisted

One Repo, Two Rulebooks: Nested AGENTS.md for Codex, Subfolder CLAUDE.md for Claude Code


apps/web/AGENTS.md says to use Vitest and to stay out of the generated API client. You start Codex at the repo root, ask it to fix a React component, and it edits src/generated/client.ts anyway.

That file never reached the prompt. Codex builds its instruction chain once per run, from the project root down to the directory you started in, and a rule file in a folder below that is left out. Claude Code works the other way: it loads a subfolder's CLAUDE.md later, once it touches a file there.

So give each package its own rulebook that both agents can use, then check what each one actually loaded.

Step 1: one root file, one file per package

Take a monorepo with a React frontend and a Go backend:

acme/
  AGENTS.md            # rules for the whole repo
  CLAUDE.md            # @AGENTS.md
  apps/web/
    AGENTS.md          # frontend rules
    CLAUDE.md          # @AGENTS.md
  services/api/
    AGENTS.md          # backend rules
    CLAUDE.md          # @AGENTS.md
Enter fullscreen mode Exit fullscreen mode

AGENTS.md is the shared format that agents.md describes for many tools, Codex among them. It holds the real rules. Each CLAUDE.md is one import line, explained in step 3. The root file covers what is true everywhere:

Rulebook: root

- Commit subjects start with the package name: `web: fix nav`.
- Never commit secrets. Use `.env.example` for new variables.
- Run package scripts from the package folder, not the root.
Enter fullscreen mode Exit fullscreen mode

The frontend file covers only the frontend:

Rulebook: web

- Tests: `npx vitest run`. Never Jest.
- Never edit `src/generated/`. Run `npm run codegen` instead.
- Components are function components in `src/components/`.
Enter fullscreen mode Exit fullscreen mode

And the backend file covers only the backend:

Rulebook: api

- Tests: `go test ./...` from `services/api`.
- Never edit a migration that has merged. Add a new one.
- Errors are wrapped with `fmt.Errorf("...: %w", err)`.
Enter fullscreen mode Exit fullscreen mode

The Rulebook: first line is there for you. It gives you a unique string to search for in step 4. Keep each file short: Anthropic's docs suggest under 200 lines per CLAUDE.md, and Codex stops adding files once their combined size reaches project_doc_max_bytes, 32 KiB by default.

Step 2: how Codex picks its files

From the Codex AGENTS.md docs, in order:

  • First, the global file in ~/.codex (or $CODEX_HOME): AGENTS.override.md if it exists and isn't empty, otherwise AGENTS.md.
  • Then every directory from the project root (usually the git root) down to the current directory. In each one it checks AGENTS.override.md, then AGENTS.md, then any names listed in project_doc_fallback_filenames, and takes at most one file per directory.
  • The files are joined root first. Files closer to your current directory come later in the prompt, so they win where rules overlap.

So where you start Codex decides which package rules it gets. For frontend work, start it in the frontend:

codex --cd apps/web
Enter fullscreen mode Exit fullscreen mode

That chain is root AGENTS.md, then apps/web/AGENTS.md. The backend file is never read. Start at the root and you get the global and root files only. The chain is built once per run, so an edit to an AGENTS.md reaches Codex in the next session, not the current one.

AGENTS.override.md replaces the AGENTS.md in the same folder instead of adding to it. Use it for a temporary change, such as a release freeze on the backend, and copy over the base rules you still want, because the normal file is ignored while the override exists. Delete the override and the normal file is back.

Step 3: how Claude Code picks its files

Claude Code's memory docs describe two moments:

  • At launch, it loads CLAUDE.md and CLAUDE.local.md from the working directory and every directory above it.
  • Later, it loads a subdirectory's CLAUDE.md once Claude reads, writes or edits a file in that subdirectory.

Unlike Codex, starting at the root is fine here: the frontend rules arrive when Claude opens a frontend file. Start Claude in apps/web and both the root and frontend files load at launch, which Anthropic's monorepo guide recommends when the work stays in one package.

Claude Code can read AGENTS.md too, from v2.1.277. By default it does so only when there is no CLAUDE.md, .claude/CLAUDE.md or CLAUDE.local.md in the working directory or above it. Add one CLAUDE.md anywhere on that path, even a personal CLAUDE.local.md, and Claude reads the CLAUDE.md files instead of your AGENTS.md.

That is why every folder in the tree above has a CLAUDE.md that holds one line:

@AGENTS.md
Enter fullscreen mode Exit fullscreen mode

An @ import resolves relative to the file it sits in, so apps/web/CLAUDE.md pulls in apps/web/AGENTS.md. The docs say the import never makes Claude read the file twice, whatever the Project instructions setting in /config says. It also keeps working in sessions that can't read AGENTS.md directly. Claude-only notes, such as "use plan mode for changes under services/api/billing/", go below the import.

One file Claude never reads: AGENTS.override.md. A Codex override does not reach Claude Code. If the freeze matters to both agents, put it in the shared AGENTS.md.

Step 4: check what each agent loaded

Now find the markers. For Codex, codex debug prompt-input renders the exact prompt input the model sees as JSON, and the command reference suggests it for debugging instruction discovery. Run it from the folder you care about and search for the markers. Its flags can differ between versions, so check --help first:

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

You want Rulebook: root and Rulebook: web, in that order, and no api. The Codex docs also give a quick check, which asks the model rather than reading the prompt:

codex --cd apps/web --ask-for-approval never \
  "List the instruction sources you loaded."
Enter fullscreen mode Exit fullscreen mode

For Claude Code, run /context in the session and read the list under Memory files. That list shows what loaded at launch. A subfolder CLAUDE.md is not in it yet, because it loads on demand. When it does load, a Loaded line with its path appears in the terminal. The docs suggest a test: create the file from your own shell rather than asking Claude to write it, then ask Claude to read a file in that folder.

For a record you can keep, add an InstructionsLoaded hook. It fires each time a CLAUDE.md or rules file enters context and gets the details as JSON on stdin. This script uses jq to append one line per load:

#!/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"
Enter fullscreen mode Exit fullscreen mode

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

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

Start Claude at the repo root for this test, ask it to read a file in apps/web, and add loads.log to .gitignore. Per the hooks reference, load_reason is session_start for files loaded at launch and nested_traversal for a subfolder CLAUDE.md loaded on demand, with trigger_file_path naming the file Claude touched. A file pulled in by an @ import shows up as include, with parent_file_path naming the file that imported it. Reading a frontend file should log apps/web/CLAUDE.md as nested_traversal and apps/web/AGENTS.md as include. The hook does not fire for an AGENTS.md that Claude reads directly through the setting, which is one more reason to use the import.

Step 5: the same rulebooks in Hermes IDE

I build Hermes IDE, so weigh this section with that in mind. It is a free, source-available (BSL 1.1) desktop app for macOS, Windows and Linux, not affiliated with Nous Research, Anthropic or OpenAI. It runs Claude Code, Codex and other agents side by side, each with its own interface in a real terminal, so the loading rules above still apply. Hermes can also point the agent at a context file with what its project scan found, so that file sits in the agent's context next to your rulebooks.

For a new project, New folder… in the ⌘N task launcher creates the folder and, if you tick the boxes, starts it with a git repository, a .gitignore, a README and an AGENTS.md for agent instructions. The agent then starts in that folder.

For an existing repo, ⌘N (Ctrl+Shift+N on Windows and Linux) starts each task on its own hermes/ branch in its own worktree. A worktree holds the files git tracks, so your committed AGENTS.md and CLAUDE.md files are there on every branch. Files git ignores are not. If you keep a personal CLAUDE.local.md or an ignored AGENTS.override.md, it stays in your main checkout and the agent in the worktree never sees it.

The copy key in a Hermes worktree recipe copies those ignored files into each new worktree. It only accepts files git ignores:

# .hermes/worktree.toml
copy = ["CLAUDE.local.md", "apps/*/CLAUDE.local.md"]
Enter fullscreen mode Exit fullscreen mode

A Claude Code session in Hermes IDE after pressing the Context chip, showing Claude Code's /context breakdown, sidebar context gauges and the status strip
A Claude Code session after pressing the Context chip: Claude Code's /context breakdown (44.4k of 1M tokens, 4%), the per-session context gauges in the sidebar, and the status strip with the token total and estimated cost.

The Context chip in the bar above a Claude Code session shows Claude Code's own /context breakdown, the same one where Memory files lives. You can run the step 4 check without typing the command.

Rules files are not a lock

Both instruction files are guidance. Claude Code's docs say it plainly: it treats CLAUDE.md as context, not enforced configuration, and to block an action whatever Claude decides, they point you to a PreToolUse hook. A permission deny rule does the same job for Claude's file edits.

So "never edit src/generated/" belongs in the rulebook, where it explains why, and in a deny rule, which blocks Claude's edit tools from it. In .claude/settings.json at the repo root, following the pattern style of Anthropic's monorepo guide:

{
  "permissions": {
    "deny": ["Edit(./**/generated/**/*)"]
  }
}
Enter fullscreen mode Exit fullscreen mode

The rule covers Claude's built-in file tools. A script Claude runs, such as npm run codegen, opens files itself and can still write there, which is what you want here. Relative patterns are anchored at the directory you started Claude in, so this one covers every generated/ folder below that point. Project settings are not inherited from parent folders the way CLAUDE.md files are, so a session started in apps/web reads apps/web/.claude/settings.json, not this one. Give that folder its own copy. On the Codex side, /status shows the session's approval policy and writable roots, which is where its limits live.

Then repeat the step 4 check whenever you add a rulebook, move one or upgrade an agent. Loading rules change between versions, and the docs above already list several version cut-offs.


If this was useful

Splitting rules by folder and checking what loaded is a guardrail question: you decide what the agent may touch, then you verify it. The AI Agents Pocket Guide covers the patterns underneath, from tool calling to the limits you put around an agent. It is one of 8 short books in Pocket Guides for Developers, on agents, RAG, prompts, observability, events, databases and system design. If you want Claude Code and Codex side by side on one repo, Hermes IDE is free and source-available on GitHub.

AI Agents Pocket Guide: Patterns for Building Autonomous Systems with LLMs

Top comments (0)