From f54f3df77685f9acc10bbfa56e6d5cdbfce6d7cb Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Wed, 18 Mar 2026 12:01:25 -0400 Subject: [PATCH] feat: structured session handoff artifact for cross-session continuity (#940) (#1122) Enhance /gsd:pause-work to write .planning/HANDOFF.json alongside .continue-here.md. The JSON provides machine-readable state that /gsd:resume-work can parse for precise resumption. HANDOFF.json includes: - Task position (phase, plan, task number, status) - Completed and remaining tasks with commit hashes - Blockers with type classification (technical/human_action/external) - Human actions pending (API keys, approvals, manual testing) - Uncommitted files list - Context notes for mental model restoration Resume-work changes: - HANDOFF.json is primary resumption source (highest priority) - Surfaces blockers and human actions immediately on session start - Validates uncommitted files against git status - Deletes HANDOFF.json after successful resumption - Falls back to .continue-here.md if no JSON exists Also checks for placeholder content in SUMMARY.md files to catch false completions (frontmatter claims complete but body has TBD). Fixes #940 --- CHANGELOG.md | 3 ++ docs/FEATURES.md | 6 ++- docs/USER-GUIDE.md | 2 +- get-shit-done/workflows/pause-work.md | 64 +++++++++++++++++++++-- get-shit-done/workflows/resume-project.md | 22 +++++++- 5 files changed, 87 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eee1e152..6f1947b3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Fixed - **Requirements `mark-complete` is now idempotent** — Re-marking already-completed requirements returns `already_complete` instead of `not_found` (#948) +### Improved +- **Structured session handoff** — `/gsd:pause-work` now writes `.planning/HANDOFF.json` alongside `.continue-here.md`. JSON provides machine-readable state (task position, blockers, human actions pending, uncommitted files) that `/gsd:resume-work` parses for precise resumption instead of generic "what do you want to do?" (#940) + ## [1.25.0] - 2026-03-16 ### Added diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 88c543a1f..b706e257d 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -513,11 +513,13 @@ **Purpose:** Maintain project continuity across context resets and sessions. **Requirements:** -- REQ-SESSION-01: Pause MUST save current position and next steps to `continue-here.md` -- REQ-SESSION-02: Resume MUST restore full project context from state files +- REQ-SESSION-01: Pause MUST save current position and next steps to `continue-here.md` and structured `HANDOFF.json` +- REQ-SESSION-02: Resume MUST restore full project context from HANDOFF.json (preferred) or state files (fallback) - REQ-SESSION-03: Progress MUST show current position, next action, and overall completion - REQ-SESSION-04: Progress MUST read all state files (STATE.md, ROADMAP.md, phase directories) - REQ-SESSION-05: All session operations MUST work after `/clear` (context reset) +- REQ-SESSION-06: HANDOFF.json MUST include blockers, human actions pending, and in-progress task state +- REQ-SESSION-07: Resume MUST surface human actions and blockers immediately on session start --- diff --git a/docs/USER-GUIDE.md b/docs/USER-GUIDE.md index d29455860..4dcfca52b 100644 --- a/docs/USER-GUIDE.md +++ b/docs/USER-GUIDE.md @@ -296,7 +296,7 @@ Controlled by `workflow.ui_safety_gate` config toggle. |---------|---------|-------------| | `/gsd:progress` | Show status and next steps | Anytime -- "where am I?" | | `/gsd:resume-work` | Restore full context from last session | Starting a new session | -| `/gsd:pause-work` | Save context handoff | Stopping mid-phase | +| `/gsd:pause-work` | Save structured handoff (HANDOFF.json + continue-here.md) | Stopping mid-phase | | `/gsd:help` | Show all commands | Quick reference | | `/gsd:update` | Update GSD with changelog preview | Check for new versions | | `/gsd:join-discord` | Open Discord community invite | Questions or community | diff --git a/get-shit-done/workflows/pause-work.md b/get-shit-done/workflows/pause-work.md index f723ef81a..ccdba267d 100644 --- a/get-shit-done/workflows/pause-work.md +++ b/get-shit-done/workflows/pause-work.md @@ -1,5 +1,5 @@ -Create `.continue-here.md` handoff file to preserve complete work state across sessions. Enables seamless resumption with full context restoration. +Create structured `.planning/HANDOFF.json` and `.continue-here.md` handoff files to preserve complete work state across sessions. The JSON provides machine-readable state for `/gsd:resume-work`; the markdown provides human-readable context. @@ -27,10 +27,61 @@ If no active phase detected, ask user which phase they're pausing work on. 3. **Work remaining**: What's left in current plan/phase 4. **Decisions made**: Key decisions and rationale 5. **Blockers/issues**: Anything stuck -6. **Mental context**: The approach, next steps, "vibe" -7. **Files modified**: What's changed but not committed +6. **Human actions pending**: Things that need manual intervention (MCP setup, API keys, approvals, manual testing) +7. **Background processes**: Any running servers/watchers that were part of the workflow +8. **Files modified**: What's changed but not committed Ask user for clarifications if needed via conversational questions. + +**Also inspect SUMMARY.md files for false completions:** +```bash +# Check for placeholder content in existing summaries +grep -l "To be filled\|placeholder\|TBD" .planning/phases/*/*.md 2>/dev/null +``` +Report any summaries with placeholder content as incomplete items. + + + +**Write structured handoff to `.planning/HANDOFF.json`:** + +```bash +timestamp=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" current-timestamp full --raw) +``` + +```json +{ + "version": "1.0", + "timestamp": "{timestamp}", + "phase": "{phase_number}", + "phase_name": "{phase_name}", + "phase_dir": "{phase_dir}", + "plan": {current_plan_number}, + "task": {current_task_number}, + "total_tasks": {total_task_count}, + "status": "paused", + "completed_tasks": [ + {"id": 1, "name": "{task_name}", "status": "done", "commit": "{short_hash}"}, + {"id": 2, "name": "{task_name}", "status": "done", "commit": "{short_hash}"}, + {"id": 3, "name": "{task_name}", "status": "in_progress", "progress": "{what_done}"} + ], + "remaining_tasks": [ + {"id": 4, "name": "{task_name}", "status": "not_started"}, + {"id": 5, "name": "{task_name}", "status": "not_started"} + ], + "blockers": [ + {"description": "{blocker}", "type": "technical|human_action|external", "workaround": "{if any}"} + ], + "human_actions_pending": [ + {"action": "{what needs to be done}", "context": "{why}", "blocking": true} + ], + "decisions": [ + {"decision": "{what}", "rationale": "{why}", "phase": "{phase_number}"} + ], + "uncommitted_files": [], + "next_action": "{specific first action when resuming}", + "context_notes": "{mental state, approach, what you were thinking}" +} +``` @@ -92,19 +143,22 @@ timestamp=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" current-timesta ```bash -node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "wip: [phase-name] paused at task [X]/[Y]" --files .planning/phases/*/.continue-here.md +node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "wip: [phase-name] paused at task [X]/[Y]" --files .planning/phases/*/.continue-here.md .planning/HANDOFF.json ``` ``` -✓ Handoff created: .planning/phases/[XX-name]/.continue-here.md +✓ Handoff created: + - .planning/HANDOFF.json (structured, machine-readable) + - .planning/phases/[XX-name]/.continue-here.md (human-readable) Current state: - Phase: [XX-name] - Task: [X] of [Y] - Status: [in_progress/blocked] +- Blockers: [count] ({human_actions_pending count} need human action) - Committed as WIP To resume: /gsd:resume-work diff --git a/get-shit-done/workflows/resume-project.md b/get-shit-done/workflows/resume-project.md index 7ebdc2150..a8dafcf2c 100644 --- a/get-shit-done/workflows/resume-project.md +++ b/get-shit-done/workflows/resume-project.md @@ -63,6 +63,9 @@ cat .planning/PROJECT.md Look for incomplete work that needs attention: ```bash +# Check for structured handoff (preferred — machine-readable) +cat .planning/HANDOFF.json 2>/dev/null + # Check for continue-here files (mid-plan resumption) ls .planning/phases/*/.continue-here*.md 2>/dev/null @@ -78,7 +81,18 @@ if [ "$has_interrupted_agent" = "true" ]; then fi ``` -**If .continue-here file exists:** +**If HANDOFF.json exists:** + +- This is the primary resumption source — structured data from `/gsd:pause-work` +- Parse `status`, `phase`, `plan`, `task`, `total_tasks`, `next_action` +- Check `blockers` and `human_actions_pending` — surface these immediately +- Check `completed_tasks` for `in_progress` items — these need attention first +- Validate `uncommitted_files` against `git status` — flag divergence +- Use `context_notes` to restore mental model +- Flag: "Found structured handoff — resuming from task {task}/{total_tasks}" +- **After successful resumption, delete HANDOFF.json** (it's a one-shot artifact) + +**If .continue-here file exists (fallback):** - This is a mid-plan resumption point - Read the file for specific resumption context @@ -145,8 +159,12 @@ Based on project state, determine the most logical next action: → Primary: Resume interrupted agent (Task tool with resume parameter) → Option: Start fresh (abandon agent work) +**If HANDOFF.json exists:** +→ Primary: Resume from structured handoff (highest priority — specific task/blocker context) +→ Option: Discard handoff and reassess from files + **If .continue-here file exists:** -→ Primary: Resume from checkpoint +→ Fallback: Resume from checkpoint → Option: Start fresh on current plan **If incomplete plan (PLAN without SUMMARY):**