Prefer AGENTS.md over CLAUDE.md for project instructions (#439)
* Prefer AGENTS.md over CLAUDE.md for project instructions * fix: preserve CLAUDE.md fallback behavior * fix: isolate onboarding tests and preserve legacy init * fix: restore full fsOperations exports in test mock and align compact cwd * Fix onboarding test isolation and init migration guidance * Tighten init prompt coverage and onboarding copy * Handle nested project instruction paths consistently * Fix NEW_INIT feature gate for Bun build --------- Co-authored-by: 赵小落 <zhaoxiaoluo@zhaoxiaoluodeMac-mini.local> Co-authored-by: zhaomo01 <zhaomo01@baidu.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* 1. Managed memory (eg. /etc/claude-code/CLAUDE.md) - Global instructions for all users
|
||||
* 2. User memory (~/.claude/CLAUDE.md) - Private global instructions for all projects
|
||||
* 3. Project memory (CLAUDE.md, .claude/CLAUDE.md, and .claude/rules/*.md in project roots) - Instructions checked into the codebase
|
||||
* 3. Project memory (AGENTS.md or fallback CLAUDE.md, plus .claude/CLAUDE.md and .claude/rules/*.md in project roots) - Instructions checked into the codebase
|
||||
* 4. Local memory (CLAUDE.local.md in project roots) - Private project-specific instructions
|
||||
*
|
||||
* Files are loaded in reverse order of priority, i.e. the latest files are highest priority
|
||||
@@ -13,7 +13,8 @@
|
||||
* - User memory is loaded from the user's home directory
|
||||
* - Project and Local files are discovered by traversing from the current directory up to root
|
||||
* - Files closer to the current directory have higher priority (loaded later)
|
||||
* - CLAUDE.md, .claude/CLAUDE.md, and all .md files in .claude/rules/ are checked in each directory for Project memory
|
||||
* - AGENTS.md is preferred for root project instructions; CLAUDE.md is only used when AGENTS.md is absent
|
||||
* - .claude/CLAUDE.md and all .md files in .claude/rules/ are checked in each directory for Project memory
|
||||
*
|
||||
* Memory @include directive:
|
||||
* - Memory files can include other files using @ notation
|
||||
@@ -75,6 +76,10 @@ import {
|
||||
import type { MemoryType } from './memory/types.js'
|
||||
import { expandPath } from './path.js'
|
||||
import { pathInWorkingPath } from './permissions/filesystem.js'
|
||||
import {
|
||||
getProjectInstructionFilePath,
|
||||
isProjectInstructionFileName,
|
||||
} from './projectInstructions.js'
|
||||
import { isSettingSourceEnabled } from './settings/constants.js'
|
||||
import { getInitialSettings } from './settings/settings.js'
|
||||
|
||||
@@ -868,7 +873,7 @@ export const getMemoryFiles = memoize(
|
||||
// When running from a git worktree nested inside its main repo (e.g.,
|
||||
// .claude/worktrees/<name>/ from `claude -w`), the upward walk passes
|
||||
// through both the worktree root and the main repo root. Both contain
|
||||
// checked-in files like CLAUDE.md and .claude/rules/*.md, so the same
|
||||
// checked-in files like AGENTS.md/CLAUDE.md and .claude/rules/*.md, so the same
|
||||
// content gets loaded twice. Skip Project-type (checked-in) files from
|
||||
// directories above the worktree but within the main repo — the worktree
|
||||
// already has its own checkout. CLAUDE.local.md is gitignored so it only
|
||||
@@ -892,9 +897,12 @@ export const getMemoryFiles = memoize(
|
||||
pathInWorkingPath(dir, canonicalRoot) &&
|
||||
!pathInWorkingPath(dir, gitRoot)
|
||||
|
||||
// Try reading CLAUDE.md (Project) - only if projectSettings is enabled
|
||||
// Try reading the root project instruction file (AGENTS.md first, otherwise CLAUDE.md)
|
||||
if (isSettingSourceEnabled('projectSettings') && !skipProject) {
|
||||
const projectPath = join(dir, 'CLAUDE.md')
|
||||
const projectPath = getProjectInstructionFilePath(
|
||||
dir,
|
||||
getFsImplementation().existsSync,
|
||||
)
|
||||
result.push(
|
||||
...(await processMemoryFile(
|
||||
projectPath,
|
||||
@@ -942,15 +950,18 @@ export const getMemoryFiles = memoize(
|
||||
}
|
||||
}
|
||||
|
||||
// Process CLAUDE.md from additional directories (--add-dir) if env var is enabled
|
||||
// Process root project instruction files from additional directories (--add-dir) if env var is enabled
|
||||
// This is controlled by CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD and defaults to off
|
||||
// Note: we don't check isSettingSourceEnabled('projectSettings') here because --add-dir
|
||||
// is an explicit user action and the SDK defaults settingSources to [] when not specified
|
||||
if (isEnvTruthy(process.env.CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD)) {
|
||||
const additionalDirs = getAdditionalDirectoriesForClaudeMd()
|
||||
for (const dir of additionalDirs) {
|
||||
// Try reading CLAUDE.md from the additional directory
|
||||
const projectPath = join(dir, 'CLAUDE.md')
|
||||
// Try reading the root project instruction file from the additional directory
|
||||
const projectPath = getProjectInstructionFilePath(
|
||||
dir,
|
||||
getFsImplementation().existsSync,
|
||||
)
|
||||
result.push(
|
||||
...(await processMemoryFile(
|
||||
projectPath,
|
||||
@@ -1248,7 +1259,7 @@ export async function getManagedAndUserConditionalRules(
|
||||
|
||||
/**
|
||||
* Gets memory files for a single nested directory (between CWD and target).
|
||||
* Loads CLAUDE.md, unconditional rules, and conditional rules for that directory.
|
||||
* Loads the root project instruction file, unconditional rules, and conditional rules for that directory.
|
||||
*
|
||||
* @param dir The directory to process
|
||||
* @param targetPath The target file path (for conditional rule matching)
|
||||
@@ -1262,9 +1273,12 @@ export async function getMemoryFilesForNestedDirectory(
|
||||
): Promise<MemoryFileInfo[]> {
|
||||
const result: MemoryFileInfo[] = []
|
||||
|
||||
// Process project memory files (CLAUDE.md and .claude/CLAUDE.md)
|
||||
// Process project memory files (AGENTS.md first, otherwise CLAUDE.md, plus .claude/CLAUDE.md)
|
||||
if (isSettingSourceEnabled('projectSettings')) {
|
||||
const projectPath = join(dir, 'CLAUDE.md')
|
||||
const projectPath = getProjectInstructionFilePath(
|
||||
dir,
|
||||
getFsImplementation().existsSync,
|
||||
)
|
||||
result.push(
|
||||
...(await processMemoryFile(
|
||||
projectPath,
|
||||
@@ -1439,13 +1453,13 @@ export async function shouldShowClaudeMdExternalIncludesWarning(): Promise<boole
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file path is a memory file (CLAUDE.md, CLAUDE.local.md, or .claude/rules/*.md)
|
||||
* Check if a file path is a memory file (AGENTS.md, CLAUDE.md, CLAUDE.local.md, or .claude/rules/*.md)
|
||||
*/
|
||||
export function isMemoryFilePath(filePath: string): boolean {
|
||||
const name = basename(filePath)
|
||||
|
||||
// CLAUDE.md or CLAUDE.local.md anywhere
|
||||
if (name === 'CLAUDE.md' || name === 'CLAUDE.local.md') {
|
||||
// Root instruction files or CLAUDE.local.md anywhere
|
||||
if (isProjectInstructionFileName(name) || name === 'CLAUDE.local.md') {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user