maestro-flow 0.3.34 → 0.3.35

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.
@@ -12,42 +12,33 @@ allowed-tools:
12
12
  - Skill
13
13
  ---
14
14
  <purpose>
15
- Unified single-step executor for both maestro and ralph sessions.
16
- All sessions stored at `.workflow/.maestro/*/status.json` with unified JSON schema.
17
-
18
- Each invocation:
19
- 1. Finds the next pending step in the session
20
- 2. Executes it based on node type (decision → ralph, skill → Skill(), cli → delegate)
21
- 3. Updates status.json
22
- 4. Hands off to next iteration via self-invocation or ralph callback
23
-
24
- Two session sources:
25
- - **source: "maestro"** — Static chain, no decision nodes. Steps are `type: "skill"|"cli"` only.
26
- - **source: "ralph"** — Adaptive chain with decision nodes. Steps include `type: "decision"`.
27
-
28
- Three node types drive different execution + handoff patterns:
29
- - **decision**: `Skill("maestro-ralph")` ralph re-evaluates state, may expand chain (ralph-only)
30
- - **skill**: `Skill({ skill, args })` — synchronous in-session → `Skill("maestro-ralph-execute")`
31
- - **cli**: `maestro delegate` background → STOP → callback → `Skill("maestro-ralph-execute")`
32
-
33
- Mutual invocation with `/maestro-ralph` forms a persistent self-perpetuating work loop (ralph sessions).
34
- For maestro sessions, execution is purely sequential with no decision callbacks.
15
+ Single-step executor for ralph (adaptive) and maestro (static) sessions.
16
+ Sessions stored at `.workflow/.maestro/*/status.json` with unified JSON schema.
17
+
18
+ Each invocation: find next pending step → execute → update status → hand off to next iteration.
19
+
20
+ Three node types:
21
+ - **decision** (ralph-only): `Skill("maestro-ralph")` — ralph re-evaluates, may expand chain
22
+ - **skill**: `Skill({ skill, args })` synchronous in-session self-invoke next
23
+ - **cli**: `maestro delegate` background → STOP → callback → self-invoke next
24
+
25
+ Session sources:
26
+ - **source: "ralph"** — Adaptive chain with decision nodes. Primary use case.
27
+ - **source: "maestro"** — Static chain, skill/cli only. No decision callbacks.
28
+
29
+ Mutual invocation with `/maestro-ralph` forms a self-perpetuating work loop.
35
30
  </purpose>
36
31
 
37
32
  <context>
38
- $ARGUMENTS — optional `-y` flag + optional session ID. If session ID omitted, finds latest running session.
33
+ $ARGUMENTS — optional `-y` flag + optional session ID.
39
34
 
40
35
  **Flag parsing:**
41
36
  ```
42
- Parse $ARGUMENTS:
43
- Contains "-y" or "--yes" auto = true, remove flag from remaining args
44
- Remaining → session_id (if matches maestro-* or ralph-* pattern)
37
+ -y / --yes → auto = true (remove from remaining args)
38
+ Remainingsession_id (if matches maestro-* or ralph-* pattern)
45
39
  ```
46
40
 
47
- **Session discovery:**
48
- Scan `.workflow/.maestro/*/status.json` for `status == "running"`, sorted by `updated_at` or dir mtime descending.
49
- If remaining args match a session ID pattern, use that specific session.
50
- Also read `session.auto_mode` from status.json — if `true`, treat as `-y` even if flag not passed.
41
+ Also read `session.auto_mode` from status.json — if `true`, treat as `-y` even without flag.
51
42
  </context>
52
43
 
53
44
  <execution>
@@ -60,7 +51,7 @@ If $ARGUMENTS matches maestro-* or ralph-* pattern:
60
51
  Else:
