fix(checkpoints): replace resume with fresh continuation agents

Resume fails when subagents use parallel tool calls due to Claude Code
serialization bug (consecutive assistant entries with same message ID).

Solution: Subagents return structured checkpoint state, orchestrator
spawns fresh agent with continuation-prompt template instead of resuming.

New files:
- templates/checkpoint-return.md: Structured format with completed tasks table
- templates/continuation-prompt.md: Template for spawning continuation agent

Updated:
- templates/subagent-task-prompt.md: Reference checkpoint-return, remove resume language
- workflows/execute-phase.md: Replace Task(resume=id) with fresh agent spawn
- workflows/execute-plan.md: Update checkpoint_return_for_orchestrator step

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Lex Christopherson
2026-01-13 17:44:43 -06:00
parent 601e67e0f2
commit 69300f975f
5 changed files with 544 additions and 58 deletions

View File

@@ -0,0 +1,204 @@
# Checkpoint Return Template
Structured format for subagent checkpoint returns. Enables orchestrator to spawn continuation agents without relying on resume.
---
## Template
```markdown
## CHECKPOINT REACHED
**Type:** [human-verify | decision | human-action]
**Plan:** {phase}-{plan}
**Progress:** {completed}/{total} tasks complete
### Completed Tasks
| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | [task name] | [hash] | [key files created/modified] |
| 2 | [task name] | [hash] | [key files created/modified] |
### Current Task
**Task {N}:** [task name]
**Status:** [blocked | awaiting verification | awaiting decision]
**Blocked by:** [specific blocker - auth required, user verification needed, decision needed]
### Checkpoint Details
[Checkpoint-specific content based on type - see below]
### Awaiting
[What user needs to do/provide]
```
---
## Checkpoint Type Details
### For human-verify
```markdown
### Checkpoint Details
**What was built:**
[Description of completed work]
**How to verify:**
1. [Step 1 - exact command/URL]
2. [Step 2 - what to check]
3. [Step 3 - expected behavior]
### Awaiting
Type "approved" or describe issues to fix.
```
### For human-action
```markdown
### Checkpoint Details
**Automation attempted:**
[What Claude tried to do]
**Error encountered:**
[Exact error message or auth failure]
**What you need to do:**
1. [Step 1]
2. [Step 2]
**I'll verify after:**
[How Claude will confirm completion]
### Awaiting
Type "done" when complete.
```
### For decision
```markdown
### Checkpoint Details
**Decision needed:**
[What's being decided]
**Context:**
[Why this matters]
**Options:**
| Option | Pros | Cons |
|--------|------|------|
| [option-a] | [benefits] | [tradeoffs] |
| [option-b] | [benefits] | [tradeoffs] |
### Awaiting
Select: [option-a | option-b | ...]
```
---
## Why This Structure
**Completed Tasks table:** Orchestrator knows exactly what's done. Fresh agent won't redo work.
**Commit hashes:** Verification that work was committed. Fresh agent can check git log.
**Files column:** Quick reference for what exists. Fresh agent can verify state.
**Current Task + Blocked by:** Precise continuation point. Fresh agent knows exactly where to pick up.
**Checkpoint Details:** User-facing content. Orchestrator presents this directly.
---
## Example: Auth Gate
```markdown
## CHECKPOINT REACHED
**Type:** human-action
**Plan:** 01-01
**Progress:** 1/3 tasks complete
### Completed Tasks
| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Initialize Next.js 15 project | d6fe73f | package.json, tsconfig.json, next.config.js, app/ |
### Current Task
**Task 2:** Initialize Convex backend
**Status:** blocked
**Blocked by:** Convex CLI authentication required
### Checkpoint Details
**Automation attempted:**
Ran `npx convex dev` to initialize Convex backend
**Error encountered:**
"Error: Not authenticated. Run `npx convex login` first."
**What you need to do:**
1. Run: `npx convex login`
2. Complete browser authentication
3. Run: `npx convex dev`
4. Create project named "convex-saas-community" when prompted
**I'll verify after:**
`cat .env.local | grep CONVEX` returns the Convex URL
### Awaiting
Type "done" when Convex is authenticated and project created.
```
---
## Example: Visual Verification
```markdown
## CHECKPOINT REACHED
**Type:** human-verify
**Plan:** 03-02
**Progress:** 2/3 tasks complete
### Completed Tasks
| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Create dashboard layout | a1b2c3d | src/app/dashboard/layout.tsx, src/components/Sidebar.tsx |
| 2 | Add responsive navigation | e4f5g6h | src/components/NavBar.tsx, src/styles/nav.css |
### Current Task
**Task 3:** Verify responsive behavior
**Status:** awaiting verification
**Blocked by:** Human visual verification required
### Checkpoint Details
**What was built:**
Responsive dashboard with collapsible sidebar navigation
**How to verify:**
1. Run: `npm run dev`
2. Visit: http://localhost:3000/dashboard
3. Desktop (>1024px): Sidebar visible on left, content on right
4. Tablet (768px): Sidebar collapses to icons
5. Mobile (375px): Sidebar hidden, hamburger menu appears
### Awaiting
Type "approved" or describe issues to fix.
```

