From db5d8c64e91b7bdaecdde7c79373f5be994b3910 Mon Sep 17 00:00:00 2001 From: dvd233 <111864431+dvd233@users.noreply.github.com> Date: Fri, 18 Sep 2026 14:21:43 -0700 Subject: [PATCH] fix(pull): include root-level claudemd files --- src/__tests__/pull-skip-sync.test.ts | 2 ++ src/pull.ts | 14 +++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/__tests__/pull-skip-sync.test.ts b/src/__tests__/pull-skip-sync.test.ts index 5492d70f..f8e988ff 100644 --- a/src/__tests__/pull-skip-sync.test.ts +++ b/src/__tests__/pull-skip-sync.test.ts @@ -673,6 +673,7 @@ describe('enabledAgents whitelist on pull inject, skip-sync, and cleanup (#510)' ); await fse.ensureDir(path.join(repoPath, 'claudemd', 'common')); await fse.writeFile(path.join(repoPath, 'claudemd', 'common', 'note.md'), 'Shared team instructions.\n'); + await fse.writeFile(path.join(repoPath, 'claudemd', 'shared.md'), 'Root-level shared instructions.\n'); vi.stubEnv('HOME', homeDir); vi.mocked(detectProjectConfig).mockResolvedValue(null); @@ -743,6 +744,7 @@ describe('enabledAgents whitelist on pull inject, skip-sync, and cleanup (#510)' const claudeMd = await fse.readFile(path.join(homeDir, '.claude', 'CLAUDE.md'), 'utf8'); expect(claudeMd).toContain(TEAMAI_CULTURE_START); expect(claudeMd).toContain(TEAMAI_CLAUDEMD_START); + expect(claudeMd).toContain('Root-level shared instructions.'); expect(claudeMd).toContain(TEAMAI_RECALL_RULES_START); const codebuddyMd = await fse.readFile(path.join(homeDir, '.codebuddy', 'CODEBUDDY.md'), 'utf8'); diff --git a/src/pull.ts b/src/pull.ts index 63e95ff7..cc2c0258 100644 --- a/src/pull.ts +++ b/src/pull.ts @@ -1520,8 +1520,8 @@ export function compileRecallRulesBlock(): string { /** * Collect claudemd .md files filtered by the user's active knowledge namespaces. * - * Walks claudemd//*.md for each active namespace. - * Falls back to collecting ALL namespace dirs when no role context is available. + * Always collects root-level claudemd/*.md files, then walks claudemd//*.md + * for each active namespace. Root-level instructions are shared with every member. */ async function collectClaudemdFiles( repoPath: string, @@ -1530,6 +1530,15 @@ async function collectClaudemdFiles( const claudemdDir = path.join(repoPath, 'claudemd'); if (!await pathExists(claudemdDir)) return []; + const contents: string[] = []; + const rootFiles = (await listFiles(claudemdDir)) + .filter((f) => f.endsWith('.md')) + .sort(); + for (const file of rootFiles) { + const content = await readFileSafe(path.join(claudemdDir, file)); + if (content) contents.push(content); + } + // Determine which namespace dirs to scan let namespaceDirs: string[]; if (roleContext) { @@ -1539,7 +1548,6 @@ async function collectClaudemdFiles( namespaceDirs = await listDirs(claudemdDir); } - const contents: string[] = []; for (const ns of namespaceDirs) { const nsDir = path.join(claudemdDir, ns); if (!await pathExists(nsDir)) continue;