gsd-opencode 1.30.0 → 1.33.0

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 (112) hide show
  1. package/agents/gsd-debugger.md +0 -1
  2. package/agents/gsd-doc-verifier.md +207 -0
  3. package/agents/gsd-doc-writer.md +608 -0
  4. package/agents/gsd-executor.md +22 -1
  5. package/agents/gsd-phase-researcher.md +41 -0
  6. package/agents/gsd-plan-checker.md +82 -0
  7. package/agents/gsd-planner.md +123 -194
  8. package/agents/gsd-security-auditor.md +129 -0
  9. package/agents/gsd-ui-auditor.md +40 -0
  10. package/agents/gsd-user-profiler.md +2 -2
  11. package/agents/gsd-verifier.md +84 -18
  12. package/commands/gsd/gsd-add-backlog.md +1 -1
  13. package/commands/gsd/gsd-analyze-dependencies.md +34 -0
  14. package/commands/gsd/gsd-autonomous.md +6 -2
  15. package/commands/gsd/gsd-cleanup.md +5 -0
  16. package/commands/gsd/gsd-debug.md +24 -21
  17. package/commands/gsd/gsd-discuss-phase.md +7 -2
  18. package/commands/gsd/gsd-docs-update.md +48 -0
  19. package/commands/gsd/gsd-execute-phase.md +4 -0
  20. package/commands/gsd/gsd-help.md +2 -0
  21. package/commands/gsd/gsd-join-discord.md +2 -1
  22. package/commands/gsd/gsd-manager.md +1 -0
  23. package/commands/gsd/gsd-new-project.md +4 -0
  24. package/commands/gsd/gsd-plan-phase.md +5 -0
  25. package/commands/gsd/gsd-quick.md +5 -3
  26. package/commands/gsd/gsd-reapply-patches.md +171 -39
  27. package/commands/gsd/gsd-research-phase.md +2 -12
  28. package/commands/gsd/gsd-review-backlog.md +1 -0
  29. package/commands/gsd/gsd-review.md +3 -2
  30. package/commands/gsd/gsd-secure-phase.md +35 -0
  31. package/commands/gsd/gsd-thread.md +1 -1
  32. package/commands/gsd/gsd-workstreams.md +7 -2
  33. package/get-shit-done/bin/gsd-tools.cjs +42 -8
  34. package/get-shit-done/bin/lib/commands.cjs +68 -14
  35. package/get-shit-done/bin/lib/config.cjs +18 -10
  36. package/get-shit-done/bin/lib/core.cjs +383 -80
  37. package/get-shit-done/bin/lib/docs.cjs +267 -0
  38. package/get-shit-done/bin/lib/frontmatter.cjs +47 -2
  39. package/get-shit-done/bin/lib/init.cjs +85 -5
  40. package/get-shit-done/bin/lib/milestone.cjs +21 -0
  41. package/get-shit-done/bin/lib/model-profiles.cjs +2 -0
  42. package/get-shit-done/bin/lib/phase.cjs +232 -189
  43. package/get-shit-done/bin/lib/profile-output.cjs +97 -1
  44. package/get-shit-done/bin/lib/roadmap.cjs +137 -113
  45. package/get-shit-done/bin/lib/schema-detect.cjs +238 -0
  46. package/get-shit-done/bin/lib/security.cjs +5 -3
  47. package/get-shit-done/bin/lib/state.cjs +366 -44
  48. package/get-shit-done/bin/lib/verify.cjs +158 -14
  49. package/get-shit-done/bin/lib/workstream.cjs +6 -2
  50. package/get-shit-done/references/agent-contracts.md +79 -0
  51. package/get-shit-done/references/artifact-types.md +113 -0
  52. package/get-shit-done/references/context-budget.md +49 -0
  53. package/get-shit-done/references/continuation-format.md +15 -15
  54. package/get-shit-done/references/domain-probes.md +125 -0
  55. package/get-shit-done/references/gate-prompts.md +100 -0
  56. package/get-shit-done/references/model-profiles.md +2 -2
  57. package/get-shit-done/references/planner-gap-closure.md +62 -0
  58. package/get-shit-done/references/planner-reviews.md +39 -0
  59. package/get-shit-done/references/planner-revision.md +87 -0
  60. package/get-shit-done/references/planning-config.md +15 -0
  61. package/get-shit-done/references/revision-loop.md +97 -0
  62. package/get-shit-done/references/ui-brand.md +2 -2
  63. package/get-shit-done/references/universal-anti-patterns.md +58 -0
  64. package/get-shit-done/references/workstream-flag.md +56 -3
  65. package/get-shit-done/templates/SECURITY.md +61 -0
  66. package/get-shit-done/templates/VALIDATION.md +3 -3
  67. package/get-shit-done/templates/claude-md.md +27 -4
  68. package/get-shit-done/templates/config.json +4 -0
  69. package/get-shit-done/templates/debug-subagent-prompt.md +2 -6
  70. package/get-shit-done/templates/planner-subagent-prompt.md +2 -10
  71. package/get-shit-done/workflows/add-phase.md +2 -2
  72. package/get-shit-done/workflows/add-todo.md +1 -1
  73. package/get-shit-done/workflows/analyze-dependencies.md +96 -0
  74. package/get-shit-done/workflows/audit-milestone.md +8 -12
  75. package/get-shit-done/workflows/autonomous.md +158 -13
  76. package/get-shit-done/workflows/check-todos.md +2 -2
  77. package/get-shit-done/workflows/complete-milestone.md +13 -4
  78. package/get-shit-done/workflows/diagnose-issues.md +8 -6
  79. package/get-shit-done/workflows/discovery-phase.md +1 -1
  80. package/get-shit-done/workflows/discuss-phase-assumptions.md +22 -4
  81. package/get-shit-done/workflows/discuss-phase-power.md +291 -0
  82. package/get-shit-done/workflows/discuss-phase.md +149 -11
  83. package/get-shit-done/workflows/docs-update.md +1093 -0
  84. package/get-shit-done/workflows/execute-phase.md +362 -66
  85. package/get-shit-done/workflows/execute-plan.md +1 -1
  86. package/get-shit-done/workflows/help.md +9 -6
  87. package/get-shit-done/workflows/insert-phase.md +2 -2
  88. package/get-shit-done/workflows/manager.md +27 -26
  89. package/get-shit-done/workflows/map-codebase.md +10 -32
  90. package/get-shit-done/workflows/new-milestone.md +14 -8
  91. package/get-shit-done/workflows/new-project.md +48 -25
  92. package/get-shit-done/workflows/next.md +1 -1
  93. package/get-shit-done/workflows/note.md +1 -1
  94. package/get-shit-done/workflows/pause-work.md +73 -10
  95. package/get-shit-done/workflows/plan-milestone-gaps.md +2 -2
  96. package/get-shit-done/workflows/plan-phase.md +184 -32
  97. package/get-shit-done/workflows/progress.md +20 -20
  98. package/get-shit-done/workflows/quick.md +102 -84
  99. package/get-shit-done/workflows/research-phase.md +2 -6
  100. package/get-shit-done/workflows/resume-project.md +4 -4
  101. package/get-shit-done/workflows/review.md +56 -3
  102. package/get-shit-done/workflows/secure-phase.md +154 -0
  103. package/get-shit-done/workflows/settings.md +13 -2
  104. package/get-shit-done/workflows/ship.md +13 -4
  105. package/get-shit-done/workflows/transition.md +6 -6
  106. package/get-shit-done/workflows/ui-phase.md +4 -14
  107. package/get-shit-done/workflows/ui-review.md +25 -7
  108. package/get-shit-done/workflows/update.md +165 -16
  109. package/get-shit-done/workflows/validate-phase.md +1 -11
  110. package/get-shit-done/workflows/verify-phase.md +127 -6
  111. package/get-shit-done/workflows/verify-work.md +69 -21
  112. package/package.json +1 -1
