get-shit-done-cc 1.22.2 → 1.22.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +2 -2
  2. package/agents/gsd-debugger.md +1 -0
  3. package/agents/gsd-executor.md +1 -0
  4. package/agents/gsd-nyquist-auditor.md +178 -0
  5. package/agents/gsd-phase-researcher.md +4 -3
  6. package/agents/gsd-plan-checker.md +15 -1
  7. package/agents/gsd-planner.md +8 -7
  8. package/agents/gsd-roadmapper.md +12 -12
  9. package/bin/install.js +67 -4
  10. package/commands/gsd/debug.md +1 -0
  11. package/commands/gsd/quick.md +6 -2
  12. package/commands/gsd/research-phase.md +1 -0
  13. package/commands/gsd/validate-phase.md +35 -0
  14. package/get-shit-done/bin/lib/config.cjs +8 -1
  15. package/get-shit-done/bin/lib/core.cjs +10 -1
  16. package/get-shit-done/bin/lib/verify.cjs +47 -0
  17. package/get-shit-done/references/model-profiles.md +1 -0
  18. package/get-shit-done/references/planning-config.md +4 -0
  19. package/get-shit-done/templates/config.json +2 -2
  20. package/get-shit-done/templates/roadmap.md +1 -1
  21. package/get-shit-done/workflows/add-phase.md +1 -0
  22. package/get-shit-done/workflows/add-tests.md +1 -0
  23. package/get-shit-done/workflows/add-todo.md +1 -0
  24. package/get-shit-done/workflows/audit-milestone.md +35 -0
  25. package/get-shit-done/workflows/check-todos.md +1 -0
  26. package/get-shit-done/workflows/complete-milestone.md +1 -0
  27. package/get-shit-done/workflows/discuss-phase.md +1 -0
  28. package/get-shit-done/workflows/execute-phase.md +1 -0
  29. package/get-shit-done/workflows/execute-plan.md +1 -0
  30. package/get-shit-done/workflows/health.md +3 -0
  31. package/get-shit-done/workflows/insert-phase.md +1 -0
  32. package/get-shit-done/workflows/map-codebase.md +1 -0
  33. package/get-shit-done/workflows/new-milestone.md +1 -0
  34. package/get-shit-done/workflows/new-project.md +19 -16
  35. package/get-shit-done/workflows/plan-phase.md +26 -14
  36. package/get-shit-done/workflows/progress.md +1 -0
  37. package/get-shit-done/workflows/quick.md +152 -4
  38. package/get-shit-done/workflows/remove-phase.md +1 -0
  39. package/get-shit-done/workflows/research-phase.md +1 -0
  40. package/get-shit-done/workflows/resume-project.md +1 -0
  41. package/get-shit-done/workflows/set-profile.md +1 -0
  42. package/get-shit-done/workflows/settings.md +3 -2
  43. package/get-shit-done/workflows/validate-phase.md +167 -0
  44. package/get-shit-done/workflows/verify-phase.md +1 -0
  45. package/get-shit-done/workflows/verify-work.md +14 -0
  46. package/package.json +1 -1
package/README.md CHANGED
@@ -516,7 +516,7 @@ You're never locked in. The system adapts.
516
516
  | `/gsd:add-todo [desc]` | Capture idea for later |
517
517
  | `/gsd:check-todos` | List pending todos |
518
518
  | `/gsd:debug [desc]` | Systematic debugging with persistent state |
519
- | `/gsd:quick [--full]` | Execute ad-hoc task with GSD guarantees (`--full` adds plan-checking and verification) |
519
+ | `/gsd:quick [--full] [--discuss]` | Execute ad-hoc task with GSD guarantees (`--full` adds plan-checking and verification, `--discuss` gathers context first) |
520
520
  | `/gsd:health [--repair]` | Validate `.planning/` directory integrity, auto-repair with `--repair` |
521
521
 
522
522
  <sup>¹ Contributed by reddit user OracleGreyBeard</sup>
@@ -532,7 +532,7 @@ GSD stores project settings in `.planning/config.json`. Configure during `/gsd:n
532
532
  | Setting | Options | Default | What it controls |
533
533
  |---------|---------|---------|------------------|
534
534
  | `mode` | `yolo`, `interactive` | `interactive` | Auto-approve vs confirm at each step |
535
- | `depth` | `quick`, `standard`, `comprehensive` | `standard` | Planning thoroughness (phases × plans) |
535
+ | `granularity` | `coarse`, `standard`, `fine` | `standard` | Phase granularity — how finely scope is sliced (phases × plans) |
536
536
 
537
537
  ### Model Profiles
538
538
 
@@ -1038,6 +1038,7 @@ mv .planning/debug/{slug}.md .planning/debug/resolved/
1038
1038
 
1039
1039
  ```bash
