From 5f5c4228830c3e3b0da78dc210b2152d34e18c35 Mon Sep 17 00:00:00 2001 From: rock-solid-sites Date: Wed, 13 May 2026 23:57:38 +0200 Subject: [PATCH 1/2] feat: add systemPromptFile config key for system prompt replacement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new optional config key 'systemPromptFile' to settings.json that replaces the built-in SYSTEM_PROMPT_BASE with custom content. Tool docs, runtime context, AGENTS.md, and matched skills continue to load after the replacement — only the content of the first system message changes. - src/settings.ts: Add systemPromptFile to DeepcodingSettings and ResolvedDeepcodingSettings types. Resolve with standard precedence (system env > project settings > user settings). - src/prompt.ts: Extend getSystemPrompt() with a systemPromptFile parameter. When set, reads the file at the resolved path and uses it as the base prompt. Fails loud if the file can't be read. - src/session.ts: Plumb systemPromptFile through SessionManager via getResolvedSettings callback into createSession(). --- src/prompt.ts | 25 ++++++++++++++++++++++--- src/session.ts | 18 +++++++++++++++--- src/settings.ts | 11 +++++++++++ 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/prompt.ts b/src/prompt.ts index f8df085..9d95f12 100644 --- a/src/prompt.ts +++ b/src/prompt.ts @@ -274,10 +274,29 @@ function readToolDocs(extensionRoot: string, _options: PromptToolOptions = {}): return docs.join("\n\n"); } -export function getSystemPrompt(projectRoot: string, options: PromptToolOptions = {}): string { +export function getSystemPrompt( + projectRoot: string, + options: PromptToolOptions = {}, + systemPromptFile?: string +): string { + let basePrompt: string; + + if (systemPromptFile) { + const resolvedPath = path.resolve(projectRoot, systemPromptFile); + try { + basePrompt = fs.readFileSync(resolvedPath, "utf8").trim(); + } catch (err) { + throw new Error( + `Failed to read systemPromptFile at ${resolvedPath}: ${err instanceof Error ? err.message : String(err)}` + ); + } + } else { + basePrompt = SYSTEM_PROMPT_BASE; + } + const toolDocs = readToolDocs(getExtensionRoot(), options); - const basePrompt = toolDocs ? `${SYSTEM_PROMPT_BASE}\n\n# Available Tools\n\n${toolDocs}` : SYSTEM_PROMPT_BASE; - return `${basePrompt}\n\n${getRuntimeContext(projectRoot)}`; + const promptWithTools = toolDocs ? `${basePrompt}\n\n# Available Tools\n\n${toolDocs}` : basePrompt; + return `${promptWithTools}\n\n${getRuntimeContext(projectRoot)}`; } export function getCompactPrompt(sessionMessages: SessionMessage[]): string { diff --git a/src/session.ts b/src/session.ts index 4c42f81..de794ed 100644 --- a/src/session.ts +++ b/src/session.ts @@ -155,7 +155,11 @@ export type SkillInfo = { type SessionManagerOptions = { projectRoot: string; createOpenAIClient: CreateOpenAIClient; - getResolvedSettings: () => { webSearchTool?: string; mcpServers?: Record }; + getResolvedSettings: () => { + webSearchTool?: string; + systemPromptFile?: string; + mcpServers?: Record; + }; renderMarkdown: (text: string) => string; onAssistantMessage: (message: SessionMessage, shouldConnect: boolean) => void; onSessionEntryUpdated?: (entry: SessionEntry) => void; @@ -174,7 +178,11 @@ export type LlmStreamProgress = { export class SessionManager { private readonly projectRoot: string; private readonly createOpenAIClient: CreateOpenAIClient; - private readonly getResolvedSettings: () => { webSearchTool?: string; mcpServers?: Record }; + private readonly getResolvedSettings: () => { + webSearchTool?: string; + systemPromptFile?: string; + mcpServers?: Record; + }; private readonly onAssistantMessage: (message: SessionMessage, shouldConnect: boolean) => void; private readonly onSessionEntryUpdated?: (entry: SessionEntry) => void; private readonly onLlmStreamProgress?: (progress: LlmStreamProgress) => void; @@ -846,7 +854,11 @@ The candidate skills are as follows:\n\n`; this.saveSessionsIndex(index); this.removeSessionMessages(droppedEntries.map((item) => item.id)); - const systemPrompt = getSystemPrompt(this.projectRoot, this.getPromptToolOptions()); + const systemPrompt = getSystemPrompt( + this.projectRoot, + this.getPromptToolOptions(), + this.getResolvedSettings().systemPromptFile + ); const systemMessage = this.buildSystemMessage(sessionId, systemPrompt); this.appendSessionMessage(sessionId, systemMessage); diff --git a/src/settings.ts b/src/settings.ts index 9fbcea2..03c28ea 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -25,6 +25,7 @@ export type DeepcodingSettings = { debugLogEnabled?: boolean; notify?: string; webSearchTool?: string; + systemPromptFile?: string; mcpServers?: Record; }; @@ -38,6 +39,7 @@ export type ResolvedDeepcodingSettings = { debugLogEnabled: boolean; notify?: string; webSearchTool?: string; + systemPromptFile?: string; mcpServers?: Record; }; @@ -222,6 +224,14 @@ export function resolveSettingsSources( trimString(userSettings?.webSearchTool) || ""; + const systemPromptFile = + trimString(systemEnv.SYSTEM_PROMPT_FILE) || + trimString(projectSettings?.systemPromptFile) || + trimString(projectEnv.SYSTEM_PROMPT_FILE) || + trimString(userSettings?.systemPromptFile) || + trimString(userEnv.SYSTEM_PROMPT_FILE) || + ""; + return { env, apiKey: trimString(env.API_KEY) || undefined, @@ -232,6 +242,7 @@ export function resolveSettingsSources( debugLogEnabled, notify: notify || undefined, webSearchTool: webSearchTool || undefined, + systemPromptFile: systemPromptFile || undefined, mcpServers: mergeMcpServers(userSettings, projectSettings, userEnv, projectEnv, systemEnv), }; } From c07dda5496394afa10a68d3516e3f09e7431df9f Mon Sep 17 00:00:00 2001 From: rock-solid-sites Date: Wed, 13 May 2026 23:57:38 +0200 Subject: [PATCH 2/2] docs: document systemPromptFile config key Add the new systemPromptFile field to the settings table and a dedicated section explaining path resolution, behavior, and the fail-loud error handling (no silent fallback to default). --- docs/configuration.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index f8e52c3..32353f8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -33,6 +33,7 @@ Deep Code 使用 `settings.json` 设置文件进行持久化配置,支持两 | `debugLogEnabled` | boolean | 是否启用调试日志输出(默认 `false`) | | `notify` | string | 任务完成通知脚本的完整路径(如 Slack 通知脚本) | | `webSearchTool` | string | 自定义联网搜索脚本的完整路径 | +| `systemPromptFile` | string | Path to a file containing a replacement system prompt (see section below) | | `mcpServers` | object | MCP 服务器配置(键为服务名,值为 McpServerConfig 对象) | #### `env` 子字段 @@ -85,6 +86,22 @@ Deep Code 内置免费可用的 Web Search 工具。如果需要自定义搜索 脚本接收一个搜索查询参数,输出 JSON 格式的结果供 AI 使用。 +#### `systemPromptFile` — System Prompt Replacement + +By default, Deep Code uses its built-in system prompt. To replace it with custom content, set `systemPromptFile` to a file path: + +```json +{ + "systemPromptFile": "/path/to/my-system-prompt.md" +} +``` + +The path is resolved relative to the project root (for project-level settings) or treated as an absolute path. Environment variable support is also available via `DEEPCODE_SYSTEM_PROMPT_FILE`. + +When set, the file content replaces the built-in base system prompt. Tool documentation, runtime context, AGENTS.md instructions, skills continue to load after the replacement — tool calling is preserved. + +If the file cannot be read (wrong path, permissions issue, deleted file), Deep Code exits with an error. It does **not** silently fall back to the default prompt. + #### `mcpServers` — MCP 服务器 MCP(Model Context Protocol)服务器配置。值是键值对,键为服务名称,值为服务器配置对象。