@@ -0,0 +1,154 @@
1
+ <objective>
2
+ Verify threat mitigations for a completed phase. Confirm PLAN.md threat register dispositions are resolved. Update SECURITY.md.
3
+ </objective>
4
+
5
+ <required_reading>
6
+ @$HOME/.config/opencode/get-shit-done/references/ui-brand.md
7
+ </required_reading>
8
+
9
+ <available_agent_types>
10
+ Valid GSD subagent types (use exact names — do not fall back to 'general'):
11
+ - gsd-security-auditor — Verifies threat mitigation coverage
12
+ </available_agent_types>
13
+
14
+ <process>
15
+
16
+ ## 0. Initialize
17
+
18
+ ```bash
19
+ INIT=$(node "$HOME/.config/opencode/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHASE_ARG}")
20
+ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
21
+ AGENT_SKILLS_AUDITOR=$(node "$HOME/.config/opencode/get-shit-done/bin/gsd-tools.cjs" agent-skills gsd-security-auditor 2>/dev/null)
22
+ ```
23
+
24
+ Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
25
+
26
+ ```bash
27
+ AUDITOR_MODEL=$(node "$HOME/.config/opencode/get-shit-done/bin/gsd-tools.cjs" resolve-model gsd-security-auditor --raw)
28
+ SECURITY_CFG=$(node "$HOME/.config/opencode/get-shit-done/bin/gsd-tools.cjs" config-get workflow.security_enforcement --raw 2>/dev/null || echo "true")
29
+ ```
30
+
31
+ If `SECURITY_CFG` is `false`: exit with "Security enforcement disabled. Enable via /gsd-settings."
32
+
33
+ Display banner: `GSD > SECURE PHASE {N}: {name}`
34
+
35
+ ## 1. Detect Input State
36
+
37
+ ```bash
38
+ SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
39
+ PLAN_FILES=$(ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null)
40
+ SUMMARY_FILES=$(ls "${PHASE_DIR}"/*-SUMMARY.md 2>/dev/null)
41
+ ```
42
+
43
+ - **State A** (`SECURITY_FILE` non-empty): Audit existing
44
+ - **State B** (`SECURITY_FILE` empty, `PLAN_FILES` and `SUMMARY_FILES` non-empty): Run from artifacts
45
+ - **State C** (`SUMMARY_FILES` empty): Exit — "Phase {N} not executed. Run /gsd-execute-phase {N} first."
46
+
47
+ ## 2. Discovery
48
+
49
+ ### 2a. read Phase Artifacts
50
+
51
+ read PLAN.md — extract `<threat_model>` block: trust boundaries, STRIDE register (`threat_id`, `category`, `component`, `disposition`, `mitigation_plan`).
52
+
53
+ ### 2b. read Summary Threat Flags
54
+
55
+ read SUMMARY.md — extract `## Threat Flags` entries.
56
+
57
+ ### 2c. Build Threat Register
58
+
59
+ Per threat: `{ threat_id, category, component, disposition, mitigation_pattern, files_to_check }`
60
+
61
+ ## 3. Threat Classification
62
+
63
+ Classify each threat:
64
+
65
+ | Status | Criteria |
66
+ |--------|----------|
67
+ | CLOSED | mitigation found OR accepted risk documented in SECURITY.md OR transfer documented |
68
+ | OPEN | none of the above |
69
+
70
+ Build: `{ threat_id, category, component, disposition, status, evidence }`
71
+
72
+ If `threats_open: 0` → skip to Step 6 directly.
73
+
74
+ ## 4. Present Threat Plan
75
+
76
+ Call question with threat table and options:
77
+ 1. "Verify all open threats" → Step 5
78
+ 2. "Accept all open — document in accepted risks log" → add to SECURITY.md accepted risks, set all CLOSED, Step 6
79
+ 3. "Cancel" → exit
80
+
81
+ ## 5. Spawn gsd-security-auditor
82
+
83
+ ```
84
+ @gsd-security-auditor "read $HOME/.config/opencode/agents/gsd-security-auditor.md for instructions.\n\n"
85
+ ```
86
+
87
+ Handle return:
88
+ - `## SECURED` → record closures → Step 6
89
+ - `## OPEN_THREATS` → record closed + open, present user with accept/block choice → Step 6
90
+ - `## ESCALATE` → present to user → Step 6
91
+
92
+ ## 6. write/Update SECURITY.md
93
+
94
+ **State B (create):**
95
+ 1. read template from `$HOME/.config/opencode/get-shit-done/templates/SECURITY.md`
96
+ 2. Fill: frontmatter, threat register, accepted risks, audit trail
97
+ 3. write to `${PHASE_DIR}/${PADDED_PHASE}-SECURITY.md`
98
+
99
+ **State A (update):**
100
+ 1. Update threat register statuses, append to audit trail:
101
+
102
+ ```markdown
103
+ ## Security Audit {date}
104
+ | Metric | Count |
105
+ |--------|-------|
106
+ | Threats found | {N} |
107
+ | Closed | {M} |
108
+ | Open | {K} |
109
+ ```
110
+
111
+ **ENFORCING GATE:** If `threats_open > 0` after all options exhausted (user did not accept, not all verified closed):
112
+
113
+ ```
114
+ GSD > PHASE {N} SECURITY BLOCKED
115
+ {K} threats open — phase advancement blocked until threats_open: 0
116
+ ▶ Fix mitigations then re-run: /gsd-secure-phase {N}
117
+ ▶ Or document accepted risks in SECURITY.md and re-run.
118
+ ```
119
+
120
+ Do NOT emit next-phase routing. Stop here.
121
+
122
+ ## 7. Commit
123
+
124
+ ```bash
125
+ node "$HOME/.config/opencode/get-shit-done/bin/gsd-tools.cjs" commit "docs(phase-${PHASE}): add/update security threat verification"
126
+ ```
127
+
128
+ ## 8. Results + Routing
129
+
130
+ **Secured (threats_open: 0):**
131
+ ```
132
+ GSD > PHASE {N} THREAT-SECURE
133
+ threats_open: 0 — all threats have dispositions.
134
+ ▶ /gsd-validate-phase {N} validate test coverage
135
+ ▶ /gsd-verify-work {N} run UAT
136
+ ```
137
+
138
+ Display `/new` reminder.
139
+
140
+ </process>
141
+
142
+ <success_criteria>
143
+ - [ ] Security enforcement checked — exit if false
144
+ - [ ] Input state detected (A/B/C) — state C exits cleanly
145
+ - [ ] PLAN.md threat model parsed, register built
146
+ - [ ] SUMMARY.md threat flags incorporated
147
+ - [ ] threats_open: 0 → skip directly to Step 6
148
+ - [ ] User gate with threat table presented
149
+ - [ ] Auditor spawned with complete context
150
+ - [ ] All three return formats (SECURED/OPEN_THREATS/ESCALATE) handled
151
+ - [ ] SECURITY.md created or updated
152
+ - [ ] threats_open > 0 BLOCKS advancement (no next-phase routing emitted)
153
+ - [ ] Results with routing presented on success
154
+ </success_criteria>
@@ -34,6 +34,7 @@ Parse current values (default to `true` if not present):
34
34
  - `workflow.ui_safety_gate` — prompt to run /gsd-ui-phase before planning frontend phases (default: true if absent)