View File

@@ -0,0 +1,235 @@
# Continuation Prompt Template
Template for spawning fresh agent to continue plan execution after checkpoint resolution.
---
## Template
```markdown
<objective>
Continue executing plan {plan_number} of phase {phase_number}-{phase_name}.
**DO NOT REDO completed tasks.** They are already committed. Start from the resume point below.
Commit each remaining task atomically. Create SUMMARY.md when all tasks complete. Update STATE.md.
</objective>
<completed_tasks>
The following tasks are ALREADY DONE. Do not repeat them.
{completed_tasks_table}
**Verify before continuing:** Check that these commits exist with `git log --oneline -5`
</completed_tasks>
<resume_point>
**Resume from:** Task {resume_task_number} - {resume_task_name}
**Status:** {resume_status}
**User response:** {user_response}
{resume_instructions}
</resume_point>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
@~/.claude/get-shit-done/references/checkpoints.md
@~/.claude/get-shit-done/references/tdd.md
</execution_context>
<context>
Plan: @{plan_path}
Project state: @.planning/STATE.md
Config: @.planning/config.json (if exists)
</context>
<checkpoint_behavior>
If you hit another checkpoint, return using the format in:
@~/.claude/get-shit-done/templates/checkpoint-return.md
Include ALL completed tasks (both previous and new) in the Completed Tasks table.
</checkpoint_behavior>
<completion_format>
When plan completes successfully, return:
## PLAN COMPLETE
**Plan:** {phase}-{plan}
**Tasks:** {total}/{total}
**SUMMARY:** {path to SUMMARY.md}
**Commits:**
- {hash}: {message}
...
Include commits from both previous execution and this continuation.
</completion_format>
<success_criteria>
- [ ] Verified previous commits exist (did not redo work)
- [ ] Remaining tasks executed
- [ ] Each new task committed individually
- [ ] SUMMARY.md created in plan directory (covers ALL tasks)
- [ ] STATE.md updated with position and decisions
</success_criteria>
```
---
## Placeholders
| Placeholder | Source | Example |
|-------------|--------|---------|
| `{phase_number}` | Checkpoint return | `01` |
| `{phase_name}` | Checkpoint return | `foundation` |
| `{plan_number}` | Checkpoint return | `01` |
| `{plan_path}` | Original prompt | `.planning/phases/01-foundation/01-01-PLAN.md` |
| `{completed_tasks_table}` | Checkpoint return | Markdown table of completed tasks |
| `{resume_task_number}` | Checkpoint return | `2` |
| `{resume_task_name}` | Checkpoint return | `Initialize Convex backend` |
| `{resume_status}` | Derived from checkpoint type | `User completed authentication` |
| `{user_response}` | User input | `done` or `approved` or `option-a` |
| `{resume_instructions}` | Derived from checkpoint type | See below |
---
## Resume Instructions by Checkpoint Type
### After human-action (e.g., auth gate)
```markdown
**Resume from:** Task 2 - Initialize Convex backend
**Status:** User completed authentication
**User response:** done
The user has completed the manual action. Verify it worked, then continue:
1. Verify: `cat .env.local | grep CONVEX` shows Convex URL
2. If verified: Continue with remaining Task 2 steps (if any), then Task 3
3. If not verified: Report what's missing, create new checkpoint
```
### After human-verify (e.g., visual check)
```markdown
**Resume from:** Task 3 - Verify responsive behavior
**Status:** User approved verification
**User response:** approved
User confirmed the implementation is correct. Continue to next task.
```
Or if issues reported:
```markdown
**Resume from:** Task 3 - Verify responsive behavior
**Status:** User reported issues
**User response:** "Sidebar overlaps content on tablet view"
Fix the reported issues:
1. Address: "Sidebar overlaps content on tablet view"
2. After fixing, re-present the verification checkpoint
```
### After decision
```markdown
**Resume from:** Task 4 - Select authentication provider
**Status:** User made decision
**User response:** clerk
Proceed with the selected option (Clerk). Implement accordingly.
```
---
## Example: Continuation After Auth Gate
```markdown
<objective>
Continue executing plan 01 of phase 01-foundation.
**DO NOT REDO completed tasks.** They are already committed. Start from the resume point below.
Commit each remaining task atomically. Create SUMMARY.md when all tasks complete. Update STATE.md.
</objective>
<completed_tasks>
The following tasks are ALREADY DONE. Do not repeat them.
| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Initialize Next.js 15 project | d6fe73f | package.json, tsconfig.json, next.config.js, app/ |
**Verify before continuing:** Check that these commits exist with `git log --oneline -5`
</completed_tasks>
<resume_point>
**Resume from:** Task 2 - Initialize Convex backend
**Status:** User completed authentication
**User response:** done
The user has completed the manual action. Verify it worked, then continue:
1. Verify: `cat .env.local | grep CONVEX` shows Convex URL
2. If verified: Continue with remaining Task 2 steps (create schema, verify deployment), then Task 3
3. If not verified: Report what's missing, create new checkpoint
</resume_point>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
@~/.claude/get-shit-done/references/checkpoints.md
@~/.claude/get-shit-done/references/tdd.md
</execution_context>
<context>
Plan: @.planning/phases/01-foundation/01-01-PLAN.md
Project state: @.planning/STATE.md
</context>
<checkpoint_behavior>
If you hit another checkpoint, return using the format in:
@~/.claude/get-shit-done/templates/checkpoint-return.md
Include ALL completed tasks (both previous and new) in the Completed Tasks table.
</checkpoint_behavior>
<completion_format>
When plan completes successfully, return:
## PLAN COMPLETE
**Plan:** 01-01
**Tasks:** 3/3
**SUMMARY:** .planning/phases/01-foundation/01-01-SUMMARY.md
**Commits:**
- d6fe73f: feat(01-01): initialize Next.js 15 with TypeScript and Tailwind
- [new]: feat(01-01): initialize Convex backend with schema
- [new]: feat(01-01): integrate Clerk authentication
</completion_format>
<success_criteria>
- [ ] Verified previous commits exist (did not redo work)
- [ ] Remaining tasks executed
- [ ] Each new task committed individually
- [ ] SUMMARY.md created in plan directory (covers ALL tasks)
- [ ] STATE.md updated with position and decisions
</success_criteria>
```
---
## Usage
Orchestrator fills placeholders from checkpoint return and user response:
```python
Task(
prompt=filled_continuation_template,
subagent_type="general-purpose"
)
```
Fresh agent loads @-references, verifies completed work, continues from resume point.

