Make AGENTS.md the source of truth with CLAUDE.md as a symlink - #923
Make AGENTS.md the source of truth with CLAUDE.md as a symlink#923billadunblock wants to merge 4 commits into
Conversation
|
@jevansnyc as we expand agent harnesses and enrich agentic workflows, this change can be pretty handy (prioritize AGENT.md wth CLAUDE.md as symlink). Consider for corporate users, they can only use Claude Code Enterprise plan (data not for training) which is not very practical for the token price, multi harnesses would be ideal in lots of cases. |
aram356
left a comment
There was a problem hiding this comment.
Summary
The direction is sound and the mechanics are mostly clean: git mv preserved
history, the symlink is well-formed (mode 120000, relative target, does not
escape the repo root), all five in-repo reference updates are correct, and the
deleted fallback summary is genuinely redundant with the moved content. All 18
CI checks pass.
One blocking issue: the branch forked 49 commits ago and the moved copy is
stale, so merging silently reverts a change that already landed on main.
1 of the inline comments below carries a one-click GitHub
suggestion— use
Commit suggestion to apply it as a commit on the PR branch. The remaining
findings are body-level because they concern the merge, the PR description,
or repo-wide tooling rather than a single line.
Blocking
🔧 wrench
- Content regression: the move reverts #767 — see inline at
AGENTS.md:9
Non-blocking
🤔 thinking
- "Distinct types" merge conflict can silently re-drop the fix — see below
- Windows symlink failure mode is documented but unmitigated — see below
📝 note
- "Docs format" in the test plan does not cover the changed file — see below
- PR description states issues are disabled; they are not — see below
🌱 seedling
- Bare
cargo testwarning was lost with the fallback summary — see below
Cross-cutting / body-level findings
-
🤔 The merge conflict is a "distinct types" conflict, and naive resolution
re-drops the blocking fix.git merge-tree origin/main <head>reports:CONFLICT (distinct types): CLAUDE.md had different types on each side; renamed one of them so each can be recorded somewhere.Git cannot auto-merge a regular-file-vs-symlink change, so it stages both
sides rather than combining them. ResolvingCLAUDE.mdin favour of the
symlink does not carrymain's text edit intoAGENTS.md— that edit
lives in a different file after this PR. The resolution therefore has two
parts, and skipping the second reintroduces the 🔧 finding even if the
suggestion is applied now:CLAUDE.md→ keep the symlink (this PR's side).AGENTS.md→ portmain's post-fork edit to the Project Overview.
Worth rebasing on
mainand re-checkinggit diff origin/main:CLAUDE.md
againstAGENTS.mdbefore merge: after the fix the two should differ only in
the intentional header. -
🤔 The Windows failure mode is silent, and nothing detects it. The PR
description documents thecore.symlinks=falsebehavior and the manual
workaround, which is good. But I reproduced the failure and the outcome is
worse than "tools see the pointer text": with symlinks disabled,CLAUDE.md
checks out as a 9-byte file whose entire contents are the string
AGENTS.md. Claude Code loads that as the project instructions, so a
contributor on such a clone gets zero conventions — noerror-stack
rule, noexpect("should ..."), no target-matched clippy/test aliases — with
no error and no failing check. Documentation only helps someone who already
suspects the problem. Filed as #1091 for a cheap CI guard; not a merge
blocker for this PR. -
📝 The "Docs format" test-plan item does not exercise this change.
docs/package.json'sformatscript isprettier --check .run from
docs/, so it never inspects root-levelAGENTS.md. The greenformat-docs
check is not evidence that the moved file is well-formed. Separately: root
AGENTS.mddoes failprettier --check— but so doesmain'sCLAUDE.md
(identical table-alignment drift), so this is pre-existing and not a
defect of this PR. Filed as #1093. -
📝 The PR description says "issues are disabled on this repository" — they
are not. The repository hashas_issues: trueand issues are actively
filed (#1085–#1089 within the last two days). Minor, but it changes what the
"Closes" section should say, and follow-ups from this review were filed as
#1091, #1092, #1093. -
🌱 One line of guidance is genuinely lost with the fallback summary.
Removing the duplicated summary is the right call, and I checked every rule
in it against the moved guide — all are covered except one: "Do NOT use bare
cargo test --workspace— it will attempt to compile the Fastly adapter for
the host target." The main guide warns about barecargo buildand bare
cargo checkbut not barecargo test. Pre-existing gap in the guide rather
than something this PR breaks; filed as #1092.
CI Status
- cargo fmt: PASS (required)
- cargo test: PASS (required)
- format-docs: PASS (required)
- format-typescript: PASS (required)
- cargo test (axum native): PASS
- cargo test (cross-adapter parity): PASS
- cargo test (ts CLI, native): PASS
- cargo check (cloudflare native + wasm32-unknown-unknown): PASS
- cargo check/build/test (spin native + wasm32-wasip1): PASS
- vitest: PASS
- integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- browser integration tests: PASS
- prepare integration artifacts: PASS
- Analyze (rust): PASS
- Analyze (javascript-typescript): PASS
- Analyze (actions): PASS
- CodeQL: PASS
All checks pass, which is expected — no code changed. Worth noting that no
gate compares documentation content across branches, so CI cannot catch the
🔧 finding above.
| # CLAUDE.md | ||
|
|
||
| > Single source of truth for all AI coding agents (Claude Code, Codex, Cursor, | ||
| > etc.). If you're reading `AGENTS.md`, it redirects here. |
There was a problem hiding this comment.
🤔 thinking — The Windows failure mode here is silent, and nothing detects it.
The PR description documents the core.symlinks=false behavior and the manual workaround, which is good. But the outcome is worse than "tools see the pointer text". I reproduced a symlinks-disabled checkout of this head:
$ git config core.symlinks false && git checkout <head>
$ ls -la CLAUDE.md
-rw-r--r-- 1 user staff 9 CLAUDE.md
$ cat CLAUDE.md
AGENTS.md
These 457 lines become a 9-byte file whose entire contents are the string AGENTS.md. Claude Code loads that as its project instructions, so a contributor on such a clone gets zero conventions — no error-stack rule, no expect("should ..."), no target-matched clippy/test aliases, no WASM constraints — with no error raised and no failing check.
Documentation only helps someone who already suspects the problem. Filed #1091 for a cheap CI guard (assert the tree entry mode is 120000, or that the checked-out file is non-trivial in size).
Not a merge blocker — it's inherent to the symlink approach this PR deliberately chose, and the tradeoff looks correct. Flagging so the silent-failure characteristic is on record.
AGENTS.md is the industry-adopted convention for AI coding agent instructions, so the full guide now lives there. CLAUDE.md becomes a symlink to AGENTS.md so Claude Code keeps resolving it by name, and the previous fallback-summary stub is no longer needed. References in the PR template, onboarding docs, and agent definitions now point at AGENTS.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
62d178b to
ac38cb5
Compare
|
@aram356 Thanks for your review (and precious tokens of course 🤖). I've forced a sync from latest CLAUDE.md and updated the PR. Please assign #1091 to me and I am happy to address in separate PR. In addition, I'll open separate PR for symlink |
We will fix how to assign tickets to you but in meantime please work on #1091 and #1092 |
A checkout with core.symlinks=false (the Git for Windows default) materializes the CLAUDE.md symlink as a plain text file containing the literal string "AGENTS.md". If that file is committed, Claude Code silently loads it as the entire project instructions and operates with no conventions. Fail CI when the tree entry for CLAUDE.md is not mode 120000, does not point at AGENTS.md, or points at a missing target. Closes IABTechLab#1091 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MiYh5XY8eN2C9Qd5uVbvqS
The build and check alias blocks already warn that the bare cargo commands fail at the workspace root, but the test aliases carried no such caveat. The only copy of that warning lived in the old AGENTS.md redirect stub, which this branch removes, so restore it alongside the test aliases in the Testing & Quality section. Closes IABTechLab#1092 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MiYh5XY8eN2C9Qd5uVbvqS
Addressed both issue in the PR. |
Summary
AGENTS.mdthe single source of truth for AI coding agent instructions, replacingCLAUDE.mdwith a symlink to it —AGENTS.mdis the tool-agnostic industry convention (used by Codex, Cursor, and others; see agents.md), while the symlink keeps Claude Code working by its conventional filename with zero duplication or drift.AGENTS.mdredirect stub and its fallback summary, so there is only one copy of the rules.AGENTS.md.Rebased onto current
main(was 49 commits behind) to resolve the review feedback — see Review feedback below.Changes
AGENTS.mdCLAUDE.mdviagit mv, sogit log --followpreserves history); redirect stub removedCLAUDE.mdAGENTS.md(mode120000).github/pull_request_template.mdAGENTS.mddocs/guide/onboarding.mdAGENTS.md.claude/agents/code-simplifier.mdAGENTS.md.claude/agents/pr-reviewer.mdAGENTS.md(the file grew from 1 to 5 references in #707, which landed after this branch forked).claude/commands/review-changes.mdAGENTS.mdHistorical
docs/superpowers/plans and specs still sayCLAUDE.md. That is deliberate — they are dated records of past decisions, and the symlink keeps those references resolving.Closes
No linked issue. Three follow-ups filed during review are intentionally not closed by this PR:
core.symlinks=falseclonescargo testfails at the workspace rootmain)Test plan
git diff main:CLAUDE.md AGENTS.mdshows only the intentional header change, nothing else.main;git merge-base --is-ancestor main HEADconfirms a clean fast-forward, so the earlier "distinct types" conflict is gone.120000with a relative target that does not escape the repo root;head -2 CLAUDE.mdresolves through to theAGENTS.mdcontent.git log --follow AGENTS.mdstill reaches the original Add CLAUDE.md and consolidate AI agent conventions #352 commit.cd docs && npm run formatpasses. Scope note: that script isprettier --check .run fromdocs/, so it exercises thedocs/guide/onboarding.mdedit but does not inspect root-levelAGENTS.md. A greenformat-docscheck is not evidence that the moved file is well-formed; root Markdown is covered by no gate today (Root Markdown is not covered by any format gate and fails prettier --check #1093).No Rust or JS code is touched, so the cargo and vitest gates don't apply to this change.
Review feedback
mainand carried #767's neutral-language wording into theAGENTS.mdProject Overview. Verified by the content-parity check above.CLAUDE.mdkeeps the symlink, andmain's post-fork edit was ported intoAGENTS.md. The branch is now a fast-forward onmain, so no conflict resolution happens at merge time.cargo testwarning lost with the stubNotes
core.symlinks=falseunless symlink support is available (Windows Developer Mode enabled, or an elevated shell). With symlinks disabled, git checks outCLAUDE.mdas a plain 9-byte text file containing the pathAGENTS.md, so an agent readingCLAUDE.mdgets that string instead of the conventions — silently, with no failing check (see Guard against CLAUDE.md symlink checking out as a plain text file #1091). To get a real symlink: enable Developer Mode (Settings → System → For developers), then clone withgit clone -c core.symlinks=true, or in an existing clone rungit config core.symlinks truefollowed bygit checkout -f CLAUDE.mdto re-materialize it.References
CLAUDE.mdfrom the project root, which the symlink satisfies while keepingAGENTS.mdas the single source.🤖 Generated with Claude Code