2 rule files that disagree, because one tool reads CLAUDE.md and another reads AGENTS.md.
Add "Shared instructions for coding agents" from ntent to this repo.
Fetch https://ntent.app/r/f/symlink-claude as plain text. Run it from the repo root.
It needs AGENTS.md. If this repo does not have it, stop and tell me.
Then check it: Run it twice: the second run says there is nothing to do. Then start a session and ask the assistant to name a rule that only exists in AGENTS.md. In Claude Code, /context lists CLAUDE.md under Memory files. Copy a line of AGENTS.md into CLAUDE.md and run it again: it names that line and leaves it where it is.Reads https://ntent.app/r/f/symlink-claude
Read the code
48 lines
# One rules file, imported rather than copied. AGENTS.md holds the rules;
# CLAUDE.md holds the import plus anything only true for one assistant.
#
# Why CLAUDE.md at all: Claude Code reads AGENTS.md by itself only when there
# is no CLAUDE.md, and older versions never do. The import covers both, and
# Claude Code does not load AGENTS.md twice.
#
# An import, not a symlink: it works everywhere including Windows, where a
# symlink needs Developer Mode, and it leaves you that second half. Re-running
# this is safe, and it never overwrites instructions CLAUDE.md already has.
if [ -L CLAUDE.md ] && [ CLAUDE.md -ef AGENTS.md ] ; then
# The older setup. The link holds nothing of its own, so nothing is lost.
# Read through it instead and the rules would be copied in under the import.
rm CLAUDE.md
printf '@AGENTS.md\n' > CLAUDE.md
echo "Replaced the CLAUDE.md symlink with an import of AGENTS.md."
elif [ -L CLAUDE.md ] ; then
# Pointing somewhere else, often a rules file shared across repos. Writing
# through the link would change that file for every repo that uses it.
echo "CLAUDE.md links to $(readlink CLAUDE.md), not AGENTS.md. Left alone."
echo "Decide with the owner: add @AGENTS.md to the file it points at, or"
echo "replace the link with a CLAUDE.md of its own that imports AGENTS.md."
exit 1
elif [ ! -e CLAUDE.md ] ; then
printf '@AGENTS.md\n' > CLAUDE.md
echo "CLAUDE.md now imports AGENTS.md."
elif grep -qx '@AGENTS.md' CLAUDE.md ; then
echo "CLAUDE.md already imports AGENTS.md. Nothing to do."
else
# Prepend. What is in there is somebody's instructions, not a placeholder.
{ printf '@AGENTS.md\n\n' ; cat CLAUDE.md ; } > CLAUDE.md.new &&
mv CLAUDE.md.new CLAUDE.md
echo "Added the @AGENTS.md import above what CLAUDE.md already had."
fi
# Checked, never fixed. A rule in both files loads twice, and the copies drift
# the first time someone edits one. Which file a rule belongs in is a
# judgement, so this names the lines and leaves them where they are. Blank
# lines and headings are skipped: a shared "## Commands" is not a duplicate.
dupes="$(awk 'NR == FNR { if ($0 !~ /^[[:space:]]*$/ && $0 !~ /^#/) seen[$0] = 1; next }
($0 in seen)' AGENTS.md CLAUDE.md)"
if [ -n "$dupes" ] ; then
echo ""
echo "These lines are in both CLAUDE.md and AGENTS.md:"
printf '%s\n' "$dupes" | sed 's/^/ /'
echo "A rule for every assistant belongs in AGENTS.md only; a rule only true"
echo "for Claude stays in CLAUDE.md. Ask before deleting either copy."
fiSuccess check: Run it twice: the second run says there is nothing to do. Then start a session and ask the assistant to name a rule that only exists in AGENTS.md. In Claude Code, /context lists CLAUDE.md under Memory files. Copy a line of AGENTS.md into CLAUDE.md and run it again: it names that line and leaves it where it is.