35
35
  - `model_profile` — which model each agent uses (default: `simple`)
36
36
  - `git.branching_strategy` — branching approach (default: `"none"`)
37
+ - `workflow.use_worktrees` — whether parallel executor agents run in worktree isolation (default: `true`)
37
38
  </step>
38
39
 
39
40
  <step name="present_settings">
@@ -153,6 +154,15 @@ question([
153
154
  { label: "No (Recommended)", description: "Run smart discuss before each phase — surfaces gray areas and captures decisions." },
154
155
  { label: "Yes", description: "Skip discuss in /gsd-autonomous — chain directly to plan. Best for backend/pipeline work where phase descriptions are the spec." }
155
156
  ]
157
+ },
158
+ {
159
+ question: "Use git worktrees for parallel agent isolation?",
160
+ header: "Worktrees",
161
+ multiSelect: false,
162
+ options: [
163
+ { label: "Yes (Recommended)", description: "Each parallel executor runs in its own worktree branch — no conflicts between agents." },
164
+ { label: "No", description: "Disable worktree isolation. Use on platforms where EnterWorktree is broken (e.g. Windows with feature branches). Agents run sequentially on the main working tree." }
165
+ ]
156
166
  }
157
167
  ])
158
168
  ```
@@ -176,7 +186,8 @@ Merge new settings into existing config.json:
176
186
  "text_mode": true/false,
177
187
  "research_before_questions": true/false,
178
188
  "discuss_mode": "discuss" | "assumptions",
179
- "skip_discuss": true/false
189
+ "skip_discuss": true/false,
190
+ "use_worktrees": true/false
180
191
  },
181
192
  "git": {
182
193
  "branching_strategy": "none" | "phase" | "milestone",
@@ -265,7 +276,7 @@ Display:
265
276
  These settings apply to future /gsd-plan-phase and /gsd-execute-phase runs.
266
277
 
267
278
  Quick commands:
268
- - /gsd-set-profile <profile> — switch model profile/choose models
279
+ - /gsd-set-profile <profile> — switch model profile
269
280
  - /gsd-plan-phase --research — force research
270
281
  - /gsd-plan-phase --skip-research — skip research
271
282
  - /gsd-plan-phase --skip-verify — skip plan check
@@ -24,6 +24,15 @@ CONFIG=$(node "$HOME/.config/opencode/get-shit-done/bin/gsd-tools.cjs" state loa
24
24
  ```