61
52
  Scan .workflow/.maestro/*/status.json
62
53
  Filter: status == "running"
63
- Sort: mtime DESC (or updated_at DESC)
54
+ Sort: updated_at DESC (or dir mtime DESC)
64
55
  Take first
65
56
 
66
57
  If no session found:
@@ -68,53 +59,44 @@ If no session found:
68
59
  End.
69
60
  ```
70
61
 
71
- Read status.json → extract: `session_id`, `source`, `steps[]`, `current_step`, `status`, `phase`, `auto_mode`.
62
+ Read status.json → extract: `session_id`, `source`, `steps[]`, `current_step`, `status`, `phase`, `milestone`, `intent`, `auto_mode`, `context`, `cli_tool`.
72
63
 
73
64
  ## Step 2: Find Next Pending Step
74
65
 
75
66
  ```
76
67
  next = steps.find(step => step.status == "pending")
77
-
78
- If no pending step:
79
- → Step 5 (Complete)
68
+ If no pending step → Step 6 (Complete)
80
69
  ```
81
70
 
82
- ## Step 2.5: Assemble Args (context propagation)
71
+ ## Step 3: Resolve Args (context propagation)
83
72
 
84
- Before execution, enrich `next.args` with context from session and prior outputs.
73
+ Before execution, enrich `next.args` with session context and prior outputs.
85
74
 
86
- **Context sources (priority order):**
87
- 1. `status.json.intent` — user's original input text
88
- 2. `status.json.phase` — current phase number
89
- 3. `status.json.milestone` — current milestone name
90
- 4. `status.json.context` — nested context object (plan_dir, analysis_dir, scratch_dir, etc.)
91
- 5. `.workflow/state.json.artifacts[]` — latest artifacts for path resolution
92
- 6. Previous completed step outputs — scratch dirs, session IDs
75
+ **Placeholder substitution:**
93
76
 
94
- **Placeholder substitution in args:**
95
- ```
96
- {phase} status.phase
97
- {milestone} status.milestone
98
- {intent} status.intent
99
- {description} status.intent (alias)
100
- {scratch_dir} status.context.scratch_dir or latest artifact path
101
- {plan_dir} status.context.plan_dir
102
- {analysis_dir} status.context.analysis_dir
103
- {issue_id} status.context.issue_id
104
- {milestone_num} status.context.milestone_num
105
- ```
77
+ | Placeholder | Source |
78
+ |-------------|--------|
79
+ | `{phase}` | status.phase |
80
+ | `{milestone}` | status.milestone |
81
+ | `{intent}` | status.intent |
82
+ | `{description}` | status.intent (alias) |
83
+ | `{scratch_dir}` | status.context.scratch_dir or latest artifact path |
84
+ | `{plan_dir}` | status.context.plan_dir |
85
+ | `{analysis_dir}` | status.context.analysis_dir |
86
+ | `{issue_id}` | status.context.issue_id |
87
+ | `{milestone_num}` | status.context.milestone_num |
106
88
 
107
89
  **Per-skill enrichment** (when args is empty or only has phase number):
108
90
 
109
91
  | Skill | Required context | Source |
110
92
  |-------|-----------------|--------|
111
- | maestro-brainstorm | topic description | `status.intent` — pass as `"{intent}"` |
112
- | maestro-roadmap | description + context | `status.intent` — pass as `"{intent}"` |
93
+ | maestro-brainstorm | topic description | `"{intent}"` |
94
+ | maestro-roadmap | description + context | `"{intent}"` |
113
95
  | maestro-analyze | phase or topic | `{phase}` or `"{intent}"` if no phase |
114
96
  | maestro-plan | phase or --dir | `{phase}`, or `--dir {scratch_dir}` if standalone |
115
97
  | maestro-execute | phase or --dir | `{phase}`, or `--dir {scratch_dir}` if standalone |
116
98
  | maestro-verify | phase | `{phase}` |
117
- | quality-debug | gap context | Read previous step's error or gap summary from artifact dir |
99
+ | quality-debug | gap context | Read previous step's error/gap summary from artifact dir |
118
100
  | quality-* | phase | `{phase}` |
119
101
 
120
102
  **Artifact dir resolution for --dir args:**
@@ -125,20 +107,15 @@ For plan commands: find latest type=="analyze" artifact → --dir .workflow/scra
125
107
  For execute commands: find latest type=="plan" artifact → --dir .workflow/scratch/{path}
126
108
  ```
127
109
 
128
- **Write enriched args back to status.json** so resume preserves them:
129
- ```
130
- next.args = enriched_args
131
- Write status.json
132
- ```
110
+ Write enriched args back to status.json (resume-safe).
133
111
 
134
- ## Step 3: Mark Running + Update JSON
112
+ ## Step 4: Mark Running
135
113
 
136
114
  ```
137
115
  next.status = "running"
138
- next.started_at = new Date().toISOString()
116
+ next.started_at = ISO timestamp
139
117
  status.current_step = next.index
140
- status.updated_at = new Date().toISOString()
141
-
118
+ status.updated_at = ISO timestamp
142
119
  Write status.json
143
120
  ```
144
121
 
@@ -149,115 +126,69 @@ Display step banner:
149
126
  ------------------------------------------------------------
150
127
  Session: {session_id} [{source}]
151
128
  Args: {next.args}
152
- {next.type == "decision" ? "Retry: " + JSON.parse(next.args).retry_count + "/" + JSON.parse(next.args).max_retries : ""}
153
129
  ```
154
130
 
155
- **Context weight hint** (after 4+ completed steps, skip if auto):
131
+ If decision node: also show `Retry: {retry_count}/{max_retries}` from parsed args.
132
+
133
+ Context weight hint (non-auto only, after 4+ completed steps):
156
134
  ```
157
- If completed_count >= 4 && !auto:
158
- Display: ⚡ 已执行 {completed_count} 步,上下文较重。可 /maestro-ralph continue 在新上下文恢复。
135
+ 已执行 {completed_count} 步,上下文较重。可 /maestro-ralph continue 在新上下文恢复。
159
136
  ```
160
137
 
161
- ## Step 4: Execute by Type
138
+ ## Step 5: Execute by Type
162
139
 
163
- ### 4a. decision node (ralph-only)
140
+ ### 5a. decision node (ralph-only)
164
141
 
165
- Decision nodes hand control back to ralph for re-evaluation.
142
+ Hand control back to ralph for re-evaluation.
166
143
 
167
144
  ```
168
145
  Skill({ skill: "maestro-ralph" })
169
146
  ```
170
147
 
171
- Ralph will:
172
- 1. Detect the running decision node in status.json
173
- 2. Evaluate execution results (verify gaps, test failures, etc.)
174
- 3. Optionally expand steps[] with fix loops
175
- 4. Mark the decision node completed
176
- 5. Call `Skill("maestro-ralph-execute")` to resume
148
+ Ralph will: detect running decision → evaluate results → optionally expand steps[] → mark completed → call ralph-execute to resume.
177
149
 
178
150
  **After Skill("maestro-ralph") returns, this execution ends.** Ralph handles the handoff.
179
151
 
180
- ### 4b. skill node
181
-
182
- Synchronous in-session execution.
183
-
184
- **`-y` auto flag 传播:** 当 `auto == true` 时,按传播表对目标 skill 附加 auto flag:
185
- ```
186
- auto_flag_map = {
187
- "maestro-init": "-y",
188
- "maestro-analyze": "-y",
189
- "maestro-brainstorm": "-y",
190
- "maestro-roadmap": "-y",
191
- "maestro-ui-design": "-y",
192
- "maestro-plan": "-y",
193
- "maestro-execute": "-y",
194
- "quality-auto-test": "-y",
195
- "quality-test": "-y --auto-fix",
196
- "quality-retrospective": "-y",
197
- "maestro-milestone-complete": "-y"
198
- }
199
- flag = auto_flag_map[next.skill] || ""
200
- effective_args = flag ? `${next.args} ${flag}` : next.args
201
- ```
152
+ ### 5b. skill node
202
153
 
203
- ```
204
- Skill({ skill: next.skill, args: effective_args })
205
- ```
154
+ HARD RULE: Every skill step MUST be executed via `Skill({ skill, args })`.
155
+ Never "simulate" or "inline" a skill's work. If Skill() is not called, the step has NOT been executed.
206
156
 
207
- On success:
208
- ```
209
- next.status = "completed"
210
- next.completed_at = new Date().toISOString()
157
+ **Auto flag propagation** (when `auto == true`):
211
158
 
212
- Scan output for context propagation signals:
213
- PHASE: N → status.phase
214
- scratch_dir: path context.scratch_dir
215
- SPEC-xxx → context.spec_session_id
159
+ | Skill | Flag appended |
160
+ |-------|---------------|
161
+ | maestro-init | `-y` |
162
+ | maestro-analyze | `-y` |
163
+ | maestro-brainstorm | `-y` |
164
+ | maestro-roadmap | `-y` |
165
+ | maestro-ui-design | `-y` |
166
+ | maestro-plan | `-y` |
167
+ | maestro-execute | `-y` |
168
+ | quality-auto-test | `-y` |
169
+ | quality-test | `-y --auto-fix` |
170
+ | quality-retrospective | `-y` |
171
+ | maestro-milestone-complete | `-y` |
216
172
 
217
- Write status.json
218
-
219
- Display: [N/total] ✓ {next.skill} completed
220
- ```
221
-
222
- On failure (Skill throws or produces error):
223
173
  ```
224
- next.status = "failed"
225
- next.error = "{error message}"
226
- next.completed_at = new Date().toISOString()
227
- Write status.json
228
-
229
- Display: [N/total] ✗ {next.skill} failed: {error}
174
+ flag = auto_flag_map[next.skill] || ""
175
+ effective_args = flag ? `${next.args} ${flag}` : next.args
230
176
 
231
- If auto:
232
- If not next.retried:
233
- next.retried = true, next.status = "pending", next.error = null → retry once
234
- Else:
235
- next.status = "skipped" → continue (auto-skip)
236
- Display: [N/total] ⏭ {next.skill} auto-skipped after retry
237
- Else:
238
- AskUserQuestion: "retry / skip / abort"
239
- retry → reset next.status = "pending", next.error = null → Skill("maestro-ralph-execute")
240
- skip → next.status = "skipped" → Skill("maestro-ralph-execute")
241
- abort → status.status = "paused" → Write status.json → End.
177
+ Skill({ skill: next.skill, args: effective_args })
242
178
  ```
243
179
 
244
- Then hand off:
245
- ```
246
- Skill({ skill: "maestro-ralph-execute" })
247
- ```
180
+ **On success** → Step 5d (Mark Complete).
181
+ **On failure** → Step 5e (Handle Failure).
248
182
 
249
- ### 4c. cli node
183
+ ### 5c. cli node
250
184
 
251
185
  Background delegate execution with stop-and-wait pattern.
252
186
 
253
- Resolve CLI tool from session or default config:
254
187
  ```
255
188
  cli_tool = session.cli_tool || "gemini"
256
- ```
257
189
 
258
- ```
259
190
  Bash({
260
- command: `maestro delegate "PURPOSE: 执行 /${next.skill} ${next.args}; success = 命令正常完成并产出 artifact
191
+ command: `maestro delegate "PURPOSE: 执行 /${next.skill} ${next.args}
261
192
  TASK: 运行 /${next.skill} ${next.args}
262
193
  MODE: write
263
194
  CONTEXT: @**/*
