maestro-flow 0.4.21 → 0.4.23

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 (63) hide show
  1. package/.agents/skills/maestro-analyze/SKILL.md +78 -34
  2. package/.agents/skills/maestro-blueprint/SKILL.md +57 -24
  3. package/.agents/skills/maestro-brainstorm/SKILL.md +69 -34
  4. package/.agents/skills/maestro-execute/SKILL.md +45 -15
  5. package/.agents/skills/maestro-grill/SKILL.md +63 -38
  6. package/.agents/skills/maestro-init/SKILL.md +59 -17
  7. package/.agents/skills/maestro-milestone-audit/SKILL.md +48 -5
  8. package/.agents/skills/maestro-milestone-complete/SKILL.md +48 -6
  9. package/.agents/skills/maestro-milestone-release/SKILL.md +42 -11
  10. package/.agents/skills/maestro-plan/SKILL.md +19 -13
  11. package/.agents/skills/maestro-roadmap/SKILL.md +59 -29
  12. package/.agents/skills/maestro-verify/SKILL.md +46 -11
  13. package/.agents/skills/team-adversarial-swarm/scripts/__pycache__/pheromone.cpython-313.pyc +0 -0
  14. package/.agents/skills/team-adversarial-swarm/scripts/__pycache__/scoring.cpython-313.pyc +0 -0
  15. package/.agents/skills/team-adversarial-swarm/scripts/aco.py +15 -15
  16. package/.agents/skills/team-adversarial-swarm/scripts/pheromone.py +2 -2
  17. package/.agents/skills/team-adversarial-swarm/scripts/scoring.py +1 -1
  18. package/.agents/skills/team-swarm/scripts/aco.py +15 -15
  19. package/.agents/skills/team-swarm/scripts/pheromone.py +2 -2
  20. package/.agents/skills/team-swarm/scripts/scoring.py +1 -1
  21. package/.agy/skills/maestro-analyze/SKILL.md +78 -34
  22. package/.agy/skills/maestro-blueprint/SKILL.md +57 -24
  23. package/.agy/skills/maestro-brainstorm/SKILL.md +69 -34
  24. package/.agy/skills/maestro-execute/SKILL.md +45 -15
  25. package/.agy/skills/maestro-grill/SKILL.md +63 -38
  26. package/.agy/skills/maestro-init/SKILL.md +59 -17
  27. package/.agy/skills/maestro-milestone-audit/SKILL.md +48 -5
  28. package/.agy/skills/maestro-milestone-complete/SKILL.md +48 -6
  29. package/.agy/skills/maestro-milestone-release/SKILL.md +42 -11
  30. package/.agy/skills/maestro-plan/SKILL.md +19 -13
  31. package/.agy/skills/maestro-roadmap/SKILL.md +59 -29
  32. package/.agy/skills/maestro-verify/SKILL.md +46 -11
  33. package/.agy/skills/team-adversarial-swarm/scripts/__pycache__/pheromone.cpython-313.pyc +0 -0
  34. package/.agy/skills/team-adversarial-swarm/scripts/__pycache__/scoring.cpython-313.pyc +0 -0
  35. package/.agy/skills/team-adversarial-swarm/scripts/aco.py +15 -15
  36. package/.agy/skills/team-adversarial-swarm/scripts/pheromone.py +2 -2
  37. package/.agy/skills/team-adversarial-swarm/scripts/scoring.py +1 -1
  38. package/.agy/skills/team-swarm/scripts/aco.py +15 -15
  39. package/.agy/skills/team-swarm/scripts/pheromone.py +2 -2
  40. package/.agy/skills/team-swarm/scripts/scoring.py +1 -1
  41. package/.claude/commands/maestro-analyze.md +78 -34
  42. package/.claude/commands/maestro-blueprint.md +57 -24
  43. package/.claude/commands/maestro-brainstorm.md +69 -34
  44. package/.claude/commands/maestro-execute.md +45 -15
  45. package/.claude/commands/maestro-grill.md +63 -38
  46. package/.claude/commands/maestro-init.md +59 -17
  47. package/.claude/commands/maestro-milestone-audit.md +48 -5
  48. package/.claude/commands/maestro-milestone-complete.md +48 -6
  49. package/.claude/commands/maestro-milestone-release.md +42 -11
  50. package/.claude/commands/maestro-plan.md +19 -13
  51. package/.claude/commands/maestro-roadmap.md +59 -29
  52. package/.claude/commands/maestro-verify.md +46 -11
  53. package/.claude/skills/team-adversarial-swarm/scripts/__pycache__/pheromone.cpython-313.pyc +0 -0
  54. package/.claude/skills/team-adversarial-swarm/scripts/__pycache__/scoring.cpython-313.pyc +0 -0
  55. package/.claude/skills/team-adversarial-swarm/scripts/aco.py +15 -15
  56. package/.claude/skills/team-adversarial-swarm/scripts/pheromone.py +2 -2
  57. package/.claude/skills/team-adversarial-swarm/scripts/scoring.py +1 -1
  58. package/.claude/skills/team-swarm/scripts/aco.py +15 -15
  59. package/.claude/skills/team-swarm/scripts/pheromone.py +2 -2
  60. package/.claude/skills/team-swarm/scripts/scoring.py +1 -1
  61. package/package.json +1 -1
  62. package/workflows/command-authoring.md +823 -0
  63. package/workflows/interview-mechanics.md +7 -0