1040
1040
  INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" state load)
1041
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
1041
1042
  # commit_docs is in the JSON output
1042
1043
  ```
1043
1044
 
@@ -46,6 +46,7 @@ Load execution context:
46
46
 
47
47
  ```bash
48
48
  INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init execute-phase "${PHASE}")
49
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
49
50
  ```
50
51
 
51
52
  Extract from init JSON: `executor_model`, `commit_docs`, `phase_dir`, `plans`, `incomplete_plans`.
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: gsd-nyquist-auditor
3
+ description: Fills Nyquist validation gaps by generating tests and verifying coverage for phase requirements
4
+ tools:
5
+ - Read
6
+ - Write
7
+ - Edit
8
+ - Bash
9
+ - Glob
10
+ - Grep
11
+ color: "#8B5CF6"
12
+ skills:
13
+ - gsd-nyquist-auditor-workflow
14
+ ---
15
+
16
+ <role>
17
+ GSD Nyquist auditor. Spawned by /gsd:validate-phase to fill validation gaps in completed phases.
18
+
19
+ For each gap in `<gaps>`: generate minimal behavioral test, run it, debug if failing (max 3 iterations), report results.
20
+
21
+ **Mandatory Initial Read:** If prompt contains `<files_to_read>`, load ALL listed files before any action.
22
+
23
+ **Implementation files are READ-ONLY.** Only create/modify: test files, fixtures, VALIDATION.md. Implementation bugs → ESCALATE. Never fix implementation.
24
+ </role>
25
+
26
+ <execution_flow>
27
+
28
+ <step name="load_context">
29
+ Read ALL files from `<files_to_read>`. Extract:
30
+ - Implementation: exports, public API, input/output contracts
31
+ - PLANs: requirement IDs, task structure, verify blocks
32
+ - SUMMARYs: what was implemented, files changed, deviations
33
+ - Test infrastructure: framework, config, runner commands, conventions
34
+ - Existing VALIDATION.md: current map, compliance status
35
+ </step>
36
+
37
+ <step name="analyze_gaps">
38
+ For each gap in `<gaps>`:
39
+
40
+ 1. Read related implementation files
41
+ 2. Identify observable behavior the requirement demands
42
+ 3. Classify test type:
43
+
44
+ | Behavior | Test Type |
45
+ |----------|-----------|
46
+ | Pure function I/O | Unit |
47
+ | API endpoint | Integration |
48
+ | CLI command | Smoke |
49
+ | DB/filesystem operation | Integration |
50
+
51
+ 4. Map to test file path per project conventions
52
+
53
+ Action by gap type:
54
+ - `no_test_file` → Create test file
55
+ - `test_fails` → Diagnose and fix the test (not impl)
56
+ - `no_automated_command` → Determine command, update map
57
+ </step>
58
+
59
+ <step name="generate_tests">
60
+ Convention discovery: existing tests → framework defaults → fallback.
61
+
62
+ | Framework | File Pattern | Runner | Assert Style |
63
+ |-----------|-------------|--------|--------------|
64
+ | pytest | `test_{name}.py` | `pytest {file} -v` | `assert result == expected` |
65
+ | jest | `{name}.test.ts` | `npx jest {file}` | `expect(result).toBe(expected)` |
66
+ | vitest | `{name}.test.ts` | `npx vitest run {file}` | `expect(result).toBe(expected)` |
67
+ | go test | `{name}_test.go` | `go test -v -run {Name}` | `if got != want { t.Errorf(...) }` |
68
+
69
+ Per gap: Write test file. One focused test per requirement behavior. Arrange/Act/Assert. Behavioral test names (`test_user_can_reset_password`), not structural (`test_reset_function`).
70
+ </step>
71
+
72
+ <step name="run_and_verify">
73
+ Execute each test. If passes: record success, next gap. If fails: enter debug loop.
74
+
75
+ Run every test. Never mark untested tests as passing.
76
+ </step>
77
+
78
+ <step name="debug_loop">
79
+ Max 3 iterations per failing test.
80
+
81
+ | Failure Type | Action |
82
+ |--------------|--------|
83
+ | Import/syntax/fixture error | Fix test, re-run |
84
+ | Assertion: actual matches impl but violates requirement | IMPLEMENTATION BUG → ESCALATE |
85
+ | Assertion: test expectation wrong | Fix assertion, re-run |
86
+ | Environment/runtime error | ESCALATE |
87
+
88
+ Track: `{ gap_id, iteration, error_type, action, result }`
89
+
90
+ After 3 failed iterations: ESCALATE with requirement, expected vs actual behavior, impl file reference.
91
+ </step>
92
+
93
+ <step name="report">
94
+ Resolved gaps: `{ task_id, requirement, test_type, automated_command, file_path, status: "green" }`
95
+ Escalated gaps: `{ task_id, requirement, reason, debug_iterations, last_error }`
96
+
97
+ Return one of three formats below.
98
+ </step>
99
+
100
+ </execution_flow>
101
+
102
+ <structured_returns>
103
+
104
+ ## GAPS FILLED
105
+
106
+ ```markdown
107
+ ## GAPS FILLED
108
+
109
+ **Phase:** {N} — {name}
110
+ **Resolved:** {count}/{count}
111
+
112
+ ### Tests Created
113
+ | # | File | Type | Command |
114
+ |---|------|------|---------|
115
+ | 1 | {path} | {unit/integration/smoke} | `{cmd}` |
116
+
117
+ ### Verification Map Updates
118
+ | Task ID | Requirement | Command | Status |
119
+ |---------|-------------|---------|--------|
120
+ | {id} | {req} | `{cmd}` | green |
121
+
122
+ ### Files for Commit
123
+ {test file paths}
124
+ ```
125
+
126
+ ## PARTIAL
127
+
128
+ ```markdown
129
+ ## PARTIAL
130
+
131
+ **Phase:** {N} — {name}
132
+ **Resolved:** {M}/{total} | **Escalated:** {K}/{total}
133
+
134
+ ### Resolved
135
+ | Task ID | Requirement | File | Command | Status |
136
+ |---------|-------------|------|---------|--------|
137
+ | {id} | {req} | {file} | `{cmd}` | green |
138
+
139
+ ### Escalated
140
+ | Task ID | Requirement | Reason | Iterations |
141
+ |---------|-------------|--------|------------|
142
+ | {id} | {req} | {reason} | {N}/3 |
143
+
144
+ ### Files for Commit
145
+ {test file paths for resolved gaps}
146
+ ```
147
+
148
+ ## ESCALATE
149
+
150
+ ```markdown
151
+ ## ESCALATE
152
+
153
+ **Phase:** {N} — {name}
154
+ **Resolved:** 0/{total}
155
+
156
+ ### Details
157
+ | Task ID | Requirement | Reason | Iterations |
158
+ |---------|-------------|--------|------------|
159
+ | {id} | {req} | {reason} | {N}/3 |
160
+
161
+ ### Recommendations
162
+ - **{req}:** {manual test instructions or implementation fix needed}
163
+ ```
164
+
165
+ </structured_returns>
166
+
167
+ <success_criteria>
168
+ - [ ] All `<files_to_read>` loaded before any action
169
+ - [ ] Each gap analyzed with correct test type
170
+ - [ ] Tests follow project conventions
171
+ - [ ] Tests verify behavior, not structure
172
+ - [ ] Every test executed — none marked passing without running
173
+ - [ ] Implementation files never modified
174
+ - [ ] Max 3 debug iterations per gap
175
+ - [ ] Implementation bugs escalated, not fixed
176
+ - [ ] Structured return provided (GAPS FILLED / PARTIAL / ESCALATE)
177
+ - [ ] Test files listed for commit
178
+ </success_criteria>
@@ -306,7 +306,7 @@ Verified patterns from official sources:
306
306
 
307
307
  ## Validation Architecture
308
308
 
309
- > Skip this section entirely if workflow.nyquist_validation is false in .planning/config.json
309
+ > Skip this section entirely if workflow.nyquist_validation is explicitly set to false in .planning/config.json. If the key is absent, treat as enabled.
310
310
 
311
311
  ### Test Framework
312
312
  | Property | Value |
@@ -368,11 +368,12 @@ Orchestrator provides: phase number/name, description/goal, requirements, constr
368
368
  Load phase context using init command:
369
369
  ```bash
