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.
@@ -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>
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: gsd:pm-start
3
- description: Plan a phase, sync to Vibe Kanban tickets, dispatch workers, optionally start autonomous monitor loop
4
- argument-hint: "<phase> [--autonomous] [--manual] [--executor=CLAUDE_CODE] [--skip-plan]"
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
- Initialize PM mode for a phase: create plans (unless --skip-plan), sync to Vibe Kanban tickets, dispatch wave 1 workers, and optionally launch the autonomous monitoring loop.
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
- **This is the main PM entry point.** It transitions GSD from local execution to external delegation.
29
+ **plan sync tickets dispatch workers monitor replan on failure advance phases → complete milestone**
30
30
 
31
- **Orchestrator role:** Validate environment, run planning pipeline if needed, sync plans to VK tickets, dispatch workers, optionally start pm-loop.sh.
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 — which phase to manage)
37
+ Phase number: $ARGUMENTS (required — starting phase)
36
38
 
37
39
  **Flags:**
38
- - `--autonomous` — After dispatch, launch pm-loop.sh for continuous monitoring
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 (use with /gsd:plan-phase)
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. Start Monitor (mode-dependent)
173
+ ## 7. Launch PM Loop (default: autonomous)
172
174
 
173
- ### Autonomous Mode (--autonomous)
175
+ ### Autonomous Mode (default)
174
176
 
175
- Initialize PM-LOG.md with INIT entry.
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} > /dev/null 2>&1 &
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 (default)
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 — WORKERS RUNNING
209
+ PM ► MANUAL MODE
202
210
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
203
211
 
204
- Workers dispatched. Use these commands to manage:
212
+ Workers dispatched. Run these commands to manage:
205
213
 
206
- /gsd:pm-checkPoll ticket status and react
214
+ /gsd:pm-cycleRun one full-brain cycle (decides + acts)
207
215
  /gsd:pm-status — View dashboard
208
- /gsd:pm-replan — Modify plans if issues found
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-cook",
3
- "version": "1.10.1",
3
+ "version": "1.10.2",
4
4
  "description": "A meta-prompting, context engineering and spec-driven development system for Claude Code, OpenCode and Gemini by TÂCHES.",
5
5
  "bin": {
6
6
  "claude-cook": "bin/install.js"
@@ -1,12 +1,16 @@
1
1
  #!/bin/bash
2
- # pm-loop.sh — Autonomous PM monitor loop
2
+ # pm-loop.sh — Fully autonomous PM loop (Ralph-style)
3
3
  #
4
- # Runs an infinite loop that invokes claude CLI with /gsd:pm-check on each cycle.
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 (TICKET-MAP.md, STATE.md, PM-LOG.md).
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 > /dev/null 2>&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 Phase number to monitor"
39
- echo " PM_POLL_INTERVAL Seconds between poll cycles (default: 60)"
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:stop
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
- # ── Run one check cycle ──
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 — polling..."
164
+ echo "[$TIMESTAMP] Cycle #$CYCLE — brain thinking..."
130
165
 
131
- # Fresh Claude invocation each cycle = no context rot
166
+ # Build the prompt
132
167
  if [ -n "$PHASE" ]; then
133
- claude --print --dangerously-skip-permissions --command "/gsd:pm-check $PHASE" 2>&1 || {
134
- echo "[$TIMESTAMP] WARNING: claude exited with error (cycle #$CYCLE)"
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] ERROR" >> "$LOG_FILE"
188
+ echo "## [$TIMESTAMP] LOOP_EXIT" >> "$LOG_FILE"
137
189
  echo "" >> "$LOG_FILE"
138
- echo "- Claude exited with error on cycle #$CYCLE" >> "$LOG_FILE"
139
- }
140
- else
141
- claude --print --dangerously-skip-permissions --command "/gsd:pm-check" 2>&1 || {
142
- echo "[$TIMESTAMP] WARNING: claude exited with error (cycle #$CYCLE)"
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 error on cycle #$CYCLE" >> "$LOG_FILE"
147
- }
148
- fi
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
- echo "[$TIMESTAMP] Next check in ${INTERVAL}s..."
208
+ TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
209
+ echo "[$TIMESTAMP] Next cycle in ${INTERVAL}s..."
154
210
  sleep "$INTERVAL"
155
211
  done