@@ -89,7 +89,7 @@ def cmd_init(args: argparse.Namespace) -> None:
89
89
  paths = SessionPaths(Path(args.session))
90
90
  if not paths.config.exists():
91
91
  _fail(2, f"config not found: {paths.config}")
92
- config = json.loads(paths.config.read_text())
92
+ config = json.loads(paths.config.read_text(encoding="utf-8"))
93
93
 
94
94
  paths.ensure_dirs()
95
95
 
@@ -107,7 +107,7 @@ def cmd_init(args: argparse.Namespace) -> None:
107
107
  "start_nodes": config.get("task_space", {}).get("start_nodes", "any"),
108
108
  "edges": config.get("task_space", {}).get("edges", "complete"),
109
109
  }
110
- paths.task_space.write_text(json.dumps(task_space, indent=2, ensure_ascii=False))
110
+ paths.task_space.write_text(json.dumps(task_space, indent=2, ensure_ascii=False), encoding="utf-8")
111
111
 
112
112
  # Initialize pheromone
113
113
  aco_cfg = config.get("aco", {})
@@ -148,9 +148,9 @@ def _pick_start_node(nodes: List[str], state: PheromoneState, mode: str) -> str:
148
148
 
149
149
  def cmd_select(args: argparse.Namespace) -> None:
150
150
  paths = SessionPaths(Path(args.session))
151
- config = json.loads(paths.config.read_text())
151
+ config = json.loads(paths.config.read_text(encoding="utf-8"))
152
152
  state = PheromoneState.load(paths.pheromone_current)
153
- task_space = json.loads(paths.task_space.read_text())
153
+ task_space = json.loads(paths.task_space.read_text(encoding="utf-8"))
154
154
 
155
155
  n_ants = config.get("swarm", {}).get("n_ants", 5)
156
156
  nodes = task_space["nodes"]
@@ -190,7 +190,7 @@ def _load_iteration_artifacts(paths: SessionPaths, iteration: int) -> List[dict]
190
190
  artifacts = []
191
191
  for f in files:
192
192
  try:
193
- artifacts.append(json.loads(Path(f).read_text()))
193
+ artifacts.append(json.loads(Path(f).read_text(encoding="utf-8")))
194
194
  except json.JSONDecodeError as e:
195
195
  print(f"warning: skipped malformed artifact {f}: {e}", file=sys.stderr)
196
196
  return artifacts
@@ -213,9 +213,9 @@ def _validate_artifact(art: dict, valid_nodes: set) -> Optional[str]:
213
213
 
214
214
  def cmd_update(args: argparse.Namespace) -> None:
215
215
  paths = SessionPaths(Path(args.session))
216
- config = json.loads(paths.config.read_text())
216
+ config = json.loads(paths.config.read_text(encoding="utf-8"))
217
217
  state = PheromoneState.load(paths.pheromone_current)
218
- task_space = json.loads(paths.task_space.read_text())
218
+ task_space = json.loads(paths.task_space.read_text(encoding="utf-8"))
219
219
  valid_nodes = set(task_space["nodes"])
220
220
 
221
221
  artifacts = _load_iteration_artifacts(paths, args.iter)
@@ -266,7 +266,7 @@ def cmd_update(args: argparse.Namespace) -> None:
266
266
  # Elitist: re-load best history, deposit extra on best path
267
267
  best_data = None
268
268
  if paths.best.exists():
269
- best_data = json.loads(paths.best.read_text())
269
+ best_data = json.loads(paths.best.read_text(encoding="utf-8"))
270
270
  current_best = max(scored, key=lambda x: x["score"]) if scored else None
271
271
  if current_best:
272
272
  best_art = next(a for a in artifacts if a["ant_id"] == current_best["ant_id"])
@@ -281,7 +281,7 @@ def cmd_update(args: argparse.Namespace) -> None:
281
281
  "evidence": best_art.get("evidence", []),
282
282
  "updated_at": time.time(),
283
283
  }
284
- paths.best.write_text(json.dumps(best_data, indent=2, ensure_ascii=False))
284
+ paths.best.write_text(json.dumps(best_data, indent=2, ensure_ascii=False), encoding="utf-8")
285
285
  # Elite deposit
286
286
  state.deposit(best_data["path"], best_data["score"])
287
287
 
@@ -292,14 +292,14 @@ def cmd_update(args: argparse.Namespace) -> None:
292
292
 
293
293
  # Persist trails
294
294
  trails_file = paths.trails / f"{args.iter}.jsonl"
295
- trails_file.write_text("\n".join(json.dumps(t, ensure_ascii=False) for t in trail_log))
295
+ trails_file.write_text("\n".join(json.dumps(t, ensure_ascii=False) for t in trail_log), encoding="utf-8")
296
296
 
297
297
  mean_score = sum(s["score"] for s in scored) / len(scored) if scored else 0.0
298
298
  best_score = best_data["score"] if best_data else 0.0
299
299
  prev_best = 0.0
