diff --git a/src/hooks/start-work/index.test.ts b/src/hooks/start-work/index.test.ts index 26b87eba4..565b2decb 100644 --- a/src/hooks/start-work/index.test.ts +++ b/src/hooks/start-work/index.test.ts @@ -417,7 +417,7 @@ describe("start-work hook", () => { detectSpy.mockRestore() }) - test("should inject model-decides instructions when no --worktree flag", async () => { + test("should NOT inject worktree instructions when no --worktree flag", async () => { // given - single plan, no worktree flag const plansDir = join(testDir, ".sisyphus", "plans") mkdirSync(plansDir, { recursive: true }) @@ -431,10 +431,10 @@ describe("start-work hook", () => { // when await hook["chat.message"]({ sessionID: "session-123" }, output) - // then - model-decides instructions should appear - expect(output.parts[0].text).toContain("Worktree Setup Required") - expect(output.parts[0].text).toContain("git worktree list --porcelain") - expect(output.parts[0].text).toContain("git worktree add") + // then - no worktree instructions should appear + expect(output.parts[0].text).not.toContain("Worktree Setup Required") + expect(output.parts[0].text).not.toContain("Worktree Active") + expect(output.parts[0].text).not.toContain("git worktree list --porcelain") }) test("should inject worktree path when --worktree flag is valid", async () => { @@ -452,8 +452,10 @@ describe("start-work hook", () => { // when await hook["chat.message"]({ sessionID: "session-123" }, output) - // then - validated path shown, no model-decides instructions - expect(output.parts[0].text).toContain("**Worktree**: /validated/worktree") + // then - strong worktree active instructions shown + expect(output.parts[0].text).toContain("Worktree Active") + expect(output.parts[0].text).toContain("/validated/worktree") + expect(output.parts[0].text).toContain("subagent") expect(output.parts[0].text).not.toContain("Worktree Setup Required") }) @@ -548,8 +550,10 @@ describe("start-work hook", () => { // when await hook["chat.message"]({ sessionID: "session-789" }, output) - // then - shows existing worktree, no model-decides instructions + // then - shows strong worktree active instructions + expect(output.parts[0].text).toContain("Worktree Active") expect(output.parts[0].text).toContain("/existing/wt") + expect(output.parts[0].text).toContain("subagent") expect(output.parts[0].text).not.toContain("Worktree Setup Required") }) }) diff --git a/src/hooks/start-work/start-work-hook.ts b/src/hooks/start-work/start-work-hook.ts index 03cdb540e..81ec85cc3 100644 --- a/src/hooks/start-work/start-work-hook.ts +++ b/src/hooks/start-work/start-work-hook.ts @@ -34,26 +34,28 @@ function findPlanByName(plans: string[], requestedName: string): string | null { return partialMatch || null } -const MODEL_DECIDES_WORKTREE_BLOCK = ` -## Worktree Setup Required +function createWorktreeActiveBlock(worktreePath: string): string { + return ` +## Worktree Active -No worktree specified. Before starting work, you MUST choose or create one: +**Worktree**: \`${worktreePath}\` -1. \`git worktree list --porcelain\` — list existing worktrees -2. Create if needed: \`git worktree add \` -3. Update \`.sisyphus/boulder.json\` — add \`"worktree_path": ""\` -4. Work exclusively inside that worktree directory` +**CRITICAL — DO NOT FORGET**: You are working inside a git worktree. ALL operations MUST be performed exclusively within this worktree directory. +- Every file read, write, edit, and git operation MUST target paths under: \`${worktreePath}\` +- When delegating tasks to subagents, you MUST include the worktree path in your delegation prompt so they also operate exclusively within the worktree +- NEVER operate on the main repository directory — always use the worktree path above` +} function resolveWorktreeContext( explicitWorktreePath: string | null, ): { worktreePath: string | undefined; block: string } { if (explicitWorktreePath === null) { - return { worktreePath: undefined, block: MODEL_DECIDES_WORKTREE_BLOCK } + return { worktreePath: undefined, block: "" } } const validatedPath = detectWorktreePath(explicitWorktreePath) if (validatedPath) { - return { worktreePath: validatedPath, block: `\n**Worktree**: ${validatedPath}` } + return { worktreePath: validatedPath, block: createWorktreeActiveBlock(validatedPath) } } return { @@ -165,7 +167,7 @@ No incomplete plans available. Create a new plan with: /plan "your task"` appendSessionId(ctx.directory, sessionId) } - const worktreeDisplay = effectiveWorktree ? `\n**Worktree**: ${effectiveWorktree}` : worktreeBlock + const worktreeDisplay = effectiveWorktree ? createWorktreeActiveBlock(effectiveWorktree) : worktreeBlock contextInfo = ` ## Active Work Session Found