370
370
  INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHASE}")
371
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
371
372
  ```
372
373
 
373
374
  Extract from init JSON: `phase_dir`, `padded_phase`, `phase_number`, `commit_docs`.
374
375
 
375
- Also read `.planning/config.json` — if `workflow.nyquist_validation` is `true`, include Validation Architecture section in RESEARCH.md. If `false`, skip it.
376
+ Also read `.planning/config.json` — include Validation Architecture section in RESEARCH.md unless `workflow.nyquist_validation` is explicitly `false`. If the key is absent or `true`, include the section.
376
377
 
377
378
  Then read CONTEXT.md if exists:
378
379
  ```bash
@@ -408,7 +409,7 @@ For each domain: Context7 first → Official docs → WebSearch → Cross-verify
408
409
 
409
410
  ## Step 4: Validation Architecture Research (if nyquist_validation enabled)
410
411
 
411
- **Skip if** workflow.nyquist_validation is false.
412
+ **Skip if** workflow.nyquist_validation is explicitly set to false. If absent, treat as enabled.
412
413
 
413
414
  ### Detect Test Infrastructure
414
415
  Scan for: test config files (pytest.ini, jest.config.*, vitest.config.*), test directories (test/, tests/, __tests__/), test files (*.test.*, *.spec.*), package.json test scripts.
