claude-cook 1.10.1 → 1.10.2
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.
- package/commands/gsd/pm-cycle.md +284 -0
- package/commands/gsd/pm-start.md +27 -20
- package/get-shit-done/workflows/pm-cycle.md +144 -0
- package/package.json +1 -1
- package/scripts/pm-loop.sh +81 -25
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsd:pm-cycle
|
|
3
|
+
description: Full-brain autonomous PM cycle — reads state, decides, acts, exits
|
|
4
|
+
argument-hint: "[phase]"
|
|
5
|
+
agent: gsd-pm
|
|
6
|
+
allowed-tools:
|
|
7
|
+
- Read
|
|
8
|
+
- Write
|
|
9
|
+
- Edit
|
|
10
|
+
- Bash
|
|
11
|
+
- Glob
|
|
12
|
+
- Grep
|
|
13
|
+
- Task
|
|
14
|
+
- mcp__vibe_kanban__*
|
|
15
|
+
- mcp__context7__*
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<execution_context>
|
|
19
|
+
@~/.claude/get-shit-done/references/ui-brand.md
|
|
20
|
+
@~/.claude/get-shit-done/references/vibe-kanban.md
|
|
21
|
+
@~/.claude/get-shit-done/workflows/pm-cycle.md
|
|
22
|
+
@~/.claude/get-shit-done/workflows/pm-check.md
|
|
23
|
+
@~/.claude/get-shit-done/workflows/pm-sync.md
|
|
24
|
+
@~/.claude/get-shit-done/workflows/pm-dispatch.md
|
|
25
|
+
@~/.claude/get-shit-done/workflows/pm-replan.md
|
|
26
|
+
</execution_context>
|
|
27
|
+
|
|
28
|
+
<objective>
|
|
29
|
+
**The autonomous PM brain.** Each invocation is a stateless decision engine — reads all persistent state, decides the single most important action to take, executes it, updates state, and exits.
|
|
30
|
+
|
|
31
|
+
Called by `pm-loop.sh` on every cycle. Each call gets a fresh 200k context. State persists via `.planning/` files.
|
|
32
|
+
|
|
33
|
+
**This is the Ralph-style loop brain.** One command runs the entire PM lifecycle: plan → sync → dispatch → monitor → replan → advance phase → complete milestone.
|
|
34
|
+
</objective>
|
|
35
|
+
|
|
36
|
+
<context>
|
|
37
|
+
Phase hint: $ARGUMENTS (optional — auto-detected from STATE.md if not provided)
|
|
38
|
+
</context>
|
|
39
|
+
|
|
40
|
+
<process>
|
|
41
|
+
|
|
42
|
+
## 1. Load All State
|
|
43
|
+
|
|
44
|
+
Read these files (all reads in parallel):
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
.planning/config.json → PM config (project_id, repos, executor, toggles)
|
|
48
|
+
.planning/STATE.md → Current position (phase, status, decisions)
|
|
49
|
+
.planning/ROADMAP.md → Phase structure, goals, milestone scope
|
|
50
|
+
.planning/PM-LOG.md → Recent activity (tail last 20 lines)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If `$ARGUMENTS` provides a phase number, use it. Otherwise, detect from STATE.md.
|
|
54
|
+
|
|
55
|
+
Identify:
|
|
56
|
+
- `current_phase`: phase number being worked on
|
|
57
|
+
- `phase_dir`: `.planning/phases/{phase-dir}/`
|
|
58
|
+
- `pm_config`: the `pm` section from config.json
|
|
59
|
+
|
|
60
|
+
If no `.planning/` directory or no `config.json` with `pm` section:
|
|
61
|
+
```
|
|
62
|
+
No PM configuration found. Run /gsd:pm-start to initialize.
|
|
63
|
+
```
|
|
64
|
+
Exit with code 0.
|
|
65
|
+
|
|
66
|
+
## 2. Assess Phase State
|
|
67
|
+
|
|
68
|
+
Check the current phase directory:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Count plans, tickets, summaries
|
|
72
|
+
ls -1 .planning/phases/{phase_dir}/*-PLAN.md 2>/dev/null | wc -l
|
|
73
|
+
ls -1 .planning/phases/{phase_dir}/TICKET-MAP.md 2>/dev/null | wc -l
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Read TICKET-MAP.md if it exists. Parse ticket statuses.
|
|
77
|
+
|
|
78
|
+
Classify the phase into exactly ONE state:
|
|
79
|
+
|
|
80
|
+
| State | Condition |
|
|
81
|
+
|-------|-----------|
|
|
82
|
+
| `NEEDS_PLANNING` | No PLAN.md files in phase directory |
|
|
83
|
+
| `NEEDS_SYNC` | PLAN.md files exist but no TICKET-MAP.md |
|
|
84
|
+
| `NEEDS_DISPATCH` | TICKET-MAP.md exists with `todo` tickets in a ready wave |
|
|
85
|
+
| `MONITORING` | Tickets are `inprogress` — workers running |
|
|
86
|
+
| `PHASE_COMPLETE` | All tickets in TICKET-MAP.md are `done` |
|
|
87
|
+
| `MILESTONE_COMPLETE` | Current phase is the last phase AND it's complete |
|
|
88
|
+
|
|
89
|
+
State: "Phase {X} state: {STATE}"
|
|
90
|
+
|
|
91
|
+
## 3. Execute Single Action
|
|
92
|
+
|
|
93
|
+
Based on the classified state, execute ONE action per cycle. Each action updates state and exits — the shell loop handles continuation.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### Action: NEEDS_PLANNING
|
|
98
|
+
|
|
99
|
+
Spawn gsd-planner agent to create plans for this phase.
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
Spawning planner for Phase {X}: {name}...
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Use Task tool to spawn gsd-planner:
|
|
106
|
+
- Provide phase goal from ROADMAP.md
|
|
107
|
+
- Provide PROJECT.md context
|
|
108
|
+
- Wait for plans to be written
|
|
109
|
+
|
|
110
|
+
Then spawn gsd-plan-checker to verify plan quality.
|
|
111
|
+
|
|
112
|
+
Update STATE.md: set phase status to "planned".
|
|
113
|
+
|
|
114
|
+
Log to PM-LOG.md:
|
|
115
|
+
```markdown
|
|
116
|
+
## [{TIMESTAMP}] PLANNED
|
|
117
|
+
|
|
118
|
+
- Phase {X}: {plan_count} plans created
|
|
119
|
+
- Plans: {list plan names}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Exit code 0** — next cycle will sync.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### Action: NEEDS_SYNC
|
|
127
|
+
|
|
128
|
+
Run pm-sync workflow:
|
|
129
|
+
1. Read all PLAN.md files in phase directory
|
|
130
|
+
2. For each plan, call `mcp__vibe_kanban__create_task` with:
|
|
131
|
+
- Title: "Phase {X} Plan {Y}: {objective}"
|
|
132
|
+
- Description: Full PLAN.md content (this IS the worker's prompt)
|
|
133
|
+
3. Write TICKET-MAP.md with all mappings
|
|
134
|
+
|
|
135
|
+
Update STATE.md: set phase status to "synced".
|
|
136
|
+
|
|
137
|
+
Log to PM-LOG.md:
|
|
138
|
+
```markdown
|
|
139
|
+
## [{TIMESTAMP}] SYNCED
|
|
140
|
+
|
|
141
|
+
- Phase {X}: {ticket_count} tickets created
|
|
142
|
+
- Project: {project_id}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Exit code 0** — next cycle will dispatch.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Action: NEEDS_DISPATCH
|
|
150
|
+
|
|
151
|
+
Run pm-dispatch workflow:
|
|
152
|
+
1. Identify the next ready wave (all prior waves complete)
|
|
153
|
+
2. For each `todo` ticket in this wave:
|
|
154
|
+
- Call `mcp__vibe_kanban__start_workspace_session` with:
|
|
155
|
+
- task_id, executor, repos (from config)
|
|
156
|
+
- Update TICKET-MAP.md: status → inprogress, dispatched timestamp
|
|
157
|
+
3. Log dispatch to PM-LOG.md
|
|
158
|
+
|
|
159
|
+
Update STATE.md: set phase status to "dispatched, wave {N}".
|
|
160
|
+
|
|
161
|
+
Log to PM-LOG.md:
|
|
162
|
+
```markdown
|
|
163
|
+
## [{TIMESTAMP}] DISPATCHED
|
|
164
|
+
|
|
165
|
+
- Wave {N}: {count} workers launched
|
|
166
|
+
- Executor: {executor}
|
|
167
|
+
- Tickets: {list ticket IDs}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Exit code 0** — next cycle will monitor.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Action: MONITORING
|
|
175
|
+
|
|
176
|
+
Run pm-check workflow:
|
|
177
|
+
1. Poll VK: `mcp__vibe_kanban__list_tasks(project_id)`
|
|
178
|
+
2. Diff against TICKET-MAP.md
|
|
179
|
+
3. Classify events and react:
|
|
180
|
+
|
|
181
|
+
**For each completed ticket:**
|
|
182
|
+
- Update TICKET-MAP.md: status → done, completed timestamp
|
|
183
|
+
- Log completion
|
|
184
|
+
|
|
185
|
+
**For each failed/cancelled ticket:**
|
|
186
|
+
- If `auto_replan_on_failure` is true in config:
|
|
187
|
+
- Run pm-replan workflow (TARGETED scope)
|
|
188
|
+
- Create fix ticket, dispatch it
|
|
189
|
+
- Else: log failure, continue monitoring
|
|
190
|
+
|
|
191
|
+
**If wave complete (all tickets in current wave done):**
|
|
192
|
+
- If `auto_dispatch_next_wave` is true AND more waves exist:
|
|
193
|
+
- Run pm-dispatch for next wave
|
|
194
|
+
- Else: log wave completion
|
|
195
|
+
|
|
196
|
+
**If all tickets done:**
|
|
197
|
+
- This is actually PHASE_COMPLETE — will be caught next cycle
|
|
198
|
+
|
|
199
|
+
**If no changes detected:**
|
|
200
|
+
- Brief log only: "No changes. {N} tickets inprogress."
|
|
201
|
+
|
|
202
|
+
Update STATE.md + TICKET-MAP.md + PM-LOG.md.
|
|
203
|
+
|
|
204
|
+
**Exit code 0** — next cycle continues monitoring or advances.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
### Action: PHASE_COMPLETE
|
|
209
|
+
|
|
210
|
+
1. Read ROADMAP.md
|
|
211
|
+
2. Identify next phase number
|
|
212
|
+
3. If next phase exists:
|
|
213
|
+
- Update STATE.md: advance to next phase, status "pending"
|
|
214
|
+
- Log phase completion
|
|
215
|
+
|
|
216
|
+
```markdown
|
|
217
|
+
## [{TIMESTAMP}] PHASE_COMPLETE
|
|
218
|
+
|
|
219
|
+
- Phase {X}: all {N} tickets done
|
|
220
|
+
- Duration: {start} → {end}
|
|
221
|
+
- Advancing to Phase {X+1}: {name}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Exit code 0** — next cycle will plan the new phase.
|
|
225
|
+
|
|
226
|
+
4. If no next phase → this is MILESTONE_COMPLETE.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
### Action: MILESTONE_COMPLETE
|
|
231
|
+
|
|
232
|
+
1. Log milestone completion:
|
|
233
|
+
|
|
234
|
+
```markdown
|
|
235
|
+
## [{TIMESTAMP}] MILESTONE_COMPLETE
|
|
236
|
+
|
|
237
|
+
- All {N} phases complete
|
|
238
|
+
- Total tickets: {count}
|
|
239
|
+
- Duration: {start} → {end}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
2. Create stop signal:
|
|
243
|
+
```bash
|
|
244
|
+
touch .planning/.pm-stop
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
3. Update STATE.md: milestone status "complete"
|
|
248
|
+
|
|
249
|
+
4. Present:
|
|
250
|
+
```
|
|
251
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
252
|
+
PM ► MILESTONE COMPLETE
|
|
253
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
254
|
+
|
|
255
|
+
All phases complete. PM loop will stop on next cycle.
|
|
256
|
+
|
|
257
|
+
Run /gsd:complete-milestone to archive and plan next.
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Exit with code 42** — signals shell loop to stop.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 4. Cycle Summary
|
|
265
|
+
|
|
266
|
+
After executing the action, output a brief cycle summary:
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
[{TIMESTAMP}] Cycle complete — State: {STATE} → Action: {ACTION}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
This is the only user-visible output per cycle (pm-loop.sh captures it).
|
|
273
|
+
|
|
274
|
+
</process>
|
|
275
|
+
|
|
276
|
+
<constraints>
|
|
277
|
+
- **One action per cycle.** Never do two lifecycle steps in one invocation. Let the loop handle progression.
|
|
278
|
+
- **Never write code.** You are a PM. You plan, delegate, monitor, replan. Workers write code.
|
|
279
|
+
- **Trust the files.** All truth is in .planning/ files. Don't assume or remember across cycles.
|
|
280
|
+
- **Exit codes matter.** 0 = continue, 42 = milestone done (stop loop), 1 = error.
|
|
281
|
+
- **Log everything.** Every action gets a PM-LOG.md entry with timestamp.
|
|
282
|
+
- **Respect wave discipline.** Never dispatch wave N+1 until all wave N tickets are done.
|
|
283
|
+
- **Replan, don't panic.** Failed tickets get auto-replanned, not abandoned.
|
|
284
|
+
</constraints>
|
package/commands/gsd/pm-start.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gsd:pm-start
|
|
3
|
-
description:
|
|
4
|
-
argument-hint: "<phase> [--
|
|
3
|
+
description: Start fully autonomous PM — plans, syncs, dispatches, monitors, and advances phases automatically
|
|
4
|
+
argument-hint: "<phase> [--manual] [--executor=CLAUDE_CODE] [--skip-plan] [--max-iterations=0]"
|
|
5
5
|
agent: gsd-pm
|
|
6
6
|
allowed-tools:
|
|
7
7
|
- Read
|
|
@@ -24,21 +24,23 @@ allowed-tools:
|
|
|
24
24
|
</execution_context>
|
|
25
25
|
|
|
26
26
|
<objective>
|
|
27
|
-
|
|
27
|
+
Start the fully autonomous PM agent. Validates environment, sets up VK connection, and launches `pm-loop.sh` — the Ralph-style infinite loop that handles the ENTIRE lifecycle:
|
|
28
28
|
|
|
29
|
-
**
|
|
29
|
+
**plan → sync tickets → dispatch workers → monitor → replan on failure → advance phases → complete milestone**
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
After this command, the PM runs unattended. Each loop cycle is a fresh Claude invocation via `/gsd:pm-cycle` — no context rot.
|
|
32
|
+
|
|
33
|
+
Use `--manual` to skip the loop and manage phases manually with `/gsd:pm-cycle`.
|
|
32
34
|
</objective>
|
|
33
35
|
|
|
34
36
|
<context>
|
|
35
|
-
Phase number: $ARGUMENTS (required —
|
|
37
|
+
Phase number: $ARGUMENTS (required — starting phase)
|
|
36
38
|
|
|
37
39
|
**Flags:**
|
|
38
|
-
- `--
|
|
39
|
-
- `--manual` — After dispatch, show status and available commands (default)
|
|
40
|
+
- `--manual` — Don't launch the loop, manage manually with `/gsd:pm-cycle`
|
|
40
41
|
- `--executor=X` — Override default executor (CLAUDE_CODE, CURSOR_AGENT, CODEX, etc.)
|
|
41
|
-
- `--skip-plan` — Skip planning, assume plans already exist
|
|
42
|
+
- `--skip-plan` — Skip initial planning, assume plans already exist
|
|
43
|
+
- `--max-iterations=N` — Safety cap on loop cycles (default: 0 = unlimited)
|
|
42
44
|
</context>
|
|
43
45
|
|
|
44
46
|
<process>
|
|
@@ -168,15 +170,14 @@ Present:
|
|
|
168
170
|
| ... | ... | ... | launched |
|
|
169
171
|
```
|
|
170
172
|
|
|
171
|
-
## 7.
|
|
173
|
+
## 7. Launch PM Loop (default: autonomous)
|
|
172
174
|
|
|
173
|
-
### Autonomous Mode (
|
|
175
|
+
### Autonomous Mode (default)
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
Launch pm-loop.sh:
|
|
177
|
+
Launch pm-loop.sh — the Ralph-style infinite loop that calls `/gsd:pm-cycle` each iteration. The brain handles everything from here: monitoring, wave advancement, replanning, phase progression.
|
|
177
178
|
|
|
178
179
|
```bash
|
|
179
|
-
nohup ~/.claude/scripts/pm-loop.sh --phase={X} --interval={poll_interval} > /
|
|
180
|
+
nohup ~/.claude/scripts/pm-loop.sh --phase={X} --interval={poll_interval} --max-iterations={max_iterations} > .planning/pm-loop.log 2>&1 &
|
|
180
181
|
echo $! > .planning/.pm-loop-pid
|
|
181
182
|
```
|
|
182
183
|
|
|
@@ -187,26 +188,32 @@ Present:
|
|
|
187
188
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
188
189
|
|
|
189
190
|
PM loop running (PID: {pid})
|
|
191
|
+
Brain: /gsd:pm-cycle (full lifecycle per iteration)
|
|
190
192
|
Polling every {interval}s
|
|
191
193
|
Log: .planning/PM-LOG.md
|
|
192
194
|
|
|
195
|
+
The PM will autonomously:
|
|
196
|
+
plan → sync → dispatch → monitor → replan → advance phases
|
|
197
|
+
|
|
193
198
|
Stop with: /gsd:pm-stop or touch .planning/.pm-stop
|
|
199
|
+
Status: /gsd:pm-status
|
|
194
200
|
```
|
|
195
201
|
|
|
196
|
-
### Manual Mode (
|
|
202
|
+
### Manual Mode (--manual)
|
|
203
|
+
|
|
204
|
+
Don't launch the loop. User runs `/gsd:pm-cycle` manually for each step.
|
|
197
205
|
|
|
198
206
|
Present:
|
|
199
207
|
```
|
|
200
208
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
201
|
-
PM ► MANUAL MODE
|
|
209
|
+
PM ► MANUAL MODE
|
|
202
210
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
203
211
|
|
|
204
|
-
Workers dispatched.
|
|
212
|
+
Workers dispatched. Run these commands to manage:
|
|
205
213
|
|
|
206
|
-
/gsd:pm-
|
|
214
|
+
/gsd:pm-cycle — Run one full-brain cycle (decides + acts)
|
|
207
215
|
/gsd:pm-status — View dashboard
|
|
208
|
-
/gsd:pm-replan — Modify plans
|
|
209
|
-
/gsd:pm-stop — Stop PM monitoring
|
|
216
|
+
/gsd:pm-replan — Modify plans with feedback
|
|
210
217
|
```
|
|
211
218
|
|
|
212
219
|
## 8. Update STATE.md
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# PM Cycle Workflow — Full-Brain Autonomous Decision Engine
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This workflow powers `/gsd:pm-cycle` — the autonomous PM brain. Each invocation reads all state, classifies the situation, executes one action, updates state, and exits. The shell loop (`pm-loop.sh`) handles repetition.
|
|
6
|
+
|
|
7
|
+
## State Classification
|
|
8
|
+
|
|
9
|
+
Read phase directory and TICKET-MAP.md to classify into exactly one state:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
NEEDS_PLANNING → No PLAN.md files
|
|
13
|
+
NEEDS_SYNC → Plans exist, no TICKET-MAP.md
|
|
14
|
+
NEEDS_DISPATCH → TICKET-MAP has todo tickets in ready wave
|
|
15
|
+
MONITORING → Tickets inprogress
|
|
16
|
+
PHASE_COMPLETE → All tickets done, more phases in roadmap
|
|
17
|
+
MILESTONE_COMPLETE → All tickets done, last phase in roadmap
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## State Machine
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
NEEDS_PLANNING ──spawn planner──→ NEEDS_SYNC
|
|
24
|
+
NEEDS_SYNC ──create tickets──→ NEEDS_DISPATCH
|
|
25
|
+
NEEDS_DISPATCH ──launch workers──→ MONITORING
|
|
26
|
+
MONITORING ──poll + react──→ MONITORING (loop)
|
|
27
|
+
──→ NEEDS_DISPATCH (wave complete, next wave ready)
|
|
28
|
+
──→ PHASE_COMPLETE (all done)
|
|
29
|
+
──→ MONITORING + replan (ticket failed)
|
|
30
|
+
PHASE_COMPLETE ──advance phase──→ NEEDS_PLANNING (next phase)
|
|
31
|
+
──→ MILESTONE_COMPLETE (last phase)
|
|
32
|
+
MILESTONE_COMPLETE ──stop signal──→ EXIT
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Action Details
|
|
36
|
+
|
|
37
|
+
### NEEDS_PLANNING
|
|
38
|
+
|
|
39
|
+
**Goal:** Create PLAN.md files for the current phase.
|
|
40
|
+
|
|
41
|
+
1. Read ROADMAP.md for phase goal and scope
|
|
42
|
+
2. Read PROJECT.md for project context
|
|
43
|
+
3. Spawn gsd-planner agent via Task tool:
|
|
44
|
+
- Provide: phase number, goal, project context, any prior learnings from PM-LOG
|
|
45
|
+
- Agent writes PLAN.md files to phase directory
|
|
46
|
+
4. Spawn gsd-plan-checker agent via Task tool:
|
|
47
|
+
- Verify plans against phase goal
|
|
48
|
+
- Max 3 planner↔checker iterations
|
|
49
|
+
5. Update STATE.md: phase status → "planned"
|
|
50
|
+
6. Log to PM-LOG.md
|
|
51
|
+
|
|
52
|
+
### NEEDS_SYNC
|
|
53
|
+
|
|
54
|
+
**Goal:** Create Vibe Kanban tickets for each plan.
|
|
55
|
+
|
|
56
|
+
Follow `pm-sync.md` workflow:
|
|
57
|
+
1. Read all PLAN.md files in phase directory
|
|
58
|
+
2. For each plan:
|
|
59
|
+
- Extract objective, wave number from frontmatter
|
|
60
|
+
- Create VK ticket: `mcp__vibe_kanban__create_task(project_id, title, description)`
|
|
61
|
+
- Description = full PLAN.md content (worker's complete prompt)
|
|
62
|
+
3. Write TICKET-MAP.md with mapping table
|
|
63
|
+
4. Update STATE.md: phase status → "synced"
|
|
64
|
+
5. Log to PM-LOG.md
|
|
65
|
+
|
|
66
|
+
### NEEDS_DISPATCH
|
|
67
|
+
|
|
68
|
+
**Goal:** Launch worker agents for the next ready wave.
|
|
69
|
+
|
|
70
|
+
Follow `pm-dispatch.md` workflow:
|
|
71
|
+
1. Parse TICKET-MAP.md for wave structure
|
|
72
|
+
2. Identify next undispatched wave where all prior waves are done
|
|
73
|
+
3. For each `todo` ticket in target wave:
|
|
74
|
+
- Call `mcp__vibe_kanban__start_workspace_session`:
|
|
75
|
+
- task_id: from TICKET-MAP
|
|
76
|
+
- executor: from config (default: CLAUDE_CODE)
|
|
77
|
+
- repos: from config (repo_id + base_branch)
|
|
78
|
+
- Update TICKET-MAP: status → inprogress, dispatched timestamp
|
|
79
|
+
4. Update STATE.md: phase status → "dispatched, wave {N}"
|
|
80
|
+
5. Log to PM-LOG.md
|
|
81
|
+
|
|
82
|
+
### MONITORING
|
|
83
|
+
|
|
84
|
+
**Goal:** Poll ticket status, react to changes.
|
|
85
|
+
|
|
86
|
+
Follow `pm-check.md` workflow:
|
|
87
|
+
1. Call `mcp__vibe_kanban__list_tasks(project_id)`
|
|
88
|
+
2. Diff current status against TICKET-MAP.md last-known status
|
|
89
|
+
3. For each change:
|
|
90
|
+
|
|
91
|
+
| Event | Reaction |
|
|
92
|
+
|-------|----------|
|
|
93
|
+
| Ticket: todo → inprogress | Update TICKET-MAP (worker started) |
|
|
94
|
+
| Ticket: inprogress → done | Update TICKET-MAP, check wave completion |
|
|
95
|
+
| Ticket: inprogress → inreview | Update TICKET-MAP (awaiting review) |
|
|
96
|
+
| Ticket: any → cancelled | If auto_replan: run pm-replan (TARGETED). Else: log warning |
|
|
97
|
+
| Wave complete | If auto_dispatch_next_wave: dispatch next wave. Else: log |
|
|
98
|
+
| All tickets done | Mark as PHASE_COMPLETE (caught next cycle) |
|
|
99
|
+
| No changes | Log: "No changes. {N} inprogress, {M} todo." |
|
|
100
|
+
|
|
101
|
+
4. Update TICKET-MAP.md + STATE.md + PM-LOG.md
|
|
102
|
+
|
|
103
|
+
**Stuck detection:** If a ticket has been `inprogress` for longer than 30 minutes (configurable), log a warning. After 60 minutes, consider re-dispatching with a different executor.
|
|
104
|
+
|
|
105
|
+
### PHASE_COMPLETE
|
|
106
|
+
|
|
107
|
+
**Goal:** Advance to next phase in roadmap.
|
|
108
|
+
|
|
109
|
+
1. Read ROADMAP.md
|
|
110
|
+
2. Find next phase after current
|
|
111
|
+
3. If next phase exists:
|
|
112
|
+
- Update STATE.md: current_phase → next phase, status → "pending"
|
|
113
|
+
- Log: "Phase {X} complete. Advancing to Phase {X+1}: {name}"
|
|
114
|
+
4. If no next phase:
|
|
115
|
+
- This is MILESTONE_COMPLETE
|
|
116
|
+
|
|
117
|
+
### MILESTONE_COMPLETE
|
|
118
|
+
|
|
119
|
+
**Goal:** Signal completion, stop loop.
|
|
120
|
+
|
|
121
|
+
1. Log: "Milestone complete. All {N} phases done."
|
|
122
|
+
2. Write `.planning/.pm-stop` file (signals pm-loop.sh to exit)
|
|
123
|
+
3. Update STATE.md: milestone_status → "complete"
|
|
124
|
+
4. Exit with code 42
|
|
125
|
+
|
|
126
|
+
## PM-LOG Entry Format
|
|
127
|
+
|
|
128
|
+
Every action writes a timestamped entry:
|
|
129
|
+
|
|
130
|
+
```markdown
|
|
131
|
+
## [{YYYY-MM-DD HH:MM:SS}] {ACTION}
|
|
132
|
+
|
|
133
|
+
- {detail 1}
|
|
134
|
+
- {detail 2}
|
|
135
|
+
- State: {previous} → {new}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Error Handling
|
|
139
|
+
|
|
140
|
+
- VK API errors: Log error, exit with code 1 (shell loop retries next cycle)
|
|
141
|
+
- Planner spawn failure: Log error, exit with code 1
|
|
142
|
+
- Dispatch failure (single ticket): Skip that ticket, continue with others, log
|
|
143
|
+
- All dispatches fail: Log error, exit with code 1
|
|
144
|
+
- State file missing: Log error, suggest `/gsd:pm-start`
|
package/package.json
CHANGED
package/scripts/pm-loop.sh
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# pm-loop.sh —
|
|
2
|
+
# pm-loop.sh — Fully autonomous PM loop (Ralph-style)
|
|
3
3
|
#
|
|
4
|
-
# Runs an infinite loop
|
|
4
|
+
# Runs an infinite loop. Each iteration invokes claude CLI with /gsd:pm-cycle —
|
|
5
|
+
# the full-brain PM that reads state, decides what to do, acts, and exits.
|
|
5
6
|
# Each invocation is a fresh 200k context — no context rot.
|
|
6
|
-
# State persists via .planning/ files
|
|
7
|
+
# State persists via .planning/ files.
|
|
8
|
+
#
|
|
9
|
+
# The PM brain handles the ENTIRE lifecycle autonomously:
|
|
10
|
+
# plan → sync tickets → dispatch workers → monitor → replan → advance phases → complete milestone
|
|
7
11
|
#
|
|
8
12
|
# Usage:
|
|
9
|
-
# ./scripts/pm-loop.sh [--phase=N] [--interval=60]
|
|
13
|
+
# ./scripts/pm-loop.sh [--phase=N] [--interval=60] [--max-iterations=50]
|
|
10
14
|
# PM_PHASE=1 PM_POLL_INTERVAL=30 ./scripts/pm-loop.sh
|
|
11
15
|
#
|
|
12
16
|
# Stop:
|
|
@@ -14,7 +18,7 @@
|
|
|
14
18
|
# OR run /gsd:pm-stop
|
|
15
19
|
#
|
|
16
20
|
# Background:
|
|
17
|
-
# nohup ./scripts/pm-loop.sh --phase=1 > /
|
|
21
|
+
# nohup ./scripts/pm-loop.sh --phase=1 > .planning/pm-loop.log 2>&1 &
|
|
18
22
|
|
|
19
23
|
set -euo pipefail
|
|
20
24
|
|
|
@@ -22,6 +26,7 @@ set -euo pipefail
|
|
|
22
26
|
|
|
23
27
|
PHASE="${PM_PHASE:-}"
|
|
24
28
|
INTERVAL="${PM_POLL_INTERVAL:-60}"
|
|
29
|
+
MAX_ITERS="${PM_MAX_ITERATIONS:-0}" # 0 = unlimited
|
|
25
30
|
|
|
26
31
|
for arg in "$@"; do
|
|
27
32
|
case $arg in
|
|
@@ -31,14 +36,27 @@ for arg in "$@"; do
|
|
|
31
36
|
--interval=*)
|
|
32
37
|
INTERVAL="${arg#*=}"
|
|
33
38
|
;;
|
|
39
|
+
--max-iterations=*)
|
|
40
|
+
MAX_ITERS="${arg#*=}"
|
|
41
|
+
;;
|
|
34
42
|
--help|-h)
|
|
35
|
-
echo "Usage: pm-loop.sh [--phase=N] [--interval=60]"
|
|
43
|
+
echo "Usage: pm-loop.sh [--phase=N] [--interval=60] [--max-iterations=0]"
|
|
44
|
+
echo ""
|
|
45
|
+
echo "Fully autonomous PM loop. Each cycle invokes /gsd:pm-cycle which"
|
|
46
|
+
echo "reads state and decides what to do: plan, sync, dispatch, monitor,"
|
|
47
|
+
echo "replan, advance phases, or complete milestone."
|
|
48
|
+
echo ""
|
|
49
|
+
echo "Options:"
|
|
50
|
+
echo " --phase=N Starting phase number (auto-detected if omitted)"
|
|
51
|
+
echo " --interval=N Seconds between cycles (default: 60)"
|
|
52
|
+
echo " --max-iterations=N Safety cap on cycles (default: 0 = unlimited)"
|
|
36
53
|
echo ""
|
|
37
54
|
echo "Environment variables:"
|
|
38
|
-
echo " PM_PHASE
|
|
39
|
-
echo " PM_POLL_INTERVAL
|
|
55
|
+
echo " PM_PHASE Phase number"
|
|
56
|
+
echo " PM_POLL_INTERVAL Seconds between cycles (default: 60)"
|
|
57
|
+
echo " PM_MAX_ITERATIONS Max cycles (default: 0 = unlimited)"
|
|
40
58
|
echo ""
|
|
41
|
-
echo "Stop: touch .planning/.pm-stop"
|
|
59
|
+
echo "Stop: touch .planning/.pm-stop OR /gsd:pm-stop"
|
|
42
60
|
exit 0
|
|
43
61
|
;;
|
|
44
62
|
*)
|
|
@@ -73,7 +91,7 @@ CYCLE=0
|
|
|
73
91
|
# Clean any stale stop signal
|
|
74
92
|
rm -f "$STOP_FILE"
|
|
75
93
|
|
|
76
|
-
# Record PID for /pm
|
|
94
|
+
# Record PID for /gsd:pm-stop
|
|
77
95
|
echo $$ > "$PID_FILE"
|
|
78
96
|
|
|
79
97
|
# ─── Init log ─────────────────────────────────────────────────────
|
|
@@ -88,6 +106,7 @@ Started: $TIMESTAMP
|
|
|
88
106
|
Mode: autonomous
|
|
89
107
|
Poll interval: ${INTERVAL}s
|
|
90
108
|
Phase: ${PHASE:-auto}
|
|
109
|
+
Max iterations: ${MAX_ITERS:-unlimited}
|
|
91
110
|
|
|
92
111
|
---
|
|
93
112
|
|
|
@@ -100,12 +119,16 @@ echo "" >> "$LOG_FILE"
|
|
|
100
119
|
echo "- PM loop started (PID: $$)" >> "$LOG_FILE"
|
|
101
120
|
echo "- Phase: ${PHASE:-auto-detect}" >> "$LOG_FILE"
|
|
102
121
|
echo "- Interval: ${INTERVAL}s" >> "$LOG_FILE"
|
|
122
|
+
echo "- Max iterations: ${MAX_ITERS:-unlimited}" >> "$LOG_FILE"
|
|
103
123
|
|
|
104
124
|
# ─── Main loop ────────────────────────────────────────────────────
|
|
105
125
|
|
|
106
126
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
107
127
|
echo " PM Loop — Phase: ${PHASE:-auto} | Interval: ${INTERVAL}s"
|
|
108
128
|
echo " PID: $$ | Stop: touch $STOP_FILE"
|
|
129
|
+
if [ "$MAX_ITERS" -gt 0 ] 2>/dev/null; then
|
|
130
|
+
echo " Max iterations: $MAX_ITERS"
|
|
131
|
+
fi
|
|
109
132
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
110
133
|
echo ""
|
|
111
134
|
|
|
@@ -123,33 +146,66 @@ while true; do
|
|
|
123
146
|
exit 0
|
|
124
147
|
fi
|
|
125
148
|
|
|
126
|
-
# ──
|
|
149
|
+
# ── Max iterations guard ──
|
|
127
150
|
CYCLE=$((CYCLE + 1))
|
|
151
|
+
if [ "$MAX_ITERS" -gt 0 ] 2>/dev/null && [ "$CYCLE" -gt "$MAX_ITERS" ]; then
|
|
152
|
+
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
|
153
|
+
echo "[$TIMESTAMP] Max iterations ($MAX_ITERS) reached. Stopping."
|
|
154
|
+
echo "" >> "$LOG_FILE"
|
|
155
|
+
echo "## [$TIMESTAMP] MAX_ITERATIONS" >> "$LOG_FILE"
|
|
156
|
+
echo "" >> "$LOG_FILE"
|
|
157
|
+
echo "- Reached max iterations: $MAX_ITERS" >> "$LOG_FILE"
|
|
158
|
+
rm -f "$PID_FILE"
|
|
159
|
+
exit 0
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# ── Run one brain cycle ──
|
|
128
163
|
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
|
129
|
-
echo "[$TIMESTAMP] Cycle #$CYCLE —
|
|
164
|
+
echo "[$TIMESTAMP] Cycle #$CYCLE — brain thinking..."
|
|
130
165
|
|
|
131
|
-
#
|
|
166
|
+
# Build the prompt
|
|
132
167
|
if [ -n "$PHASE" ]; then
|
|
133
|
-
|
|
134
|
-
|
|
168
|
+
PROMPT="/gsd:pm-cycle $PHASE"
|
|
169
|
+
else
|
|
170
|
+
PROMPT="/gsd:pm-cycle"
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
# Fresh Claude invocation — full brain, fresh 200k context
|
|
174
|
+
claude -p --dangerously-skip-permissions "$PROMPT" 2>&1
|
|
175
|
+
EXIT_CODE=$?
|
|
176
|
+
|
|
177
|
+
# ── Handle exit codes ──
|
|
178
|
+
case $EXIT_CODE in
|
|
179
|
+
0)
|
|
180
|
+
# Normal — more work to do, continue loop
|
|
181
|
+
;;
|
|
182
|
+
42)
|
|
183
|
+
# Milestone complete — all done
|
|
184
|
+
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
|
185
|
+
echo ""
|
|
186
|
+
echo "[$TIMESTAMP] Milestone complete! PM loop exiting."
|
|
135
187
|
echo "" >> "$LOG_FILE"
|
|
136
|
-
echo "## [$TIMESTAMP]
|
|
188
|
+
echo "## [$TIMESTAMP] LOOP_EXIT" >> "$LOG_FILE"
|
|
137
189
|
echo "" >> "$LOG_FILE"
|
|
138
|
-
echo "-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
190
|
+
echo "- Milestone complete after $CYCLE cycles" >> "$LOG_FILE"
|
|
191
|
+
rm -f "$PID_FILE"
|
|
192
|
+
exit 0
|
|
193
|
+
;;
|
|
194
|
+
*)
|
|
195
|
+
# Error — log and continue (don't crash the loop)
|
|
196
|
+
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
|
197
|
+
echo "[$TIMESTAMP] WARNING: claude exited with code $EXIT_CODE (cycle #$CYCLE)"
|
|
143
198
|
echo "" >> "$LOG_FILE"
|
|
144
199
|
echo "## [$TIMESTAMP] ERROR" >> "$LOG_FILE"
|
|
145
200
|
echo "" >> "$LOG_FILE"
|
|
146
|
-
echo "- Claude exited with
|
|
147
|
-
|
|
148
|
-
|
|
201
|
+
echo "- Claude exited with code $EXIT_CODE on cycle #$CYCLE" >> "$LOG_FILE"
|
|
202
|
+
;;
|
|
203
|
+
esac
|
|
149
204
|
|
|
150
205
|
echo ""
|
|
151
206
|
|
|
152
207
|
# ── Sleep until next cycle ──
|
|
153
|
-
|
|
208
|
+
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
|
209
|
+
echo "[$TIMESTAMP] Next cycle in ${INTERVAL}s..."
|
|
154
210
|
sleep "$INTERVAL"
|
|
155
211
|
done
|