fix(coding-agent): tighten system prompt

This commit is contained in:
Armin Ronacher 2026-10-31 16:10:55 +01:00
parent ed2bdde64b
commit 705d047cb5
5 changed files with 18 additions and 12 deletions

View file

@ -12,6 +12,7 @@
### Changed
- Tightened system prompt
- `pi update` for installs from the pi.dev installer no longer passes `--min-release-age=0` to `npm ci`. The release lockfile pins every package, so the flag had no effect, and security scanners that block it stopped the update ([#11262](https://github.com/earendil-works/pi/issues/11262))
- `/model` and `/scoped-models` now show a model's name next to its ID when the name adds words the ID lacks, such as a renamed `models.json` override ([#5916](https://github.com/earendil-works/pi/issues/5916), [#11347](https://github.com/earendil-works/pi/pull/11347))
- MCP OAuth sign-in now uses pi's Client ID Metadata Document by default when the authorization server supports it for public clients, and registers a client dynamically otherwise, like Codex, Claude Code, and opencode. Clients registered before stay in use while their redirect URI matches. The new default `oauth.clientRegistration: "auto"` registers when `clientName` or a non-default `callbackUrl` is set; `"dcr"` always registers. `pi mcp add --oauth-client-registration` sets the mode ([#11426](https://github.com/earendil-works/pi/issues/11426))

View file

@ -369,7 +369,7 @@ export function formatSkillsForPrompt(skills: Skill[], fileReadTool: "read" | "b
: fileReadTool === "bash"
? "Use bash to load a skill's file when the task matches its description."
: "Load a skill's file when the task matches its description.",
"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.",
"Resolve relative paths against the skill's directory (parent of SKILL.md). Use absolute paths in tool calls.",
"",
"<available_skills>",
];

View file

@ -153,20 +153,19 @@ export function buildSystemPromptSections(input: BuildSystemPromptOptions): Syst
promptSections.preamble = customPrompt;
} else {
promptSections.preamble =
"You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.";
"You are a coding assistant running inside pi, a coding agent harness. Help users inspect files, run commands, and modify code.";
const visibleTools = declaredTools.filter((name) => !!toolSnippets[name]);
const tools =
visibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets[name]}`).join("\n") : "(none)";
promptSections.tools = `${tools}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.`;
promptSections.tools = `${tools}\n\nAdditional tools may be available.`;
promptSections.rules = buildRules(declaredTools, toolGuidelines, promptGuidelines);
promptSections.docs = `Pi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):
promptSections.docs = `Pi documentation (read only when the user asks about the harness itself, its SDK, extensions, themes, skills, or TUI):
- Main documentation: ${getReadmePath()}
- Additional docs: ${getDocsPath()}
- Examples: ${getExamplesPath()} (extensions, custom tools, SDK)
- When reading pi docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory
- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md), environment variables (docs/environment-variables.md), MCP servers (docs/mcp.md), codemode scripts and non-LLM models such as classifiers and image models (docs/codemode.md)
- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing
- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;
- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), packages (docs/packages.md), environment variables (docs/environment-variables.md), MCP servers (docs/mcp.md), codemode scripts and non-LLM models such as classifiers and image models (docs/codemode.md)
- Before implementing harness changes, read the relevant docs and examples in full, following related cross-references.`;
}
if (appendSystemPrompt) promptSections.addendum = appendSystemPrompt;

View file

@ -43,10 +43,8 @@ const editSchema = Type.Object(
export const editToolSystemPromptContribution = {
snippet: "Make precise file edits with exact text replacement, including multiple disjoint edits in one call",
guidelines: [
"Use edit for precise changes (edits[].oldText must match exactly)",
"When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls",
"Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.",
"Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.",
"Use edit for targeted changes. Batch changes to one file in a single call.",
"Each edits[].oldText must exactly and uniquely match the original file. Keep matches short and non-overlapping; merge nearby changes without including large unchanged regions.",
],
} as const;

View file

@ -48,7 +48,9 @@ describe("buildSystemPrompt", () => {
skills: [],
});
expect(defaultPrompt.startsWith("You are an expert coding assistant operating inside pi")).toBe(true);
expect(defaultPrompt.startsWith("You are a coding assistant running inside pi, a coding agent harness.")).toBe(
true,
);
expect(customPrompt.startsWith("You are Exact.\n\n<cwd>")).toBe(true);
});
@ -119,6 +121,9 @@ describe("buildSystemPrompt", () => {
"- When reading pi docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory",
);
expect(prompt).toContain("environment variables (docs/environment-variables.md), MCP servers (docs/mcp.md)");
expect(prompt).toContain(
"Before implementing harness changes, read the relevant docs and examples in full, following related cross-references.",
);
});
});
@ -192,6 +197,9 @@ describe("buildSystemPrompt", () => {
expect(prompt).toContain("<available_skills>");
expect(prompt).toContain("<name>test-skill</name>");
expect(prompt).toContain("Use bash to load a skill's file");
expect(prompt).toContain(
"Resolve relative paths against the skill's directory (parent of SKILL.md). Use absolute paths in tool calls.",
);
});
test("omits skills without read or bash", () => {