25
25
 
26
26
  Extract: `branching_strategy`, `branch_name`.
27
+
28
+ Detect base branch for PRs and merges:
29
+ ```bash
30
+ BASE_BRANCH=$(node "$HOME/.config/opencode/get-shit-done/bin/gsd-tools.cjs" config-get git.base_branch 2>/dev/null || echo "")
31
+ if [ -z "$BASE_BRANCH" ] || [ "$BASE_BRANCH" = "null" ]; then
32
+ BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||')
33
+ BASE_BRANCH="${BASE_BRANCH:-main}"
34
+ fi
35
+ ```
27
36
  </step>
28
37
 
29
38
  <step name="preflight_checks">
@@ -46,7 +55,7 @@ Verify the work is ready to ship:
46
55
  ```bash
47
56
  CURRENT_BRANCH=$(git branch --show-current)
48
57
  ```
49
- If on `main`/`master`: warn — should be on a feature branch.
58
+ If on `${BASE_BRANCH}`: warn — should be on a feature branch.
50
59
  If branching_strategy is `none`: offer to create a branch now.
51
60
 
52
61
  4. **Remote configured?**
@@ -74,7 +83,7 @@ If push fails (e.g., no upstream): set upstream:
74
83
  git push --set-upstream origin ${CURRENT_BRANCH} 2>&1
75
84
  ```
76
85
 
77
- Report: "Pushed `{branch}` to origin ({commit_count} commits ahead of main)"
86
+ Report: "Pushed `{branch}` to origin ({commit_count} commits ahead of ${BASE_BRANCH})"
78
87
  </step>
79
88
 
80
89
  <step name="generate_pr_body">
@@ -141,7 +150,7 @@ Create the PR using the generated body:
141
150
  gh pr create \
142
151
  --title "Phase ${PHASE_NUMBER}: ${PHASE_NAME}" \
143
152
  --body "${PR_BODY}" \
144
- --base main
153
+ --base ${BASE_BRANCH}
145
154
  ```
146
155
 
147
156
  If `--draft` flag was passed: add `--draft`.
@@ -194,7 +203,7 @@ node "$HOME/.config/opencode/get-shit-done/bin/gsd-tools.cjs" commit "docs(${pad
194
203
  ## ✓ Phase {X}: {Name} — Shipped
195
204
 
196
205
  PR: #{number} ({url})
197
- Branch: {branch} → main
206
+ Branch: {branch} → ${BASE_BRANCH}
198
207
  Commits: {count}
199
208
  Verification: ✓ Passed
200
209
  Requirements: {N} REQ-IDs addressed
@@ -475,9 +475,9 @@ Exit skill and invoke command("/gsd-discuss-phase [X+1] --auto ${GSD_WS}")
475
475
 
476
476
  **Phase [X+1]: [Name]** — [Goal from ROADMAP.md]
477
477
 
478
- `/gsd-discuss-phase [X+1] ${GSD_WS}` — gather context and clarify approach
478
+ `/new` then:
479
479
 
480
- *`/new` first fresh context window*
480
+ `/gsd-discuss-phase [X+1] ${GSD_WS}` gather context and clarify approach
481
481
 
482
482
  ---
483
483
 
@@ -500,9 +500,9 @@ Exit skill and invoke command("/gsd-discuss-phase [X+1] --auto ${GSD_WS}")
500
500
  **Phase [X+1]: [Name]** — [Goal from ROADMAP.md]
501
501
  *✓ Context gathered, ready to plan*
502
502
 
503
- `/gsd-plan-phase [X+1] ${GSD_WS}`
503
+ `/new` then:
504
504
 
505
- *`/new` first → fresh context window*
505
+ `/gsd-plan-phase [X+1] ${GSD_WS}`
506
506
 
507
507
  ---
508
508
 
@@ -610,9 +610,9 @@ Exit skill and invoke command("/gsd-complete-milestone {version} ${GSD_WS}")
610
610
 
611
611
  **Complete Milestone {version}** — archive and prepare for next
612
612
 
613
- `/gsd-complete-milestone {version} ${GSD_WS}`
613
+ `/new` then:
614
614
 
615
- *`/new` first → fresh context window*
615
+ `/gsd-complete-milestone {version} ${GSD_WS}`
616
616
 
617
617
  ---
618
618
 
@@ -141,12 +141,7 @@ padded_phase: {padded_phase}
141
141
  Omit null file paths from `<files_to_read>`.
142
142
 
143
143
  ```
144
- task(
145
- prompt=ui_research_prompt,
146
- subagent_type="gsd-ui-researcher",
147
- model="{UI_RESEARCHER_MODEL}",
148
- description="UI Design Contract Phase {N}"
149
- )
144
+ @gsd-ui-researcher ui_research_prompt
150
145
  ```
151
146
 
152
147
  ## 6. Handle Researcher Return
@@ -192,12 +187,7 @@ ui_safety_gate: {ui_safety_gate config value}
192
187
  ```
193
188
 
194
189
  ```
