Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/coding-agent/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Restored bare `prime-agent --resume` opening the agents view and the `/resume [id|path]` slash command; bare commands open the agents view and an argument resumes that session in place.
- Fixed URLs not opening on click in fullscreen mode on terminals such as Ghostty; clicking a link in the transcript, dock, or overlays now opens it in the browser.
- Fixed ctrl+p ("Toggle agent message expansion") only toggling received agent messages; it now expands and collapses sent agent messages together with received ones.
- Fixed inherited root-controller prompts overriding the role of recursive child agents.

## [0.7.2] - 2026-08-11

Expand Down
10 changes: 7 additions & 3 deletions packages/coding-agent/src/core/prompts/rlm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export interface RlmPromptOptions {
depth?: number;
parentAgent?: string;
activeTools?: string[];
/** Whether to include child-role doctrine inline. Disable when a higher-level prompt builder appends it last. */
includeChildDoctrine?: boolean;
}

const IPYTHON_CONTROL_PROMPT = [
Expand Down Expand Up @@ -79,9 +81,11 @@ export function buildRlmPrompt(options: RlmPromptOptions): string {
"Install additional packages with `uv pip install <pkg>` (this is a uv-managed venv with no pip module).",
];

const childDoctrine = buildChildAgentDoctrine(options);
if (childDoctrine) {
parts.push("", childDoctrine);
if (options.includeChildDoctrine ?? true) {
const childDoctrine = buildChildAgentDoctrine(options);
if (childDoctrine) {
parts.push("", childDoctrine);
}
}

const skillLines: string[] = [];
Expand Down
25 changes: 15 additions & 10 deletions packages/coding-agent/src/core/system-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions): string {
const visibleSkills = skills.filter((skill) => !skill.disableModelInvocation);
const visiblePythonSkillImportNames = getPythonSkillRuntimeInfo(visibleSkills).map((skill) => skill.importName);
const hasRefineSkill = visibleSkills.some((skill) => skill.name === REFINE_SKILL_NAME);
const childDoctrine = buildChildAgentDoctrine({
depth: options.rlmDepth,
parentAgent: options.rlmParentAgent,
installedSkills: visiblePythonSkillImportNames,
activeTools: tools,
});

if (customPrompt) {
let prompt = customPrompt;
Expand All @@ -92,16 +98,6 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions): string {
prompt += `\nCurrent date: ${date}`;
prompt += `\nCurrent working directory: ${promptCwd}`;

const childDoctrine = buildChildAgentDoctrine({
depth: options.rlmDepth,
parentAgent: options.rlmParentAgent,
installedSkills: visiblePythonSkillImportNames,
activeTools: tools,
});
if (childDoctrine) {
prompt += `\n\n${childDoctrine}`;
}

if (harnessState) {
prompt += `\n\n${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill })}`;
}
Expand All @@ -110,6 +106,10 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions): string {
prompt += appendSection;
}

if (childDoctrine) {
prompt += `\n\n${childDoctrine}`;
}

return prompt;
}

Expand All @@ -121,6 +121,7 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions): string {
allowRecursion,
depth: options.rlmDepth,
parentAgent: options.rlmParentAgent,
includeChildDoctrine: false,
});

// Appended AFTER the trained buildRlmPrompt prefix, and before the harness-state
Expand Down Expand Up @@ -165,6 +166,10 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions): string {
prompt += appendSection;
}

if (childDoctrine) {
prompt += `\n\n${childDoctrine}`;
}

return prompt;
}

Expand Down
27 changes: 25 additions & 2 deletions packages/coding-agent/test/system-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -597,9 +597,10 @@ describe("buildSystemPrompt", () => {
expect(prompt.indexOf("# Continual Harness State")).toBeLessThan(prompt.indexOf("custom append"));
});

test("adds child reply doctrine to custom prompts when messaging is available", () => {
test("gives child doctrine final precedence over inherited controller prompts", () => {
const prompt = buildSystemPrompt({
customPrompt: "custom body",
customPrompt: "You are the root controller.",
appendSystemPrompt: "Spawn a child and poll it until completion.",
selectedTools: ["ipython"],
contextFiles: [],
skills: [pythonSkill("agent-message")],
Expand All @@ -608,11 +609,33 @@ describe("buildSystemPrompt", () => {
rlmParentAgent: "orchestrator",
});

expect(prompt).toContain("You are the root controller.");
expect(prompt).toContain("Spawn a child and poll it until completion.");
expect(prompt).toContain("You are a child agent spawned by orchestrator");
expect(prompt.indexOf("Spawn a child and poll it until completion.")).toBeLessThan(
prompt.indexOf("You are a child agent spawned by orchestrator"),
);
expect(prompt).toContain('await agent_message.send(message, receiver_role="parent")');
expect(prompt).not.toContain("You are a general purpose agent that uses code to solve tasks.");
});

test("keeps recursive delegation available when child doctrine follows appended instructions", () => {
const prompt = buildSystemPrompt({
selectedTools: ["ipython"],
appendSystemPrompt: "You are the root controller.",
contextFiles: [],
skills: [],
cwd: "/repo",
allowRecursion: true,
rlmDepth: 1,
});

expect(prompt).toContain("await rlm('sub-task')");
expect(prompt.indexOf("You are the root controller.")).toBeLessThan(
prompt.indexOf("You are a child agent spawned by your parent agent"),
);
});

test("gates custom-prompt child reply doctrine on IPython and agent messaging", () => {
const build = (selectedTools: string[], skills: Skill[]) =>
buildSystemPrompt({
Expand Down