diff --git a/docs/cli/configuration.md b/docs/cli/configuration.md index a03a325afd3..28ba6a40260 100644 --- a/docs/cli/configuration.md +++ b/docs/cli/configuration.md @@ -535,7 +535,8 @@ the `excludedProjectEnvVars` setting in your `settings.json` file. - This is useful for development and testing. - **`GEMINI_SYSTEM_MD`**: - Overrides the base system prompt with the contents of a Markdown file. - - If set to `1` or `true`, it uses the file at `.gemini/system.md`. + - If set to `1` or `true`, it uses the file at `.gemini/system.md`. If that + file is missing, it falls back to `~/.gemini/system.md`. - If set to a file path, it uses that file. The path can be absolute or relative. `~` is supported for the home directory. - The specified file must exist. diff --git a/docs/cli/system-prompt.md b/docs/cli/system-prompt.md index c7fe5fc4ba1..7ecf55f489c 100644 --- a/docs/cli/system-prompt.md +++ b/docs/cli/system-prompt.md @@ -27,7 +27,7 @@ via a `.gemini/.env` file. See - Use the project default path (`.gemini/system.md`): - `GEMINI_SYSTEM_MD=true` or `GEMINI_SYSTEM_MD=1` - The CLI reads `./.gemini/system.md` (relative to your current project - directory). + directory). If it does not exist, it falls back to `~/.gemini/system.md`. - Use a custom file path: - `GEMINI_SYSTEM_MD=/absolute/path/to/my-system.md` @@ -85,7 +85,8 @@ GEMINI.md focused on high‑level guidance and project specifics. - Error: `missing system prompt file '…'` - Ensure the referenced path exists and is readable. - - For `GEMINI_SYSTEM_MD=1|true`, create `./.gemini/system.md` in your project. + - For `GEMINI_SYSTEM_MD=1|true`, create `./.gemini/system.md` in your project + or `~/.gemini/system.md` in your home directory. - Override not taking effect - Confirm the variable is loaded (use `.gemini/.env` or export in your shell). - Paths are resolved from the current working directory; try an absolute path. diff --git a/docs/get-started/configuration.md b/docs/get-started/configuration.md index a6e0d68f343..552229290f4 100644 --- a/docs/get-started/configuration.md +++ b/docs/get-started/configuration.md @@ -1152,7 +1152,8 @@ the `advanced.excludedEnvVars` setting in your `settings.json` file. - Accepts `true`, `false`, `docker`, `podman`, or a custom command string. - **`GEMINI_SYSTEM_MD`**: - Replaces the built‑in system prompt with content from a Markdown file. - - `true`/`1`: Use project default path `./.gemini/system.md`. + - `true`/`1`: Use project default path `./.gemini/system.md`; if missing, fall + back to `~/.gemini/system.md`. - Any other string: Treat as a path (relative/absolute supported, `~` expands). - `false`/`0` or unset: Use the built‑in prompt. See diff --git a/packages/core/src/core/prompts.test.ts b/packages/core/src/core/prompts.test.ts index cb346b01c36..6f9e6d1e990 100644 --- a/packages/core/src/core/prompts.test.ts +++ b/packages/core/src/core/prompts.test.ts @@ -231,6 +231,33 @@ describe('Core System Prompt (prompts.ts)', () => { }, ); + it.each(['1', 'true'])( + 'should fall back to home system.md when GEMINI_SYSTEM_MD is "%s" and project file is missing', + (value) => { + const defaultPath = path.resolve(path.join(GEMINI_DIR, 'system.md')); + const homeDir = '/Users/test'; + const homePath = path.resolve( + path.join(homeDir, GEMINI_DIR, 'system.md'), + ); + vi.stubEnv('GEMINI_SYSTEM_MD', value); + vi.spyOn(os, 'homedir').mockReturnValue(homeDir); + vi.mocked(fs.existsSync).mockImplementation((targetPath) => { + if (targetPath === defaultPath) { + return false; + } + if (targetPath === homePath) { + return true; + } + return false; + }); + vi.mocked(fs.readFileSync).mockReturnValue('custom system prompt'); + + const prompt = getCoreSystemPrompt(mockConfig); + expect(fs.readFileSync).toHaveBeenCalledWith(homePath, 'utf8'); + expect(prompt).toBe('custom system prompt'); + }, + ); + it('should read from custom path when GEMINI_SYSTEM_MD provides one, preserving case', () => { const customPath = path.resolve('/custom/path/SyStEm.Md'); vi.stubEnv('GEMINI_SYSTEM_MD', customPath); diff --git a/packages/core/src/core/prompts.ts b/packages/core/src/core/prompts.ts index 0165ad6228e..d1c62696521 100644 --- a/packages/core/src/core/prompts.ts +++ b/packages/core/src/core/prompts.ts @@ -77,6 +77,18 @@ export function resolvePathFromEnv(envVar?: string): { }; } +function getGlobalSystemMdPath(): string | null { + try { + return path.join(os.homedir(), GEMINI_DIR, 'system.md'); + } catch (error) { + debugLogger.warn( + 'Could not resolve home directory for system prompt fallback.', + error, + ); + return null; + } +} + export function getCoreSystemPrompt( config: Config, userMemory?: string, @@ -101,7 +113,21 @@ export function getCoreSystemPrompt( // require file to exist when override is enabled if (!fs.existsSync(systemMdPath)) { - throw new Error(`missing system prompt file '${systemMdPath}'`); + if (!systemMdResolution.isSwitch) { + throw new Error(`missing system prompt file '${systemMdPath}'`); + } + const globalSystemMdPath = getGlobalSystemMdPath(); + if (!globalSystemMdPath) { + throw new Error( + `missing system prompt file '${systemMdPath}' (failed to resolve home directory)`, + ); + } + if (!fs.existsSync(globalSystemMdPath)) { + throw new Error( + `missing system prompt file '${systemMdPath}' (also checked '${globalSystemMdPath}')`, + ); + } + systemMdPath = globalSystemMdPath; } }