195
- task(
196
- prompt=ui_checker_prompt,
197
- subagent_type="gsd-ui-checker",
198
- model="{UI_CHECKER_MODEL}",
199
- description="Verify UI-SPEC Phase {N}"
200
- )
190
+ @gsd-ui-checker ui_checker_prompt
201
191
  ```
202
192
 
203
193
  ## 8. Handle Checker Return
@@ -263,9 +253,9 @@ Dimensions: 6/6 passed
263
253
 
264
254
  **Plan Phase {N}** — planner will use UI-SPEC.md as design context
265
255
 
266
- `/gsd-plan-phase {N}`
256
+ `/new` then:
267
257
 
268
- */new first → fresh context window*
258
+ `/gsd-plan-phase {N}`
269
259
 
270
260
  ───────────────────────────────────────────────────────────────
271
261
  ```
@@ -97,12 +97,7 @@ padded_phase: {padded_phase}
97
97
  Omit null file paths.
98
98
 
99
99
  ```
100
- task(
101
- prompt=ui_audit_prompt,
102
- subagent_type="gsd-ui-auditor",
103
- model="{UI_AUDITOR_MODEL}",
104
- description="UI Audit Phase {N}"
105
- )
100
+ @gsd-ui-auditor ui_audit_prompt
106
101
  ```
107
102
 
108
103
  ## 4. Handle Return
@@ -138,14 +133,37 @@ Full review: {path to UI-REVIEW.md}
138
133
 
139
134
  ## ▶ Next
140
135
 
136
+ `/new` then one of:
137
+
141
138
  - `/gsd-verify-work {N}` — UAT testing
142
139
  - `/gsd-plan-phase {N+1}` — plan next phase
143
140
 
144
- */new first fresh context window*
141
+ - `/gsd-verify-work {N}` UAT testing
142
+ - `/gsd-plan-phase {N+1}` — plan next phase
145
143
 
146
144
  ───────────────────────────────────────────────────────────────
147
145
  ```
148
146
 
147
+ ## Automated UI Verification (when Playwright-MCP is available)
148
+
149
+ If `mcp__playwright__*` tools are accessible in this session:
150
+
151
+ 1. Navigate to each UI component described in the phase's UI-SPEC.md using
152
+ `mcp__playwright__navigate` (or equivalent Playwright-MCP tool).
153
+ 2. Take a screenshot of each component using `mcp__playwright__screenshot`.
154
+ 3. Compare against the spec's visual requirements — dimensions, color palette,
155
+ layout, spacing scale, and typography.
156
+ 4. Report any dimension, color, or layout discrepancies automatically as
157
+ additional findings within the relevant pillar section of UI-REVIEW.md.
158
+ 5. Flag items that require human judgment (brand feel, content tone) as
159
+ `needs_human_review: true` in the findings — these are surfaced to the user
160
+ separately after the automated pass completes.
161
+
162
+ If Playwright-MCP is not available in this session, this section is skipped
163
+ entirely. The audit falls back to the standard code-only review described above.
164
+ No configuration change is required — the availability of `mcp__playwright__*`
165
+ tools is detected at runtime.
166
+
149
167
  ## 5. Commit (if configured)
150
168
 
151
169
  ```bash
@@ -11,28 +11,59 @@ read all files referenced by the invoking prompt's execution_context before star
11
11
  <step name="get_installed_version">
12
12
  Detect whether GSD is installed locally or globally by checking both locations and validating install integrity.
13
13
 
14
- First, derive `PREFERRED_RUNTIME` from the invoking prompt's `execution_context` path:
14
+ First, derive `PREFERRED_CONFIG_DIR` and `PREFERRED_RUNTIME` from the invoking prompt's `execution_context` path:
15
+ - If the path contains `/get-shit-done/workflows/update.md`, strip that suffix and store the remainder as `PREFERRED_CONFIG_DIR`
15
16
  - Path contains `/.codex/` -> `codex`
16
17
  - Path contains `/.gemini/` -> `gemini`
17
- - Path contains `/.config/opencode/` or `/.opencode/` -> `opencode`
18
+ - Path contains `/.config/kilo/` or `/.kilo/`, or `PREFERRED_CONFIG_DIR` contains `kilo.json` / `kilo.jsonc` -> `kilo`
19
+ - Path contains `/.config/opencode/` or `/.opencode/`, or `PREFERRED_CONFIG_DIR` contains `opencode.json` / `opencode.jsonc` -> `opencode`
18
20
  - Otherwise -> `OpenCode`
19
21
 
22
+ Use `PREFERRED_CONFIG_DIR` when available so custom `--config-dir` installs are checked before default locations.
20
23
  Use `PREFERRED_RUNTIME` as the first runtime checked so `/gsd-update` targets the runtime that invoked it.
21
24
 