@@ -271,41 +202,68 @@ STOP — wait for background callback.
271
202
  ```
272
203
 
273
204
  **On callback:**
205
+ - Retrieve output: `maestro delegate output <exec_id>`
206
+ - **On success** → Step 5d (Mark Complete)
207
+ - **On failure** → Step 5e (Handle Failure)
274
208
 
275
- ```
276
- Retrieve output: maestro delegate output <exec_id>
209
+ ### 5d. Mark Complete (shared)
277
210
 
211
+ ```
278
212
  next.status = "completed"
279
- next.completed_at = new Date().toISOString()
213
+ next.completed_at = ISO timestamp
280
214
 
281
- Scan output for context propagation (same as 4b).
215
+ Scan output for context propagation signals:
216
+ PHASE: N → status.phase
217
+ scratch_dir: path → context.scratch_dir
218
+ SPEC-xxx → context.spec_session_id
282
219
 
283
220
  Write status.json
221
+ Display: [{next.index}/{total}] ✓ {next.skill} completed {next.type == "cli" ? "[cli]" : ""}
222
+ ```
284
223
 
285
- Display: [N/total] ✓ {next.skill} completed [cli]
224
+ Then hand off:
225
+ ```
226
+ Skill({ skill: "maestro-ralph-execute" })
286
227
  ```
