diff --git a/src/hooks/start-work/context-info-builder.test.ts b/src/hooks/start-work/context-info-builder.test.ts
new file mode 100644
index 000000000..ffc08978b
--- /dev/null
+++ b/src/hooks/start-work/context-info-builder.test.ts
@@ -0,0 +1,171 @@
+///
+
+import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"
+import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
+import { randomUUID } from "node:crypto"
+import { join } from "node:path"
+import { tmpdir } from "node:os"
+import { buildStartWorkContextInfo } from "./context-info-builder"
+import {
+ addBoulderWork,
+ createBoulderState,
+ getBoulderFilePath,
+ getWorkByPlanName,
+ readBoulderState,
+ writeBoulderState,
+} from "../../features/boulder-state"
+import * as boulderState from "../../features/boulder-state"
+
+describe("buildStartWorkContextInfo", () => {
+ let testDirectory = ""
+
+ function createPluginInput() {
+ return {
+ directory: testDirectory,
+ } as never
+ }
+
+ function writePlan(planName: string, content: string): string {
+ const plansDirectory = join(testDirectory, ".sisyphus", "plans")
+ mkdirSync(plansDirectory, { recursive: true })
+ const planPath = join(plansDirectory, `${planName}.md`)
+ writeFileSync(planPath, content)
+ return planPath
+ }
+
+ function readExistingState() {
+ return readBoulderState(testDirectory)
+ }
+
+ beforeEach(() => {
+ testDirectory = join(tmpdir(), `context-info-builder-${randomUUID()}`)
+ mkdirSync(testDirectory, { recursive: true })
+ })
+
+ afterEach(() => {
+ if (existsSync(testDirectory)) {
+ rmSync(testDirectory, { recursive: true, force: true })
+ }
+ })
+
+ test("lists multiple active works and asks agent to choose resume vs new when no explicit plan", () => {
+ // given
+ const clearSpy = spyOn(boulderState, "clearBoulderState")
+ const planAPath = writePlan("plan-alpha", "## TODOs\n- [ ] 1. Alpha")
+ const planBPath = writePlan("plan-beta", "## TODOs\n- [ ] 1. Beta")
+ const initialState = createBoulderState(planAPath, "session-a", "atlas", "/tmp/worktree-a")
+ writeBoulderState(testDirectory, initialState)
+ addBoulderWork(testDirectory, {
+ planPath: planBPath,
+ sessionId: "session-b",
+ agent: "atlas",
+ worktreePath: "/tmp/worktree-b",
+ })
+
+ // when
+ const contextInfo = buildStartWorkContextInfo({
+ ctx: createPluginInput(),
+ explicitPlanName: null,
+ existingState: readExistingState(),
+ sessionId: "session-current",
+ timestamp: "2026-05-11T00:00:00.000Z",
+ activeAgent: "atlas",
+ worktreePath: undefined,
+ worktreeBlock: "",
+ })
+
+ // then
+ expect(contextInfo).toContain("plan-alpha")
+ expect(contextInfo).toContain("plan-beta")
+ expect(contextInfo).toContain("Use the Question tool")
+ expect(clearSpy).toHaveBeenCalledTimes(0)
+ })
+
+ test("auto-resumes when exactly one active work exists and no explicit plan", () => {
+ // given
+ const clearSpy = spyOn(boulderState, "clearBoulderState")
+ const planPath = writePlan("single-active-plan", "## TODOs\n- [ ] 1. Single task")
+ const initialState = createBoulderState(planPath, "session-a", "atlas", "/tmp/worktree-single")
+ writeBoulderState(testDirectory, initialState)
+
+ // when
+ const contextInfo = buildStartWorkContextInfo({
+ ctx: createPluginInput(),
+ explicitPlanName: null,
+ existingState: readExistingState(),
+ sessionId: "session-current",
+ timestamp: "2026-05-11T00:00:00.000Z",
+ activeAgent: "atlas",
+ worktreePath: undefined,
+ worktreeBlock: "",
+ })
+
+ // then
+ expect(contextInfo).toContain("RESUMING existing work")
+ expect(contextInfo).toContain("single-active-plan")
+ expect(contextInfo).not.toContain("Use the Question tool")
+ expect(clearSpy).toHaveBeenCalledTimes(0)
+ })
+
+ test("explicit plan selects matching work only and never clears boulder state", () => {
+ // given
+ const clearSpy = spyOn(boulderState, "clearBoulderState")
+ const planAPath = writePlan("explicit-plan-a", "## TODOs\n- [ ] 1. A")
+ const planBPath = writePlan("explicit-plan-b", "## TODOs\n- [ ] 1. B")
+ const initialState = createBoulderState(planAPath, "session-a", "atlas", "/tmp/worktree-a")
+ writeBoulderState(testDirectory, initialState)
+ addBoulderWork(testDirectory, {
+ planPath: planBPath,
+ sessionId: "session-b",
+ agent: "atlas",
+ worktreePath: "/tmp/worktree-b",
+ })
+
+ // when
+ const contextInfo = buildStartWorkContextInfo({
+ ctx: createPluginInput(),
+ explicitPlanName: "explicit-plan-a",
+ existingState: readExistingState(),
+ sessionId: "session-current",
+ timestamp: "2026-05-11T00:00:00.000Z",
+ activeAgent: "atlas",
+ worktreePath: "/tmp/worktree-a",
+ worktreeBlock: "",
+ })
+
+ // then
+ expect(contextInfo).toContain("explicit-plan-a")
+ expect(contextInfo).not.toContain("explicit-plan-b")
+ expect(clearSpy).toHaveBeenCalledTimes(0)
+
+ const selectedWork = getWorkByPlanName(testDirectory, "explicit-plan-a", { worktreePath: "/tmp/worktree-a" })
+ const nextState = readBoulderState(testDirectory)
+ expect(selectedWork).not.toBeNull()
+ expect(nextState?.active_work_id).toBe(selectedWork?.work_id)
+ })
+
+ test("falls back to auto-select latest plan when no works exist", () => {
+ // given
+ const clearSpy = spyOn(boulderState, "clearBoulderState")
+ const coldStartPlanPath = writePlan("cold-start-plan", "## TODOs\n- [ ] 1. Cold start")
+
+ // when
+ const contextInfo = buildStartWorkContextInfo({
+ ctx: createPluginInput(),
+ explicitPlanName: null,
+ existingState: null,
+ sessionId: "session-current",
+ timestamp: "2026-05-11T00:00:00.000Z",
+ activeAgent: "atlas",
+ worktreePath: undefined,
+ worktreeBlock: "",
+ })
+
+ // then
+ expect(contextInfo).toContain("Auto-Selected Plan")
+ expect(contextInfo).toContain("cold-start-plan")
+ expect(contextInfo).toContain(coldStartPlanPath)
+ expect(existsSync(getBoulderFilePath(testDirectory))).toBe(true)
+ expect(clearSpy).toHaveBeenCalledTimes(0)
+ })
+})
diff --git a/src/hooks/start-work/context-info-builder.ts b/src/hooks/start-work/context-info-builder.ts
index 4ad7859c0..5ea4d8fce 100644
--- a/src/hooks/start-work/context-info-builder.ts
+++ b/src/hooks/start-work/context-info-builder.ts
@@ -1,13 +1,17 @@
import { statSync } from "node:fs"
import {
appendSessionId,
- clearBoulderState,
+ addBoulderWork,
createBoulderState,
findPrometheusPlans,
+ getActiveWorks,
getPlanName,
getPlanProgress,
+ getWorkByPlanName,
+ getWorkResumeOptions,
readBoulderState,
resolveBoulderPlanPath,
+ selectActiveWork,
writeBoulderState,
} from "../../features/boulder-state"
import { log } from "../../shared/logger"
@@ -99,9 +103,73 @@ Ask the user which plan to work on.`
No incomplete plans available. Create a new plan using the Prometheus agent.`
}
+function formatElapsedHuman(elapsedMs: number | undefined): string {
+ if (typeof elapsedMs !== "number" || elapsedMs <= 0) {
+ return "running"
+ }
+
+ const totalSeconds = Math.floor(elapsedMs / 1000)
+ const seconds = totalSeconds % 60
+ const totalMinutes = Math.floor(totalSeconds / 60)
+ const minutes = totalMinutes % 60
+ const hours = Math.floor(totalMinutes / 60)
+ if (hours > 0) {
+ return `${hours}h ${minutes}m ${seconds}s`
+ }
+ if (minutes > 0) {
+ return `${minutes}m ${seconds}s`
+ }
+ return `${seconds}s`
+}
+
+function buildMultipleActiveWorksContext(params: {
+ resumeOptions: ReturnType
+ sessionId: string
+ timestamp: string
+}): string {
+ const { resumeOptions, sessionId, timestamp } = params
+ const optionList = resumeOptions
+ .map((option, index) => `${index + 1}. ${option.plan_name} - ${option.progress.completed}/${option.progress.total} (${option.progress.total === 0 ? 0 : Math.floor((option.progress.completed / option.progress.total) * 100)}%) - elapsed: ${formatElapsedHuman(option.elapsed_ms)} - worktree: ${option.worktree_path ?? "current directory"} - sessions: ${option.session_count}`)
+ .join("\n")
+
+ return `
+
+## Multiple Active Works Found
+
+Current Time: ${timestamp}
+Session ID: ${sessionId}
+
+${optionList}
+
+Use the Question tool to ask the user which plan to resume.
+- If the user chooses one option, run /start-work {plan-name} for that plan.
+- If the user chooses to start a new plan, proceed with cold-start auto-selection flow.
+`
+}
+
+function createNewWorkOrInitialize(params: {
+ directory: string
+ planPath: string
+ sessionId: string
+ activeAgent: string
+ worktreePath: string | undefined
+}): void {
+ const { directory, planPath, sessionId, activeAgent, worktreePath } = params
+ const created = addBoulderWork(directory, {
+ planPath,
+ sessionId,
+ agent: activeAgent,
+ worktreePath,
+ })
+
+ if (!created) {
+ const initializedState = createBoulderState(planPath, sessionId, activeAgent, worktreePath)
+ writeBoulderState(directory, initializedState)
+ }
+}
+
function buildExplicitPlanContext(params: {
explicitPlanName: string
- existingState: ReturnType
sessionId: string
timestamp: string
activeAgent: string
@@ -109,9 +177,24 @@ function buildExplicitPlanContext(params: {
worktreeBlock: string
directory: string
}): string {
- const { explicitPlanName, existingState, sessionId, timestamp, activeAgent, worktreePath, worktreeBlock, directory } = params
+ const { explicitPlanName, sessionId, timestamp, activeAgent, worktreePath, worktreeBlock, directory } = params
log(`[${HOOK_NAME}] Explicit plan name requested: ${explicitPlanName}`, { sessionID: sessionId })
+ const matchedWork = getWorkByPlanName(directory, explicitPlanName, { worktreePath })
+ if (matchedWork) {
+ const selectedState = selectActiveWork(directory, matchedWork.work_id)
+ if (selectedState) {
+ return buildExistingSessionContext({
+ existingState: selectedState,
+ sessionId,
+ activeAgent,
+ worktreePath,
+ worktreeBlock,
+ directory,
+ })
+ }
+ }
+
const allPlans = findPrometheusPlans(directory)
const matchedPlan = findPlanByName(allPlans, explicitPlanName)
if (!matchedPlan) {
@@ -127,9 +210,13 @@ function buildExplicitPlanContext(params: {
All ${progress.total} tasks are done. Create a new plan using the Prometheus agent.`
}
- if (existingState) {
- clearBoulderState(directory)
- }
+ createNewWorkOrInitialize({
+ directory,
+ planPath: matchedPlan,
+ sessionId,
+ activeAgent,
+ worktreePath,
+ })
return buildAutoSelectedPlanContext({
planPath: matchedPlan,
@@ -287,11 +374,48 @@ export function buildStartWorkContextInfo(params: {
}): string {
const { ctx, explicitPlanName, existingState, sessionId, timestamp, activeAgent, worktreePath, worktreeBlock } = params
+ const resumeOptions = getWorkResumeOptions(ctx.directory)
+ .filter((option) => option.status === "active" || option.status === "paused")
+
+ if (!explicitPlanName && resumeOptions.length > 1) {
+ return buildMultipleActiveWorksContext({
+ resumeOptions,
+ sessionId,
+ timestamp,
+ })
+ }
+
+ if (!explicitPlanName && resumeOptions.length === 1) {
+ const onlyOption = resumeOptions[0]
+ const selectedState = selectActiveWork(ctx.directory, onlyOption.work_id)
+ if (selectedState) {
+ return buildExistingSessionContext({
+ existingState: selectedState,
+ sessionId,
+ activeAgent,
+ worktreePath,
+ worktreeBlock,
+ directory: ctx.directory,
+ })
+ }
+ }
+
+ if (!explicitPlanName && resumeOptions.length === 0 && getActiveWorks(ctx.directory).length === 0) {
+ return buildPlanDiscoveryContext({
+ contextInfo: "",
+ sessionId,
+ timestamp,
+ activeAgent,
+ worktreePath,
+ worktreeBlock,
+ directory: ctx.directory,
+ })
+ }
+
let contextInfo = ""
if (explicitPlanName) {
contextInfo = buildExplicitPlanContext({
explicitPlanName,
- existingState,
sessionId,
timestamp,
activeAgent,