25
+ Kilo config precedence must match the installer: `KILO_CONFIG_DIR` -> `dirname(KILO_CONFIG)` -> `XDG_CONFIG_HOME/kilo` -> `~/.config/kilo`.
26
+
22
27
  ```bash
28
+ expand_home() {
29
+ case "$1" in
30
+ "~/"*) printf '%s/%s\n' "$HOME" "${1#~/}" ;;
31
+ *) printf '%s\n' "$1" ;;
32
+ esac
33
+ }
34
+
23
35
  # Runtime candidates: "<runtime>:<config-dir>" stored as an array.
24
36
  # Using an array instead of a space-separated string ensures correct
25
37
  # iteration in both bash and zsh (zsh does not word-split unquoted
26
38
  # variables by default). Fixes #1173.
27
- RUNTIME_DIRS=( "OpenCode:.OpenCode" "opencode:.config/opencode" "opencode:.opencode" "gemini:.gemini" "codex:.codex" )
39
+ RUNTIME_DIRS=( "OpenCode:.OpenCode" "opencode:.config/opencode" "opencode:.opencode" "gemini:.gemini" "kilo:.config/kilo" "kilo:.kilo" "codex:.codex" )
40
+ ENV_RUNTIME_DIRS=()
41
+
42
+ # PREFERRED_CONFIG_DIR / PREFERRED_RUNTIME should be set from execution_context
43
+ # before running this block.
44
+ if [ -n "$PREFERRED_CONFIG_DIR" ]; then
45
+ PREFERRED_CONFIG_DIR="$(expand_home "$PREFERRED_CONFIG_DIR")"
46
+ if [ -z "$PREFERRED_RUNTIME" ]; then
47
+ if [ -f "$PREFERRED_CONFIG_DIR/kilo.json" ] || [ -f "$PREFERRED_CONFIG_DIR/kilo.jsonc" ]; then
48
+ PREFERRED_RUNTIME="kilo"
49
+ elif [ -f "$PREFERRED_CONFIG_DIR/opencode.json" ] || [ -f "$PREFERRED_CONFIG_DIR/opencode.jsonc" ]; then
50
+ PREFERRED_RUNTIME="opencode"
51
+ elif [ -f "$PREFERRED_CONFIG_DIR/config.toml" ]; then
52
+ PREFERRED_RUNTIME="codex"
53
+ fi
54
+ fi
55
+ fi
28
56
 
29
- # PREFERRED_RUNTIME should be set from execution_context before running this block.
30
- # If not set, infer from runtime env vars; fallback to OpenCode.
57
+ # If runtime is still unknown, infer from runtime env vars; fallback to OpenCode.
31
58
  if [ -z "$PREFERRED_RUNTIME" ]; then
32
59
  if [ -n "$CODEX_HOME" ]; then
33
60
  PREFERRED_RUNTIME="codex"
34
61
  elif [ -n "$GEMINI_CONFIG_DIR" ]; then
35
62
  PREFERRED_RUNTIME="gemini"
63
+ elif [ -n "$KILO_CONFIG_DIR" ]; then
64
+ PREFERRED_RUNTIME="kilo"
65
+ elif [ -n "$KILO_CONFIG" ]; then
66
+ PREFERRED_RUNTIME="kilo"
36
67
  elif [ -n "$OPENCODE_CONFIG_DIR" ] || [ -n "$OPENCODE_CONFIG" ]; then
37
68
  PREFERRED_RUNTIME="opencode"
38
69
  elif [ -n "$CLAUDE_CONFIG_DIR" ]; then
@@ -42,6 +73,56 @@ if [ -z "$PREFERRED_RUNTIME" ]; then
42
73
  fi
43
74
  fi
44
75
 
76
+ # If execution_context already points at an installed config dir, trust it first.
77
+ # This covers custom --config-dir installs that do not live under the default
78
+ # runtime directories.
79
+ if [ -n "$PREFERRED_CONFIG_DIR" ] && { [ -f "$PREFERRED_CONFIG_DIR/get-shit-done/VERSION" ] || [ -f "$PREFERRED_CONFIG_DIR/get-shit-done/workflows/update.md" ]; }; then
80
+ INSTALL_SCOPE="GLOBAL"
81
+ for dir in .OpenCode .config/opencode .opencode .gemini .config/kilo .kilo .codex; do
82
+ resolved_local="$(cd "./$dir" 2>/dev/null && pwd)"
83
+ if [ -n "$resolved_local" ] && [ "$resolved_local" = "$PREFERRED_CONFIG_DIR" ]; then
84
+ INSTALL_SCOPE="LOCAL"
85
+ break
86
+ fi
87
+ done
88
+
89
+ if [ -f "$PREFERRED_CONFIG_DIR/get-shit-done/VERSION" ] && grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+' "$PREFERRED_CONFIG_DIR/get-shit-done/VERSION"; then
90
+ INSTALLED_VERSION="$(cat "$PREFERRED_CONFIG_DIR/get-shit-done/VERSION")"
91
+ else
92
+ INSTALLED_VERSION="0.0.0"
93
+ fi
94
+
95
+ echo "$INSTALLED_VERSION"
96
+ echo "$INSTALL_SCOPE"
97
+ echo "${PREFERRED_RUNTIME:-OpenCode}"
98
+ exit 0
99
+ fi
100
+
101
+ # Absolute global candidates from env overrides (covers custom config dirs).
102
+ if [ -n "$CLAUDE_CONFIG_DIR" ]; then
103
+ ENV_RUNTIME_DIRS+=( "OpenCode:$(expand_home "$CLAUDE_CONFIG_DIR")" )
104
+ fi
105
+ if [ -n "$GEMINI_CONFIG_DIR" ]; then
106
+ ENV_RUNTIME_DIRS+=( "gemini:$(expand_home "$GEMINI_CONFIG_DIR")" )
107
+ fi
108
+ if [ -n "$KILO_CONFIG_DIR" ]; then
109
+ ENV_RUNTIME_DIRS+=( "kilo:$(expand_home "$KILO_CONFIG_DIR")" )
110
+ elif [ -n "$KILO_CONFIG" ]; then
111
+ ENV_RUNTIME_DIRS+=( "kilo:$(dirname "$(expand_home "$KILO_CONFIG")")" )
112
+ elif [ -n "$XDG_CONFIG_HOME" ]; then
113
+ ENV_RUNTIME_DIRS+=( "kilo:$(expand_home "$XDG_CONFIG_HOME")/kilo" )
114
+ fi
115
+ if [ -n "$OPENCODE_CONFIG_DIR" ]; then
116
+ ENV_RUNTIME_DIRS+=( "opencode:$(expand_home "$OPENCODE_CONFIG_DIR")" )
117
+ elif [ -n "$OPENCODE_CONFIG" ]; then
118
+ ENV_RUNTIME_DIRS+=( "opencode:$(dirname "$(expand_home "$OPENCODE_CONFIG")")" )
119
+ elif [ -n "$XDG_CONFIG_HOME" ]; then
120
+ ENV_RUNTIME_DIRS+=( "opencode:$(expand_home "$XDG_CONFIG_HOME")/opencode" )
121
+ fi
122
+ if [ -n "$CODEX_HOME" ]; then
123
+ ENV_RUNTIME_DIRS+=( "codex:$(expand_home "$CODEX_HOME")" )
124
+ fi
125
+
45
126
  # Reorder entries so preferred runtime is checked first.
46
127
  ORDERED_RUNTIME_DIRS=()
47
128
  for entry in "${RUNTIME_DIRS[@]}"; do
@@ -50,6 +131,19 @@ for entry in "${RUNTIME_DIRS[@]}"; do
50
131
  ORDERED_RUNTIME_DIRS+=( "$entry" )
51
132
  fi
52
133
  done
134
+ ORDERED_ENV_RUNTIME_DIRS=()
135
+ for entry in "${ENV_RUNTIME_DIRS[@]}"; do
136
+ runtime="${entry%%:*}"
137
+ if [ "$runtime" = "$PREFERRED_RUNTIME" ]; then
138
+ ORDERED_ENV_RUNTIME_DIRS+=( "$entry" )
139
+ fi
140
+ done
141
+ for entry in "${ENV_RUNTIME_DIRS[@]}"; do
142
+ runtime="${entry%%:*}"
143
+ if [ "$runtime" != "$PREFERRED_RUNTIME" ]; then
144
+ ORDERED_ENV_RUNTIME_DIRS+=( "$entry" )
145
+ fi
146
+ done
53
147
  for entry in "${RUNTIME_DIRS[@]}"; do
54
148
  runtime="${entry%%:*}"
55
149
  if [ "$runtime" != "$PREFERRED_RUNTIME" ]; then
@@ -72,18 +166,32 @@ for entry in "${ORDERED_RUNTIME_DIRS[@]}"; do
72
166
  done
73
167
 
74
168
  GLOBAL_VERSION_FILE="" GLOBAL_MARKER_FILE="" GLOBAL_DIR="" GLOBAL_RUNTIME=""
75
- for entry in "${ORDERED_RUNTIME_DIRS[@]}"; do
169
+ for entry in "${ORDERED_ENV_RUNTIME_DIRS[@]}"; do
76
170
  runtime="${entry%%:*}"
77
171
  dir="${entry#*:}"
78
- if [ -f "$HOME/$dir/get-shit-done/VERSION" ] || [ -f "$HOME/$dir/get-shit-done/workflows/update.md" ]; then
172
+ if [ -f "$dir/get-shit-done/VERSION" ] || [ -f "$dir/get-shit-done/workflows/update.md" ]; then
79
173
  GLOBAL_RUNTIME="$runtime"
80
- GLOBAL_VERSION_FILE="$HOME/$dir/get-shit-done/VERSION"
81
- GLOBAL_MARKER_FILE="$HOME/$dir/get-shit-done/workflows/update.md"
82
- GLOBAL_DIR="$(cd "$HOME/$dir" 2>/dev/null && pwd)"
174
+ GLOBAL_VERSION_FILE="$dir/get-shit-done/VERSION"
175
+ GLOBAL_MARKER_FILE="$dir/get-shit-done/workflows/update.md"
176
+ GLOBAL_DIR="$(cd "$dir" 2>/dev/null && pwd)"
83
177
  break
84
178
  fi
85
179
  done
86
180
 
181
+ if [ -z "$GLOBAL_RUNTIME" ]; then
182
+ for entry in "${ORDERED_RUNTIME_DIRS[@]}"; do
183
+ runtime="${entry%%:*}"
184
+ dir="${entry#*:}"
185
+ if [ -f "$HOME/$dir/get-shit-done/VERSION" ] || [ -f "$HOME/$dir/get-shit-done/workflows/update.md" ]; then
186
+ GLOBAL_RUNTIME="$runtime"
187
+ GLOBAL_VERSION_FILE="$HOME/$dir/get-shit-done/VERSION"
188
+ GLOBAL_MARKER_FILE="$HOME/$dir/get-shit-done/workflows/update.md"
189
+ GLOBAL_DIR="$(cd "$HOME/$dir" 2>/dev/null && pwd)"
190
+ break
191
+ fi
192
+ done
193
+ fi
194
+
87
195
  # Only treat as LOCAL if the resolved paths differ (prevents misdetection when CWD=$HOME)
88
196
  IS_LOCAL=false
89
197
  if [ -n "$LOCAL_VERSION_FILE" ] && [ -f "$LOCAL_VERSION_FILE" ] && [ -f "$LOCAL_MARKER_FILE" ] && grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+' "$LOCAL_VERSION_FILE"; then
@@ -123,7 +231,7 @@ echo "$TARGET_RUNTIME"
123
231
  Parse output:
124
232
  - Line 1 = installed version (`0.0.0` means unknown version)
125
233
  - Line 2 = install scope (`LOCAL`, `GLOBAL`, or `UNKNOWN`)
126
- - Line 3 = target runtime (`OpenCode`, `opencode`, `gemini`, or `codex`)
234
+ - Line 3 = target runtime (`OpenCode`, `opencode`, `gemini`, `kilo`, or `codex`)
127
235
  - If scope is `UNKNOWN`, proceed to install step using `--OpenCode --global` fallback.
128
236
 
129
237
  If multiple runtime installs are detected and the invoking runtime cannot be determined from execution_context, ask the user which runtime to update before running install.
@@ -221,8 +329,8 @@ Exit.
221
329
  - `agents/gsd-*` files will be replaced
222
330
 
223
331
  (Paths are relative to detected runtime install location:
224
- global: `$HOME/.config/opencode/`, `~/.config/opencode/`, `~/.opencode/`, `~/.gemini/`, or `~/.codex/`
225
- local: `./.OpenCode/`, `./.config/opencode/`, `./.opencode/`, `./.gemini/`, or `./.codex/`)
332
+ global: `$HOME/.config/opencode/`, `~/.config/opencode/`, `~/.opencode/`, `~/.gemini/`, `~/.config/kilo/`, or `~/.codex/`
333
+ local: `./.OpenCode/`, `./.config/opencode/`, `./.opencode/`, `./.gemini/`, `./.kilo/`, or `./.codex/`)
226
334
 
227
335
  Your custom files in other locations are preserved:
228
336
  - Custom commands not in `commands/gsd/` ✓
@@ -270,14 +378,55 @@ Capture output. If install fails, show error and exit.
270
378
  Clear the update cache so statusline indicator disappears:
271
379
 
272
380
  ```bash
