diff --git a/src/agents/atlas/default.ts b/src/agents/atlas/default.ts index a5d68b654..64e6a3348 100644 --- a/src/agents/atlas/default.ts +++ b/src/agents/atlas/default.ts @@ -213,7 +213,7 @@ After EVERY delegation, complete ALL of these steps — no shortcuts: After verification, READ the plan file directly — every time, no exceptions: \`\`\` -Read(".sisyphus/tasks/{plan-name}.yaml") +Read(".sisyphus/plans/{plan-name}.md") \`\`\` Count remaining \`- [ ]\` tasks. This is your ground truth for what comes next. @@ -335,7 +335,7 @@ task(category="quick", load_skills=[], run_in_background=false, prompt="Task 4.. \`\`\` **Path convention**: -- Plan: \`.sisyphus/plans/{name}.md\` (READ ONLY) +- Plan: \`.sisyphus/plans/{name}.md\` (you may EDIT to mark checkboxes) - Notepad: \`.sisyphus/notepads/{name}/\` (READ/APPEND) @@ -372,6 +372,7 @@ You are the QA gate. Subagents lie. Verify EVERYTHING. - Use lsp_diagnostics, grep, glob - Manage todos - Coordinate and verify +- **EDIT \`.sisyphus\/plans\/*.md\` to change \`- [ ]\` to \`- [x]\` after verified task completion** **YOU DELEGATE**: - All code writing/editing @@ -403,6 +404,20 @@ You are the QA gate. Subagents lie. Verify EVERYTHING. - **Store session_id from every delegation output** - **Use \`session_id="{session_id}"\` for retries, fixes, and follow-ups** + + +## POST-DELEGATION RULE (MANDATORY) + +After EVERY verified task() completion, you MUST: + +1. **EDIT the plan checkbox**: Change \`- [ ]\` to \`- [x]\` for the completed task in \`.sisyphus/plans/{plan-name}.md\` + +2. **READ the plan to confirm**: Read \`.sisyphus/plans/{plan-name}.md\` and verify the checkbox count changed (fewer \`- [ ]\` remaining) + +3. **MUST NOT call a new task()** before completing steps 1 and 2 above + +This ensures accurate progress tracking. Skip this and you lose visibility into what remains. + ` export function getDefaultAtlasPrompt(): string { diff --git a/src/agents/atlas/gemini.ts b/src/agents/atlas/gemini.ts index c76597892..6ddfa94a0 100644 --- a/src/agents/atlas/gemini.ts +++ b/src/agents/atlas/gemini.ts @@ -309,7 +309,7 @@ task(category="quick", load_skills=[], run_in_background=false, prompt="Task 3.. - Instruct subagent to append findings (never overwrite) **Paths**: -- Plan: \`.sisyphus/plans/{name}.md\` (READ ONLY) +- Plan: \`.sisyphus\/plans\/{name}.md\` (you may EDIT to mark checkboxes) - Notepad: \`.sisyphus/notepads/{name}/\` (READ/APPEND) @@ -343,6 +343,7 @@ Subagents CLAIM "done" when: - Use lsp_diagnostics, grep, glob - Manage todos - Coordinate and verify +- **EDIT \`.sisyphus\/plans\/*.md\` to change \`- [ ]\` to \`- [x]\` after verified task completion** **YOU DELEGATE (NO EXCEPTIONS):** - All code writing/editing @@ -373,6 +374,20 @@ Subagents CLAIM "done" when: - Store and reuse session_id for retries - **USE TOOL CALLS for verification — not internal reasoning** + + +## POST-DELEGATION RULE (MANDATORY) + +After EVERY verified task() completion, you MUST: + +1. **EDIT the plan checkbox**: Change \`- [ ]\` to \`- [x]\` for the completed task in \`.sisyphus/plans/{plan-name}.md\` + +2. **READ the plan to confirm**: Read \`.sisyphus/plans/{plan-name}.md\` and verify the checkbox count changed (fewer \`- [ ]\` remaining) + +3. **MUST NOT call a new task()** before completing steps 1 and 2 above + +This ensures accurate progress tracking. Skip this and you lose visibility into what remains. + ` export function getGeminiAtlasPrompt(): string { diff --git a/src/agents/atlas/gpt.ts b/src/agents/atlas/gpt.ts index 570e4e774..64b144b50 100644 --- a/src/agents/atlas/gpt.ts +++ b/src/agents/atlas/gpt.ts @@ -313,7 +313,7 @@ task(category="quick", load_skills=[], run_in_background=false, prompt="Task 3.. - Instruct subagent to append findings (never overwrite) **Paths**: -- Plan: \`.sisyphus/plans/{name}.md\` (READ ONLY) +- Plan: \`.sisyphus/plans/{name}.md\` (you may EDIT to mark checkboxes) - Notepad: \`.sisyphus/notepads/{name}/\` (READ/APPEND) @@ -348,6 +348,7 @@ Your job is to CATCH THEM. Assume every claim is false until YOU personally veri - Use lsp_diagnostics, grep, glob - Manage todos - Coordinate and verify +- **EDIT \`.sisyphus\/plans\/*.md\` to change \`- [ ]\` to \`- [x]\` after verified task completion** **YOU DELEGATE**: - All code writing/editing @@ -376,15 +377,19 @@ Your job is to CATCH THEM. Assume every claim is false until YOU personally veri - Store and reuse session_id for retries - -- Send brief updates (1-2 sentences) only when: - - Starting a new major phase - - Discovering something that changes the plan -- Avoid narrating routine tool calls -- Each update must include a concrete outcome ("Found X", "Verified Y", "Delegated Z") -- Keep updates varied in structure — don't start each the same way -- Do NOT expand task scope; if you notice new work, call it out as optional - + +## POST-DELEGATION RULE (MANDATORY) + +After EVERY verified task() completion, you MUST: + +1. **EDIT the plan checkbox**: Change \`- [ ]\` to \`- [x]\` for the completed task in \`.sisyphus/plans/{plan-name}.md\` + +2. **READ the plan to confirm**: Read \`.sisyphus/plans/{plan-name}.md\` and verify the checkbox count changed (fewer \`- [ ]\` remaining) + +3. **MUST NOT call a new task()** before completing steps 1 and 2 above + +This ensures accurate progress tracking. Skip this and you lose visibility into what remains. + `; export function getGptAtlasPrompt(): string { diff --git a/src/agents/atlas/prompt-checkbox-enforcement.test.ts b/src/agents/atlas/prompt-checkbox-enforcement.test.ts new file mode 100644 index 000000000..51f352729 --- /dev/null +++ b/src/agents/atlas/prompt-checkbox-enforcement.test.ts @@ -0,0 +1,155 @@ +import { describe, test, expect } from "bun:test" +import { ATLAS_SYSTEM_PROMPT } from "./default" +import { ATLAS_GPT_SYSTEM_PROMPT } from "./gpt" +import { ATLAS_GEMINI_SYSTEM_PROMPT } from "./gemini" + +describe("ATLAS prompt checkbox enforcement", () => { + describe("default prompt", () => { + test("plan should NOT be marked (READ ONLY)", () => { + // given + const prompt = ATLAS_SYSTEM_PROMPT + + // when / then + expect(prompt).not.toMatch(/\(READ ONLY\)/) + }) + + test("plan description should include EDIT for checkboxes", () => { + // given + const prompt = ATLAS_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/edit.*checkbox|checkbox.*edit/) + }) + + test("boundaries should include exception for editing .sisyphus/plans/*.md checkboxes", () => { + // given + const prompt = ATLAS_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/\.sisyphus\/plans\/\*\.md/) + expect(lowerPrompt).toMatch(/checkbox/) + }) + + test("prompt should include POST-DELEGATION RULE", () => { + // given + const prompt = ATLAS_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/post-delegation/) + }) + + test("prompt should include MUST NOT call a new task() before", () => { + // given + const prompt = ATLAS_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/must not.*call.*new.*task/) + }) + + test("default prompt should NOT reference .sisyphus/tasks/", () => { + // given + const prompt = ATLAS_SYSTEM_PROMPT + + // when / then + expect(prompt).not.toMatch(/\.sisyphus\/tasks\//) + }) + }) + + describe("GPT prompt", () => { + test("plan should NOT be marked (READ ONLY)", () => { + // given + const prompt = ATLAS_GPT_SYSTEM_PROMPT + + // when / then + expect(prompt).not.toMatch(/\(READ ONLY\)/) + }) + + test("plan description should include EDIT for checkboxes", () => { + // given + const prompt = ATLAS_GPT_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/edit.*checkbox|checkbox.*edit/) + }) + + test("boundaries should include exception for editing .sisyphus/plans/*.md checkboxes", () => { + // given + const prompt = ATLAS_GPT_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/\.sisyphus\/plans\/\*\.md/) + expect(lowerPrompt).toMatch(/checkbox/) + }) + + test("prompt should include POST-DELEGATION RULE", () => { + // given + const prompt = ATLAS_GPT_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/post-delegation/) + }) + + test("prompt should include MUST NOT call a new task() before", () => { + // given + const prompt = ATLAS_GPT_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/must not.*call.*new.*task/) + }) + }) + + describe("Gemini prompt", () => { + test("plan should NOT be marked (READ ONLY)", () => { + // given + const prompt = ATLAS_GEMINI_SYSTEM_PROMPT + + // when / then + expect(prompt).not.toMatch(/\(READ ONLY\)/) + }) + + test("plan description should include EDIT for checkboxes", () => { + // given + const prompt = ATLAS_GEMINI_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/edit.*checkbox|checkbox.*edit/) + }) + + test("boundaries should include exception for editing .sisyphus/plans/*.md checkboxes", () => { + // given + const prompt = ATLAS_GEMINI_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/\.sisyphus\/plans\/\*\.md/) + expect(lowerPrompt).toMatch(/checkbox/) + }) + + test("prompt should include POST-DELEGATION RULE", () => { + // given + const prompt = ATLAS_GEMINI_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/post-delegation/) + }) + + test("prompt should include MUST NOT call a new task() before", () => { + // given + const prompt = ATLAS_GEMINI_SYSTEM_PROMPT + const lowerPrompt = prompt.toLowerCase() + + // when / then + expect(lowerPrompt).toMatch(/must not.*call.*new.*task/) + }) + }) +}) diff --git a/src/hooks/atlas/index.test.ts b/src/hooks/atlas/index.test.ts index 8e3b4b6d4..cd01eb71a 100644 --- a/src/hooks/atlas/index.test.ts +++ b/src/hooks/atlas/index.test.ts @@ -409,6 +409,123 @@ describe("atlas hook", () => { cleanupMessageStorage(sessionID) }) + describe("completion gate output ordering", () => { + const COMPLETION_GATE_SESSION = "completion-gate-order-test" + + beforeEach(() => { + setupMessageStorage(COMPLETION_GATE_SESSION, "atlas") + }) + + afterEach(() => { + cleanupMessageStorage(COMPLETION_GATE_SESSION) + }) + + test("should include completion gate before Subagent Response in transformed boulder output", async () => { + // given - Atlas caller with boulder state + const planPath = join(TEST_DIR, "test-plan.md") + writeFileSync(planPath, "# Plan\n- [ ] Task 1\n- [x] Task 2") + + const state: BoulderState = { + active_plan: planPath, + started_at: "2026-01-02T10:00:00Z", + session_ids: ["session-1"], + plan_name: "test-plan", + } + writeBoulderState(TEST_DIR, state) + + const hook = createAtlasHook(createMockPluginInput()) + const output = { + title: "Sisyphus Task", + output: "Task completed successfully", + metadata: {}, + } + + // when + await hook["tool.execute.after"]( + { tool: "task", sessionID: COMPLETION_GATE_SESSION }, + output + ) + + // then - completion gate should appear BEFORE Subagent Response + const subagentResponseIndex = output.output.indexOf("**Subagent Response:**") + const completionGateIndex = output.output.indexOf("COMPLETION GATE") + + expect(completionGateIndex).toBeGreaterThanOrEqual(0) + expect(subagentResponseIndex).toBeGreaterThanOrEqual(0) + expect(completionGateIndex).toBeLessThan(subagentResponseIndex) + }) + + test("should include completion gate before verification phase text", async () => { + // given - Atlas caller with boulder state + const planPath = join(TEST_DIR, "test-plan.md") + writeFileSync(planPath, "# Plan\n- [ ] Task 1\n- [x] Task 2") + + const state: BoulderState = { + active_plan: planPath, + started_at: "2026-01-02T10:00:00Z", + session_ids: ["session-1"], + plan_name: "test-plan", + } + writeBoulderState(TEST_DIR, state) + + const hook = createAtlasHook(createMockPluginInput()) + const output = { + title: "Sisyphus Task", + output: "Task completed successfully", + metadata: {}, + } + + // when + await hook["tool.execute.after"]( + { tool: "task", sessionID: COMPLETION_GATE_SESSION }, + output + ) + + // then - completion gate should appear BEFORE verification phase text + const completionGateIndex = output.output.indexOf("COMPLETION GATE") + const lyingIndex = output.output.indexOf("LYING") + const phase1Index = output.output.indexOf("PHASE 1") + + expect(completionGateIndex).toBeGreaterThanOrEqual(0) + expect(lyingIndex).toBeGreaterThanOrEqual(0) + expect(completionGateIndex).toBeLessThan(lyingIndex) + if (phase1Index !== -1) { + expect(completionGateIndex).toBeLessThan(phase1Index) + } + }) + + test("should not contain old STEP 7 MARK COMPLETION IN PLAN FILE text", async () => { + // given - Atlas caller with boulder state + const planPath = join(TEST_DIR, "test-plan.md") + writeFileSync(planPath, "# Plan\n- [ ] Task 1\n- [x] Task 2") + + const state: BoulderState = { + active_plan: planPath, + started_at: "2026-01-02T10:00:00Z", + session_ids: ["session-1"], + plan_name: "test-plan", + } + writeBoulderState(TEST_DIR, state) + + const hook = createAtlasHook(createMockPluginInput()) + const output = { + title: "Sisyphus Task", + output: "Task completed successfully", + metadata: {}, + } + + // when + await hook["tool.execute.after"]( + { tool: "task", sessionID: COMPLETION_GATE_SESSION }, + output + ) + + // then - old STEP 7 MARK COMPLETION IN PLAN FILE should be absent + expect(output.output).not.toContain("STEP 7: MARK COMPLETION IN PLAN FILE") + expect(output.output).not.toContain("MARK COMPLETION IN PLAN FILE") + }) + }) + describe("Write/Edit tool direct work reminder", () => { const ORCHESTRATOR_SESSION = "orchestrator-write-test" diff --git a/src/hooks/atlas/system-reminder-templates.test.ts b/src/hooks/atlas/system-reminder-templates.test.ts new file mode 100644 index 000000000..a1a91a443 --- /dev/null +++ b/src/hooks/atlas/system-reminder-templates.test.ts @@ -0,0 +1,37 @@ +import { describe, it, expect } from "bun:test" +import { BOULDER_CONTINUATION_PROMPT } from "./system-reminder-templates" + +describe("BOULDER_CONTINUATION_PROMPT", () => { + describe("checkbox-first priority rules", () => { + it("first rule after RULES: mentions both reading the plan AND marking a still-unchecked completed task", () => { + const rulesSection = BOULDER_CONTINUATION_PROMPT.split("RULES:")[1]! + const firstRule = rulesSection.split("\n")[1]!.trim() + + expect(firstRule).toContain("Read the plan") + expect(firstRule).toContain("mark") + expect(firstRule).toContain("completed") + }) + + it("first rule includes IMMEDIATELY keyword", () => { + const rulesSection = BOULDER_CONTINUATION_PROMPT.split("RULES:")[1]! + const firstRule = rulesSection.split("\n")[1]!.trim() + + expect(firstRule).toContain("IMMEDIATELY") + }) + + it("checkbox-marking guidance appears BEFORE Proceed without asking for permission", () => { + const rulesSection = BOULDER_CONTINUATION_PROMPT.split("RULES:")[1]! + + const checkboxMarkingMatch = rulesSection.match(/- \[x\]/i) + const proceedMatch = rulesSection.match(/Proceed without asking for permission/) + + expect(checkboxMarkingMatch).not.toBeNull() + expect(proceedMatch).not.toBeNull() + + const checkboxPosition = checkboxMarkingMatch!.index + const proceedPosition = proceedMatch!.index + + expect(checkboxPosition).toBeLessThan(proceedPosition) + }) + }) +}) diff --git a/src/hooks/atlas/system-reminder-templates.ts b/src/hooks/atlas/system-reminder-templates.ts index 16d71767c..af3274637 100644 --- a/src/hooks/atlas/system-reminder-templates.ts +++ b/src/hooks/atlas/system-reminder-templates.ts @@ -33,9 +33,8 @@ export const BOULDER_CONTINUATION_PROMPT = `${createSystemDirective(SystemDirect You have an active work plan with incomplete tasks. Continue working. RULES: -- **FIRST**: Read the plan file NOW to check exact current progress — count remaining \`- [ ]\` tasks +- **FIRST**: Read the plan file NOW. If the last completed task is still unchecked, mark it \`- [x]\` IMMEDIATELY before anything else - Proceed without asking for permission -- Change \`- [ ]\` to \`- [x]\` in the plan file when done - Use the notepad at .sisyphus/notepads/{PLAN_NAME}/ to record learnings - Do not stop until all tasks are complete - If blocked, document the blocker and move to the next task` diff --git a/src/hooks/atlas/tool-execute-after.ts b/src/hooks/atlas/tool-execute-after.ts index 818fdb737..fd8c1824c 100644 --- a/src/hooks/atlas/tool-execute-after.ts +++ b/src/hooks/atlas/tool-execute-after.ts @@ -7,7 +7,7 @@ import { HOOK_NAME } from "./hook-name" import { DIRECT_WORK_REMINDER } from "./system-reminder-templates" import { isSisyphusPath } from "./sisyphus-path" import { extractSessionIdFromOutput } from "./subagent-session-id" -import { buildOrchestratorReminder, buildStandaloneVerificationReminder } from "./verification-reminders" +import { buildCompletionGate, buildOrchestratorReminder, buildStandaloneVerificationReminder } from "./verification-reminders" import { isWriteOrEditToolName } from "./write-edit-tool-policy" import type { ToolExecuteAfterInput, ToolExecuteAfterOutput } from "./types" @@ -76,7 +76,11 @@ export function createToolExecuteAfterHandler(input: { // Preserve original subagent response - critical for debugging failed tasks const originalResponse = toolOutput.output -toolOutput.output = ` + toolOutput.output = ` + +${buildCompletionGate(boulderState.plan_name, subagentSessionId)} + + ## SUBAGENT WORK COMPLETED ${fileChanges} @@ -88,7 +92,7 @@ ${fileChanges} ${originalResponse} -${buildOrchestratorReminder(boulderState.plan_name, progress, subagentSessionId, autoCommit)} +${buildOrchestratorReminder(boulderState.plan_name, progress, subagentSessionId, autoCommit, false)} ` log(`[${HOOK_NAME}] Output transformed for orchestrator mode (boulder)`, { plan: boulderState.plan_name, diff --git a/src/hooks/atlas/verification-reminders.test.ts b/src/hooks/atlas/verification-reminders.test.ts new file mode 100644 index 000000000..ae3c15b10 --- /dev/null +++ b/src/hooks/atlas/verification-reminders.test.ts @@ -0,0 +1,94 @@ +import { describe, expect, it } from "bun:test" +import { buildOrchestratorReminder, buildCompletionGate } from "./verification-reminders" + +// Test helpers for given/when/then pattern +const given = describe +const when = describe +const then = it + +describe("buildCompletionGate", () => { + given("a plan name and session id", () => { + const planName = "test-plan" + const sessionId = "test-session-123" + + when("buildCompletionGate is called", () => { + const gate = buildCompletionGate(planName, sessionId) + + then("completion gate text is present", () => { + expect(gate).toContain("COMPLETION GATE") + }) + + then("gate appears before verification phase text", () => { + const gateIndex = gate.indexOf("COMPLETION GATE") + const verificationIndex = gate.indexOf("VERIFICATION_REMINDER") + expect(gateIndex).toBeLessThan(verificationIndex) + }) + + then("gate interpolates the plan name path", () => { + expect(gate).toContain(planName) + expect(gate).toContain(`.sisyphus/plans/${planName}.md`) + }) + + then("gate includes Edit instructions", () => { + expect(gate.toLowerCase()).toContain("edit") + }) + + then("gate includes Read instructions", () => { + expect(gate.toLowerCase()).toContain("read") + }) + + then("old STEP 7 MARK COMPLETION text is absent", () => { + expect(gate).not.toContain("STEP 7") + expect(gate).not.toContain("MARK COMPLETION IN PLAN FILE") + }) + + then("step numbering remains consecutive after removal", () => { + const stepMatches = gate.match(/STEP \d+:/g) ?? [] + if (stepMatches.length > 1) { + const numbers = stepMatches.map((s: string) => parseInt(s.match(/\d+/)?.[0] ?? "0")) + for (let i = 1; i < numbers.length; i++) { + expect(numbers[i]).toBe(numbers[i - 1] + 1) + } + } + }) + }) + }) +}) + +describe("buildOrchestratorReminder", () => { + given("progress with completed tasks", () => { + const planName = "my-test-plan" + const sessionId = "session-abc" + const progress = { total: 10, completed: 3 } + + when("buildOrchestratorReminder is called with autoCommit true", () => { + const reminder = buildOrchestratorReminder(planName, progress, sessionId, true) + + then("old STEP 7 MARK COMPLETION IN PLAN FILE text is absent", () => { + expect(reminder).not.toContain("STEP 7: MARK COMPLETION IN PLAN FILE") + }) + + then("completion gate appears before verification reminder", () => { + const gateIndex = reminder.indexOf("COMPLETION GATE") + const verificationIndex = reminder.indexOf("VERIFICATION_REMINDER") + expect(gateIndex).toBeGreaterThanOrEqual(0) + expect(gateIndex).toBeLessThan(verificationIndex) + }) + }) + + when("buildOrchestratorReminder is called with autoCommit false", () => { + const reminder = buildOrchestratorReminder(planName, progress, sessionId, false) + + then("old STEP 7 MARK COMPLETION IN PLAN FILE text is absent", () => { + expect(reminder).not.toContain("STEP 7: MARK COMPLETION IN PLAN FILE") + }) + + then("completion gate appears before verification reminder", () => { + const gateIndex = reminder.indexOf("COMPLETION GATE") + const verificationIndex = reminder.indexOf("VERIFICATION_REMINDER") + expect(gateIndex).toBeGreaterThanOrEqual(0) + expect(gateIndex).toBeLessThan(verificationIndex) + }) + }) + }) +}) diff --git a/src/hooks/atlas/verification-reminders.ts b/src/hooks/atlas/verification-reminders.ts index 1955dde32..019e5e869 100644 --- a/src/hooks/atlas/verification-reminders.ts +++ b/src/hooks/atlas/verification-reminders.ts @@ -1,7 +1,37 @@ import { VERIFICATION_REMINDER } from "./system-reminder-templates" +export function buildCompletionGate(planName: string, sessionId: string): string { + return ` +**COMPLETION GATE — DO NOT PROCEED UNTIL THIS IS DONE** + +Your completion will NOT be recorded until you complete ALL of the following: + +1. **Edit** the plan file \`.sisyphus/plans/${planName}.md\`: + - Change \`- [ ]\` to \`- [x]\` for the completed task + - Use \`Edit\` tool to modify the checkbox + +2. **Read** the plan file AGAIN: + \`\`\` + Read(".sisyphus/plans/${planName}.md") + \`\`\` + - Verify the checkbox count changed (more \`- [x]\` than before) + +3. **DO NOT call \`task()\` again** until you have completed steps 1 and 2 above. + +If anything fails while closing this out, resume the same session immediately: +\`\`\`typescript +task(session_id="${sessionId}", prompt="fix: checkbox not recorded correctly") +\`\`\` + +**Your completion is NOT tracked until the checkbox is marked in the plan file.** + +**VERIFICATION_REMINDER**` +} + function buildVerificationReminder(sessionId: string): string { - return `${VERIFICATION_REMINDER} + return `**VERIFICATION_REMINDER** + +${VERIFICATION_REMINDER} --- @@ -15,20 +45,21 @@ export function buildOrchestratorReminder( planName: string, progress: { total: number; completed: number }, sessionId: string, - autoCommit: boolean = true + autoCommit: boolean = true, + includeCompletionGate: boolean = true ): string { const remaining = progress.total - progress.completed - + const commitStep = autoCommit ? ` -**STEP 8: COMMIT ATOMIC UNIT** +**STEP 7: COMMIT ATOMIC UNIT** - Stage ONLY the verified changes - Commit with clear message describing what was done ` : "" - const nextStepNumber = autoCommit ? 9 : 8 + const nextStepNumber = autoCommit ? 8 : 7 return ` --- @@ -37,7 +68,9 @@ export function buildOrchestratorReminder( --- -${buildVerificationReminder(sessionId)} +${includeCompletionGate ? `${buildCompletionGate(planName, sessionId)} + +` : ""}${buildVerificationReminder(sessionId)} **STEP 5: READ SUBAGENT NOTEPAD (LEARNINGS, ISSUES, PROBLEMS)** @@ -64,22 +97,13 @@ Read(".sisyphus/plans/${planName}.md") Count exactly: how many \`- [ ]\` remain? How many \`- [x]\` completed? This is YOUR ground truth. Use it to decide what comes next. -**STEP 7: MARK COMPLETION IN PLAN FILE (IMMEDIATELY)** - -RIGHT NOW - Do not delay. Verification passed → Mark IMMEDIATELY. - -Update the plan file \`.sisyphus/plans/${planName}.md\`: -- Change \`- [ ]\` to \`- [x]\` for the completed task -- Use \`Edit\` tool to modify the checkbox - -**DO THIS BEFORE ANYTHING ELSE. Unmarked = Untracked = Lost progress.** ${commitStep} **STEP ${nextStepNumber}: PROCEED TO NEXT TASK** - Read the plan file AGAIN to identify the next \`- [ ]\` task - Start immediately - DO NOT STOP -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ **${remaining} tasks remain. Keep bouldering.**` }