View File

@@ -12,7 +12,7 @@ Execute plan {plan_number} of phase {phase_number}-{phase_name}.
Commit each task atomically. Create SUMMARY.md. Update STATE.md.
**Checkpoint handling:** If you hit a checkpoint task, STOP and return a checkpoint message (see checkpoint_behavior below). The orchestrator will present it to the user and resume you with their response.
**Checkpoint handling:** If you hit a checkpoint task or auth gate, STOP and return a structured checkpoint message. The orchestrator will spawn a fresh agent to continue after the user responds.
</objective>
<execution_context>
@@ -29,21 +29,17 @@ Config: @.planning/config.json (if exists)
</context>
<checkpoint_behavior>
When you encounter a checkpoint task (type="checkpoint:*"), STOP execution and return this format:
When you encounter a checkpoint task (type="checkpoint:*") or auth gate, STOP execution and return using the structured format in:
## CHECKPOINT REACHED
@~/.claude/get-shit-done/templates/checkpoint-return.md
**Type:** [human-verify | decision | human-action]
**Plan:** {phase}-{plan}
**Progress:** {completed}/{total} tasks complete
**Required in your return:**
1. Completed Tasks table with commit hashes and files
2. Current task name and what's blocking it
3. Checkpoint details for the user
4. What you're awaiting from the user
[Checkpoint content from checkpoint_protocol in execute-plan.md]
**Awaiting:** [Resume signal from the task]
The orchestrator will present this to the user and resume you with their response.
When resumed, you'll receive: "User response: {their_input}"
Parse and continue appropriately.
The orchestrator will present this to the user. After they respond, a FRESH agent will continue from your checkpoint using the continuation-prompt template. You will NOT be resumed.
</checkpoint_behavior>
<completion_format>
@@ -61,7 +57,7 @@ When plan completes successfully, return:
</completion_format>
<success_criteria>
- [ ] All tasks executed (or paused at checkpoint)
- [ ] All tasks executed (or paused at checkpoint with full state returned)
- [ ] Each task committed individually
- [ ] SUMMARY.md created in plan directory
- [ ] STATE.md updated with position and decisions
@@ -95,5 +91,5 @@ Task(
Agent reads @-references, loads full workflow context, executes plan.
When agent returns:
- If contains "## CHECKPOINT REACHED": Parse and present to user, then resume
- If contains "## CHECKPOINT REACHED": Parse checkpoint, present to user, spawn fresh agent with continuation-prompt.md
- If contains "## PLAN COMPLETE": Finalize execution

View File

@@ -211,55 +211,70 @@ Plans with `autonomous: false` require user interaction.
2. **Agent runs until checkpoint:**
- Executes auto tasks normally
- Reaches checkpoint task (e.g., `type="checkpoint:human-verify"`)
- Agent returns with checkpoint details in its response
- Reaches checkpoint task (e.g., `type="checkpoint:human-verify"`) or auth gate
- Agent returns with structured checkpoint (see checkpoint-return.md template)
3. **Agent return includes:**
- Checkpoint type (human-verify, decision, human-action)
- Checkpoint details (what-built, options, instructions)
- Agent ID for resumption
- Progress so far (tasks completed)
3. **Agent return includes (structured format):**
- Completed Tasks table with commit hashes and files
- Current task name and blocker
- Checkpoint type and details for user
- What's awaited from user
4. **Orchestrator presents checkpoint to user:**
Extract and display the "Checkpoint Details" and "Awaiting" sections from agent return:
```
## Checkpoint: Visual Verification Required
## Checkpoint: [Type]
**Plan:** 03-03 Dashboard Layout
**Progress:** 2/3 tasks complete
**What was built:**
Responsive dashboard with sidebar navigation
[Checkpoint Details section from agent return]
**Please verify:**
1. Run: npm run dev
2. Visit: http://localhost:3000/dashboard
3. Desktop (>1024px): Verify sidebar left, content right
4. Mobile (375px): Verify single column layout
Type "approved" to continue, or describe issues to fix.
[Awaiting section from agent return]
```
5. **User responds:**
- "approved" → resume agent
- Description of issues → resume agent with feedback
- "approved" / "done" → spawn continuation agent
- Description of issues → spawn continuation agent with feedback
- Decision selection → spawn continuation agent with choice
6. **Resume agent:**
6. **Spawn continuation agent (NOT resume):**
Use the continuation-prompt.md template:
```
Task(resume="{agent_id}", prompt="User response: {user_input}")
Task(
prompt=filled_continuation_template,
subagent_type="general-purpose"
)
```
7. **Agent continues from checkpoint:**
- If approved: proceed to next task
- If issues: fix and re-present checkpoint, or ask for clarification
Fill template with:
- `{completed_tasks_table}`: From agent's checkpoint return
- `{resume_task_number}`: Current task from checkpoint
- `{resume_task_name}`: Current task name from checkpoint
- `{user_response}`: What user provided
- `{resume_instructions}`: Based on checkpoint type (see continuation-prompt.md)
7. **Continuation agent executes:**
- Verifies previous commits exist
- Continues from resume point
- May hit another checkpoint (repeat from step 4)
- Or completes plan
8. **Repeat until plan completes or user stops**
**Why fresh agent instead of resume:**
Resume relies on Claude Code's internal serialization which breaks with parallel tool calls.
Fresh agents with explicit state are more reliable and maintain full context.
**Checkpoint in parallel context:**
If a plan in a parallel wave has a checkpoint:
- Spawn as normal
- Agent pauses at checkpoint and returns
- Agent pauses at checkpoint and returns with structured state
- Other parallel agents may complete while waiting
- Handle checkpoint, resume agent
- Present checkpoint to user
- Spawn continuation agent with user response
- Wait for all agents to finish before next wave
</step>

View File

@@ -1155,36 +1155,72 @@ See ~/.claude/get-shit-done/references/checkpoints.md for complete checkpoint gu
<step name="checkpoint_return_for_orchestrator">
**When spawned by an orchestrator (execute-phase or execute-plan command):**
If you were spawned via Task tool and hit a checkpoint, you cannot directly interact with the user. Instead, RETURN to the orchestrator with checkpoint details so it can present to the user and resume you.
If you were spawned via Task tool and hit a checkpoint, you cannot directly interact with the user. Instead, RETURN to the orchestrator with structured checkpoint state so it can present to the user and spawn a fresh continuation agent.
**Return format for checkpoints:**
Use the structured format from:
@~/.claude/get-shit-done/templates/checkpoint-return.md
**Required in your return:**
1. **Completed Tasks table** - Tasks done so far with commit hashes and files created
2. **Current Task** - Which task you're on and what's blocking it
3. **Checkpoint Details** - User-facing content (verification steps, decision options, or action instructions)
4. **Awaiting** - What you need from the user
**Example return:**
```
## CHECKPOINT REACHED
**Type:** [human-verify | decision | human-action]
**Plan:** {phase}-{plan}
**Progress:** {completed}/{total} tasks complete
**Type:** human-action
**Plan:** 01-01
**Progress:** 1/3 tasks complete
[Checkpoint content - same as checkpoint_protocol display above]
### Completed Tasks
**Awaiting:** [Resume signal from the task]
| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | Initialize Next.js 15 project | d6fe73f | package.json, tsconfig.json, app/ |
### Current Task
**Task 2:** Initialize Convex backend
**Status:** blocked
**Blocked by:** Convex CLI authentication required
### Checkpoint Details
**Automation attempted:**
Ran `npx convex dev` to initialize Convex backend
**Error encountered:**
"Error: Not authenticated. Run `npx convex login` first."
**What you need to do:**
1. Run: `npx convex login`
2. Complete browser authentication
3. Run: `npx convex dev`
4. Create project when prompted
**I'll verify after:**
`cat .env.local | grep CONVEX` returns the Convex URL
### Awaiting
Type "done" when Convex is authenticated and project created.
```
**After you return:**
The orchestrator will:
1. Parse your return
2. Present the checkpoint to the user
1. Parse your structured return
2. Present checkpoint details to the user
3. Collect user's response
4. Resume you with: `Task(resume=your_agent_id, prompt="User response: {their_input}")`
4. Spawn a FRESH continuation agent with your completed tasks state
**When resumed after checkpoint:**
You will receive a prompt like: `"User response: approved"` or `"User response: option-a"`
- Parse the user's response
- If approved/done: continue to next task
- If issues described: address them, then continue or re-present checkpoint
- If option selected: proceed with that choice
You will NOT be resumed. A new agent continues from where you stopped, using your Completed Tasks table to know what's done.
**How to know if you were spawned:**