Problem
PR #923 replaces CLAUDE.md with a symlink to AGENTS.md. When a clone has
core.symlinks=false — the Git for Windows default unless Developer Mode is
enabled or the shell is elevated — Git materializes the symlink as a plain
text file whose entire contents are the target path.
Reproduced locally against the PR head:
$ git config core.symlinks false
$ git checkout <pr-head>
$ ls -la CLAUDE.md
-rw-r--r-- 1 user staff 9 CLAUDE.md
$ cat CLAUDE.md
AGENTS.md
The result is a 9-byte CLAUDE.md containing the literal string AGENTS.md.
Why this matters
Claude Code loads CLAUDE.md from the repository root as its project
instructions. On such a checkout it loads the string AGENTS.md and nothing
else, so the agent operates with zero project conventions: no
error-stack rule, no expect("should ...") rule, no target-matched clippy
or test aliases, no WASM constraints.
The failure is silent. Nothing errors, no check fails, and the contributor has
no signal that their agent is unconfigured. The resulting PRs simply violate
conventions for reasons that are hard to trace back to the cause.
Proposed fix
Add a cheap CI guard that fails when the root CLAUDE.md is not a working
symlink. Either check is sufficient:
- Assert the tree entry mode is
120000:
git ls-tree HEAD CLAUDE.md | grep -q '^120000'
- Or assert the checked-out file resolves and is non-trivial in size
(a real load would be ~19KB; the broken form is 9 bytes).
Documenting the workaround (as PR #923 does in its description) helps someone
who already suspects the problem, but does not detect it.
Context
Found while reviewing #923. The PR body documents the Windows behavior and the
manual core.symlinks=true workaround, but ships no automated detection.
Problem
PR #923 replaces
CLAUDE.mdwith a symlink toAGENTS.md. When a clone hascore.symlinks=false— the Git for Windows default unless Developer Mode isenabled or the shell is elevated — Git materializes the symlink as a plain
text file whose entire contents are the target path.
Reproduced locally against the PR head:
The result is a 9-byte
CLAUDE.mdcontaining the literal stringAGENTS.md.Why this matters
Claude Code loads
CLAUDE.mdfrom the repository root as its projectinstructions. On such a checkout it loads the string
AGENTS.mdand nothingelse, so the agent operates with zero project conventions: no
error-stackrule, noexpect("should ...")rule, no target-matched clippyor test aliases, no WASM constraints.
The failure is silent. Nothing errors, no check fails, and the contributor has
no signal that their agent is unconfigured. The resulting PRs simply violate
conventions for reasons that are hard to trace back to the cause.
Proposed fix
Add a cheap CI guard that fails when the root
CLAUDE.mdis not a workingsymlink. Either check is sufficient:
120000:git ls-tree HEAD CLAUDE.md | grep -q '^120000'(a real load would be ~19KB; the broken form is 9 bytes).
Documenting the workaround (as PR #923 does in its description) helps someone
who already suspects the problem, but does not detect it.
Context
Found while reviewing #923. The PR body documents the Windows behavior and the
manual
core.symlinks=trueworkaround, but ships no automated detection.