287
228
 
288
- On failure:
229
+ ### 5e. Handle Failure (shared)
230
+
289
231
  ```
290
232
  next.status = "failed"
291
- next.error = "{error details}"
233
+ next.error = "{error message}"
234
+ next.completed_at = ISO timestamp
292
235
  Write status.json
293
236
 
294
- (same as 4b failure handling: auto → retry once then skip; else → AskUserQuestion)
237
+ Display: [{next.index}/{total}] {next.skill} failed: {error}
295
238
  ```
296
239
 
297
- Then hand off:
240
+ **Auto mode:**
298
241
  ```
299
- Skill({ skill: "maestro-ralph-execute" })
242
+ If not next.retried:
243
+ next.retried = true, next.status = "pending", next.error = null
244
+ Write status.json → Skill("maestro-ralph-execute") // retry once
245
+ Else:
246
+ next.status = "skipped"
247
+ Write status.json
248
+ Display: [{next.index}/{total}] ⏭ {next.skill} auto-skipped after retry
249
+ → Skill("maestro-ralph-execute") // continue
300
250
  ```
301
251
 
302
- ## Step 5: Complete Session
252
+ **Interactive mode (non-auto):**
253
+ ```
254
+ AskUserQuestion: "retry / skip / abort"
255
+ retry → next.status = "pending", next.error = null → Skill("maestro-ralph-execute")
256
+ skip → next.status = "skipped" → Skill("maestro-ralph-execute")
257
+ abort → status.status = "paused" → Write status.json → End.
258
+ ```
259
+
260
+ ## Step 6: Complete Session
303
261
 