273
- # Clear update cache across all runtime directories
274
- for dir in .OpenCode .config/opencode .opencode .gemini .codex; do
381
+ expand_home() {
382
+ case "$1" in
383
+ "~/"*) printf '%s/%s\n' "$HOME" "${1#~/}" ;;
384
+ *) printf '%s\n' "$1" ;;
385
+ esac
386
+ }
387
+
388
+ # Clear update cache across preferred, env-derived, and default runtime directories
389
+ CACHE_DIRS=()
390
+ if [ -n "$PREFERRED_CONFIG_DIR" ]; then
391
+ CACHE_DIRS+=( "$(expand_home "$PREFERRED_CONFIG_DIR")" )
392
+ fi
393
+ if [ -n "$CLAUDE_CONFIG_DIR" ]; then
394
+ CACHE_DIRS+=( "$(expand_home "$CLAUDE_CONFIG_DIR")" )
395
+ fi
396
+ if [ -n "$GEMINI_CONFIG_DIR" ]; then
397
+ CACHE_DIRS+=( "$(expand_home "$GEMINI_CONFIG_DIR")" )
398
+ fi
399
+ if [ -n "$KILO_CONFIG_DIR" ]; then
400
+ CACHE_DIRS+=( "$(expand_home "$KILO_CONFIG_DIR")" )
401
+ elif [ -n "$KILO_CONFIG" ]; then
402
+ CACHE_DIRS+=( "$(dirname "$(expand_home "$KILO_CONFIG")")" )
403
+ elif [ -n "$XDG_CONFIG_HOME" ]; then
404
+ CACHE_DIRS+=( "$(expand_home "$XDG_CONFIG_HOME")/kilo" )
405
+ fi
406
+ if [ -n "$OPENCODE_CONFIG_DIR" ]; then
407
+ CACHE_DIRS+=( "$(expand_home "$OPENCODE_CONFIG_DIR")" )
408
+ elif [ -n "$OPENCODE_CONFIG" ]; then
409
+ CACHE_DIRS+=( "$(dirname "$(expand_home "$OPENCODE_CONFIG")")" )
410
+ elif [ -n "$XDG_CONFIG_HOME" ]; then
411
+ CACHE_DIRS+=( "$(expand_home "$XDG_CONFIG_HOME")/opencode" )
412
+ fi
413
+ if [ -n "$CODEX_HOME" ]; then
414
+ CACHE_DIRS+=( "$(expand_home "$CODEX_HOME")" )
415
+ fi
416
+
417
+ for dir in "${CACHE_DIRS[@]}"; do
418
+ if [ -n "$dir" ]; then
419
+ rm -f "$dir/cache/gsd-update-check.json"
420
+ fi
421
+ done
422
+
423
+ for dir in .OpenCode .config/opencode .opencode .gemini .config/kilo .kilo .codex; do
275
424
  rm -f "./$dir/cache/gsd-update-check.json"