300
300
  history_files = sorted(paths.pheromone_history.glob("*.json"))
301
301
  if len(history_files) >= 2:
302
- prev = json.loads(history_files[-2].read_text())
302
+ prev = json.loads(history_files[-2].read_text(encoding="utf-8"))
303
303
  prev_best = prev.get("stats", {}).get("best_known", best_score)
304
304
  delta = best_score - prev_best
305
305
 
@@ -323,7 +323,7 @@ def cmd_update(args: argparse.Namespace) -> None:
323
323
 
324
324
  def cmd_converged(args: argparse.Namespace) -> None:
325
325
  paths = SessionPaths(Path(args.session))
326
- config = json.loads(paths.config.read_text())
326
+ config = json.loads(paths.config.read_text(encoding="utf-8"))
327
327
  cv = config.get("convergence", {})
328
328
 
329
329
  state = PheromoneState.load(paths.pheromone_current)
@@ -339,7 +339,7 @@ def cmd_converged(args: argparse.Namespace) -> None:
339
339
  }
340
340
 
341
341
  if paths.best.exists():
342
- metrics["best_score"] = json.loads(paths.best.read_text()).get("score", 0.0)
342
+ metrics["best_score"] = json.loads(paths.best.read_text(encoding="utf-8")).get("score", 0.0)
343
343
 
344
344
  # max_iterations
345
345
  max_iter = cv.get("max_iterations", 5)
@@ -397,7 +397,7 @@ def cmd_report(args: argparse.Namespace) -> None:
397
397
 
398
398
  best = None
399
399
  if paths.best.exists():
400
- best = json.loads(paths.best.read_text())
400
+ best = json.loads(paths.best.read_text(encoding="utf-8"))
401
401
 
402
402
  # Top-K trails across all iterations
403
403
  all_trails = []
@@ -410,7 +410,7 @@ def cmd_report(args: argparse.Namespace) -> None:
410
410
  # Convergence curve
411
411
  curve = []
412
412
  for hf in sorted(paths.pheromone_history.glob("*.json"), key=lambda p: int(p.stem)):