@@ -316,7 +316,20 @@ issue:
316
316
 
317
317
  ## Dimension 8: Nyquist Compliance
318
318
 
319
- Skip if: `workflow.nyquist_validation` is false, phase has no RESEARCH.md, or RESEARCH.md has no "Validation Architecture" section. Output: "Dimension 8: SKIPPED (nyquist_validation disabled or not applicable)"
319
+ Skip if: `workflow.nyquist_validation` is explicitly set to `false` in config.json (absent key = enabled), phase has no RESEARCH.md, or RESEARCH.md has no "Validation Architecture" section. Output: "Dimension 8: SKIPPED (nyquist_validation disabled or not applicable)"
320
+
321
+ ### Check 8e — VALIDATION.md Existence (Gate)
322
+
323
+ Before running checks 8a-8d, verify VALIDATION.md exists:
324
+
325
+ ```bash
326
+ ls "${PHASE_DIR}"/*-VALIDATION.md 2>/dev/null
327
+ ```
328
+
329
+ **If missing:** **BLOCKING FAIL** — "VALIDATION.md not found for phase {N}. Re-run `/gsd:plan-phase {N} --research` to regenerate."
330
+ Skip checks 8a-8d entirely. Report Dimension 8 as FAIL with this single issue.
331
+
332
+ **If exists:** Proceed to checks 8a-8d.
320
333
 
321
334
  ### Check 8a — Automated Verify Presence
322
335
 
@@ -368,6 +381,7 @@ If FAIL: return to planner with specific fixes. Same revision loop as other dime
368
381
  Load phase operation context:
369
382
  ```bash
370
383
  INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHASE_ARG}")
384
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
371
385
  ```
372
386
 
373
387
  Extract from init JSON: `phase_dir`, `phase_number`, `has_plans`, `plan_count`.
@@ -371,15 +371,15 @@ Plans should complete within ~50% context (not 80%). No context anxiety, quality
371
371
 
372
372
  **CONSIDER splitting:** >5 files total, complex domains, uncertainty about approach, natural semantic boundaries.
373
373
 
374
- ## Depth Calibration
374
+ ## Granularity Calibration
375
375
 
376
- | Depth | Typical Plans/Phase | Tasks/Plan |
377
- |-------|---------------------|------------|
378
- | Quick | 1-3 | 2-3 |
376
+ | Granularity | Typical Plans/Phase | Tasks/Plan |
377
+ |-------------|---------------------|------------|
378
+ | Coarse | 1-3 | 2-3 |
379
379
  | Standard | 3-5 | 2-3 |
380
- | Comprehensive | 5-10 | 2-3 |
380
+ | Fine | 5-10 | 2-3 |
381
381
 
382
- Derive plans from actual work. Depth determines compression tolerance, not a target. Don't pad small work to hit a number. Don't compress complex work to look efficient.
382
+ Derive plans from actual work. Granularity determines compression tolerance, not a target. Don't pad small work to hit a number. Don't compress complex work to look efficient.
383
383
 
384
384
  ## Context Per Task Estimates
385
385
 
@@ -973,6 +973,7 @@ Load planning context:
973
973
 
974
974
  ```bash
975
975
  INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init plan-phase "${PHASE}")
976
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
976
977
  ```
977
978
 
978
979
  Extract from init JSON: `planner_model`, `researcher_model`, `checker_model`, `commit_docs`, `research_enabled`, `phase_dir`, `phase_number`, `has_research`, `has_context`.
@@ -1135,7 +1136,7 @@ Apply goal-backward methodology (see goal_backward section):
1135
1136
  </step>
1136
1137
 
1137
1138
  <step name="estimate_scope">
1138
- Verify each plan fits context budget: 2-3 tasks, ~50% target. Split if necessary. Check depth setting.
1139
+ Verify each plan fits context budget: 2-3 tasks, ~50% target. Split if necessary. Check granularity setting.
1139
1140
  </step>
1140
1141
 
1141
1142
  <step name="confirm_breakdown">
@@ -200,17 +200,17 @@ Track coverage as you go.
200
200
  - New milestone: Start at 1
201
201
  - Continuing milestone: Check existing phases, start at last + 1
202
202
 
203
- ## Depth Calibration
203
+ ## Granularity Calibration
204
204
 
205
- Read depth from config.json. Depth controls compression tolerance.
205
+ Read granularity from config.json. Granularity controls compression tolerance.
206
206
 