276
425
  rm -f "$HOME/$dir/cache/gsd-update-check.json"
277
426
  done
278
427
  ```
279
428
 
280
- The SessionStart hook (`gsd-check-update.js`) writes to the detected runtime's cache directory, so all paths must be cleared to prevent stale update indicators.
429
+ The SessionStart hook (`gsd-check-update.js`) writes to the detected runtime's cache directory, so preferred/env-derived paths and default paths must all be cleared to prevent stale update indicators.
281
430
  </step>
282
431
 
283
432
  <step name="display_result">
@@ -91,17 +91,7 @@ Call question with gap table and options:
91
91
  ## 5. Spawn gsd-nyquist-auditor
92
92
 
93
93
  ```
94
- task(
95
- prompt="read $HOME/.config/opencode/agents/gsd-nyquist-auditor.md for instructions.\n\n" +
96
- "<files_to_read>{PLAN, SUMMARY, impl files, VALIDATION.md}</files_to_read>" +
97
- "<gaps>{gap list}</gaps>" +
98
- "<test_infrastructure>{framework, config, commands}</test_infrastructure>" +
99
- "<constraints>Never modify impl files. Max 3 debug iterations. Escalate impl bugs.</constraints>" +
100
- "${AGENT_SKILLS_AUDITOR}",
101
- subagent_type="gsd-nyquist-auditor",
102
- model="{AUDITOR_MODEL}",
103
- description="Fill validation gaps for Phase {N}"
104
- )
94
+ @gsd-nyquist-auditor "read $HOME/.config/opencode/agents/gsd-nyquist-auditor.md for instructions.\n\n"
105
95
  ```
106
96
 
107
97
  Handle return: