feat(gsd-tools): add compound init commands and update workflows (#468)

* feat(gsd-tools): add compound init commands for workflow setup

Adds 8 compound commands that return all context a workflow needs in
one JSON blob, replacing 5-10 atomic calls per workflow:

- init execute-phase: models, config, phase info, plan inventory
- init plan-phase: models, workflow flags, existing artifacts
- init new-project: models, brownfield detection, state checks
- init new-milestone: models, milestone info
- init quick: models, next task number, timestamps
- init resume: file existence, interrupted agent
- init verify-work: models, phase info
- init phase-op: generic phase context

Updated 8 workflows to use compound commands:
- execute-phase, plan-phase, new-project, quick
- resume-project, verify-work, discuss-phase

Token savings: ~200 lines of bash setup replaced with single init calls.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(gsd-tools): add 4 new init commands and update files to use compound commands

Add new compound init commands:
- init todos - context for todo workflows
- init milestone-op - context for milestone operations
- init map-codebase - context for codebase mapping
- init progress - context for progress workflow

Update 24 files to use compound init commands instead of atomic calls:
- 4 phase operation workflows (add-phase, insert-phase, remove-phase, verify-phase)
- 5 todo/milestone workflows (add-todo, check-todos, audit-milestone, complete-milestone, new-milestone)
- 6 misc workflows (execute-plan, map-codebase, pause-work, progress, set-profile, settings)
- 6 agent files (gsd-executor, gsd-planner, gsd-phase-researcher, gsd-plan-checker, gsd-debugger, gsd-research-synthesizer)
- 2 command files (debug, research-phase)
- 1 reference file (planning-config)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(gsd-tools): add init to help output

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(verify-phase): correct expected init fields

The workflow was referencing plans/summaries from init phase-op,
but those fields come from ls command. Updated to reference
has_plans and plan_count which are actually in phase-op output.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
TÂCHES
2026-02-07 22:09:07 -06:00
committed by GitHub
parent e02b37d5e8
commit 246d542c65
31 changed files with 1017 additions and 389 deletions

View File

@@ -979,10 +979,11 @@ mkdir -p .planning/debug/resolved
mv .planning/debug/{slug}.md .planning/debug/resolved/
```
**Check planning config:**
**Check planning config using state load (commit_docs is available from the output):**
```bash
COMMIT_PLANNING_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
# commit_docs is in the JSON output
```
**Commit the fix:**

View File

@@ -16,22 +16,21 @@ Your job: Execute the plan completely, commit each task, create SUMMARY.md, upda
<execution_flow>
<step name="load_project_state" priority="first">
Read project state:
Load execution context:
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "${PHASE}")
```
Extract from init JSON: `executor_model`, `commit_docs`, `phase_dir`, `plans`, `incomplete_plans`.
Also read STATE.md for position, decisions, blockers:
```bash
cat .planning/STATE.md 2>/dev/null
```
Parse: current position, accumulated decisions, blockers/concerns.
If STATE.md missing but .planning/ exists: offer to reconstruct or continue without.
If .planning/ missing: Error — project not initialized.
**Load planning config:**
```bash
COMMIT_PLANNING_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
```
</step>
<step name="load_plan">

View File

@@ -293,11 +293,16 @@ Verified patterns from official sources:
Orchestrator provides: phase number/name, description/goal, requirements, constraints, output path.
Load phase context using init command:
```bash
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE" --raw)
PADDED_PHASE=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE" | grep -o '"phase_number":"[^"]*"' | cut -d'"' -f4)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${PHASE}")
```
cat "$PHASE_DIR"/*-CONTEXT.md 2>/dev/null
Extract from init JSON: `phase_dir`, `padded_phase`, `phase_number`, `commit_docs`.
Then read CONTEXT.md if exists:
```bash
cat "$phase_dir"/*-CONTEXT.md 2>/dev/null
```
**If CONTEXT.md exists**, it constrains research:

View File

@@ -297,13 +297,19 @@ issue:
## Step 1: Load Context
Load phase operation context:
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${PHASE_ARG}")
```
Extract from init JSON: `phase_dir`, `phase_number`, `has_plans`, `plan_count`.
Orchestrator provides CONTEXT.md content in the verification prompt. If provided, parse for locked decisions, discretion areas, deferred ideas.
```bash
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE_ARG" --raw)
ls "$PHASE_DIR"/*-PLAN.md 2>/dev/null
grep -A 10 "Phase $PHASE_NUM" .planning/ROADMAP.md | head -15
ls "$PHASE_DIR"/*-BRIEF.md 2>/dev/null
ls "$phase_dir"/*-PLAN.md 2>/dev/null
grep -A 10 "Phase $phase_number" .planning/ROADMAP.md | head -15
ls "$phase_dir"/*-BRIEF.md 2>/dev/null
```
**Extract:** Phase goal, requirements (decompose goal), locked decisions, deferred ideas.

View File

@@ -683,14 +683,14 @@ Triggered by `--gaps` flag. Creates plans to address verification or UAT failure
**1. Find gap sources:**
```bash
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE_ARG" --raw)
Use init context (from load_project_state) which provides `phase_dir`:
```bash
# Check for VERIFICATION.md (code verification gaps)
ls "$PHASE_DIR"/*-VERIFICATION.md 2>/dev/null
ls "$phase_dir"/*-VERIFICATION.md 2>/dev/null
# Check for UAT.md with diagnosed status (user testing gaps)
grep -l "status: diagnosed" "$PHASE_DIR"/*-UAT.md 2>/dev/null
grep -l "status: diagnosed" "$phase_dir"/*-UAT.md 2>/dev/null
```
**2. Parse gaps:** Each gap has: truth (failed behavior), reason, artifacts (files with issues), missing (things to add/fix).
@@ -830,15 +830,20 @@ node ~/.claude/get-shit-done/bin/gsd-tools.js commit "fix($PHASE): revise plans
<execution_flow>
<step name="load_project_state" priority="first">
Read `.planning/STATE.md` — parse current position, accumulated decisions, pending todos, blockers/concerns.
If STATE.md missing but .planning/ exists, offer to reconstruct or continue without.
**Load planning config:**
Load planning context:
```bash
COMMIT_PLANNING_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init plan-phase "${PHASE}")
```
Extract from init JSON: `planner_model`, `researcher_model`, `checker_model`, `commit_docs`, `research_enabled`, `phase_dir`, `phase_number`, `has_research`, `has_context`.
Also read STATE.md for position, decisions, blockers:
```bash
cat .planning/STATE.md 2>/dev/null
```
If STATE.md missing but .planning/ exists, offer to reconstruct or continue without.
</step>
<step name="load_codebase_context">
@@ -905,17 +910,17 @@ done
</step>
<step name="gather_phase_context">
```bash
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE" --raw)
Use `phase_dir` from init context (already loaded in load_project_state).
cat "$PHASE_DIR"/*-CONTEXT.md 2>/dev/null # From /gsd:discuss-phase
cat "$PHASE_DIR"/*-RESEARCH.md 2>/dev/null # From /gsd:research-phase
cat "$PHASE_DIR"/*-DISCOVERY.md 2>/dev/null # From mandatory discovery
```bash
cat "$phase_dir"/*-CONTEXT.md 2>/dev/null # From /gsd:discuss-phase
cat "$phase_dir"/*-RESEARCH.md 2>/dev/null # From /gsd:research-phase
cat "$phase_dir"/*-DISCOVERY.md 2>/dev/null # From mandatory discovery
```
**If CONTEXT.md exists:** Honor user's vision, prioritize essential features, respect boundaries. Locked decisions — do not revisit.
**If CONTEXT.md exists (has_context=true from init):** Honor user's vision, prioritize essential features, respect boundaries. Locked decisions — do not revisit.
**If RESEARCH.md exists:** Use standard_stack, architecture_patterns, dont_hand_roll, common_pitfalls.
**If RESEARCH.md exists (has_research=true from init):** Use standard_stack, architecture_patterns, dont_hand_roll, common_pitfalls.
</step>
<step name="break_into_tasks">

View File

@@ -28,8 +28,13 @@ ls .planning/debug/*.md 2>/dev/null | grep -v resolved | head -5
<process>
## 0. Resolve Model Profile
## 0. Initialize Context
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
```
Extract `commit_docs` from init JSON. Resolve debugger model:
```bash
DEBUGGER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-debugger --raw)
```

View File

@@ -31,23 +31,26 @@ Normalize phase input in step 1 before any directory lookups.
<process>
## 0. Resolve Model Profile
## 0. Initialize Context
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "$ARGUMENTS")
```
Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`, `phase_found`, `commit_docs`, `has_research`.
Resolve researcher model:
```bash
RESEARCHER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-phase-researcher --raw)
```
## 1. Normalize and Validate Phase
## 1. Validate Phase
```bash
PHASE_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$ARGUMENTS")
PHASE_DIR=$(echo "$PHASE_INFO" | grep -o '"directory":"[^"]*"' | cut -d'"' -f4)
PHASE=$(echo "$PHASE_INFO" | grep -o '"phase_number":"[^"]*"' | cut -d'"' -f4)
grep -A5 "Phase ${PHASE}:" .planning/ROADMAP.md 2>/dev/null
grep -A5 "Phase ${phase_number}:" .planning/ROADMAP.md 2>/dev/null
```
**If not found:** Error and exit. **If found:** Extract phase number, name, description.
**If not found (phase_found=false):** Error and exit. **If found:** Extract phase number, name, description.
## 2. Check Existing Research

View File

@@ -8,13 +8,27 @@
*
* Usage: node gsd-tools.js <command> [args] [--raw]
*
* Commands:
* Atomic Commands:
* state load Load project config + state
* state update <field> <value> Update a STATE.md field
* resolve-model <agent-type> Get model for agent based on profile
* find-phase <phase> Find phase directory by number
* commit <message> [--files f1 f2] Commit planning docs
* verify-summary <path> Verify a SUMMARY.md file
*
* Compound Commands (workflow-specific initialization):
* init execute-phase <phase> All context for execute-phase workflow
* init plan-phase <phase> All context for plan-phase workflow
* init new-project All context for new-project workflow
* init new-milestone All context for new-milestone workflow
* init quick <description> All context for quick workflow
* init resume All context for resume-project workflow
* init verify-work <phase> All context for verify-work workflow
* init phase-op <phase> Generic phase operation context
* init todos [area] All context for todo workflows
* init milestone-op All context for milestone operations
* init map-codebase All context for map-codebase workflow
* init progress All context for progress workflow
*/
const fs = require('fs');
@@ -556,6 +570,654 @@ function cmdVerifySummary(cwd, summaryPath, checkFileCount, raw) {
output(result, raw, passed ? 'passed' : 'failed');
}
// ─── Compound Commands ────────────────────────────────────────────────────────
function resolveModelInternal(cwd, agentType) {
const config = loadConfig(cwd);
const profile = config.model_profile || 'balanced';
const agentModels = MODEL_PROFILES[agentType];
if (!agentModels) return 'sonnet';
return agentModels[profile] || agentModels['balanced'] || 'sonnet';
}
function findPhaseInternal(cwd, phase) {
if (!phase) return null;
const phasesDir = path.join(cwd, '.planning', 'phases');
const normalized = normalizePhaseName(phase);
try {
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
const match = dirs.find(d => d.startsWith(normalized));
if (!match) return null;
const dirMatch = match.match(/^(\d+(?:\.\d+)?)-?(.*)/);
const phaseNumber = dirMatch ? dirMatch[1] : normalized;
const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
const phaseDir = path.join(phasesDir, match);
const phaseFiles = fs.readdirSync(phaseDir);
const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').sort();
const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md').sort();
const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
const hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
const hasVerification = phaseFiles.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
// Determine incomplete plans (plans without matching summaries)
const completedPlanIds = new Set(
summaries.map(s => s.replace('-SUMMARY.md', '').replace('SUMMARY.md', ''))
);
const incompletePlans = plans.filter(p => {
const planId = p.replace('-PLAN.md', '').replace('PLAN.md', '');
return !completedPlanIds.has(planId);
});
return {
found: true,
directory: path.join('.planning', 'phases', match),
phase_number: phaseNumber,
phase_name: phaseName,
phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
plans,
summaries,
incomplete_plans: incompletePlans,
has_research: hasResearch,
has_context: hasContext,
has_verification: hasVerification,
};
} catch {
return null;
}
}
function pathExistsInternal(cwd, targetPath) {
const fullPath = path.isAbsolute(targetPath) ? targetPath : path.join(cwd, targetPath);
try {
fs.statSync(fullPath);
return true;
} catch {
return false;
}
}
function generateSlugInternal(text) {
if (!text) return null;
return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
}
function getMilestoneInfo(cwd) {
try {
const roadmap = fs.readFileSync(path.join(cwd, '.planning', 'ROADMAP.md'), 'utf-8');
const versionMatch = roadmap.match(/v(\d+\.\d+)/);
const nameMatch = roadmap.match(/## .*v\d+\.\d+[:\s]+([^\n(]+)/);
return {
version: versionMatch ? versionMatch[0] : 'v1.0',
name: nameMatch ? nameMatch[1].trim() : 'milestone',
};
} catch {
return { version: 'v1.0', name: 'milestone' };
}
}
function cmdInitExecutePhase(cwd, phase, raw) {
if (!phase) {
error('phase required for init execute-phase');
}
const config = loadConfig(cwd);
const phaseInfo = findPhaseInternal(cwd, phase);
const milestone = getMilestoneInfo(cwd);
const result = {
// Models
executor_model: resolveModelInternal(cwd, 'gsd-executor'),
verifier_model: resolveModelInternal(cwd, 'gsd-verifier'),
// Config flags
commit_docs: config.commit_docs,
parallelization: config.parallelization,
branching_strategy: config.branching_strategy,
phase_branch_template: config.phase_branch_template,
milestone_branch_template: config.milestone_branch_template,
verifier_enabled: config.verifier,
// Phase info
phase_found: !!phaseInfo,
phase_dir: phaseInfo?.directory || null,
phase_number: phaseInfo?.phase_number || null,
phase_name: phaseInfo?.phase_name || null,
phase_slug: phaseInfo?.phase_slug || null,
// Plan inventory
plans: phaseInfo?.plans || [],
summaries: phaseInfo?.summaries || [],
incomplete_plans: phaseInfo?.incomplete_plans || [],
plan_count: phaseInfo?.plans?.length || 0,
incomplete_count: phaseInfo?.incomplete_plans?.length || 0,
// Branch name (pre-computed)
branch_name: config.branching_strategy === 'phase' && phaseInfo
? config.phase_branch_template
.replace('{phase}', phaseInfo.phase_number)
.replace('{slug}', phaseInfo.phase_slug || 'phase')
: config.branching_strategy === 'milestone'
? config.milestone_branch_template
.replace('{milestone}', milestone.version)
.replace('{slug}', generateSlugInternal(milestone.name) || 'milestone')
: null,
// Milestone info
milestone_version: milestone.version,
milestone_name: milestone.name,
milestone_slug: generateSlugInternal(milestone.name),
// File existence
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
config_exists: pathExistsInternal(cwd, '.planning/config.json'),
};
output(result, raw);
}
function cmdInitPlanPhase(cwd, phase, raw) {
if (!phase) {
error('phase required for init plan-phase');
}
const config = loadConfig(cwd);
const phaseInfo = findPhaseInternal(cwd, phase);
const result = {
// Models
researcher_model: resolveModelInternal(cwd, 'gsd-phase-researcher'),
planner_model: resolveModelInternal(cwd, 'gsd-planner'),
checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
// Workflow flags
research_enabled: config.research,
plan_checker_enabled: config.plan_checker,
commit_docs: config.commit_docs,
// Phase info
phase_found: !!phaseInfo,
phase_dir: phaseInfo?.directory || null,
phase_number: phaseInfo?.phase_number || null,
phase_name: phaseInfo?.phase_name || null,
phase_slug: phaseInfo?.phase_slug || null,
padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
// Existing artifacts
has_research: phaseInfo?.has_research || false,
has_context: phaseInfo?.has_context || false,
has_plans: (phaseInfo?.plans?.length || 0) > 0,
plan_count: phaseInfo?.plans?.length || 0,
// Environment
planning_exists: pathExistsInternal(cwd, '.planning'),
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
};
output(result, raw);
}
function cmdInitNewProject(cwd, raw) {
const config = loadConfig(cwd);
// Detect existing code
let hasCode = false;
let hasPackageFile = false;
try {
const files = execSync('find . -maxdepth 3 \\( -name "*.ts" -o -name "*.js" -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.swift" -o -name "*.java" \\) 2>/dev/null | grep -v node_modules | grep -v .git | head -5', {
cwd,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe'],
});
hasCode = files.trim().length > 0;
} catch {}
hasPackageFile = pathExistsInternal(cwd, 'package.json') ||
pathExistsInternal(cwd, 'requirements.txt') ||
pathExistsInternal(cwd, 'Cargo.toml') ||
pathExistsInternal(cwd, 'go.mod') ||
pathExistsInternal(cwd, 'Package.swift');
const result = {
// Models
researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
// Config
commit_docs: config.commit_docs,
// Existing state
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
has_codebase_map: pathExistsInternal(cwd, '.planning/codebase'),
planning_exists: pathExistsInternal(cwd, '.planning'),
// Brownfield detection
has_existing_code: hasCode,
has_package_file: hasPackageFile,
is_brownfield: hasCode || hasPackageFile,
needs_codebase_map: (hasCode || hasPackageFile) && !pathExistsInternal(cwd, '.planning/codebase'),
// Git state
has_git: pathExistsInternal(cwd, '.git'),
};
output(result, raw);
}
function cmdInitNewMilestone(cwd, raw) {
const config = loadConfig(cwd);
const milestone = getMilestoneInfo(cwd);
const result = {
// Models
researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
// Config
commit_docs: config.commit_docs,
research_enabled: config.research,
// Current milestone
current_milestone: milestone.version,
current_milestone_name: milestone.name,
// File existence
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
};
output(result, raw);
}
function cmdInitQuick(cwd, description, raw) {
const config = loadConfig(cwd);
const now = new Date();
const slug = description ? generateSlugInternal(description)?.substring(0, 40) : null;
// Find next quick task number
const quickDir = path.join(cwd, '.planning', 'quick');
let nextNum = 1;
try {
const existing = fs.readdirSync(quickDir)
.filter(f => /^\d+-/.test(f))
.map(f => parseInt(f.split('-')[0], 10))
.filter(n => !isNaN(n));
if (existing.length > 0) {
nextNum = Math.max(...existing) + 1;
}
} catch {}
const result = {
// Models
planner_model: resolveModelInternal(cwd, 'gsd-planner'),
executor_model: resolveModelInternal(cwd, 'gsd-executor'),
// Config
commit_docs: config.commit_docs,
// Quick task info
next_num: nextNum,
slug: slug,
description: description || null,
// Timestamps
date: now.toISOString().split('T')[0],
timestamp: now.toISOString(),
// Paths
quick_dir: '.planning/quick',
task_dir: slug ? `.planning/quick/${nextNum}-${slug}` : null,
// File existence
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
planning_exists: pathExistsInternal(cwd, '.planning'),
};
output(result, raw);
}
function cmdInitResume(cwd, raw) {
const config = loadConfig(cwd);
// Check for interrupted agent
let interruptedAgentId = null;
try {
interruptedAgentId = fs.readFileSync(path.join(cwd, '.planning', 'current-agent-id.txt'), 'utf-8').trim();
} catch {}
const result = {
// File existence
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
planning_exists: pathExistsInternal(cwd, '.planning'),
// Agent state
has_interrupted_agent: !!interruptedAgentId,
interrupted_agent_id: interruptedAgentId,
// Config
commit_docs: config.commit_docs,
};
output(result, raw);
}
function cmdInitVerifyWork(cwd, phase, raw) {
if (!phase) {
error('phase required for init verify-work');
}
const config = loadConfig(cwd);
const phaseInfo = findPhaseInternal(cwd, phase);
const result = {
// Models
planner_model: resolveModelInternal(cwd, 'gsd-planner'),
checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
// Config
commit_docs: config.commit_docs,
// Phase info
phase_found: !!phaseInfo,
phase_dir: phaseInfo?.directory || null,
phase_number: phaseInfo?.phase_number || null,
phase_name: phaseInfo?.phase_name || null,
// Existing artifacts
has_verification: phaseInfo?.has_verification || false,
};
output(result, raw);
}
function cmdInitPhaseOp(cwd, phase, raw) {
const config = loadConfig(cwd);
const phaseInfo = findPhaseInternal(cwd, phase);
const result = {
// Config
commit_docs: config.commit_docs,
// Phase info
phase_found: !!phaseInfo,
phase_dir: phaseInfo?.directory || null,
phase_number: phaseInfo?.phase_number || null,
phase_name: phaseInfo?.phase_name || null,
phase_slug: phaseInfo?.phase_slug || null,
padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
// Existing artifacts
has_research: phaseInfo?.has_research || false,
has_context: phaseInfo?.has_context || false,
has_plans: (phaseInfo?.plans?.length || 0) > 0,
has_verification: phaseInfo?.has_verification || false,
plan_count: phaseInfo?.plans?.length || 0,
// File existence
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
planning_exists: pathExistsInternal(cwd, '.planning'),
};
output(result, raw);
}
function cmdInitTodos(cwd, area, raw) {
const config = loadConfig(cwd);
const now = new Date();
// List todos (reuse existing logic)
const pendingDir = path.join(cwd, '.planning', 'todos', 'pending');
let count = 0;
const todos = [];
try {
const files = fs.readdirSync(pendingDir).filter(f => f.endsWith('.md'));
for (const file of files) {
try {
const content = fs.readFileSync(path.join(pendingDir, file), 'utf-8');
const createdMatch = content.match(/^created:\s*(.+)$/m);
const titleMatch = content.match(/^title:\s*(.+)$/m);
const areaMatch = content.match(/^area:\s*(.+)$/m);
const todoArea = areaMatch ? areaMatch[1].trim() : 'general';
if (area && todoArea !== area) continue;
count++;
todos.push({
file,
created: createdMatch ? createdMatch[1].trim() : 'unknown',
title: titleMatch ? titleMatch[1].trim() : 'Untitled',
area: todoArea,
path: path.join('.planning', 'todos', 'pending', file),
});
} catch {}
}
} catch {}
const result = {
// Config
commit_docs: config.commit_docs,
// Timestamps
date: now.toISOString().split('T')[0],
timestamp: now.toISOString(),
// Todo inventory
todo_count: count,
todos,
area_filter: area || null,
// Paths
pending_dir: '.planning/todos/pending',
completed_dir: '.planning/todos/completed',
// File existence
planning_exists: pathExistsInternal(cwd, '.planning'),
todos_dir_exists: pathExistsInternal(cwd, '.planning/todos'),
pending_dir_exists: pathExistsInternal(cwd, '.planning/todos/pending'),
};
output(result, raw);
}
function cmdInitMilestoneOp(cwd, raw) {
const config = loadConfig(cwd);
const milestone = getMilestoneInfo(cwd);
// Count phases
let phaseCount = 0;
let completedPhases = 0;
const phasesDir = path.join(cwd, '.planning', 'phases');
try {
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
phaseCount = dirs.length;
// Count phases with summaries (completed)
for (const dir of dirs) {
try {
const phaseFiles = fs.readdirSync(path.join(phasesDir, dir));
const hasSummary = phaseFiles.some(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
if (hasSummary) completedPhases++;
} catch {}
}
} catch {}
// Check archive
const archiveDir = path.join(cwd, '.planning', 'archive');
let archivedMilestones = [];
try {
archivedMilestones = fs.readdirSync(archiveDir, { withFileTypes: true })
.filter(e => e.isDirectory())
.map(e => e.name);
} catch {}
const result = {
// Config
commit_docs: config.commit_docs,
// Current milestone
milestone_version: milestone.version,
milestone_name: milestone.name,
milestone_slug: generateSlugInternal(milestone.name),
// Phase counts
phase_count: phaseCount,
completed_phases: completedPhases,
all_phases_complete: phaseCount > 0 && phaseCount === completedPhases,
// Archive
archived_milestones: archivedMilestones,
archive_count: archivedMilestones.length,
// File existence
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
archive_exists: pathExistsInternal(cwd, '.planning/archive'),
phases_dir_exists: pathExistsInternal(cwd, '.planning/phases'),
};
output(result, raw);
}
function cmdInitMapCodebase(cwd, raw) {
const config = loadConfig(cwd);
// Check for existing codebase maps
const codebaseDir = path.join(cwd, '.planning', 'codebase');
let existingMaps = [];
try {
existingMaps = fs.readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
} catch {}
const result = {
// Models
mapper_model: resolveModelInternal(cwd, 'gsd-codebase-mapper'),
// Config
commit_docs: config.commit_docs,
search_gitignored: config.search_gitignored,
parallelization: config.parallelization,
// Paths
codebase_dir: '.planning/codebase',
// Existing maps
existing_maps: existingMaps,
has_maps: existingMaps.length > 0,
// File existence
planning_exists: pathExistsInternal(cwd, '.planning'),
codebase_dir_exists: pathExistsInternal(cwd, '.planning/codebase'),
};
output(result, raw);
}
function cmdInitProgress(cwd, raw) {
const config = loadConfig(cwd);
const milestone = getMilestoneInfo(cwd);
// Analyze phases
const phasesDir = path.join(cwd, '.planning', 'phases');
const phases = [];
let currentPhase = null;
let nextPhase = null;
try {
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
for (const dir of dirs) {
const match = dir.match(/^(\d+(?:\.\d+)?)-?(.*)/);
const phaseNumber = match ? match[1] : dir;
const phaseName = match && match[2] ? match[2] : null;
const phasePath = path.join(phasesDir, dir);
const phaseFiles = fs.readdirSync(phasePath);
const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
const status = summaries.length >= plans.length && plans.length > 0 ? 'complete' :
plans.length > 0 ? 'in_progress' :
hasResearch ? 'researched' : 'pending';
const phaseInfo = {
number: phaseNumber,
name: phaseName,
directory: path.join('.planning', 'phases', dir),
status,
plan_count: plans.length,
summary_count: summaries.length,
has_research: hasResearch,
};
phases.push(phaseInfo);
// Find current (first incomplete with plans) and next (first pending)
if (!currentPhase && (status === 'in_progress' || status === 'researched')) {
currentPhase = phaseInfo;
}
if (!nextPhase && status === 'pending') {
nextPhase = phaseInfo;
}
}
} catch {}
// Check for paused work
let pausedAt = null;
try {
const state = fs.readFileSync(path.join(cwd, '.planning', 'STATE.md'), 'utf-8');
const pauseMatch = state.match(/\*\*Paused At:\*\*\s*(.+)/);
if (pauseMatch) pausedAt = pauseMatch[1].trim();
} catch {}
const result = {
// Models
executor_model: resolveModelInternal(cwd, 'gsd-executor'),
planner_model: resolveModelInternal(cwd, 'gsd-planner'),
// Config
commit_docs: config.commit_docs,
// Milestone
milestone_version: milestone.version,
milestone_name: milestone.name,
// Phase overview
phases,
phase_count: phases.length,
completed_count: phases.filter(p => p.status === 'complete').length,
in_progress_count: phases.filter(p => p.status === 'in_progress').length,
// Current state
current_phase: currentPhase,
next_phase: nextPhase,
paused_at: pausedAt,
has_work_in_progress: !!currentPhase,
// File existence
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
};
output(result, raw);
}
// ─── CLI Router ───────────────────────────────────────────────────────────────
function main() {
@@ -568,7 +1230,7 @@ function main() {
const cwd = process.cwd();
if (!command) {
error('Usage: gsd-tools <command> [args] [--raw]\nCommands: state, resolve-model, find-phase, commit, verify-summary, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section');
error('Usage: gsd-tools <command> [args] [--raw]\nCommands: state, resolve-model, find-phase, commit, verify-summary, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, init');
}
switch (command) {
@@ -634,6 +1296,51 @@ function main() {
break;
}
case 'init': {
const workflow = args[1];
switch (workflow) {
case 'execute-phase':
cmdInitExecutePhase(cwd, args[2], raw);
break;
case 'plan-phase':
cmdInitPlanPhase(cwd, args[2], raw);
break;
case 'new-project':
cmdInitNewProject(cwd, raw);
break;
case 'new-milestone':
cmdInitNewMilestone(cwd, raw);
break;
case 'quick':
cmdInitQuick(cwd, args.slice(2).join(' '), raw);
break;
case 'resume':
cmdInitResume(cwd, raw);
break;
case 'verify-work':
cmdInitVerifyWork(cwd, args[2], raw);
break;
case 'phase-op':
cmdInitPhaseOp(cwd, args[2], raw);
break;
case 'todos':
cmdInitTodos(cwd, args[2], raw);
break;
case 'milestone-op':
cmdInitMilestoneOp(cwd, raw);
break;
case 'map-codebase':
cmdInitMapCodebase(cwd, raw);
break;
case 'progress':
cmdInitProgress(cwd, raw);
break;
default:
error(`Unknown init workflow: ${workflow}\nAvailable: execute-phase, plan-phase, new-project, new-milestone, quick, resume, verify-work, phase-op, todos, milestone-op, map-codebase, progress`);
}
break;
}
default:
error(`Unknown command: ${command}`);
}

View File

@@ -42,8 +42,13 @@ Configuration options for `.planning/` directory behavior.
# Commit with automatic commit_docs + gitignore checks:
node ~/.claude/get-shit-done/bin/gsd-tools.js commit "docs: update state" --files .planning/STATE.md
# Or read config manually:
COMMIT_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
# Load config via state load (returns JSON):
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
# commit_docs is available in the JSON output
# Or use init commands which include commit_docs:
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "1")
# commit_docs is included in all init command outputs
```
**Auto-detection:** If `.planning/` is gitignored, `commit_docs` is automatically `false` regardless of config.json. This prevents git errors when users have `.planning/` in `.gitignore`.
@@ -136,11 +141,16 @@ To use uncommitted mode:
**Checking the config:**
Use `init execute-phase` which returns all config as JSON:
```bash
GSD_CONFIG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw)
BRANCHING_STRATEGY=$(echo "$GSD_CONFIG" | grep '^branching_strategy=' | cut -d= -f2)
PHASE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^phase_branch_template=' | cut -d= -f2)
MILESTONE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^milestone_branch_template=' | cut -d= -f2)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "1")
# JSON output includes: branching_strategy, phase_branch_template, milestone_branch_template
```
Or use `state load` for the config values:
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
# Parse branching_strategy, phase_branch_template, milestone_branch_template from JSON
```
**Branch creation:**

View File

@@ -25,14 +25,14 @@ Example: /gsd:add-phase Add authentication system
Exit.
</step>
<step name="load_roadmap">
Load the roadmap file:
<step name="init_context">
Load phase operation context:
```bash
node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "0")
```
If false:
Check `roadmap_exists` from init JSON. If false:
```
ERROR: No roadmap found (.planning/ROADMAP.md)
Run /gsd:new-project to initialize.
@@ -75,8 +75,9 @@ Format as two-digit: `printf "%02d" $next_phase`
</step>
<step name="generate_slug">
Convert the phase description to a kebab-case slug:
Convert the phase description to a kebab-case slug.
Use `init phase-op` which provides `phase_slug` computed from phase name, or call:
```bash
slug=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$description" --raw)
```

View File

@@ -8,18 +8,21 @@ Read all files referenced by the invoking prompt's execution_context before star
<process>
<step name="ensure_directory">
<step name="init_context">
Load todo context:
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init todos)
```
Extract from init JSON: `commit_docs`, `date`, `timestamp`, `todo_count`, `todos`, `pending_dir`, `todos_dir_exists`.
Ensure directories exist:
```bash
mkdir -p .planning/todos/pending .planning/todos/done
```
</step>
<step name="check_existing_areas">
```bash
node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos | grep -oP '"area":\s*"\K[^"]+' | sort -u
```
Note existing areas for consistency in infer_area step.
Note existing areas from the todos array for consistency in infer_area step.
</step>
<step name="extract_content">
@@ -76,13 +79,14 @@ If overlapping, use AskUserQuestion:
</step>
<step name="create_file">
Use values from init context: `timestamp` and `date` are already available.
Generate slug for the title:
```bash
timestamp=$(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp full --raw)
date_prefix=$(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp date --raw)
slug=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$title" --raw)
```
Write to `.planning/todos/pending/${date_prefix}-${slug}.md`:
Write to `.planning/todos/pending/${date}-${slug}.md`:
```markdown
---
@@ -106,7 +110,7 @@ files:
<step name="update_state">
If `.planning/STATE.md` exists:
1. Count todos: `node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos --raw`
1. Use `todo_count` from init context (or re-run `init todos` if count changed)
2. Update "### Pending Todos" under "## Accumulated Context"
</step>

View File

@@ -8,8 +8,15 @@ Read all files referenced by the invoking prompt's execution_context before star
<process>
## 0. Resolve Model Profile
## 0. Initialize Milestone Context
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init milestone-op)
```
Extract from init JSON: `milestone_version`, `milestone_name`, `phase_count`, `completed_phases`, `commit_docs`.
Resolve integration checker model:
```bash
CHECKER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-integration-checker --raw)
```

View File

@@ -8,13 +8,16 @@ Read all files referenced by the invoking prompt's execution_context before star
<process>
<step name="check_exist">
<step name="init_context">
Load todo context:
```bash
TODO_COUNT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos --raw)
echo "Pending todos: $TODO_COUNT"
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init todos)
```
If count is 0:
Extract from init JSON: `todo_count`, `todos`, `pending_dir`.
If `todo_count` is 0:
```
No pending todos.
@@ -38,12 +41,9 @@ Check for area filter in arguments:
</step>
<step name="list_todos">
```bash
# Get todos JSON
node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos [area]
```
Use the `todos` array from init context (already filtered by area if specified).
Parse JSON output and display as numbered list:
Parse and display as numbered list:
```
Pending Todos:
@@ -90,11 +90,9 @@ If `files` field has entries, read and briefly summarize each.
</step>
<step name="check_roadmap">
```bash
node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw
```
Check for roadmap (can use init progress or directly check file existence):
If roadmap exists:
If `.planning/ROADMAP.md` exists:
1. Check if todo's area matches an upcoming phase
2. Check if todo's files overlap with a phase's scope
3. Note any match for action options
@@ -148,11 +146,7 @@ Return to list_todos step.
<step name="update_state">
After any action that changes todo count:
```bash
node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos --raw
```
Update STATE.md "### Pending Todos" section if exists.
Re-run `init todos` to get updated count, then update STATE.md "### Pending Todos" section if exists.
</step>
<step name="git_commit">

View File

@@ -450,11 +450,11 @@ Archive requirements for next milestone.
<step name="archive_audit">
Move audit file to archive (if exists):
Move audit file to archive (if exists). Use init context or check directly:
```bash
AUDIT_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/v[X.Y]-MILESTONE-AUDIT.md --raw)
[ "$AUDIT_EXISTS" = "true" ] && mv .planning/v[X.Y]-MILESTONE-AUDIT.md .planning/milestones/
# Check if audit file exists
[ -f ".planning/v[X.Y]-MILESTONE-AUDIT.md" ] && mv .planning/v[X.Y]-MILESTONE-AUDIT.md .planning/milestones/
```
Confirm: `✅ Audit archived to milestones/v[X.Y]-MILESTONE-AUDIT.md`
@@ -500,13 +500,14 @@ Progress: [updated progress bar]
Check branching strategy and offer merge options.
Use `init milestone-op` for context, or load config directly:
```bash
GSD_CONFIG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw)
BRANCHING_STRATEGY=$(echo "$GSD_CONFIG" | grep '^branching_strategy=' | cut -d= -f2)
PHASE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^phase_branch_template=' | cut -d= -f2)
MILESTONE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^milestone_branch_template=' | cut -d= -f2)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "1")
```
Extract `branching_strategy`, `phase_branch_template`, `milestone_branch_template` from init JSON.
**If "none":** Skip to git_tag.
**For "phase" strategy:**

View File

@@ -107,15 +107,16 @@ Phase: "API documentation"
<process>
<step name="validate_phase" priority="first">
<step name="initialize" priority="first">
Phase number from argument (required).
Load and validate:
- Read `.planning/ROADMAP.md`
- Find phase entry
- Extract: number, name, description, status
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${PHASE}")
```
**If phase not found:**
Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`, `plan_count`, `roadmap_exists`, `planning_exists`.
**If `phase_found` is false:**
```
Phase [X] not found in roadmap.
@@ -123,15 +124,14 @@ Use /gsd:progress to see available phases.
```
Exit workflow.
**If phase found:** Continue to analyze_phase.
**If `phase_found` is true:** Continue to check_existing.
</step>
<step name="check_existing">
Check if CONTEXT.md already exists:
Check if CONTEXT.md already exists using `has_context` from init.
```bash
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE}" --raw)
ls ${PHASE_DIR}/*-CONTEXT.md 2>/dev/null
ls ${phase_dir}/*-CONTEXT.md 2>/dev/null
```
**If exists:**
@@ -280,20 +280,14 @@ Create CONTEXT.md capturing decisions made.
**Find or create phase directory:**
Use values from init: `phase_dir`, `phase_slug`, `padded_phase`.
If `phase_dir` is null (phase exists in roadmap but no directory):
```bash
PHASE_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE}")
PHASE_DIR=$(echo "$PHASE_INFO" | grep -o '"directory":"[^"]*"' | cut -d'"' -f4)
PADDED_PHASE=$(echo "$PHASE_INFO" | grep -o '"phase_number":"[^"]*"' | cut -d'"' -f4)
if [ -z "$PHASE_DIR" ]; then
PHASE_NAME=$(grep "Phase ${PHASE}:" .planning/ROADMAP.md | sed 's/.*Phase [0-9]*: //')
PHASE_SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$PHASE_NAME" --raw)
PADDED_PHASE=$(printf "%02d" ${PHASE})
mkdir -p ".planning/phases/${PADDED_PHASE}-${PHASE_SLUG}"
PHASE_DIR=".planning/phases/${PADDED_PHASE}-${PHASE_SLUG}"
fi
mkdir -p ".planning/phases/${padded_phase}-${phase_slug}"
```
**File location:** `${PHASE_DIR}/${PADDED_PHASE}-CONTEXT.md`
**File location:** `${phase_dir}/${padded_phase}-CONTEXT.md`
**Structure the content by what was discussed:**
@@ -391,13 +385,13 @@ Created: .planning/phases/${PADDED_PHASE}-${SLUG}/${PADDED_PHASE}-CONTEXT.md
</step>
<step name="git_commit">
Commit phase context:
Commit phase context (uses `commit_docs` from init internally):
```bash
node ~/.claude/get-shit-done/bin/gsd-tools.js commit "docs(${PADDED_PHASE}): capture phase context" --files "${PHASE_DIR}/${PADDED_PHASE}-CONTEXT.md"
node ~/.claude/get-shit-done/bin/gsd-tools.js commit "docs(${padded_phase}): capture phase context" --files "${phase_dir}/${padded_phase}-CONTEXT.md"
```
Confirm: "Committed: docs(${PADDED_PHASE}): capture phase context"
Confirm: "Committed: docs(${padded_phase}): capture phase context"
</step>
</process>

View File

@@ -7,63 +7,34 @@ Orchestrator coordinates, not executes. Each subagent loads the full execute-pla
</core_principle>
<required_reading>
Read STATE.md and config.json before any operation.
Read STATE.md before any operation to load project context.
</required_reading>
<process>
<step name="resolve_model_profile" priority="first">
<step name="initialize" priority="first">
Load all context in one call:
```bash
EXECUTOR_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-executor --raw)
VERIFIER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-verifier --raw)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "${PHASE_ARG}")
```
</step>
Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelization`, `branching_strategy`, `branch_name`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `plans`, `incomplete_plans`, `plan_count`, `incomplete_count`, `state_exists`, `roadmap_exists`.
<step name="load_project_state">
**If `phase_found` is false:** Error — phase directory not found.
**If `plan_count` is 0:** Error — no plans found in phase.
**If `state_exists` is false but `.planning/` exists:** Offer reconstruct or continue.
```bash
cat .planning/STATE.md 2>/dev/null
```
**If exists:** Parse current position, accumulated decisions, blockers.
**If missing but .planning/ exists:** Offer reconstruct from artifacts or continue without state.
**If .planning/ missing:** Error — project not initialized.
**Load configs:**
```bash
GSD_CONFIG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw)
COMMIT_PLANNING_DOCS=$(echo "$GSD_CONFIG" | grep '^commit_docs=' | cut -d= -f2)
PARALLELIZATION=$(echo "$GSD_CONFIG" | grep '^parallelization=' | cut -d= -f2)
BRANCHING_STRATEGY=$(echo "$GSD_CONFIG" | grep '^branching_strategy=' | cut -d= -f2)
PHASE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^phase_branch_template=' | cut -d= -f2)
MILESTONE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^milestone_branch_template=' | cut -d= -f2)
```
When `PARALLELIZATION=false`, plans within a wave execute sequentially.
When `parallelization` is false, plans within a wave execute sequentially.
</step>
<step name="handle_branching">
Create or switch to branch based on `BRANCHING_STRATEGY`.
Check `branching_strategy` from init:
**"none":** Skip, continue on current branch.
**"phase":**
**"phase" or "milestone":** Use pre-computed `branch_name` from init:
```bash
PHASE_NAME=$(basename "$PHASE_DIR" | sed 's/^[0-9]*-//')
PHASE_SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$PHASE_NAME" --raw)
BRANCH_NAME=$(echo "$PHASE_BRANCH_TEMPLATE" | sed "s/{phase}/$PADDED_PHASE/g" | sed "s/{slug}/$PHASE_SLUG/g")
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
```
**"milestone":**
```bash
MILESTONE_VERSION=$(grep -oE 'v[0-9]+\.[0-9]+' .planning/ROADMAP.md | head -1 || echo "v1.0")
MILESTONE_NAME=$(grep -A1 "## .*$MILESTONE_VERSION" .planning/ROADMAP.md | tail -1 | sed 's/.*- //' | cut -d'(' -f1 | tr -d ' ' || echo "milestone")
MILESTONE_SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$MILESTONE_NAME" --raw)
BRANCH_NAME=$(echo "$MILESTONE_BRANCH_TEMPLATE" | sed "s/{milestone}/$MILESTONE_VERSION/g" | sed "s/{slug}/$MILESTONE_SLUG/g")
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
```
@@ -71,23 +42,9 @@ All subsequent commits go to this branch. User handles merging.
</step>
<step name="validate_phase">
From init JSON: `phase_dir`, `plan_count`, `incomplete_count`.
```bash
PHASE_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE_ARG}")
PHASE_DIR=$(echo "$PHASE_INFO" | grep -o '"directory":"[^"]*"' | cut -d'"' -f4)
if [ -z "$PHASE_DIR" ]; then
echo "ERROR: No phase directory matching '${PHASE_ARG}'"
exit 1
fi
PLAN_COUNT=$(ls -1 "$PHASE_DIR"/*-PLAN.md 2>/dev/null | wc -l | tr -d ' ')
if [ "$PLAN_COUNT" -eq 0 ]; then
echo "ERROR: No plans found in $PHASE_DIR"
exit 1
fi
```
Report: "Found {N} plans in {phase_dir}"
Report: "Found {plan_count} plans in {phase_dir} ({incomplete_count} incomplete)"
</step>
<step name="discover_plans">

View File

@@ -11,22 +11,21 @@ Read config.json for planning behavior settings.
<process>
<step name="resolve_model_profile" priority="first">
```bash
EXECUTOR_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-executor --raw)
```
</step>
<step name="init_context" priority="first">
Load execution context (uses `init execute-phase` for full context):
<step name="load_project_state">
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "${PHASE}")
```
Extract from init JSON: `executor_model`, `commit_docs`, `phase_dir`, `phase_number`, `plans`, `summaries`, `incomplete_plans`.
Also read STATE.md for current position, decisions, blockers:
```bash
cat .planning/STATE.md 2>/dev/null
```
Parse current position, decisions, blockers, alignment. If missing but .planning/ exists: offer reconstruct or continue. If .planning/ missing: error.
```bash
COMMIT_PLANNING_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
```
If `.planning/` missing: error.
</step>
<step name="identify_plan">

View File

@@ -44,19 +44,19 @@ fi
</step>
<step name="load_roadmap">
Load the roadmap file:
<step name="init_context">
Load phase operation context:
```bash
ROADMAP_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw)
if [ "$ROADMAP_EXISTS" = "true" ]; then
ROADMAP=".planning/ROADMAP.md"
else
echo "ERROR: No roadmap found (.planning/ROADMAP.md)"
exit 1
fi
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${after_phase}")
```
Check `roadmap_exists` from init JSON. If false:
```
ERROR: No roadmap found (.planning/ROADMAP.md)
```
Exit.
Read roadmap content for parsing.
</step>
@@ -94,8 +94,9 @@ Store as: `decimal_phase="$(printf "%02d" $after_phase).${next_decimal}"`
</step>
<step name="generate_slug">
Convert the phase description to a kebab-case slug:
Convert the phase description to a kebab-case slug.
Use `generate-slug` command (init phase-op provides `phase_slug` for existing phase, but this is a new phase):
```bash
slug=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$description" --raw)
```

View File

@@ -22,18 +22,22 @@ Documents are reference material for Claude when planning/executing. Always incl
<process>
<step name="resolve_model_profile" priority="first">
<step name="init_context" priority="first">
Load codebase mapping context:
```bash
MAPPER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-codebase-mapper --raw)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init map-codebase)
```
Extract from init JSON: `mapper_model`, `commit_docs`, `codebase_dir`, `existing_maps`, `has_maps`, `codebase_dir_exists`.
</step>
<step name="check_existing">
Check if .planning/codebase/ already exists:
Check if .planning/codebase/ already exists using `has_maps` from init context.
If `codebase_dir_exists` is true:
```bash
CODEBASE_MAP_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/codebase --raw)
[ "$CODEBASE_MAP_EXISTS" = "true" ] && ls -la .planning/codebase/
ls -la .planning/codebase/
```
**If exists:**

View File

@@ -74,14 +74,14 @@ Delete MILESTONE-CONTEXT.md if exists (consumed).
node ~/.claude/get-shit-done/bin/gsd-tools.js commit "docs: start milestone v[X.Y] [Name]" --files .planning/PROJECT.md .planning/STATE.md
```
## 7. Resolve Model Profile
## 7. Load Context and Resolve Models
```bash
RESEARCHER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-project-researcher --raw)
SYNTHESIZER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-research-synthesizer --raw)
ROADMAPPER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-roadmapper --raw)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init new-milestone)
```
Extract from init JSON: `researcher_model`, `synthesizer_model`, `roadmapper_model`, `commit_docs`, `research_enabled`, `current_milestone`, `project_exists`, `roadmap_exists`.
## 8. Research Decision
AskUserQuestion: "Research the domain ecosystem for new features before defining requirements?"

View File

@@ -12,39 +12,22 @@ Read all files referenced by the invoking prompt's execution_context before star
**MANDATORY FIRST STEP — Execute these checks before ANY user interaction:**
1. **Abort if project exists:**
```bash
PROJECT_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/PROJECT.md --raw)
[ "$PROJECT_EXISTS" = "true" ] && echo "ERROR: Project already initialized. Use /gsd:progress" && exit 1
```
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init new-project)
```
2. **Initialize git repo in THIS directory** (required even if inside a parent repo):
```bash
if [ -d .git ] || [ -f .git ]; then
echo "Git repo exists in current directory"
else
git init
echo "Initialized new git repo"
fi
```
Parse JSON for: `researcher_model`, `synthesizer_model`, `roadmapper_model`, `commit_docs`, `project_exists`, `has_codebase_map`, `planning_exists`, `has_existing_code`, `has_package_file`, `is_brownfield`, `needs_codebase_map`, `has_git`.
3. **Detect existing code (brownfield detection):**
```bash
CODE_FILES=$(find . -name "*.ts" -o -name "*.js" -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.swift" -o -name "*.java" 2>/dev/null | grep -v node_modules | grep -v .git | head -20)
HAS_PACKAGE=$([ -f package.json ] || [ -f requirements.txt ] || [ -f Cargo.toml ] || [ -f go.mod ] || [ -f Package.swift ] && echo "yes")
HAS_CODEBASE_MAP=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/codebase --raw)
[ "$HAS_CODEBASE_MAP" = "true" ] && HAS_CODEBASE_MAP="yes"
```
**If `project_exists` is true:** Error — project already initialized. Use `/gsd:progress`.
**You MUST run all bash commands above using the Bash tool before proceeding.**
**If `has_git` is false:** Initialize git:
```bash
git init
```
## 2. Brownfield Offer
**If existing code detected and .planning/codebase/ doesn't exist:**
Check the results from setup step:
- If `CODE_FILES` is non-empty OR `HAS_PACKAGE` is "yes"
- AND `HAS_CODEBASE_MAP` is NOT "yes"
**If `needs_codebase_map` is true** (from init — existing code detected but no codebase map):
Use AskUserQuestion:
- header: "Existing Code"
@@ -59,9 +42,7 @@ Run `/gsd:map-codebase` first, then return to `/gsd:new-project`
```
Exit command.
**If "Skip mapping":** Continue to Step 3.
**If no existing code detected OR codebase already mapped:** Continue to Step 3.
**If "Skip mapping" OR `needs_codebase_map` is false:** Continue to Step 3.
## 3. Deep Questioning
@@ -335,13 +316,7 @@ node ~/.claude/get-shit-done/bin/gsd-tools.js commit "chore: add project config"
## 5.5. Resolve Model Profile
Read model profile for agent spawning:
```bash
RESEARCHER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-project-researcher --raw)
SYNTHESIZER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-research-synthesizer --raw)
ROADMAPPER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-roadmapper --raw)
```
Use models from init: `researcher_model`, `synthesizer_model`, `roadmapper_model`.
## 6. Research Decision

View File

@@ -84,7 +84,7 @@ Start with: [specific first action when resuming]
Be specific enough for a fresh Claude to understand immediately.
Use `current-timestamp` for last_updated field:
Use `current-timestamp` for last_updated field. You can use init todos (which provides timestamps) or call directly:
```bash
timestamp=$(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp full --raw)
```

View File

@@ -10,22 +10,17 @@ Read all files referenced by the invoking prompt's execution_context before star
<process>
## 1. Validate Environment and Resolve Model Profile
## 1. Initialize
Load all context in one call:
```bash
PLANNING_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning --raw)
echo "$PLANNING_EXISTS"
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init plan-phase "$PHASE")
```
**If not found:** Error — run `/gsd:new-project` first.
Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_enabled`, `plan_checker_enabled`, `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `plan_count`, `planning_exists`, `roadmap_exists`.
**Resolve models:**
```bash
RESEARCHER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-phase-researcher --raw)
PLANNER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-planner --raw)
CHECKER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-plan-checker --raw)
```
**If `planning_exists` is false:** Error — run `/gsd:new-project` first.
## 2. Parse and Normalize Arguments
@@ -33,28 +28,12 @@ Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`-
**If no phase number:** Detect next unplanned phase from roadmap.
**Find phase directory:**
**If `phase_found` is false:** Validate phase exists in ROADMAP.md. If valid, create the directory using `phase_slug` and `padded_phase` from init:
```bash
PHASE_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE")
PHASE_DIR=$(echo "$PHASE_INFO" | grep -o '"directory":"[^"]*"' | cut -d'"' -f4)
mkdir -p ".planning/phases/${padded_phase}-${phase_slug}"
```
If `found` is false, validate phase exists in ROADMAP.md. If valid, create the directory:
```bash
PHASE_NAME=$(grep "Phase ${PHASE}:" .planning/ROADMAP.md | sed 's/.*Phase [0-9]*: //')
PHASE_SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$PHASE_NAME" --raw)
PADDED=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE" --raw | grep -o '^[0-9]*' || printf "%02d" "$PHASE")
mkdir -p ".planning/phases/${PADDED}-${PHASE_SLUG}"
PHASE_DIR=".planning/phases/${PADDED}-${PHASE_SLUG}"
```
**Check for existing research and plans:**
```bash
ls ${PHASE_DIR}/*-RESEARCH.md 2>/dev/null
ls ${PHASE_DIR}/*-PLAN.md 2>/dev/null
```
**Existing artifacts from init:** `has_research`, `has_plans`, `plan_count`.
## 3. Validate Phase
@@ -76,13 +55,9 @@ If CONTEXT.md exists, display: `Using phase context from: ${PHASE_DIR}/*-CONTEXT
## 5. Handle Research
**Skip if:** `--gaps` flag, `--skip-research` flag, or config `workflow.research=false` (without `--research` override).
**Skip if:** `--gaps` flag, `--skip-research` flag, or `research_enabled` is false (from init) without `--research` override.
```bash
WORKFLOW_RESEARCH=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^research=' | cut -d= -f2)
```
**If RESEARCH.md exists AND no `--research` flag:** Use existing, skip to step 6.
**If `has_research` is true (from init) AND no `--research` flag:** Use existing, skip to step 6.
**If RESEARCH.md missing OR `--research` flag:**
@@ -229,10 +204,7 @@ Task(
## 9. Handle Planner Return
- **`## PLANNING COMPLETE`:** Display plan count. If `--skip-verify` or config `workflow.plan_check=false`: skip to step 13. Otherwise: step 10.
```bash
WORKFLOW_PLAN_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^plan_checker=' | cut -d= -f2)
```
- **`## PLANNING COMPLETE`:** Display plan count. If `--skip-verify` or `plan_checker_enabled` is false (from init): skip to step 13. Otherwise: step 10.
- **`## CHECKPOINT REACHED`:** Present to user, get response, spawn continuation (step 12)
- **`## PLANNING INCONCLUSIVE`:** Show attempts, offer: Add context / Retry / Manual

View File

@@ -8,16 +8,16 @@ Read all files referenced by the invoking prompt's execution_context before star
<process>
<step name="verify">
**Verify planning structure exists:**
Use Bash (not Glob) to check—Glob respects .gitignore but .planning/ is often gitignored:
<step name="init_context">
**Load progress context:**
```bash
node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning --raw
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init progress)
```
If no `.planning/` directory:
Extract from init JSON: `project_exists`, `roadmap_exists`, `state_exists`, `phases`, `current_phase`, `next_phase`, `milestone_version`, `completed_count`, `phase_count`, `paused_at`.
If `project_exists` is false (no `.planning/` directory):
```
No planning structure found.
@@ -54,13 +54,13 @@ If missing both ROADMAP.md and PROJECT.md: suggest `/gsd:new-project`.
</step>
<step name="position">
**Parse current position:**
**Parse current position from init context:**
- From STATE.md: current phase, plan number, status
- Calculate: total plans, completed plans, remaining plans
- Note any blockers or concerns
- Use `current_phase` and `next_phase` from init for position
- Use `phases` array for plan counts per phase
- Note `paused_at` if work was paused
- Check for CONTEXT.md: For phases without PLAN.md files, check if `{phase}-CONTEXT.md` exists in phase directory
- Count pending todos: `node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos --raw`
- Count pending todos: use `init todos` or `list-todos`
- Check for active debug sessions: `ls .planning/debug/*.md 2>/dev/null | grep -v resolved | wc -l`
</step>

View File

@@ -7,35 +7,7 @@ Read all files referenced by the invoking prompt's execution_context before star
</required_reading>
<process>
**Step 0: Resolve Model Profile**
```bash
PLANNER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-planner --raw)
EXECUTOR_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-executor --raw)
```
---
**Step 1: Pre-flight validation**
Check that an active GSD project exists:
```bash
ROADMAP_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw)
if [ "$ROADMAP_EXISTS" != "true" ]; then
echo "Quick mode requires an active project with ROADMAP.md."
echo "Run /gsd:new-project first."
exit 1
fi
```
If validation fails, stop immediately with the error message.
Quick tasks can run mid-phase - validation only checks ROADMAP.md exists, not phase status.
---
**Step 2: Get task description**
**Step 1: Get task description**
Prompt user interactively for the task description:
@@ -51,29 +23,26 @@ Store response as `$DESCRIPTION`.
If empty, re-prompt: "Please provide a task description."
Generate slug from description:
---
**Step 2: Initialize**
```bash
slug=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$DESCRIPTION" --raw | cut -c1-40)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init quick "$DESCRIPTION")
```
Parse JSON for: `planner_model`, `executor_model`, `commit_docs`, `next_num`, `slug`, `date`, `timestamp`, `quick_dir`, `task_dir`, `roadmap_exists`, `planning_exists`.
**If `roadmap_exists` is false:** Error — Quick mode requires an active project with ROADMAP.md. Run `/gsd:new-project` first.
Quick tasks can run mid-phase - validation only checks ROADMAP.md exists, not phase status.
---
**Step 3: Calculate next quick task number**
Ensure `.planning/quick/` directory exists and find the next sequential number:
**Step 3: Create task directory**
```bash
# Ensure .planning/quick/ exists
mkdir -p .planning/quick
# Find highest existing number and increment
last=$(ls -1d .planning/quick/[0-9][0-9][0-9]-* 2>/dev/null | sort -r | head -1 | xargs -I{} basename {} | grep -oE '^[0-9]+')
if [ -z "$last" ]; then
next_num="001"
else
next_num=$(printf "%03d" $((10#$last + 1)))
fi
mkdir -p "${task_dir}"
```
---
@@ -199,15 +168,16 @@ Insert after `### Blockers/Concerns` section:
**7c. Append new row to table:**
Use `date` from init:
```markdown
| ${next_num} | ${DESCRIPTION} | $(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp date --raw) | ${commit_hash} | [${next_num}-${slug}](./quick/${next_num}-${slug}/) |
| ${next_num} | ${DESCRIPTION} | ${date} | ${commit_hash} | [${next_num}-${slug}](./quick/${next_num}-${slug}/) |
```
**7d. Update "Last activity" line:**
Find and update the line:
Use `date` from init:
```
Last activity: $(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp date --raw) - Completed quick task ${next_num}: ${DESCRIPTION}
Last activity: ${date} - Completed quick task ${next_num}: ${DESCRIPTION}
```
Use Edit tool to make these changes atomically

View File

@@ -25,15 +25,16 @@ Example: /gsd:remove-phase 17
Exit.
</step>
<step name="load_state">
Load project state:
<step name="init_context">
Load phase operation context:
```bash
cat .planning/STATE.md 2>/dev/null
cat .planning/ROADMAP.md 2>/dev/null
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${target}")
```
Parse current phase number from STATE.md "Current Position" section.
Extract: `phase_found`, `phase_dir`, `phase_number`, `commit_docs`, `roadmap_exists`.
Also read STATE.md and ROADMAP.md content for parsing current position.
</step>
<step name="validate_phase_exists">
@@ -132,17 +133,19 @@ Wait for confirmation.
</step>
<step name="delete_phase_directory">
Use the init context from earlier. The `phase_dir` from `init phase-op` provides the path.
Delete the target phase directory if it exists:
```bash
TARGET_PHASE_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists ".planning/phases/{target}-{slug}" --raw)
if [ "$TARGET_PHASE_EXISTS" = "true" ]; then
rm -rf ".planning/phases/{target}-{slug}"
echo "Deleted: .planning/phases/{target}-{slug}/"
# phase_dir from init phase-op contains the path if found
if [ -n "$phase_dir" ]; then
rm -rf "$phase_dir"
echo "Deleted: $phase_dir/"
fi
```
If directory doesn't exist, note: "No directory to delete (phase not yet created)"
If directory doesn't exist (`phase_found=false` from init), note: "No directory to delete (phase not yet created)"
</step>
<step name="renumber_directories">

View File

@@ -16,21 +16,18 @@ Instantly restore full project context so "Where were we?" has an immediate, com
<process>
<step name="detect_existing_project">
Check if this is an existing project:
<step name="initialize">
Load all context in one call:
```bash
STATE_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/STATE.md --raw)
ROADMAP_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw)
PROJECT_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/PROJECT.md --raw)
[ "$STATE_EXISTS" = "true" ] && echo "Project exists"
[ "$ROADMAP_EXISTS" = "true" ] && echo "Roadmap exists"
[ "$PROJECT_EXISTS" = "true" ] && echo "Project file exists"
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init resume)
```
**If STATE.md exists:** Proceed to load_state
**If only ROADMAP.md/PROJECT.md exist:** Offer to reconstruct STATE.md
**If .planning/ doesn't exist:** This is a new project - route to /gsd:new-project
Parse JSON for: `state_exists`, `roadmap_exists`, `project_exists`, `planning_exists`, `has_interrupted_agent`, `interrupted_agent_id`, `commit_docs`.
**If `state_exists` is true:** Proceed to load_state
**If `state_exists` is false but `roadmap_exists` or `project_exists` is true:** Offer to reconstruct STATE.md
**If `planning_exists` is false:** This is a new project - route to /gsd:new-project
</step>
<step name="load_state">
@@ -74,11 +71,9 @@ for plan in .planning/phases/*/*-PLAN.md; do
[ ! -f "$summary" ] && echo "Incomplete: $plan"
done 2>/dev/null
# Check for interrupted agents
AGENT_FILE_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/current-agent-id.txt --raw)
if [ "$AGENT_FILE_EXISTS" = "true" ] && [ -s .planning/current-agent-id.txt ]; then
AGENT_ID=$(cat .planning/current-agent-id.txt | tr -d '\n')
echo "Interrupted agent: $AGENT_ID"
# Check for interrupted agents (use has_interrupted_agent and interrupted_agent_id from init)
if [ "$has_interrupted_agent" = "true" ]; then
echo "Interrupted agent: $interrupted_agent_id"
fi
```

View File

@@ -19,19 +19,19 @@ if $ARGUMENTS.profile not in ["quality", "balanced", "budget"]:
```
</step>
<step name="ensure_config">
<step name="ensure_and_load_config">
Ensure config exists and load current state:
```bash
node ~/.claude/get-shit-done/bin/gsd-tools.js config-ensure-section
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
```
Creates `.planning/config.json` with defaults if missing.
This creates `.planning/config.json` with defaults if missing and loads current config.
</step>
<step name="update_config">
Read current config:
```bash
cat .planning/config.json
```
Read current config from state load or directly:
Update `model_profile` field:
```json

View File

@@ -8,12 +8,15 @@ Read all files referenced by the invoking prompt's execution_context before star
<process>
<step name="ensure_config">
<step name="ensure_and_load_config">
Ensure config exists and load current state:
```bash
node ~/.claude/get-shit-done/bin/gsd-tools.js config-ensure-section
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
```
Creates `.planning/config.json` with defaults if missing.
Creates `.planning/config.json` with defaults if missing and loads current config values.
</step>
<step name="read_current">

View File

@@ -25,12 +25,19 @@ Then verify each level against the actual codebase.
<process>
<step name="load_context" priority="first">
```bash
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE_ARG}" --raw)
Load phase operation context:
grep -A 5 "Phase ${PHASE_NUM}" .planning/ROADMAP.md
grep -E "^| ${PHASE_NUM}" .planning/REQUIREMENTS.md 2>/dev/null
ls "$PHASE_DIR"/*-SUMMARY.md "$PHASE_DIR"/*-PLAN.md 2>/dev/null
```bash
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${PHASE_ARG}")
```
Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`, `has_plans`, `plan_count`.
Then load phase details and list plans/summaries:
```bash
grep -A 5 "Phase ${phase_number}" .planning/ROADMAP.md
grep -E "^| ${phase_number}" .planning/REQUIREMENTS.md 2>/dev/null
ls "$phase_dir"/*-SUMMARY.md "$phase_dir"/*-PLAN.md 2>/dev/null
```
Extract **phase goal** from ROADMAP.md (the outcome to verify, not tasks) and **requirements** from REQUIREMENTS.md if it exists.

View File

@@ -20,11 +20,14 @@ No Pass/Fail buttons. No severity questions. Just: "Here's what should happen. D
<process>
<step name="resolve_model_profile" priority="first">
<step name="initialize" priority="first">
If $ARGUMENTS contains a phase number, load context:
```bash
PLANNER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-planner --raw)
CHECKER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-plan-checker --raw)
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init verify-work "${PHASE_ARG}")
```
Parse JSON for: `planner_model`, `checker_model`, `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `has_verification`.
</step>
<step name="check_active_session">
@@ -77,13 +80,10 @@ Continue to `create_uat_file`.
<step name="find_summaries">
**Find what to test:**
Parse $ARGUMENTS as phase number (e.g., "4") or plan number (e.g., "04-02").
Use `phase_dir` from init (or run init if not already done).
```bash
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE_ARG}" --raw)
# Find SUMMARY files
ls "$PHASE_DIR"/*-SUMMARY.md 2>/dev/null
ls "$phase_dir"/*-SUMMARY.md 2>/dev/null
```
Read each SUMMARY.md to extract testable deliverables.