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

> Source: <https://dev.to/gabrielanhaia/one-repo-two-rulebooks-nested-agentsmd-for-codex-subfolder-claudemd-for-claude-code-505k>
> Published: 2026-10-19 15:01:46+00:00

`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](https://learn.chatgpt.com/docs/agent-configuration/agents-md) 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](https://code.claude.com/docs/en/memory) 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.

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
```

`AGENTS.md` is the shared format that [agents.md](https://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.
```

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/`.
```

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)`.
```

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](https://code.claude.com/docs/en/memory#write-effective-instructions), and Codex stops adding files once their combined size reaches `project_doc_max_bytes`, [32 KiB by default](https://learn.chatgpt.com/docs/agent-configuration/agents-md).

From the [Codex AGENTS.md docs](https://learn.chatgpt.com/docs/agent-configuration/agents-md), in order:

`~/.codex` (or `$CODEX_HOME`): `AGENTS.override.md` if it exists and isn't empty, otherwise `AGENTS.md`.` project_doc_fallback_filenames`, and takes at most one file per directory.
So where you start Codex decides which package rules it gets. For frontend work, start it in the frontend:

```
codex --cd apps/web
```

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.

[Claude Code's memory docs](https://code.claude.com/docs/en/memory) describe two moments:

`CLAUDE.md` and `CLAUDE.local.md` from the working directory and every directory above it.
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](https://code.claude.com/docs/en/large-codebases#choose-where-to-start-claude) recommends when the work stays in one package.

Claude Code can [read `AGENTS.md` too, from v2.1.277](https://code.claude.com/docs/en/memory#agents-md). 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
```

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](https://code.claude.com/docs/en/memory#remove-an-earlier-agents-md-workaround), 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`.

Now find the markers. For Codex, `codex debug prompt-input` renders the exact prompt input the model sees as JSON, and the [command reference](https://learn.chatgpt.com/docs/developer-commands.md?surface=cli) 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]*'
```

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."
```

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](https://code.claude.com/docs/en/hooks). It fires each time a `CLAUDE.md` or rules file enters context and gets the details as JSON on stdin. This script uses [jq](https://jqlang.org) to append one line per load:

``` bash
#!/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 `.claude/settings.json` at the repo root:

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

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.

I build [Hermes IDE](https://hermes-ide.com), 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](https://github.com/hermes-hq/hermes-ide/blob/main/docs/worktree-recipes.md) 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"]
```

*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.

Both instruction files are guidance. Claude Code's docs say it plainly: it [treats CLAUDE.md as context, not enforced configuration](https://code.claude.com/docs/en/memory#claude-md-vs-auto-memory), 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](https://code.claude.com/docs/en/large-codebases#block-reads-of-generated-and-vendored-code):

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

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](https://code.claude.com/docs/en/large-codebases#choose-where-to-start-claude) 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.

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](https://www.amazon.com/dp/B0GYLH38X4), 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](https://hermes-ide.com/download) is free and source-available on [GitHub](https://github.com/hermes-hq/hermes-ide).