207
- | Depth | Typical Phases | What It Means |
208
- |-------|----------------|---------------|
209
- | Quick | 3-5 | Combine aggressively, critical path only |
207
+ | Granularity | Typical Phases | What It Means |
208
+ |-------------|----------------|---------------|
209
+ | Coarse | 3-5 | Combine aggressively, critical path only |
210
210
  | Standard | 5-8 | Balanced grouping |
211
- | Comprehensive | 8-12 | Let natural boundaries stand |
211
+ | Fine | 8-12 | Let natural boundaries stand |
212
212
 
213
- **Key:** Derive phases from work, then apply depth as compression guidance. Don't pad small projects or compress complex ones.
213
+ **Key:** Derive phases from work, then apply granularity as compression guidance. Don't pad small projects or compress complex ones.
214
214
 
215
215
  ## Good Phase Patterns
216
216
 
@@ -357,7 +357,7 @@ When presenting to user for approval:
357
357
  ## ROADMAP DRAFT
358
358
 
359
359
  **Phases:** [N]
360
- **Depth:** [from config]
360
+ **Granularity:** [from config]
361
361
  **Coverage:** [X]/[Y] requirements mapped
362
362
 
363
363
  ### Phase Structure
@@ -401,7 +401,7 @@ Orchestrator provides:
401
401
  - PROJECT.md content (core value, constraints)
402
402
  - REQUIREMENTS.md content (v1 requirements with REQ-IDs)
403
403
  - research/SUMMARY.md content (if exists - phase suggestions)
404
- - config.json (depth setting)
404
+ - config.json (granularity setting)
405
405
 
406
406
  Parse and confirm understanding before proceeding.
407
407
 
@@ -437,7 +437,7 @@ Apply phase identification methodology:
437
437
  1. Group requirements by natural delivery boundaries
438
438
  2. Identify dependencies between groups
439
439
  3. Create phases that complete coherent capabilities
440
- 4. Check depth setting for compression guidance
440
+ 4. Check granularity setting for compression guidance
441
441
 
442
442
  ## Step 5: Derive Success Criteria
443
443
 
@@ -502,7 +502,7 @@ When files are written and returning to orchestrator:
502
502
  ### Summary
503
503
 
504
504
  **Phases:** {N}
505
- **Depth:** {from config}
505
+ **Granularity:** {from config}
506
506
  **Coverage:** {X}/{X} requirements mapped ✓
507
507
 
508
508
  | Phase | Goal | Requirements |
@@ -628,7 +628,7 @@ Roadmap is complete when:
628
628
  - [ ] All v1 requirements extracted with IDs
629
629
  - [ ] Research context loaded (if exists)
630
630
  - [ ] Phases derived from requirements (not imposed)
631
- - [ ] Depth calibration applied
631
+ - [ ] Granularity calibration applied
632
632
  - [ ] Dependencies between phases identified
633
633
  - [ ] Success criteria derived for each phase (2-5 observable behaviors)
634
634
  - [ ] Success criteria cross-checked against requirements (gaps resolved)
package/bin/install.js CHANGED
@@ -58,6 +58,21 @@ if (hasAll) {
58
58
  if (hasCodex) selectedRuntimes.push('codex');
59
59
  }
60
60
 
61
+ /**
62
+ * Convert a pathPrefix (which uses absolute paths for global installs) to a
63
+ * $HOME-relative form for replacing $HOME/.claude/ references in bash code blocks.
64
+ * Preserves $HOME as a shell variable so paths remain portable across machines.
65
+ */
66
+ function toHomePrefix(pathPrefix) {
67
+ const home = os.homedir().replace(/\\/g, '/');
68
+ const normalized = pathPrefix.replace(/\\/g, '/');
69
+ if (normalized.startsWith(home)) {
70
+ return '$HOME' + normalized.slice(home.length);
71
+ }
72
+ // For relative paths or paths not under $HOME, return as-is
73
+ return normalized;
74
+ }
75
+
61
76
  // Helper to get directory name for a runtime (used for local/project installs)