413
- snap = json.loads(hf.read_text())
413
+ snap = json.loads(hf.read_text(encoding="utf-8"))
414
414
  curve.append({
415
415
  "iteration": snap["iteration"],
416
416
  "entropy": snap["stats"]["entropy"],
@@ -114,11 +114,11 @@ class PheromoneState:
114
114
 
115
115
  def save(self, path: Path) -> None:
116
116
  path.parent.mkdir(parents=True, exist_ok=True)
117
- path.write_text(json.dumps(self.to_dict(), indent=2, ensure_ascii=False))
117
+ path.write_text(json.dumps(self.to_dict(), indent=2, ensure_ascii=False), encoding="utf-8")
118
118
 
119
119
  @classmethod
120
120
  def load(cls, path: Path) -> "PheromoneState":
121
- return cls.from_dict(json.loads(path.read_text()))
121
+ return cls.from_dict(json.loads(path.read_text(encoding="utf-8")))
122
122
 
123
123
  def select_neighbors(
124
124
  self,
@@ -62,7 +62,7 @@ def load_verified_scores(scores_file: Path) -> Dict[str, float]:
62
62
  """Load pre-computed verified_scores from scorer role output (if exists)."""
63
63
  if not scores_file.exists():
64
64
  return {}
65
- data = json.loads(scores_file.read_text())
65
+ data = json.loads(scores_file.read_text(encoding="utf-8"))
66
66
  return {
67
67
  ant_id: entry["verified_score"]
68
68
  for ant_id, entry in data.get("scores", {}).items()
@@ -89,7 +89,7 @@ def cmd_init(args: argparse.Namespace) -> None:
89
89
  paths = SessionPaths(Path(args.session))
90
90
  if not paths.config.exists():
91
91
  _fail(2, f"config not found: {paths.config}")
92
- config = json.loads(paths.config.read_text())
92
+ config = json.loads(paths.config.read_text(encoding="utf-8"))
93
93
 
94
94
  paths.ensure_dirs()
95
95
 
@@ -107,7 +107,7 @@ def cmd_init(args: argparse.Namespace) -> None:
107
107
  "start_nodes": config.get("task_space", {}).get("start_nodes", "any"),
108
108
  "edges": config.get("task_space", {}).get("edges", "complete"),
109
109
  }
110
- paths.task_space.write_text(json.dumps(task_space, indent=2, ensure_ascii=False))
110
+ paths.task_space.write_text(json.dumps(task_space, indent=2, ensure_ascii=False), encoding="utf-8")
111
111
 
112
112
  # Initialize pheromone
113
113
  aco_cfg = config.get("aco", {})
@@ -148,9 +148,9 @@ def _pick_start_node(nodes: List[str], state: PheromoneState, mode: str) -> str:
148
148
 
149
149
  def cmd_select(args: argparse.Namespace) -> None:
150
150
  paths = SessionPaths(Path(args.session))
151
- config = json.loads(paths.config.read_text())
151
+ config = json.loads(paths.config.read_text(encoding="utf-8"))
152
152
  state = PheromoneState.load(paths.pheromone_current)
153
- task_space = json.loads(paths.task_space.read_text())
153
+ task_space = json.loads(paths.task_space.read_text(encoding="utf-8"))
154
154
 
155
155
  n_ants = config.get("swarm", {}).get("n_ants", 5)
156
156
  nodes = task_space["nodes"]
@@ -190,7 +190,7 @@ def _load_iteration_artifacts(paths: SessionPaths, iteration: int) -> List[dict]
190
190
  artifacts = []
191
191
  for f in files:
192
192
  try:
193
- artifacts.append(json.loads(Path(f).read_text()))
193
+ artifacts.append(json.loads(Path(f).read_text(encoding="utf-8")))
194
194
  except json.JSONDecodeError as e:
195
195
  print(f"warning: skipped malformed artifact {f}: {e}", file=sys.stderr)
196
196
  return artifacts
@@ -213,9 +213,9 @@ def _validate_artifact(art: dict, valid_nodes: set) -> Optional[str]:
213
213
 
214
214
  def cmd_update(args: argparse.Namespace) -> None:
215
215
  paths = SessionPaths(Path(args.session))
216
- config = json.loads(paths.config.read_text())
216
+ config = json.loads(paths.config.read_text(encoding="utf-8"))
217
217
  state = PheromoneState.load(paths.pheromone_current)
218
- task_space = json.loads(paths.task_space.read_text())
218
+ task_space = json.loads(paths.task_space.read_text(encoding="utf-8"))
219
219
  valid_nodes = set(task_space["nodes"])
220
220
 
221
221
  artifacts = _load_iteration_artifacts(paths, args.iter)
@@ -266,7 +266,7 @@ def cmd_update(args: argparse.Namespace) -> None:
266
266
  # Elitist: re-load best history, deposit extra on best path
267
267
  best_data = None
268
268
  if paths.best.exists():
269
- best_data = json.loads(paths.best.read_text())
269
+ best_data = json.loads(paths.best.read_text(encoding="utf-8"))
270
270
  current_best = max(scored, key=lambda x: x["score"]) if scored else None
271
271
  if current_best:
272
272
  best_art = next(a for a in artifacts if a["ant_id"] == current_best["ant_id"])
@@ -281,7 +281,7 @@ def cmd_update(args: argparse.Namespace) -> None:
281
281
  "evidence": best_art.get("evidence", []),
282
282
  "updated_at": time.time(),
283
283
  }
284
- paths.best.write_text(json.dumps(best_data, indent=2, ensure_ascii=False))
284
+ paths.best.write_text(json.dumps(best_data, indent=2, ensure_ascii=False), encoding="utf-8")
285
285
  # Elite deposit
286
286
  state.deposit(best_data["path"], best_data["score"])
287
287
 
@@ -292,14 +292,14 @@ def cmd_update(args: argparse.Namespace) -> None:
292
292
 
293
293
  # Persist trails
294
294
  trails_file = paths.trails / f"{args.iter}.jsonl"
295
- trails_file.write_text("\n".join(json.dumps(t, ensure_ascii=False) for t in trail_log))
295
+ trails_file.write_text("\n".join(json.dumps(t, ensure_ascii=False) for t in trail_log), encoding="utf-8")
296
296
 
297
297
  mean_score = sum(s["score"] for s in scored) / len(scored) if scored else 0.0
298
298
  best_score = best_data["score"] if best_data else 0.0
299
299
  prev_best = 0.0
300
300
  history_files = sorted(paths.pheromone_history.glob("*.json"))
301
301
  if len(history_files) >= 2:
302
- prev = json.loads(history_files[-2].read_text())
302
+ prev = json.loads(history_files[-2].read_text(encoding="utf-8"))
303
303
  prev_best = prev.get("stats", {}).get("best_known", best_score)
304
304
  delta = best_score - prev_best
305
305
 
@@ -323,7 +323,7 @@ def cmd_update(args: argparse.Namespace) -> None:
323
323
 
324
324
  def cmd_converged(args: argparse.Namespace) -> None:
325
325
  paths = SessionPaths(Path(args.session))
326
- config = json.loads(paths.config.read_text())
326
+ config = json.loads(paths.config.read_text(encoding="utf-8"))
327
327
  cv = config.get("convergence", {})
328
328
 
329
329
  state = PheromoneState.load(paths.pheromone_current)
@@ -339,7 +339,7 @@ def cmd_converged(args: argparse.Namespace) -> None:
339
339
  }
340
340
 
341
341
  if paths.best.exists():
342
- metrics["best_score"] = json.loads(paths.best.read_text()).get("score", 0.0)
342
+ metrics["best_score"] = json.loads(paths.best.read_text(encoding="utf-8")).get("score", 0.0)
343
343
 
344
344
  # max_iterations
345
345
  max_iter = cv.get("max_iterations", 5)
@@ -397,7 +397,7 @@ def cmd_report(args: argparse.Namespace) -> None:
397
397
 
398
398
  best = None
399
399
  if paths.best.exists():
400
- best = json.loads(paths.best.read_text())
400
+ best = json.loads(paths.best.read_text(encoding="utf-8"))
401
401
 
402
402
  # Top-K trails across all iterations
403
403
  all_trails = []
@@ -410,7 +410,7 @@ def cmd_report(args: argparse.Namespace) -> None:
410
410
  # Convergence curve
411
411
  curve = []
412
412
  for hf in sorted(paths.pheromone_history.glob("*.json"), key=lambda p: int(p.stem)):
413
- snap = json.loads(hf.read_text())
413
+ snap = json.loads(hf.read_text(encoding="utf-8"))
414
414
  curve.append({
415
415
  "iteration": snap["iteration"],
416
416
  "entropy": snap["stats"]["entropy"],
@@ -114,11 +114,11 @@ class PheromoneState:
114
114
 
115
115
  def save(self, path: Path) -> None:
116
116
  path.parent.mkdir(parents=True, exist_ok=True)
117
- path.write_text(json.dumps(self.to_dict(), indent=2, ensure_ascii=False))
117
+ path.write_text(json.dumps(self.to_dict(), indent=2, ensure_ascii=False), encoding="utf-8")
118
118
 
119
119
  @classmethod
120
120
  def load(cls, path: Path) -> "PheromoneState":
121
- return cls.from_dict(json.loads(path.read_text()))
121
+ return cls.from_dict(json.loads(path.read_text(encoding="utf-8")))
122
122
 
123
123
  def select_neighbors(
124
124
  self,
@@ -62,7 +62,7 @@ def load_verified_scores(scores_file: Path) -> Dict[str, float]:
62
62
  """Load pre-computed verified_scores from scorer role output (if exists)."""
63
63
  if not scores_file.exists():
64
64
  return {}
65
- data = json.loads(scores_file.read_text())
65
+ data = json.loads(scores_file.read_text(encoding="utf-8"))
66
66
  return {
67
67
  ant_id: entry["verified_score"]
68
68
  for ant_id, entry in data.get("scores", {}).items()
@@ -22,6 +22,8 @@ Combines structured 6-dimension scoring with iterative deepening and decision ex
22
22
  Use `-q` for quick decision extraction only (skip exploration + scoring).
23
23
 
24
24
  Use `--gaps` for issue-focused root cause analysis (replaces manage-issue-analyze). Loads issues from issues.jsonl, performs CLI exploration against issue context/location, synthesizes root cause into issue.analysis, and outputs context.md for downstream `plan --gaps`.
25
+
26
+ Pipeline position: downstream of maestro-grill, maestro-brainstorm, and maestro-blueprint (optional upstream enrichment); upstream of maestro-plan and maestro-roadmap (consumes analysis context).
25
27
  </purpose>
26
28
 
27
29
  <required_reading>
@@ -47,31 +49,47 @@ $ARGUMENTS -- phase number for micro mode, topic text for macro/adhoc mode, no a
47
49
  - Mixed input like `"1 phase"` is treated as text → macro mode (only bare numerics trigger micro)
48
50
 
49
51
  **Flags:**
50
- - `-y` / `--yes`: Auto mode — skip interactive scoping, use recommended defaults, auto-deepen
51
- - `-c` / `--continue`: Resume from existing session (auto-detect session folder + discussion.md)
52
- - `-q` / `--quick`: Quick mode — skip exploration + scoring, go straight to decision extraction (context.md only)
53
- - `--from <source>`: Load upstream context package (grill:ID, brainstorm:ID, blueprint:BLP-xxx, @file, or path)
54
- - `--gaps [ISS-ID]`: Issue root cause analysis mode. If ISS-ID provided, analyze single issue. If omitted, analyze all open/registered issues from issues.jsonl.
55
52
 
56
- Scope routing, output directory format, artifact registration schema, and output artifact listing are defined in workflow analyze.md (Scope Routing and Output Structure sections).
53
+ | Flag | Effect | Default |
54
+ |------|--------|---------|
55
+ | `-y` / `--yes` | Auto mode — skip interactive scoping, use recommended defaults, auto-deepen | false |
56
+ | `-c` / `--continue` | Resume from existing session (auto-detect session folder + discussion.md) | false |
57
+ | `-q` / `--quick` | Quick mode — skip exploration + scoring, go straight to decision extraction (context.md only) | false |
58
+ | `--from <source>` | Load upstream context package (grill:ID, brainstorm:ID, blueprint:BLP-xxx, @file, or path) | — |
59
+ | `--gaps [ISS-ID]` | Issue root cause analysis mode. If ISS-ID provided, analyze single issue. If omitted, analyze all open/registered issues from issues.jsonl | — |
60
+
61
+ **Scope routing:**
62
+ | Input | Mode | Scope |
63
+ |-------|------|-------|
64
+ | Pure digits (e.g. `1`, `42`) | micro | Phase-level deep analysis |
65
+ | Non-numeric text (e.g. `auth-refactor`) | macro | Topic impact surface |
66
+ | No positional arg + roadmap | micro | Milestone-wide |
67
+ | No positional arg + no roadmap | macro | Fallback |
68
+ | `--gaps [ISS-ID]` | gaps | Issue root cause analysis |
69
+
70
+ Output directory format, artifact registration schema, and output artifact listing are defined in workflow analyze.md (Output Structure section).
71
+
72
+ ### Pre-load
73
+
74
+ 1. **Codebase docs**: IF `.workflow/codebase/doc-index.json` exists → Read ARCHITECTURE.md for module boundaries
75
+ 2. **Specs**: `maestro spec load --category arch` — load architecture constraints
76
+ 3. **Wiki search**: `maestro wiki search "{topic keywords}" --json` → top 5-10 entries as prior knowledge
77
+ 4. All optional — proceed without if unavailable (log warning)
57
78
 
58
79
  ### Role Knowledge
59
80
  `maestro wiki list --category debug` → select relevant → `maestro wiki load`
60
81
  </context>
61
82
 
62
83
  <interview_protocol>
63
- Interview the user relentlessly until shared understanding is reached. Active only in interactive mode; skip when `-y/--yes`, `-c/--continue`, or input is already specific (explicit phase number or unambiguous topic).
64
-
65
- - One decision per turn via ask_question with 2–4 options + a (Recommended) default. The user controls termination — keep interviewing until convergence; they can interrupt naturally or via `Other` at any time.
66
- - Search-first when uncertain: before asking, resolve via `state.json`, `roadmap.md`, `issues.jsonl`, `maestro spec load`, `maestro wiki search`, Grep, Read, or — for open-ended multi-file scans — spawn `invoke_subagent([{ TypeName: "<TypeName>", Role: "<Role>", Prompt: "<Prompt>", Workspace: "inherit" }])` / `maestro delegate ... --role explore`. Never ask what code or memory can verify; never bounce your own ambiguity back to the user search first, then ask only what truly needs human judgment.
67
- - Writeback cadence: each settled decision is immediately appended/updated in `discussion.md` (top table) and mirrored into `context.md` "Interview Decisions". Do NOT batch writeback to the end — partial decisions must already be on disk before the next question.
68
- - Walk the decision dependency tree strictly: scope → depth → dimensions → Go/No-Go threshold. Do not open the next branch until the current one is settled.
69
- - Scope guard: only ask about decisions owned by `analyze`. Do not prejudge plan/execute concerns.
70
-
71
- Decision points: scope (phase / topic / milestone-wide / adhoc / --gaps) depth (quick / standard / deep) → dimensions (which of the 6 to keep) → Go/No-Go threshold.
72
-
73
- Exit: when all decision points are settled (or user explicitly signals to proceed), finalize session metadata. The decision table (populated incrementally during interview) uses this schema:
74
- `| # | Decision | Choice | Source (user / code / default) |`
84
+ Follows @~/.maestro/workflows/interview-mechanics.md standard.
85
+
86
+ **Interaction mode**: convergent menu-driven
87
+ **Decision tree** (strict order): scope (phase / topic / milestone-wide / adhoc / --gaps) depth (quick / standard / deep) dimensions (which of the 6 to keep) Go/No-Go threshold
88
+ **Scope guard**: only analyze decisions; do not prejudge plan/execute concerns
89
+ **Writeback target**: discussion.md (top table) + context.md "Interview Decisions"
90
+ **Additional search sources**: issues.jsonl (--gaps mode), roadmap.md
91
+ **Additional skip conditions**: input is already specific (explicit phase number or unambiguous topic)
92
+ **Exit condition**: all decision points settledfinalize session metadata
75
93
  </interview_protocol>
76
94
 
77
95
  <execution>
@@ -108,23 +126,52 @@ Phase 4: Output context.md for downstream plan --gaps
108
126
  - `large` (3+ independent subsystems or hard serial dependencies) → suggest `/maestro-roadmap --from analyze:ANL-xxx`
109
127
  - `medium` (1-2 subsystems, parallelizable) → suggest `/maestro-plan --from analyze:ANL-xxx`
110
128
  - `small` (single-file or few-file change) → suggest `/maestro-plan --from analyze:ANL-xxx`
129
+ </execution>
111
130
 
112
- **Next-step routing on completion:**
131
+ <completion>
132
+ ### Standalone report
113
133
 
114
- Phase/Milestone scope (micro mode):
115
- - Go recommendation, UI work needed → `/maestro-impeccable build {target}`
116
- - Go recommendation, ready to plan → `/maestro-plan` or `/maestro-plan {phase}`
117
- - No-Go recommendation → revisit requirements or `/maestro-brainstorm {topic}`
134
+ ```
135
+ === ANALYSIS READY ===
136
+ Artifact: ANL-{id}
137
+ Scope: {micro|macro|adhoc|gaps}
138
+ Go/No-Go: {GO|NO-GO|CONDITIONAL}
139
+ Confidence: {high|medium|low}
140
+ Outputs: analysis.md, context.md, conclusions.json, discussion.md
141
+ Session dir: {output_dir}
142
+ ===
143
+ ```
118
144
 
119
- Macro/Adhoc/Standalone scope:
120
- - scope_verdict = large → `/maestro-roadmap --from analyze:ANL-xxx`
121
- - scope_verdict = medium/small → `/maestro-plan --from analyze:ANL-xxx`
122
- - Need more exploration → `/maestro-analyze {topic} -c`
145
+ ### Ralph-invoked completion
123
146
 
124
- Gaps scope:
125
- - Issues analyzed → `/maestro-plan --gaps` (plan fix tasks linked to issues)
126
- - Need more context `/maestro-analyze --gaps {ISS-ID}` (re-analyze specific issue)
127
- </execution>
147
+ End the step by calling the CLI (no text block output):
148
+ ```
149
+ maestro ralph complete <idx> --status {STATUS} [--evidence {path}]
150
+ ```
151
+
152
+ Status verdicts:
153
+ - **DONE** — Normal completion
154
+ - **DONE_WITH_CONCERNS** — Completed with caveats; pass `--concerns`
155
+ - **NEEDS_RETRY** — Tooling error / transient issue; ralph will retry
156
+ - **BLOCKED** — External hard blocker; pass `--reason`
157
+
158
+ ### Next-step routing
159
+
160
+ | Condition | Suggestion |
161
+ |-----------|-----------|
162
+ | Phase/Milestone scope, Go, UI work needed | `/maestro-impeccable build {target}` |
163
+ | Phase/Milestone scope, Go, ready to plan | `/maestro-plan` or `/maestro-plan {phase}` |
164
+ | Phase/Milestone scope, No-Go | Revisit requirements or `/maestro-brainstorm {topic}` |
165
+ | Macro/Adhoc, scope_verdict = large | `/maestro-roadmap --from analyze:ANL-xxx` |
166
+ | Macro/Adhoc, scope_verdict = medium/small | `/maestro-plan --from analyze:ANL-xxx` |
167
+ | Need more exploration | `/maestro-analyze {topic} -c` |
168
+ | Gaps scope, issues analyzed | `/maestro-plan --gaps` |
169
+ | Gaps scope, need more context | `/maestro-analyze --gaps {ISS-ID}` |
170
+
171
+ ### Session seal
172
+
173
+ @~/.maestro/workflows/finish-work.md — SESSION_DIR=OUTPUT_DIR, SESSION_TYPE=analyze, SESSION_ID={artifact_id}, LINKED_MILESTONE={target_milestone or null}
174
+ </completion>
128
175
 
129
176
  <error_codes>
130
177
  | Code | Severity | Condition | Recovery |
@@ -168,6 +215,3 @@ Both modes (full + quick):
168
215
  - [ ] Session sealed via finish-work (archive.json written, optional spec/knowhow extraction)
169
216
  </success_criteria>
170
217
 
171
- <on_complete>
172
- @~/.maestro/workflows/finish-work.md — SESSION_DIR=OUTPUT_DIR, SESSION_TYPE=analyze, SESSION_ID={artifact_id}, LINKED_MILESTONE={target_milestone or null}
173
- </on_complete>
@@ -22,6 +22,8 @@ Parallel to `brainstorm` as an upstream origin command:
22
22
  - **blueprint** = convergent documentation (heavyweight, 6-phase formal spec chain)
23
23
 
24
24
  Output: `.workflow/blueprint/BLP-{slug}-{date}/` containing Product Brief, PRD, Architecture, and Epics.
25
+
26
+ Pipeline position: downstream of maestro-brainstorm (optional). Upstream of maestro-analyze, maestro-roadmap, and maestro-plan.
25
27
  </purpose>
26
28
 
27
29
  <required_reading>
@@ -36,10 +38,13 @@ Output: `.workflow/blueprint/BLP-{slug}-{date}/` containing Product Brief, PRD,
36
38
  $ARGUMENTS -- idea text, @file reference, or upstream context source.
37
39
 
38
40
  **Flags:**
39
- - `-y` / `--yes`: Auto mode — skip interactive questions, use recommended defaults
40
- - `-c` / `--continue`: Resume from last checkpoint (reads blueprint-config.json)
41
- - `--from <source>`: Load upstream context package (brainstorm:ID, @file, or path). Consumes context-package.json
42
- - `--from-brainstorm SESSION-ID`: (backward compat alias for `--from brainstorm:ID`)
41
+
42
+ | Flag | Effect | Default |
43
+ |------|--------|---------|
44
+ | `-y` / `--yes` | Auto mode skip interactive questions, use recommended defaults | false |
45
+ | `-c` / `--continue` | Resume from last checkpoint (reads blueprint-config.json) | false |
46
+ | `--from <source>` | Load upstream context package (brainstorm:ID, @file, or path). Consumes context-package.json | — |
47
+ | `--from-brainstorm SESSION-ID` | Backward compat alias for `--from brainstorm:ID` | — |
43
48
 
44
49
  **Input types:**
45
50
  - Direct text: `"Build a real-time collaboration platform with WebSocket"`
@@ -58,23 +63,22 @@ maestro-analyze → maestro-roadmap → maestro-plan
58
63
 
59
64
  **Output boundary**: ALL file writes MUST target `.workflow/blueprint/BLP-{slug}-{date}/` or `.workflow/state.json` only. NEVER modify source code or files outside these paths.
60
65
 
61
- ### Pre-load specs
62
- 1. **Architecture specs**: Run `maestro spec load --category arch` to load architecture constraints. Use as context for architecture decisions (Phase 4).
63
- 2. Optionalproceed without if unavailable.
66
+ ### Pre-load
67
+
68
+ 1. **Specs**: `maestro spec load --category arch` load architecture constraints for Phase 4 decisions
69
+ 2. **Wiki search**: `maestro wiki search "{topic keywords}" --json` → prior knowledge context
70
+ 3. All optional — proceed without if unavailable
64
71
  </context>
65
72
 
66
73
  <interview_protocol>
67
- Interview the user relentlessly about every aspect of the spec until shared understanding is reached. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one; if a question can be answered by exploring the codebase, explore the codebase instead. Active only in interactive mode; skip when `-y/--yes`, `-c/--continue`, or input is already specific (clear idea + scope).
68
-
69
- - Ask one question per turn via ask_question and wait for the user's feedback before continuing; every question must carry a recommended answer marked `(Recommended)`, 2–4 options total. The user controls termination — keep interviewing until convergence; they can interrupt naturally or via `Other` at any time.
70
- - Search-first when uncertain: before asking, resolve via `state.json`, existing artifacts, `maestro spec load`, direct codebase exploration (Glob/Grep/Read), or for open-ended multi-file scans — spawn `invoke_subagent([{ TypeName: "<TypeName>", Role: "<Role>", Prompt: "<Prompt>", Workspace: "inherit" }])` / `maestro delegate ... --role explore`. Never ask what code or memory can verify; never bounce your own ambiguity back to the user search first, then ask only what truly needs human judgment.
71
- - Writeback cadence: each settled decision is immediately persisted into `blueprint-config.json` before the next question. Do NOT batch writeback to the end — partial decisions must already be on disk.
72
- - Walk the decision dependency tree depth-first: scope → spec type → focus areas → requirement priorities. Do not open the next branch until the current one is settled.
73
- - Scope guard: only decide the shape of the specification. Do not pre-resolve roadmap phases or plan tasks — those belong to downstream commands.
74
-
75
- Decision points: scope (full product / feature set / single feature) → spec type (service / api / library / platform) → focus areas → whether to run codebase exploration.
76
-
77
- Exit: on consensus or explicit user signal to proceed, finalize blueprint-config.json (decisions already written incrementally) and proceed to Phase 1.
74
+ Follows @~/.maestro/workflows/interview-mechanics.md standard.
75
+
76
+ **Interaction mode**: convergent menu-driven, depth-first
77
+ **Decision tree** (strict depth-first): scope (full product / feature set / single feature) spec type (service / api / library / platform) focus areas whether to run codebase exploration requirement priorities
78
+ **Scope guard**: only specification shape; do not pre-resolve roadmap phases or plan tasks
79
+ **Writeback target**: blueprint-config.json (each decision persisted before next question)
80
+ **Additional skip conditions**: none beyond standard (-y, -c)
81
+ **Exit condition**: all decision points settled → finalize blueprint-config.json, proceed to Phase 1
78
82
  </interview_protocol>
79
83
 
80
84
  <execution>
@@ -88,15 +92,44 @@ P0: Spec Study → P1: Discovery → P1.5: Req Expansion → P2: Product Brief
88
92
 
89
93
  P6 gate: Pass (>=80%) → Handoff | Review (60-79%) → Handoff w/caveats | Fail (<60%) → P6.5 Auto-Fix (max 2 iter) → re-check
90
94
 
91
- ### Next-step routing on completion
95
+ </execution>
96
+
97
+ <completion>
98
+ ### Standalone report
99
+
100
+ ```
101
+ === BLUEPRINT READY ===
102
+ Session: BLP-{slug}-{date}
103
+ Phases completed: P0–P6
104
+ Readiness score: {score}%
105
+ Gate verdict: {Pass|Review|Fail}
106
+ Output: .workflow/blueprint/BLP-{slug}-{date}/
107
+ Key artifacts: product-brief.md, requirements/, architecture/, epics/, readiness-report.md
108
+ ===
109
+ ```
110
+
111
+ ### Ralph-invoked completion
112
+
113
+ End the step by calling the CLI (no text block output):
114
+ ```
115
+ maestro ralph complete <idx> --status {STATUS} [--evidence {path}]
116
+ ```
117
+
118
+ Status verdicts:
119
+ - **DONE** — Normal completion
120
+ - **DONE_WITH_CONCERNS** — Completed with caveats; pass `--concerns`
121
+ - **NEEDS_RETRY** — Tooling error / transient issue; ralph will retry
122
+ - **BLOCKED** — External hard blocker; pass `--reason`
123
+
124
+ ### Next-step routing
92
125
 
93
126
  | Condition | Suggestion |
94
127
  |-----------|-----------|
95
- | Need codebase analysis | /maestro-analyze {topic} --from blueprint:BLP-xxx |
96
- | Ready for roadmap | /maestro-roadmap --from blueprint:BLP-xxx |
97
- | Small scope, direct plan | /maestro-plan --from blueprint:BLP-xxx |
98
- | Need project setup | /maestro-init |
99
- </execution>
128
+ | Need codebase analysis | `/maestro-analyze {topic} --from blueprint:BLP-xxx` |
129
+ | Ready for roadmap | `/maestro-roadmap --from blueprint:BLP-xxx` |
130
+ | Small scope, direct plan | `/maestro-plan --from blueprint:BLP-xxx` |
131
+ | Need project setup | `/maestro-init` |
132
+ </completion>
100
133
 
101
134
  <error_codes>
102
135
  | Code | Severity | Condition | Recovery |