From b1363966102b9afe6924e7f6deb8c66faf8c756b Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Tue, 17 Mar 2026 08:03:03 -0400 Subject: [PATCH 1/2] feat: add backlog parking lot and persistent context threads (#1005) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three new commands for managing ideas and cross-session context: /gsd:add-backlog Adds a 999.x numbered backlog item to ROADMAP.md. Creates phase directory immediately so /gsd:discuss-phase and /gsd:plan-phase work on them. No dependencies, no sequencing โ€” pure parking lot. /gsd:review-backlog Lists all 999.x items, lets user promote to active milestone, keep, or remove. Promotion renumbers to next sequential phase with proper deps. /gsd:thread [name | description] Three modes: - No args: list all threads with status - Existing name: resume thread, load context - New description: create thread from current conversation context Threads live in .planning/threads/ as lightweight markdown files with Goal, Context, References, and Next Steps sections. Design: - Self-contained command files, no core changes needed - 999.x numbering keeps backlog out of active sequence - Threads are independent of phases โ€” cross-session knowledge stores - Both features compose with existing GSD commands Fixes #1005 --- commands/gsd/add-backlog.md | 76 ++++++++++++++++++++ commands/gsd/review-backlog.md | 61 ++++++++++++++++ commands/gsd/thread.md | 127 +++++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 commands/gsd/add-backlog.md create mode 100644 commands/gsd/review-backlog.md create mode 100644 commands/gsd/thread.md diff --git a/commands/gsd/add-backlog.md b/commands/gsd/add-backlog.md new file mode 100644 index 000000000..a144fb975 --- /dev/null +++ b/commands/gsd/add-backlog.md @@ -0,0 +1,76 @@ +--- +name: gsd:add-backlog +description: Add an idea to the backlog parking lot (999.x numbering) +argument-hint: +allowed-tools: + - Read + - Write + - Bash +--- + + +Add a backlog item to the roadmap using 999.x numbering. Backlog items are +unsequenced ideas that aren't ready for active planning โ€” they live outside +the normal phase sequence and accumulate context over time. + + + + +1. **Read ROADMAP.md** to find existing backlog entries: + ```bash + cat .planning/ROADMAP.md + ``` + +2. **Find next backlog number:** + ```bash + NEXT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" phase next-decimal 999 --raw) + ``` + If no 999.x phases exist, start at 999.1. + +3. **Create the phase directory:** + ```bash + SLUG=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" generate-slug "$ARGUMENTS") + mkdir -p ".planning/phases/${NEXT}-${SLUG}" + touch ".planning/phases/${NEXT}-${SLUG}/.gitkeep" + ``` + +4. **Add to ROADMAP.md** under a `## Backlog` section. If the section doesn't exist, create it at the end: + + ```markdown + ## Backlog + + ### Phase {NEXT}: {description} (BACKLOG) + + **Goal:** [Captured for future planning] + **Requirements:** TBD + **Plans:** 0 plans + + Plans: + - [ ] TBD (promote with /gsd:review-backlog when ready) + ``` + +5. **Commit:** + ```bash + node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs: add backlog item ${NEXT} โ€” ${ARGUMENTS}" --files .planning/ROADMAP.md ".planning/phases/${NEXT}-${SLUG}/.gitkeep" + ``` + +6. **Report:** + ``` + ## ๐Ÿ“‹ Backlog Item Added + + Phase {NEXT}: {description} + Directory: .planning/phases/{NEXT}-{slug}/ + + This item lives in the backlog parking lot. + Use /gsd:discuss-phase {NEXT} to explore it further. + Use /gsd:review-backlog to promote items to active milestone. + ``` + + + + +- 999.x numbering keeps backlog items out of the active phase sequence +- Phase directories are created immediately, so /gsd:discuss-phase and /gsd:plan-phase work on them +- No `Depends on:` field โ€” backlog items are unsequenced by definition +- Sparse numbering is fine (999.1, 999.3) โ€” always uses next-decimal + diff --git a/commands/gsd/review-backlog.md b/commands/gsd/review-backlog.md new file mode 100644 index 000000000..91de5dd83 --- /dev/null +++ b/commands/gsd/review-backlog.md @@ -0,0 +1,61 @@ +--- +name: gsd:review-backlog +description: Review and promote backlog items to active milestone +allowed-tools: + - Read + - Write + - Bash +--- + + +Review all 999.x backlog items and optionally promote them into the active +milestone sequence or remove stale entries. + + + + +1. **List backlog items:** + ```bash + ls -d .planning/phases/999* 2>/dev/null || echo "No backlog items found" + ``` + +2. **Read ROADMAP.md** and extract all 999.x phase entries: + ```bash + cat .planning/ROADMAP.md + ``` + Show each backlog item with its description, any accumulated context (CONTEXT.md, RESEARCH.md), and creation date. + +3. **Present the list to the user** via AskUserQuestion: + - For each backlog item, show: phase number, description, accumulated artifacts + - Options per item: **Promote** (move to active), **Keep** (leave in backlog), **Remove** (delete) + +4. **For items to PROMOTE:** + - Find the next sequential phase number in the active milestone + - Rename the directory from `999.x-slug` to `{new_num}-slug`: + ```bash + NEW_NUM=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" phase add "${DESCRIPTION}" --raw) + ``` + - Move accumulated artifacts to the new phase directory + - Update ROADMAP.md: move the entry from `## Backlog` section to the active phase list + - Remove `(BACKLOG)` marker + - Add appropriate `**Depends on:**` field + +5. **For items to REMOVE:** + - Delete the phase directory + - Remove the entry from ROADMAP.md `## Backlog` section + +6. **Commit changes:** + ```bash + node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs: review backlog โ€” promoted N, removed M" --files .planning/ROADMAP.md + ``` + +7. **Report summary:** + ``` + ## ๐Ÿ“‹ Backlog Review Complete + + Promoted: {list of promoted items with new phase numbers} + Kept: {list of items remaining in backlog} + Removed: {list of deleted items} + ``` + + diff --git a/commands/gsd/thread.md b/commands/gsd/thread.md new file mode 100644 index 000000000..fe921184b --- /dev/null +++ b/commands/gsd/thread.md @@ -0,0 +1,127 @@ +--- +name: gsd:thread +description: Manage persistent context threads for cross-session work +argument-hint: [name | description] +allowed-tools: + - Read + - Write + - Bash +--- + + +Create, list, or resume persistent context threads. Threads are lightweight +cross-session knowledge stores for work that spans multiple sessions but +doesn't belong to any specific phase. + + + + +**Parse $ARGUMENTS to determine mode:** + + +**If no arguments or $ARGUMENTS is empty:** + +List all threads: +```bash +ls .planning/threads/*.md 2>/dev/null +``` + +For each thread, read the first few lines to show title and status: +``` +## Active Threads + +| Thread | Status | Last Updated | +|--------|--------|-------------| +| fix-deploy-key-auth | OPEN | 2026-03-15 | +| pasta-tcp-timeout | RESOLVED | 2026-03-12 | +| perf-investigation | IN PROGRESS | 2026-03-17 | +``` + +If no threads exist, show: +``` +No threads found. Create one with: /gsd:thread +``` + + + +**If $ARGUMENTS matches an existing thread name (file exists):** + +Resume the thread โ€” load its context into the current session: +```bash +cat ".planning/threads/${THREAD_NAME}.md" +``` + +Display the thread content and ask what the user wants to work on next. +Update the thread's status to `IN PROGRESS` if it was `OPEN`. + + + +**If $ARGUMENTS is a new description (no matching thread file):** + +Create a new thread: + +1. Generate slug from description: + ```bash + SLUG=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" generate-slug "$ARGUMENTS") + ``` + +2. Create the threads directory if needed: + ```bash + mkdir -p .planning/threads + ``` + +3. Write the thread file: + ```bash + cat > ".planning/threads/${SLUG}.md" << 'EOF' + # Thread: {description} + + ## Status: OPEN + + ## Goal + + {description} + + ## Context + + *Created from conversation on {today's date}.* + + ## References + + - *(add links, file paths, or issue numbers)* + + ## Next Steps + + - *(what the next session should do first)* + EOF + ``` + +4. If there's relevant context in the current conversation (code snippets, + error messages, investigation results), extract and add it to the Context + section. + +5. Commit: + ```bash + node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs: create thread โ€” ${ARGUMENTS}" --files ".planning/threads/${SLUG}.md" + ``` + +6. Report: + ``` + ## ๐Ÿงต Thread Created + + Thread: {slug} + File: .planning/threads/{slug}.md + + Resume anytime with: /gsd:thread {slug} + ``` + + + + + +- Threads are NOT phase-scoped โ€” they exist independently of the roadmap +- Lighter weight than /gsd:pause-work โ€” no phase state, no plan context +- The value is in Context and Next Steps โ€” a cold-start session can pick up immediately +- Threads can be promoted to phases or backlog items when they mature: + /gsd:add-phase or /gsd:add-backlog with context from the thread +- Thread files live in .planning/threads/ โ€” no collision with phases or other GSD structures + From 12e4cfe041421d0b340020107463334ec2f6774a Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Tue, 17 Mar 2026 08:14:11 -0400 Subject: [PATCH 2/2] fix: update Copilot skill count in tests for 3 new commands Tests expected 39 skill folders but got 42 after adding add-backlog, review-backlog, and thread commands. Updated both the hardcoded count and EXPECTED_SKILLS constant. --- tests/copilot-install.test.cjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/copilot-install.test.cjs b/tests/copilot-install.test.cjs index b6510d0e7..249d8a89a 100644 --- a/tests/copilot-install.test.cjs +++ b/tests/copilot-install.test.cjs @@ -625,7 +625,7 @@ describe('copyCommandsAsCopilotSkills', () => { // Count gsd-* directories โ€” should be 31 const dirs = fs.readdirSync(tempDir, { withFileTypes: true }) .filter(e => e.isDirectory() && e.name.startsWith('gsd-')); - assert.strictEqual(dirs.length, 43, `expected 43 skill folders, got ${dirs.length}`); + assert.strictEqual(dirs.length, 46, `expected 46 skill folders, got ${dirs.length}`); } finally { fs.rmSync(tempDir, { recursive: true }); } @@ -1119,7 +1119,7 @@ const { execFileSync } = require('child_process'); const crypto = require('crypto'); const INSTALL_PATH = path.join(__dirname, '..', 'bin', 'install.js'); -const EXPECTED_SKILLS = 43; +const EXPECTED_SKILLS = 46; const EXPECTED_AGENTS = 16; function runCopilotInstall(cwd) {