Skip to content

Commit df4bd64

Browse files
facelezzzzwangboxue
authored andcommitted
feat(core): add home fallback for GEMINI_SYSTEM_MD switch
1 parent e6344a8 commit df4bd64

File tree

5 files changed

+61
-5
lines changed

5 files changed

+61
-5
lines changed

docs/cli/configuration.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,8 @@ the `excludedProjectEnvVars` setting in your `settings.json` file.
535535
- This is useful for development and testing.
536536
- **`GEMINI_SYSTEM_MD`**:
537537
- Overrides the base system prompt with the contents of a Markdown file.
538-
- If set to `1` or `true`, it uses the file at `.gemini/system.md`.
538+
- If set to `1` or `true`, it uses the file at `.gemini/system.md`. If that
539+
file is missing, it falls back to `~/.gemini/system.md`.
539540
- If set to a file path, it uses that file. The path can be absolute or
540541
relative. `~` is supported for the home directory.
541542
- The specified file must exist.

docs/cli/system-prompt.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ via a `.gemini/.env` file. See
2727
- Use the project default path (`.gemini/system.md`):
2828
- `GEMINI_SYSTEM_MD=true` or `GEMINI_SYSTEM_MD=1`
2929
- The CLI reads `./.gemini/system.md` (relative to your current project
30-
directory).
30+
directory). If it does not exist, it falls back to `~/.gemini/system.md`.
3131

3232
- Use a custom file path:
3333
- `GEMINI_SYSTEM_MD=/absolute/path/to/my-system.md`
@@ -85,7 +85,8 @@ GEMINI.md focused on high‑level guidance and project specifics.
8585

8686
- Error: `missing system prompt file '…'`
8787
- Ensure the referenced path exists and is readable.
88-
- For `GEMINI_SYSTEM_MD=1|true`, create `./.gemini/system.md` in your project.
88+
- For `GEMINI_SYSTEM_MD=1|true`, create `./.gemini/system.md` in your project
89+
or `~/.gemini/system.md` in your home directory.
8990
- Override not taking effect
9091
- Confirm the variable is loaded (use `.gemini/.env` or export in your shell).
9192
- Paths are resolved from the current working directory; try an absolute path.

docs/get-started/configuration.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,8 @@ the `advanced.excludedEnvVars` setting in your `settings.json` file.
11521152
- Accepts `true`, `false`, `docker`, `podman`, or a custom command string.
11531153
- **`GEMINI_SYSTEM_MD`**:
11541154
- Replaces the built‑in system prompt with content from a Markdown file.
1155-
- `true`/`1`: Use project default path `./.gemini/system.md`.
1155+
- `true`/`1`: Use project default path `./.gemini/system.md`; if missing, fall
1156+
back to `~/.gemini/system.md`.
11561157
- Any other string: Treat as a path (relative/absolute supported, `~`
11571158
expands).
11581159
- `false`/`0` or unset: Use the built‑in prompt. See

packages/core/src/core/prompts.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,33 @@ describe('Core System Prompt (prompts.ts)', () => {
231231
},
232232
);
233233

234+
it.each(['1', 'true'])(
235+
'should fall back to home system.md when GEMINI_SYSTEM_MD is "%s" and project file is missing',
236+
(value) => {
237+
const defaultPath = path.resolve(path.join(GEMINI_DIR, 'system.md'));
238+
const homeDir = '/Users/test';
239+
const homePath = path.resolve(
240+
path.join(homeDir, GEMINI_DIR, 'system.md'),
241+
);
242+
vi.stubEnv('GEMINI_SYSTEM_MD', value);
243+
vi.spyOn(os, 'homedir').mockReturnValue(homeDir);
244+
vi.mocked(fs.existsSync).mockImplementation((targetPath) => {
245+
if (targetPath === defaultPath) {
246+
return false;
247+
}
248+
if (targetPath === homePath) {
249+
return true;
250+
}
251+
return false;
252+
});
253+
vi.mocked(fs.readFileSync).mockReturnValue('custom system prompt');
254+
255+
const prompt = getCoreSystemPrompt(mockConfig);
256+
expect(fs.readFileSync).toHaveBeenCalledWith(homePath, 'utf8');
257+
expect(prompt).toBe('custom system prompt');
258+
},
259+
);
260+
234261
it('should read from custom path when GEMINI_SYSTEM_MD provides one, preserving case', () => {
235262
const customPath = path.resolve('/custom/path/SyStEm.Md');
236263
vi.stubEnv('GEMINI_SYSTEM_MD', customPath);

packages/core/src/core/prompts.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ export function resolvePathFromEnv(envVar?: string): {
7777
};
7878
}
7979

80+
function getGlobalSystemMdPath(): string | null {
81+
try {
82+
return path.join(os.homedir(), GEMINI_DIR, 'system.md');
83+
} catch (error) {
84+
debugLogger.warn(
85+
'Could not resolve home directory for system prompt fallback.',
86+
error,
87+
);
88+
return null;
89+
}
90+
}
91+
8092
export function getCoreSystemPrompt(
8193
config: Config,
8294
userMemory?: string,
@@ -101,7 +113,21 @@ export function getCoreSystemPrompt(
101113

102114
// require file to exist when override is enabled
103115
if (!fs.existsSync(systemMdPath)) {
104-
throw new Error(`missing system prompt file '${systemMdPath}'`);
116+
if (!systemMdResolution.isSwitch) {
117+
throw new Error(`missing system prompt file '${systemMdPath}'`);
118+
}
119+
const globalSystemMdPath = getGlobalSystemMdPath();
120+
if (!globalSystemMdPath) {
121+
throw new Error(
122+
`missing system prompt file '${systemMdPath}' (failed to resolve home directory)`,
123+
);
124+
}
125+
if (!fs.existsSync(globalSystemMdPath)) {
126+
throw new Error(
127+
`missing system prompt file '${systemMdPath}' (also checked '${globalSystemMdPath}')`,
128+
);
129+
}
130+
systemMdPath = globalSystemMdPath;
105131
}
106132
}
107133

0 commit comments

Comments
 (0)