Why this matters
Claude Code does not just read one CLAUDE.md file. It walks several
instruction sources, decides which ones are active, and then shapes the result
into prompt text. The easiest way to understand this page is to separate the
two jobs:
loadMemoryPrompt()builds the memory-mechanics instructions that tell the model how to use memory files.getClaudeMds(...)turns discovered instruction files into the user-context text that later prompt assembly can carry forward.
Big picture first
Read the loading order from top to bottom: managed memory, user memory, project memory, and local memory. Then remember that the runtime can wrap those files in a prompt and also surface them as user-context text.
const MEMORY_INSTRUCTION_PROMPT =
'Codebase and user instructions are shown below. Be sure to adhere to these instructions. IMPORTANT: These instructions OVERRIDE any default behavior and you MUST follow them exactly as written.'
Codebase and user instructions are shown below. Be sure to adhere to these instructions. IMPORTANT: These instructions OVERRIDE any default behavior and you MUST follow them exactly as written. MemoryFileInfo
Each memory file is tracked with a path, a type, and the text that will be shown to the model.
| Field | Meaning | First Pass |
|---|---|---|
path | The file path Claude Code found on disk. | Usually the easiest way to trace where the instruction came from. |
type | Which memory layer the file belongs to, such as User, Project, or Local. | This tells you how the file will be prioritized later. |
content | The file text carried through discovery before getClaudeMds() adds MEMORY_INSTRUCTION_PROMPT. | This is the part that later gets wrapped into prompt text. |
globs | Optional path patterns that make a memory file conditional. | Safe to skim on the first pass. |
The memory file shape
export type MemoryFileInfo = {
path: string
type: MemoryType
content: string
parent?: string // Path of the file that included this one
globs?: string[] // Glob patterns for file paths this rule applies to
// True when auto-injection transformed `content` (stripped HTML comments,
// stripped frontmatter, truncated MEMORY.md) such that it no longer matches
// the bytes on disk. When set, `rawContent` holds the unmodified disk bytes
// so callers can cache a `isPartialView` readFileState entry — presence in
// cache provides dedup + change detection, but Edit/Write still require an
// explicit Read before proceeding.
contentDiffersFromDisk?: boolean
rawContent?: string
}
How files are discovered
export const getMemoryFiles = memoize(
async (forceIncludeExternal: boolean = false): Promise<MemoryFileInfo[]> => {
const startTime = Date.now()
logForDiagnosticsNoPII('info', 'memory_files_started')
const result: MemoryFileInfo[] = []
const processedPaths = new Set<string>()
const config = getCurrentProjectConfig()
const includeExternal =
forceIncludeExternal ||
config.hasClaudeMdExternalIncludesApproved ||
false
// Process Managed file first (always loaded - policy settings)
const managedClaudeMd = getMemoryPath('Managed')
result.push(
...(await processMemoryFile(
managedClaudeMd,
'Managed',
processedPaths,
includeExternal,
)),
)
getMemoryFiles(...) is the discovery step. It walks the current tree, any
additional directories that were added, and the feature-gated AutoMem / TeamMem
layers when they are enabled. It returns MemoryFileInfo objects, but it does
not turn them into the final instruction wrapper yet.
How files become prompt text
export const getClaudeMds = (
memoryFiles: MemoryFileInfo[],
filter?: (type: MemoryType) => boolean,
): string => {
const memories: string[] = []
const skipProjectLevel = getFeatureValue_CACHED_MAY_BE_STALE(
'tengu_paper_halyard',
false,
)
for (const file of memoryFiles) {
if (filter && !filter(file.type)) continue
if (skipProjectLevel && (file.type === 'Project' || file.type === 'Local'))
continue
if (file.content) {
const description =
file.type === 'Project'
? ' (project instructions, checked into the codebase)'
: file.type === 'Local'
? " (user's private project instructions, not checked in)"
: feature('TEAMMEM') && file.type === 'TeamMem'
? ' (shared team memory, synced across the organization)'
: file.type === 'AutoMem'
? " (user's auto-memory, persists across conversations)"
: " (user's private global instructions for all projects)"
const content = file.content.trim()
if (feature('TEAMMEM') && file.type === 'TeamMem') {
memories.push(
`Contents of ${file.path}${description}:\n\n<team-memory-content source="shared">\n${content}\n</team-memory-content>`,
)
} else {
memories.push(`Contents of ${file.path}${description}:\n\n${content}`)
}
}
}
if (memories.length === 0) {
return ''
}
return `${MEMORY_INSTRUCTION_PROMPT}\n\n${memories.join('\n\n')}`
}
The wrapper text is the important part here: MEMORY_INSTRUCTION_PROMPT
prefaces the file contents so the model knows these are instructions, not just
ordinary notes.
The prompt builder
export async function loadMemoryPrompt(): Promise<string | null> {
const autoEnabled = isAutoMemoryEnabled()
const skipIndex = getFeatureValue_CACHED_MAY_BE_STALE(
'tengu_moth_copse',
false,
)
if (feature('KAIROS') && autoEnabled && getKairosActive()) {
logMemoryDirCounts(getAutoMemPath(), {
memory_type:
'auto' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
})
return buildAssistantDailyLogPrompt(skipIndex)
}
const coworkExtraGuidelines =
process.env.CLAUDE_COWORK_MEMORY_EXTRA_GUIDELINES
const extraGuidelines =
coworkExtraGuidelines && coworkExtraGuidelines.trim().length > 0
? [coworkExtraGuidelines]
: undefined
if (feature('TEAMMEM')) {
if (teamMemPaths!.isTeamMemoryEnabled()) {
const autoDir = getAutoMemPath()
const teamDir = teamMemPaths!.getTeamMemPath()
await ensureMemoryDirExists(teamDir)
logMemoryDirCounts(autoDir, {
memory_type:
'auto' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
})
logMemoryDirCounts(teamDir, {
memory_type:
'team' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
})
return teamMemPrompts!.buildCombinedMemoryPrompt(
extraGuidelines,
skipIndex,
)
}
}
if (autoEnabled) {
const autoDir = getAutoMemPath()
await ensureMemoryDirExists(autoDir)
logMemoryDirCounts(autoDir, {
memory_type:
'auto' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
})
return buildMemoryLines(
'auto memory',
autoDir,
extraGuidelines,
skipIndex,
).join('\n')
}
return null
}
loadMemoryPrompt() is about the memory mechanics path. It decides whether the
runtime should emit auto-memory instructions at all and then builds the concrete
search guidance that teaches the model where to look.
getClaudeMds(...), by contrast, packages discovered instruction files into the
user-context text that other prompt builders can carry forward.
Searching past context
export function buildSearchingPastContextSection(autoMemDir: string): string[] {
if (!getFeatureValue_CACHED_MAY_BE_STALE('tengu_coral_fern', false)) {
return []
}
const projectDir = getProjectDir(getOriginalCwd())
// Ant-native builds alias grep to embedded ugrep and remove the dedicated
// Grep tool, so give the model a real shell invocation there.
// In REPL mode, both Grep and Bash are hidden from direct use — the model
// calls them from inside REPL scripts, so the grep shell form is what it
// will write in the script anyway.
const embedded = hasEmbeddedSearchTools() || isReplModeEnabled()
const memSearch = embedded
? `grep -rn "<search term>" ${autoMemDir} --include="*.md"`
: `${GREP_TOOL_NAME} with pattern="<search term>" path="${autoMemDir}" glob="*.md"`
const transcriptSearch = embedded
? `grep -rn "<search term>" ${projectDir}/ --include="*.jsonl"`
: `${GREP_TOOL_NAME} with pattern="<search term>" path="${projectDir}/" glob="*.jsonl"`
return [
'## Searching past context',
'',
'When looking for past context:',
'1. Search topic files in your memory directory:',
'```',
memSearch,
'```',
'2. Session transcript logs (last resort — large files, slow):',
'```',
transcriptSearch,
'```',
'Use narrow search terms (error messages, file paths, function names) rather than broad keywords.',
'',
]
}
That helper is not a generic label. It only emits when the feature gate is on, and it gives the model concrete search instructions for memory files and session transcript logs.
Takeaways
- Instruction files are discovered in layers, not from one path.
- loadMemoryPrompt() builds the memory mechanics prompt, while getClaudeMds(...) packages file contents into user context.
- The wrapper prompt tells the model that the file contents are instructions it must follow.