304
262
  When no pending steps remain:
305
263
 
306
264
  ```
307
265
  status.status = "completed"
308
- status.updated_at = new Date().toISOString()
266
+ status.updated_at = ISO timestamp
309
267
  Write status.json
310
268
  ```
311
269
 
@@ -319,17 +277,18 @@ Display completion report:
319
277
  Phase: {phase}
320
278
  Steps: {completed}/{total}
321
279
 
322
- {steps.map(step => {
323
- icon = step.status == "completed" ? "✓" :
324
- step.status == "skipped" ? "—" :
325
- step.status == "failed" ? "✗" : " "
326
- type_badge = step.type == "decision" ? "◆" :
327
- step.type == "cli" ? "⚡" : " "
328
- return ` [${icon}] ${step.index}. ${type_badge} ${step.skill} ${step.args} [${step.type}]`
329
- })}
280
+ [✓] 0. maestro-plan 1 [skill]
281
+ [✓] 1. maestro-execute 1 [cli]
282
+ [✓] 2. maestro-verify 1 [skill]
283
+ [✓] 3. post-verify [decision]
284
+ [—] 4. quality-auto-test 1 [skill] (skipped)
285
+ ...
330
286
  ============================================================
331
287
  ```
332
288
 
289
+ Status icons: `✓` completed, `—` skipped, `✗` failed, ` ` pending.
290
+ Type badges: `◆` decision, `⚡` cli, (none) skill.
291
+
333
292
  **End.**
334
293
 
335
294
  </execution>
@@ -337,25 +296,25 @@ Display completion report:
337
296
  <error_codes>
338
297
  | Code | Severity | Description | Recovery |
339
298
  |------|----------|-------------|----------|
340
- | E001 | error | No running session found | Suggest /maestro or /maestro-ralph to create |
341
- | E002 | error | Session status.json corrupt or unreadable | Show path, suggest manual check |
342
- | E003 | error | CLI delegate failed + user chose abort | Mark paused, suggest resume |
299
+ | E001 | error | No running session found | Suggest /maestro or /maestro-ralph |
300
+ | E002 | error | Session status.json corrupt | Show path, suggest manual check |
301
+ | E003 | error | CLI delegate failed + user abort | Mark paused, suggest resume |
343
302
  | W001 | warning | Step completed with warnings | Log and continue |
344
- | W002 | warning | Context getting heavy (step >= 4) | Hint: fresh context resume |
303
+ | W002 | warning | Context heavy (step >= 4) | Hint: /maestro-ralph continue |
345
304
  </error_codes>
346
305
 
347
306
  <success_criteria>
348
- - [ ] Session discovery scans .workflow/.maestro/ (covers both maestro-* and ralph-* sessions)
349
- - [ ] Reads unified JSON: steps[], current_step, session_id, auto_mode, source
307
+ - [ ] Session discovery scans .workflow/.maestro/ (covers both maestro-* and ralph-*)
350
308
  - [ ] `-y` flag parsed from args OR inherited from session.auto_mode
351
- - [ ] Pending step correctly identified from steps[]
309
+ - [ ] Placeholder substitution resolves all `{...}` tokens from session context
310
+ - [ ] Per-skill enrichment provides correct args when empty/minimal
311
+ - [ ] Artifact dir resolution finds latest artifact for --dir args
352
312
  - [ ] decision nodes hand off to maestro-ralph via Skill() (ralph sessions only)
353
- - [ ] skill nodes execute synchronously via Skill() and self-invoke next
354
- - [ ] cli nodes use maestro delegate with run_in_background + stop pattern
355
- - [ ] `-y` auto flag 按传播表附加到目标 skill args
313
+ - [ ] skill nodes execute via Skill() with auto flag propagation
314
+ - [ ] cli nodes use maestro delegate with run_in_background + STOP pattern
356
315
  - [ ] Context propagation: output signals update status.json.context
357
316
  - [ ] status.json updated after every status change (resume-safe)
358
- - [ ] auto 模式:失败重试一次后 auto-skip;非 auto:AskUserQuestion retry/skip/abort
317
+ - [ ] Auto mode: retry once then skip; interactive: AskUserQuestion retry/skip/abort
359
318
  - [ ] Completion report shows all steps with status icons and type badges
360
- - [ ] Self-invocation chain continues until all steps complete
319
+ - [ ] Self-invocation chain continues until all steps complete or session paused
361
320
  </success_criteria>