62
77
  function getDirName(runtime) {
63
78
  if (runtime === 'opencode') return '.opencode';
@@ -700,8 +715,14 @@ function installCodexConfig(targetDir, agentsSrc) {
700
715
  const agentEntries = fs.readdirSync(agentsSrc).filter(f => f.startsWith('gsd-') && f.endsWith('.md'));
701
716
  const agents = [];
702
717
 
718
+ // Compute the Codex pathPrefix for replacing .claude paths
719
+ const codexPathPrefix = `${targetDir.replace(/\\/g, '/')}/`;
720
+
703
721
  for (const file of agentEntries) {
704
- const content = fs.readFileSync(path.join(agentsSrc, file), 'utf8');
722
+ let content = fs.readFileSync(path.join(agentsSrc, file), 'utf8');
723
+ // Replace .claude paths before generating TOML (source files use ~/.claude and $HOME/.claude)
724
+ content = content.replace(/~\/\.claude\//g, codexPathPrefix);
725
+ content = content.replace(/\$HOME\/\.claude\//g, toHomePrefix(codexPathPrefix));
705
726
  const { frontmatter } = extractFrontmatterAndBody(content);
706
727
  const name = extractFrontmatterField(frontmatter, 'name') || file.replace('.md', '');
707
728
  const description = extractFrontmatterField(frontmatter, 'description') || '';
@@ -823,8 +844,9 @@ function convertClaudeToOpencodeFrontmatter(content) {
823
844
  convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite');
824
845
  // Replace /gsd:command with /gsd-command for opencode (flat command structure)
825
846
  convertedContent = convertedContent.replace(/\/gsd:/g, '/gsd-');
826
- // Replace ~/.claude with ~/.config/opencode (OpenCode's correct config location)
847
+ // Replace ~/.claude and $HOME/.claude with OpenCode's config location
827
848
  convertedContent = convertedContent.replace(/~\/\.claude\b/g, '~/.config/opencode');
849
+ convertedContent = convertedContent.replace(/\$HOME\/\.claude\b/g, '$HOME/.config/opencode');
828
850
  // Replace general-purpose subagent type with OpenCode's equivalent "general"
829
851
  convertedContent = convertedContent.replace(/subagent_type="general-purpose"/g, 'subagent_type="general"');
830
852
 
@@ -1006,9 +1028,11 @@ function copyFlattenedCommands(srcDir, destDir, prefix, pathPrefix, runtime) {
1006
1028
 
1007
1029
  let content = fs.readFileSync(srcPath, 'utf8');
1008
1030
  const globalClaudeRegex = /~\/\.claude\//g;
1031
+ const globalClaudeHomeRegex = /\$HOME\/\.claude\//g;
1009
1032
  const localClaudeRegex = /\.\/\.claude\//g;
1010
1033
  const opencodeDirRegex = /~\/\.opencode\//g;
1011
1034
  content = content.replace(globalClaudeRegex, pathPrefix);
1035
+ content = content.replace(globalClaudeHomeRegex, toHomePrefix(pathPrefix));
1012
1036
  content = content.replace(localClaudeRegex, `./${getDirName(runtime)}/`);
1013
1037
  content = content.replace(opencodeDirRegex, pathPrefix);
1014
1038
  content = processAttribution(content, getCommitAttribution(runtime));
@@ -1065,9 +1089,11 @@ function copyCommandsAsCodexSkills(srcDir, skillsDir, prefix, pathPrefix, runtim
1065
1089
 
1066
1090
  let content = fs.readFileSync(srcPath, 'utf8');
1067
1091
  const globalClaudeRegex = /~\/\.claude\//g;
1092
+ const globalClaudeHomeRegex = /\$HOME\/\.claude\//g;
1068
1093
  const localClaudeRegex = /\.\/\.claude\//g;
1069
1094
  const codexDirRegex = /~\/\.codex\//g;
1070
1095
  content = content.replace(globalClaudeRegex, pathPrefix);
1096
+ content = content.replace(globalClaudeHomeRegex, toHomePrefix(pathPrefix));
1071
1097
  content = content.replace(localClaudeRegex, `./${getDirName(runtime)}/`);
1072
1098
  content = content.replace(codexDirRegex, pathPrefix);
1073
1099
  content = processAttribution(content, getCommitAttribution(runtime));
@@ -1108,11 +1134,13 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand
1108
1134
  if (entry.isDirectory()) {
1109
1135
  copyWithPathReplacement(srcPath, destPath, pathPrefix, runtime, isCommand);
1110
1136
  } else if (entry.name.endsWith('.md')) {
1111
- // Replace ~/.claude/ and ./.claude/ with runtime-appropriate paths
1137
+ // Replace ~/.claude/ and $HOME/.claude/ and ./.claude/ with runtime-appropriate paths
1112
1138
  let content = fs.readFileSync(srcPath, 'utf8');
1113
1139
  const globalClaudeRegex = /~\/\.claude\//g;
1140
+ const globalClaudeHomeRegex = /\$HOME\/\.claude\//g;
1114
1141
  const localClaudeRegex = /\.\/\.claude\//g;
1115
1142
  content = content.replace(globalClaudeRegex, pathPrefix);
1143
+ content = content.replace(globalClaudeHomeRegex, toHomePrefix(pathPrefix));
1116
1144
  content = content.replace(localClaudeRegex, `./${dirName}/`);
1117
1145
  content = processAttribution(content, getCommitAttribution(runtime));
1118
1146
 
@@ -1953,9 +1981,11 @@ function install(isGlobal, runtime = 'claude') {
1953
1981
  for (const entry of agentEntries) {
1954
1982
  if (entry.isFile() && entry.name.endsWith('.md')) {
1955
1983
  let content = fs.readFileSync(path.join(agentsSrc, entry.name), 'utf8');
1956
- // Always replace ~/.claude/ as it is the source of truth in the repo
1984
+ // Replace ~/.claude/ and $HOME/.claude/ as they are the source of truth in the repo
1957
1985
  const dirRegex = /~\/\.claude\//g;
1986
+ const homeDirRegex = /\$HOME\/\.claude\//g;
1958
1987
  content = content.replace(dirRegex, pathPrefix);
1988
+ content = content.replace(homeDirRegex, toHomePrefix(pathPrefix));
1959
1989
  content = processAttribution(content, getCommitAttribution(runtime));
1960
1990
  // Convert frontmatter for runtime compatibility
1961
1991
  if (isOpencode) {
@@ -2046,6 +2076,39 @@ function install(isGlobal, runtime = 'claude') {
2046
2076
  // Report any backed-up local patches
2047
2077
  reportLocalPatches(targetDir, runtime);
2048
2078
 
2079
+ // Verify no leaked .claude paths in non-Claude runtimes
2080
+ if (runtime !== 'claude') {
2081
+ const leakedPaths = [];
2082
+ function scanForLeakedPaths(dir) {
2083
+ if (!fs.existsSync(dir)) return;
2084
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
2085
+ for (const entry of entries) {
2086
+ const fullPath = path.join(dir, entry.name);
2087
+ if (entry.isDirectory()) {
2088
+ scanForLeakedPaths(fullPath);
2089
+ } else if ((entry.name.endsWith('.md') || entry.name.endsWith('.toml')) && entry.name !== 'CHANGELOG.md') {
2090
+ const content = fs.readFileSync(fullPath, 'utf8');
2091
+ const matches = content.match(/(?:~|\$HOME)\/\.claude\b/g);
2092
+ if (matches) {
2093
+ leakedPaths.push({ file: fullPath.replace(targetDir + '/', ''), count: matches.length });
2094
+ }
2095
+ }
2096
+ }
2097
+ }
2098
+ scanForLeakedPaths(targetDir);
2099
+ if (leakedPaths.length > 0) {
2100
+ const totalLeaks = leakedPaths.reduce((sum, l) => sum + l.count, 0);
2101
+ console.warn(`\n ${yellow}⚠${reset} Found ${totalLeaks} unreplaced .claude path reference(s) in ${leakedPaths.length} file(s):`);
2102
+ for (const leak of leakedPaths.slice(0, 5)) {
2103
+ console.warn(` ${dim}${leak.file}${reset} (${leak.count})`);
2104
+ }
2105
+ if (leakedPaths.length > 5) {
2106
+ console.warn(` ${dim}... and ${leakedPaths.length - 5} more file(s)${reset}`);
2107
+ }
2108
+ console.warn(` ${dim}These paths may not resolve correctly for ${runtimeLabel}.${reset}`);
2109
+ }
2110
+ }
2111
+
2049
2112
  if (isCodex) {
2050
2113
  // Generate Codex config.toml and per-agent .toml files
2051
2114
  const agentCount = installCodexConfig(targetDir, agentsSrc);
@@ -32,6 +32,7 @@ ls .planning/debug/*.md 2>/dev/null | grep -v resolved | head -5
32
32
 
33
33
  ```bash
34
34
  INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" state load)
35
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
35
36
  ```
36
37
 
37
38
  Extract `commit_docs` from init JSON. Resolve debugger model:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: gsd:quick
3
3
  description: Execute a quick task with GSD guarantees (atomic commits, state tracking) but skip optional agents
4
- argument-hint: "[--full]"
4
+ argument-hint: "[--full] [--discuss]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Write
@@ -20,9 +20,13 @@ Quick mode is the same system with a shorter path:
20
20
  - Quick tasks live in `.planning/quick/` separate from planned phases
21
21
  - Updates STATE.md "Quick Tasks Completed" table (NOT ROADMAP.md)
22
22
 
23
- **Default:** Skips research, plan-checker, verifier. Use when you know exactly what to do.
23
+ **Default:** Skips research, discussion, plan-checker, verifier. Use when you know exactly what to do.
24
+
25
+ **`--discuss` flag:** Lightweight discussion phase before planning. Surfaces assumptions, clarifies gray areas, captures decisions in CONTEXT.md. Use when the task has ambiguity worth resolving upfront.
24
26
 
25
27
  **`--full` flag:** Enables plan-checking (max 2 iterations) and post-execution verification. Use when you want quality guarantees without full milestone ceremony.
28
+
29
+ Flags are composable: `--discuss --full` gives discussion + plan-checking + verification.
26
30
  </objective>
27
31
 
28
32
  <execution_context>
@@ -35,6 +35,7 @@ Normalize phase input in step 1 before any directory lookups.
35
35
 
36
36
  ```bash
37
37
  INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "$ARGUMENTS")
38
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
38
39
  ```
39
40
 
40
41
  Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`, `phase_found`, `commit_docs`, `has_research`, `state_path`, `requirements_path`, `context_path`, `research_path`.
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: gsd:validate-phase
3
+ description: Retroactively audit and fill Nyquist validation gaps for a completed phase
4
+ argument-hint: "[phase number]"
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Edit
9
+ - Bash
10
+ - Glob
11
+ - Grep
12
+ - Task
13
+ - AskUserQuestion
14
+ ---
15
+ <objective>
16
+ Audit Nyquist validation coverage for a completed phase. Three states:
17
+ - (A) VALIDATION.md exists — audit and fill gaps
18
+ - (B) No VALIDATION.md, SUMMARY.md exists — reconstruct from artifacts
19
+ - (C) Phase not executed — exit with guidance
20
+
21
+ Output: updated VALIDATION.md + generated test files.
22
+ </objective>
23
+
24
+ <execution_context>
25
+ @~/.claude/get-shit-done/workflows/validate-phase.md
26
+ </execution_context>
27
+
28
+ <context>
29
+ Phase: $ARGUMENTS — optional, defaults to last completed phase.
30
+ </context>
31
+
32
+ <process>
33
+ Execute @~/.claude/get-shit-done/workflows/validate-phase.md.
34
+ Preserve all workflow gates.
35
+ </process>
@@ -37,6 +37,13 @@ function cmdConfigEnsureSection(cwd, raw) {
37
37
  try {
38
38
  if (fs.existsSync(globalDefaultsPath)) {
39
39
  userDefaults = JSON.parse(fs.readFileSync(globalDefaultsPath, 'utf-8'));
40
+ // Migrate deprecated "depth" key to "granularity"
41
+ if ('depth' in userDefaults && !('granularity' in userDefaults)) {
42
+ const depthToGranularity = { quick: 'coarse', standard: 'standard', comprehensive: 'fine' };
43
+ userDefaults.granularity = depthToGranularity[userDefaults.depth] || userDefaults.depth;
44
+ delete userDefaults.depth;
45
+ try { fs.writeFileSync(globalDefaultsPath, JSON.stringify(userDefaults, null, 2), 'utf-8'); } catch {}
46
+ }
40
47
  }
41
48
  } catch (err) {
42
49
  // Ignore malformed global defaults, fall back to hardcoded
@@ -54,7 +61,7 @@ function cmdConfigEnsureSection(cwd, raw) {
54
61
  research: true,
55
62
  plan_check: true,
56
63
  verifier: true,
57
- nyquist_validation: false,
64
+ nyquist_validation: true,
58
65
  },
59
66
  parallelization: true,
60
67
  brave_search: hasBraveSearch,
@@ -27,6 +27,7 @@ const MODEL_PROFILES = {
27
27
  'gsd-verifier': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
28
28
  'gsd-plan-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
29
29
  'gsd-integration-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
30
+ 'gsd-nyquist-auditor': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
30
31
  };
31
32
 
32
33
  // ─── Output helpers ───────────────────────────────────────────────────────────
@@ -76,7 +77,7 @@ function loadConfig(cwd) {
76
77
  research: true,
77
78
  plan_checker: true,
78
79
  verifier: true,
79
- nyquist_validation: false,
80
+ nyquist_validation: true,
80
81
  parallelization: true,
81
82
  brave_search: false,
82
83
  };
@@ -85,6 +86,14 @@ function loadConfig(cwd) {
85
86
  const raw = fs.readFileSync(configPath, 'utf-8');
86
87
  const parsed = JSON.parse(raw);
87
88
 
89
+ // Migrate deprecated "depth" key to "granularity" with value mapping
90
+ if ('depth' in parsed && !('granularity' in parsed)) {
91
+ const depthToGranularity = { quick: 'coarse', standard: 'standard', comprehensive: 'fine' };
92
+ parsed.granularity = depthToGranularity[parsed.depth] || parsed.depth;
93
+ delete parsed.depth;
94
+ try { fs.writeFileSync(configPath, JSON.stringify(parsed, null, 2), 'utf-8'); } catch {}
95
+ }
96
+
88
97
  const get = (key, nested) => {
89
98
  if (parsed[key] !== undefined) return parsed[key];
90
99
  if (nested && parsed[nested.section] && parsed[nested.section][nested.field] !== undefined) {