The shared project I work on has a CLAUDE.md of about 12,000 tokens. My replacement is about 900.
In Codex, an AGENTS.override.md does the swap. Claude Code has no override file, so I built one from 2 parts: a setting that skips the team’s file, and a hook that loads mine.
What loads at startup
Claude Code loads ~/.claude/CLAUDE.md, then the CLAUDE.md in the folder you start in and every folder above it. (That’s the instruction side of memory. I wrote about where auto memory lives before.)
A subfolder’s CLAUDE.md loads later, only when Claude reads a file in that folder. A folder added as an extra working directory doesn’t load its CLAUDE.md at all, unless you set CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1.
So if you start in ~/Workspace/acme/app/ios, the big ios/CLAUDE.md is in context before you type anything.
Run /context to see it. The “Memory files” section lists every loaded file with its token count.
Step 1: exclude the team’s file
Add claudeMdExcludes to ~/.claude/settings.json:
{
"claudeMdExcludes": [
"/Users/me/Workspace/acme/app/ios/CLAUDE.md",
"/Users/me/Workspace/acme/app/.claude/worktrees/*/ios/CLAUDE.md",
"/Users/me/Worktrees/app/*/ios/CLAUDE.md"
]
}
Entries are absolute paths or picomatch globs, matched against each file’s absolute path. They apply to user, project and local memory files only.
Don’t forget the worktrees. Every worktree has its own copy of ios/CLAUDE.md, at a different path, so the main checkout’s path alone misses all of them.
Step 2: load my own
A SessionStart hook can add text to the conversation before the first prompt. Mine runs on startup, clear and compact:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|clear|compact",
"hooks": [
{ "type": "command", "command": "~/.claude/acme-overrides.sh" }
]
}
]
}
}
It skips resume. A resumed session already holds the old copy, and a second one is just waste.
The script reads the same override files Codex uses. They live in one dotfiles folder, so I edit them once for both tools.
#!/bin/bash
set -euo pipefail
SOURCE="$HOME/.agents/project-overrides/acme-app"
CHECKOUT="$HOME/Workspace/acme/app"
cwd="$(jq -r '.cwd // empty')"
[ -n "$cwd" ] || cwd="$PWD"
common_dir="$(git -C "$cwd" rev-parse --path-format=absolute --git-common-dir 2>/dev/null)" || exit 0
[ "$(dirname "$common_dir")" = "$CHECKOUT" ] || exit 0
toplevel="$(cd "$(git -C "$cwd" rev-parse --show-toplevel)" && pwd -P)"
rel="$(cd "$cwd" && pwd -P)"
rel="${rel#"$toplevel"}"
rel="${rel#/}"
context="# Personal project instructions
These replace ios/CLAUDE.md, which is excluded. Read it when a task needs details these don't cover."
append() {
[ -f "$1" ] && context+=$'\n\n'"$(cat "$1")"
return 0
}
append "$SOURCE/AGENTS.override.md"
case "$rel" in
ios | ios/*) append "$SOURCE/ios/AGENTS.override.md" ;;
esac
jq -n --arg ctx "$context" \
'{hookSpecificOutput: {hookEventName: "SessionStart", additionalContext: $ctx}}'
2 details matter.
git rev-parse --git-common-dir points at the main checkout’s .git, even from a worktree. So every worktree is recognised as the same repo, wherever it lives.
And the files layer per folder, like Codex. The root override always loads; the iOS one loads only when the session starts in ios/ or below.
Verify it
Start with claude --debug and look for a line like this:
Hook SessionStart (...) provided additionalContext (N chars)
Then run /context. The team’s ios/CLAUDE.md should be gone from Memory files.
Don’t look for your replacement there, though. Hook output counts as messages, not memory files.
Pitfall: why not an import?
The obvious shortcut is an @path import of your override file in a project CLAUDE.md. It works, but an import from outside the project needs a one-time approval, stored per project in ~/.claude.json.
The desktop app never shows that approval dialog. So the import is dropped without a word, and your instructions just aren’t there.
Other options
CLAUDE.local.md: per checkout and gitignored, so new worktrees don’t have it.- A pointer in
~/.claude/CLAUDE.md: costs nothing at startup, but it only works when the agent remembers to read the file. .claude/rules/withpaths:frontmatter: loads rules only for matching files. Great if the team adopts it, less great as a personal fix for a file you don’t own.
Whatever you pick, your copy drifts from the team’s file, so re-sync it now and then.
It’s a fork of the team’s instructions, with all the joy of keeping a fork up to date.
What’s next
The project file is only one of the things that load before my first message. Skills are next. Their listing loads into every session too, and the same idea should apply: skip the team’s version, load my own.
One backpack at a time.