convoke-agents 2.3.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/INSTALLATION.md +109 -86
  3. package/README.md +236 -104
  4. package/UPDATE-GUIDE.md +63 -23
  5. package/_bmad/bme/_enhance/config.yaml +8 -0
  6. package/_bmad/bme/_enhance/extensions/bmm-pm.yaml +9 -0
  7. package/_bmad/bme/_enhance/guides/.gitkeep +0 -0
  8. package/_bmad/bme/_enhance/guides/ENHANCE-GUIDE.md +252 -0
  9. package/_bmad/bme/_enhance/workflows/initiatives-backlog/SKILL.md +6 -0
  10. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-c/.gitkeep +0 -0
  11. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-c/step-c-01-init.md +106 -0
  12. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-c/step-c-02-gather.md +136 -0
  13. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-c/step-c-03-score.md +146 -0
  14. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-c/step-c-04-prioritize.md +181 -0
  15. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-r/.gitkeep +0 -0
  16. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-r/step-r-01-load.md +120 -0
  17. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-r/step-r-02-rescore.md +141 -0
  18. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-r/step-r-03-update.md +154 -0
  19. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-t/.gitkeep +0 -0
  20. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-t/step-t-01-ingest.md +86 -0
  21. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-t/step-t-02-extract.md +169 -0
  22. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-t/step-t-03-score.md +147 -0
  23. package/_bmad/bme/_enhance/workflows/initiatives-backlog/steps-t/step-t-04-update.md +155 -0
  24. package/_bmad/bme/_enhance/workflows/initiatives-backlog/templates/backlog-format-spec.md +219 -0
  25. package/_bmad/bme/_enhance/workflows/initiatives-backlog/templates/rice-scoring-guide.md +154 -0
  26. package/_bmad/bme/_enhance/workflows/initiatives-backlog/workflow.md +88 -0
  27. package/_bmad/bme/_gyre/README.md +100 -0
  28. package/_bmad/bme/_gyre/agents/.gitkeep +0 -0
  29. package/_bmad/bme/_gyre/agents/model-curator.md +128 -0
  30. package/_bmad/bme/_gyre/agents/readiness-analyst.md +127 -0
  31. package/_bmad/bme/_gyre/agents/review-coach.md +130 -0
  32. package/_bmad/bme/_gyre/agents/stack-detective.md +125 -0
  33. package/_bmad/bme/_gyre/compass-routing-reference.md +168 -0
  34. package/_bmad/bme/_gyre/config.yaml +22 -0
  35. package/_bmad/bme/_gyre/contracts/.gitkeep +0 -0
  36. package/_bmad/bme/_gyre/contracts/gc1-stack-profile.md +152 -0
  37. package/_bmad/bme/_gyre/contracts/gc2-capabilities-manifest.md +189 -0
  38. package/_bmad/bme/_gyre/contracts/gc3-findings-report.md +197 -0
  39. package/_bmad/bme/_gyre/contracts/gc4-feedback-loop.md +209 -0
  40. package/_bmad/bme/_gyre/guides/ATLAS-USER-GUIDE.md +177 -0
  41. package/_bmad/bme/_gyre/guides/COACH-USER-GUIDE.md +172 -0
  42. package/_bmad/bme/_gyre/guides/LENS-USER-GUIDE.md +181 -0
  43. package/_bmad/bme/_gyre/guides/SCOUT-USER-GUIDE.md +158 -0
  44. package/_bmad/bme/_gyre/workflows/.gitkeep +0 -0
  45. package/_bmad/bme/_gyre/workflows/accuracy-validation/steps/step-01-select-repos.md +55 -0
  46. package/_bmad/bme/_gyre/workflows/accuracy-validation/steps/step-02-run-validation.md +78 -0
  47. package/_bmad/bme/_gyre/workflows/accuracy-validation/steps/step-03-score-results.md +143 -0
  48. package/_bmad/bme/_gyre/workflows/accuracy-validation/workflow.md +41 -0
  49. package/_bmad/bme/_gyre/workflows/delta-report/steps/step-01-load-history.md +63 -0
  50. package/_bmad/bme/_gyre/workflows/delta-report/steps/step-02-compute-delta.md +72 -0
  51. package/_bmad/bme/_gyre/workflows/delta-report/steps/step-03-present-delta.md +143 -0
  52. package/_bmad/bme/_gyre/workflows/delta-report/workflow.md +34 -0
  53. package/_bmad/bme/_gyre/workflows/full-analysis/steps/step-01-initialize.md +68 -0
  54. package/_bmad/bme/_gyre/workflows/full-analysis/steps/step-02-detect-stack.md +49 -0
  55. package/_bmad/bme/_gyre/workflows/full-analysis/steps/step-03-generate-model.md +52 -0
  56. package/_bmad/bme/_gyre/workflows/full-analysis/steps/step-04-analyze-gaps.md +42 -0
  57. package/_bmad/bme/_gyre/workflows/full-analysis/steps/step-05-review-findings.md +128 -0
  58. package/_bmad/bme/_gyre/workflows/full-analysis/workflow.md +39 -0
  59. package/_bmad/bme/_gyre/workflows/gap-analysis/steps/step-01-load-manifest.md +70 -0
  60. package/_bmad/bme/_gyre/workflows/gap-analysis/steps/step-02-observability-analysis.md +110 -0
  61. package/_bmad/bme/_gyre/workflows/gap-analysis/steps/step-03-deployment-analysis.md +87 -0
  62. package/_bmad/bme/_gyre/workflows/gap-analysis/steps/step-04-cross-domain-correlation.md +105 -0
  63. package/_bmad/bme/_gyre/workflows/gap-analysis/steps/step-05-present-findings.md +172 -0
  64. package/_bmad/bme/_gyre/workflows/gap-analysis/workflow.md +38 -0
  65. package/_bmad/bme/_gyre/workflows/model-generation/steps/step-01-load-profile.md +74 -0
  66. package/_bmad/bme/_gyre/workflows/model-generation/steps/step-02-generate-capabilities.md +116 -0
  67. package/_bmad/bme/_gyre/workflows/model-generation/steps/step-03-web-enrichment.md +89 -0
  68. package/_bmad/bme/_gyre/workflows/model-generation/steps/step-04-write-manifest.md +122 -0
  69. package/_bmad/bme/_gyre/workflows/model-generation/workflow.md +40 -0
  70. package/_bmad/bme/_gyre/workflows/model-review/steps/step-01-load-context.md +86 -0
  71. package/_bmad/bme/_gyre/workflows/model-review/steps/step-02-walkthrough.md +116 -0
  72. package/_bmad/bme/_gyre/workflows/model-review/steps/step-03-apply-amendments.md +92 -0
  73. package/_bmad/bme/_gyre/workflows/model-review/steps/step-04-capture-feedback.md +107 -0
  74. package/_bmad/bme/_gyre/workflows/model-review/steps/step-05-summary.md +60 -0
  75. package/_bmad/bme/_gyre/workflows/model-review/workflow.md +41 -0
  76. package/_bmad/bme/_gyre/workflows/stack-detection/steps/step-01-scan-filesystem.md +176 -0
  77. package/_bmad/bme/_gyre/workflows/stack-detection/steps/step-02-classify-stack.md +111 -0
  78. package/_bmad/bme/_gyre/workflows/stack-detection/steps/step-03-guard-questions.md +117 -0
  79. package/_bmad/bme/_gyre/workflows/stack-detection/workflow.md +42 -0
  80. package/_bmad/bme/_vortex/config.yaml +1 -1
  81. package/package.json +7 -2
  82. package/scripts/archive.js +304 -0
  83. package/scripts/convoke-doctor.js +146 -132
  84. package/scripts/docs-audit.js +21 -5
  85. package/scripts/install-gyre-agents.js +140 -0
  86. package/scripts/install-vortex-agents.js +0 -0
  87. package/scripts/update/lib/agent-registry.js +70 -0
  88. package/scripts/update/lib/refresh-installation.js +290 -29
  89. package/scripts/update/lib/validator.js +281 -1
@@ -133,6 +133,71 @@ const WAVE3_STREAMS = new Set(['Synthesize', 'Hypothesize', 'Sensitize']);
133
133
  const _wave3AgentIds = new Set(AGENTS.filter(a => WAVE3_STREAMS.has(a.stream)).map(a => a.id));
134
134
  const WAVE3_WORKFLOW_NAMES = new Set(WORKFLOWS.filter(w => _wave3AgentIds.has(w.agent)).map(w => w.name));
135
135
 
136
+ // ── Gyre Module ──────────────────────────────────────────────────────
137
+ const GYRE_AGENTS = [
138
+ {
139
+ id: 'stack-detective', name: 'Scout', icon: '\u{1F50E}',
140
+ title: 'Stack Detective', stream: 'Detect',
141
+ persona: {
142
+ role: 'Technology Stack Detective + Architecture Classification Specialist',
143
+ identity: 'Methodical investigator who detects project technology stacks by analyzing filesystem artifacts. Reads manifests, configs, and IaC files. Never guesses — reports what evidence supports. Asks targeted guard questions derived from detection results to confirm architecture intent. Produces the Stack Profile (GC1) that downstream agents use to generate contextual models.',
144
+ communication_style: 'Methodical and evidence-driven. Reports findings with source references. Says things like \'I found evidence of...\' and \'Based on the manifests, this appears to be...\' Never speculates — distinguishes confirmed detections from inferences.',
145
+ expertise: '- Evidence over inference — every detection claim cites a specific file or pattern - Guard questions clarify ambiguity, not confirm the obvious - Privacy boundary: Stack Profile carries categories, never file contents or secrets - Report secondary stacks as warnings, not errors - Detection is the foundation — get it right and everything downstream improves',
146
+ },
147
+ },
148
+ {
149
+ id: 'model-curator', name: 'Atlas', icon: '\u{1F4D0}',
150
+ title: 'Model Curator', stream: 'Model',
151
+ persona: {
152
+ role: 'Contextual Model Generation + Capabilities Curation Specialist',
153
+ identity: 'Knowledgeable curator who generates capabilities manifests unique to each detected stack. Balances industry standards (DORA, OpenTelemetry, Google PRR) with practical relevance. Explains why each capability matters. Transparent about confidence levels — distinguishes well-known patterns from emerging practices.',
154
+ communication_style: 'Knowledgeable and transparent — explains reasoning behind each capability. Says things like \'This capability matters for your stack because...\' and \'I\'m less confident about this one — it\'s an emerging practice.\' Respects team ownership of the model.',
155
+ expertise: '- Industry standards inform but don\'t dictate — every capability must be relevant to THIS stack - Web search for current best practices keeps the model fresh - Model is team-owned — amendments from Coach (GC4) are respected on regeneration - Transparency about sources and confidence builds trust - Generate ≥20 capabilities for supported archetypes',
156
+ },
157
+ },
158
+ {
159
+ id: 'readiness-analyst', name: 'Lens', icon: '\u{1F52C}',
160
+ title: 'Readiness Analyst', stream: 'Analyze',
161
+ persona: {
162
+ role: 'Absence Detection + Cross-Domain Correlation Specialist',
163
+ identity: 'Thorough analyst who compares the capabilities manifest against what actually exists in the project. Identifies absences — what\'s missing, not just what\'s misconfigured. Runs observability and deployment domain analyses with cross-domain correlation for compound findings.',
164
+ communication_style: 'Thorough and honest — presents findings with evidence and confidence levels. Says things like \'I found no evidence of...\' and \'These two gaps amplify each other.\' Never inflates severity — a nice-to-have stays a nice-to-have.',
165
+ expertise: '- Absence detection finds what\'s missing, not just what\'s broken - Source-tag every finding (static analysis vs contextual model) - Cross-domain correlation reveals compound gaps that single-domain analysis misses - Confidence levels must reflect actual evidence strength - Never inflate severity — accuracy builds credibility',
166
+ },
167
+ },
168
+ {
169
+ id: 'review-coach', name: 'Coach', icon: '\u{1F3CB}',
170
+ title: 'Review Coach', stream: 'Review',
171
+ persona: {
172
+ role: 'Findings Review + Model Amendment + Feedback Capture Specialist',
173
+ identity: 'Patient guide who respects the user\'s expertise. Presents findings clearly — severity-first summary, then walkthrough. For model review, presents each capability one at a time with keep/remove/edit options. Captures feedback on missed gaps to improve the model over time.',
174
+ communication_style: 'Patient and respectful — lets the user decide what\'s relevant. Says things like \'Here\'s what we found — let me walk you through it\' and \'Did Gyre miss anything you know about?\' Explains why feedback matters for model improvement.',
175
+ expertise: '- Severity-first presentation respects the user\'s time - Model review is a conversation, not a checklist - Feedback capture improves the model for the whole team - Amendments persist — the model becomes team-owned through review - Never push — the user knows their system best',
176
+ },
177
+ },
178
+ ];
179
+
180
+ const GYRE_WORKFLOWS = [
181
+ // Scout — Detect
182
+ { name: 'stack-detection', agent: 'stack-detective' },
183
+ // Atlas — Model
184
+ { name: 'model-generation', agent: 'model-curator' },
185
+ // Lens — Analyze
186
+ { name: 'gap-analysis', agent: 'readiness-analyst' },
187
+ { name: 'delta-report', agent: 'readiness-analyst' },
188
+ // Coach — Review
189
+ { name: 'model-review', agent: 'review-coach' },
190
+ // Orchestration
191
+ { name: 'full-analysis', agent: 'stack-detective' },
192
+ // Validation
193
+ { name: 'accuracy-validation', agent: 'model-curator' },
194
+ ];
195
+
196
+ // Derived lists for Gyre
197
+ const GYRE_AGENT_FILES = GYRE_AGENTS.map(a => `${a.id}.md`);
198
+ const GYRE_AGENT_IDS = GYRE_AGENTS.map(a => a.id);
199
+ const GYRE_WORKFLOW_NAMES = GYRE_WORKFLOWS.map(w => w.name);
200
+
136
201
  module.exports = {
137
202
  AGENTS,
138
203
  WORKFLOWS,
@@ -141,4 +206,9 @@ module.exports = {
141
206
  WORKFLOW_NAMES,
142
207
  USER_GUIDES,
143
208
  WAVE3_WORKFLOW_NAMES,
209
+ GYRE_AGENTS,
210
+ GYRE_WORKFLOWS,
211
+ GYRE_AGENT_FILES,
212
+ GYRE_AGENT_IDS,
213
+ GYRE_WORKFLOW_NAMES,
144
214
  };
@@ -2,9 +2,10 @@
2
2
 
3
3
  const fs = require('fs-extra');
4
4
  const path = require('path');
5
+ const yaml = require('js-yaml');
5
6
  const { getPackageVersion } = require('./utils');
6
7
  const configMerger = require('./config-merger');
7
- const { AGENTS, AGENT_FILES, AGENT_IDS, WORKFLOW_NAMES, USER_GUIDES } = require('./agent-registry');
8
+ const { AGENTS, AGENT_FILES, AGENT_IDS, WORKFLOW_NAMES, USER_GUIDES, GYRE_AGENTS, GYRE_AGENT_FILES, GYRE_AGENT_IDS, GYRE_WORKFLOW_NAMES } = require('./agent-registry');
8
9
 
9
10
  /**
10
11
  * Refresh Installation for Convoke
@@ -90,6 +91,181 @@ async function refreshInstallation(projectRoot, options = {}) {
90
91
  if (verbose) console.log(' Skipped workflow copy (dev environment)');
91
92
  }
92
93
 
94
+ // 2a. Enhance module — read config, copy directory tree, patch target agent menu
95
+ const packageEnhance = path.join(packageRoot, '_bmad', 'bme', '_enhance');
96
+ const enhanceConfigPath = path.join(packageEnhance, 'config.yaml');
97
+
98
+ let enhanceConfig = null;
99
+ if (fs.existsSync(enhanceConfigPath)) {
100
+ try {
101
+ enhanceConfig = yaml.load(fs.readFileSync(enhanceConfigPath, 'utf8'));
102
+ } catch (err) {
103
+ const msg = `Enhance config.yaml parse error: ${err.message} — skipping Enhance installation`;
104
+ changes.push(msg);
105
+ if (verbose) console.log(` ⚠ ${msg}`);
106
+ }
107
+ } else {
108
+ changes.push('Enhance config.yaml not found — skipping Enhance installation');
109
+ if (verbose) console.log(' ⚠ Enhance config.yaml not found — skipping Enhance installation');
110
+ }
111
+
112
+ if (enhanceConfig) {
113
+ // 2b. Copy _enhance/ directory tree
114
+ const targetEnhance = path.join(projectRoot, '_bmad', 'bme', '_enhance');
115
+
116
+ if (!isSameRoot) {
117
+ await fs.copy(packageEnhance, targetEnhance, { overwrite: true });
118
+ changes.push('Refreshed Enhance module: _bmad/bme/_enhance/');
119
+ if (verbose) console.log(' Refreshed Enhance module: _bmad/bme/_enhance/');
120
+ } else {
121
+ changes.push('Skipped Enhance copy (dev environment — files already in place)');
122
+ if (verbose) console.log(' Skipped Enhance copy (dev environment)');
123
+ }
124
+
125
+ // 2c. Patch target agent menu for each registered workflow
126
+ if (isSameRoot) {
127
+ changes.push('Skipped Enhance menu patch (dev environment — source files unchanged)');
128
+ if (verbose) console.log(' Skipped Enhance menu patch (dev environment)');
129
+ }
130
+
131
+ for (const workflow of (isSameRoot ? [] : enhanceConfig.workflows || [])) {
132
+ const targetAgentRel = workflow.target_agent;
133
+ const targetAgentPath = path.join(projectRoot, '_bmad', targetAgentRel);
134
+
135
+ if (!fs.existsSync(targetAgentPath)) {
136
+ const msg = `${targetAgentRel} not found — BMM module must be installed first. Skipping Enhance menu patch.`;
137
+ changes.push(msg);
138
+ if (verbose) console.log(` ⚠ ${msg}`);
139
+ continue;
140
+ }
141
+
142
+ let agentContent = fs.readFileSync(targetAgentPath, 'utf8');
143
+ const patchName = workflow.menu_patch_name || workflow.name;
144
+
145
+ // Idempotency: skip if patch already present
146
+ if (agentContent.includes(patchName)) {
147
+ changes.push(`Enhance menu patch already present in ${targetAgentRel} — skipping`);
148
+ if (verbose) console.log(` Enhance menu patch already present in ${targetAgentRel} — skipping`);
149
+ continue;
150
+ }
151
+
152
+ // Build the <item> tag
153
+ const entryPath = `{project-root}/_bmad/bme/_enhance/${workflow.entry}`;
154
+ const itemTag = ` <item cmd="IB or fuzzy match on ${patchName}" exec="${entryPath}">[IB] 📦 Initiatives Backlog (Convoke Enhance)</item>`;
155
+
156
+ // Find insertion anchor: prefer </menu>, fallback to last <item>
157
+ const menuCloseIdx = agentContent.lastIndexOf('</menu>');
158
+ if (menuCloseIdx !== -1) {
159
+ // Insert before the </menu> line (not at the </menu> character position,
160
+ // which would prepend existing line indentation to the inserted tag)
161
+ const lineStart = agentContent.lastIndexOf('\n', menuCloseIdx - 1) + 1;
162
+ agentContent = agentContent.slice(0, lineStart) + itemTag + '\n' + agentContent.slice(lineStart);
163
+ } else {
164
+ // Fallback: insert after last <item>...</item> line
165
+ const lastItemMatch = agentContent.match(/.*<item[^]*?<\/item>/g);
166
+ if (lastItemMatch) {
167
+ const lastItem = lastItemMatch[lastItemMatch.length - 1];
168
+ const lastItemIdx = agentContent.lastIndexOf(lastItem);
169
+ const insertIdx = lastItemIdx + lastItem.length;
170
+ agentContent = agentContent.slice(0, insertIdx) + '\n' + itemTag + agentContent.slice(insertIdx);
171
+ } else {
172
+ const msg = `${targetAgentRel} menu structure not recognized — manual patch required. Skipping Enhance menu patch.`;
173
+ changes.push(msg);
174
+ if (verbose) console.log(` ⚠ ${msg}`);
175
+ continue;
176
+ }
177
+ }
178
+
179
+ fs.writeFileSync(targetAgentPath, agentContent, 'utf8');
180
+ changes.push(`Patched ${targetAgentRel} with Enhance menu item: ${patchName}`);
181
+ if (verbose) console.log(` Patched ${targetAgentRel} with Enhance menu item: ${patchName}`);
182
+ }
183
+ }
184
+
185
+ // 2d. Gyre module — copy agents, workflows, contracts, config
186
+ const packageGyre = path.join(packageRoot, '_bmad', 'bme', '_gyre');
187
+ const targetGyre = path.join(projectRoot, '_bmad', 'bme', '_gyre');
188
+
189
+ if (fs.existsSync(packageGyre)) {
190
+ // Copy Gyre agents
191
+ const gyreAgentsSource = path.join(packageGyre, 'agents');
192
+ const gyreAgentsTarget = path.join(targetGyre, 'agents');
193
+ await fs.ensureDir(gyreAgentsTarget);
194
+
195
+ if (!isSameRoot) {
196
+ for (const file of GYRE_AGENT_FILES) {
197
+ const src = path.join(gyreAgentsSource, file);
198
+ if (fs.existsSync(src)) {
199
+ await fs.copy(src, path.join(gyreAgentsTarget, file), { overwrite: true });
200
+ changes.push(`Refreshed Gyre agent: ${file}`);
201
+ if (verbose) console.log(` Refreshed Gyre agent: ${file}`);
202
+ }
203
+ }
204
+ } else {
205
+ changes.push('Skipped Gyre agent copy (dev environment)');
206
+ if (verbose) console.log(' Skipped Gyre agent copy (dev environment)');
207
+ }
208
+
209
+ // Copy Gyre workflows
210
+ const gyreWorkflowsSource = path.join(packageGyre, 'workflows');
211
+ const gyreWorkflowsTarget = path.join(targetGyre, 'workflows');
212
+ await fs.ensureDir(gyreWorkflowsTarget);
213
+
214
+ if (!isSameRoot) {
215
+ for (const wf of GYRE_WORKFLOW_NAMES) {
216
+ const src = path.join(gyreWorkflowsSource, wf);
217
+ const dest = path.join(gyreWorkflowsTarget, wf);
218
+ if (fs.existsSync(src)) {
219
+ if (fs.existsSync(dest)) {
220
+ await fs.remove(dest);
221
+ }
222
+ await fs.copy(src, dest, { overwrite: true });
223
+ changes.push(`Refreshed Gyre workflow: ${wf}`);
224
+ if (verbose) console.log(` Refreshed Gyre workflow: ${wf}`);
225
+ }
226
+ }
227
+ } else {
228
+ changes.push('Skipped Gyre workflow copy (dev environment)');
229
+ if (verbose) console.log(' Skipped Gyre workflow copy (dev environment)');
230
+ }
231
+
232
+ // Copy Gyre contracts
233
+ const gyreContractsSource = path.join(packageGyre, 'contracts');
234
+ const gyreContractsTarget = path.join(targetGyre, 'contracts');
235
+ if (fs.existsSync(gyreContractsSource)) {
236
+ await fs.ensureDir(gyreContractsTarget);
237
+ if (!isSameRoot) {
238
+ await fs.copy(gyreContractsSource, gyreContractsTarget, { overwrite: true });
239
+ changes.push('Refreshed Gyre contracts');
240
+ if (verbose) console.log(' Refreshed Gyre contracts');
241
+ }
242
+ }
243
+
244
+ // Copy Gyre config.yaml
245
+ const gyreConfigSource = path.join(packageGyre, 'config.yaml');
246
+ const gyreConfigTarget = path.join(targetGyre, 'config.yaml');
247
+ if (!isSameRoot && fs.existsSync(gyreConfigSource)) {
248
+ // Merge Gyre config preserving user prefs, same as Vortex
249
+ const gyreUpdates = {
250
+ agents: GYRE_AGENT_IDS,
251
+ workflows: GYRE_WORKFLOW_NAMES
252
+ };
253
+ const gyreConfigMerged = await configMerger.mergeConfig(gyreConfigTarget, version, gyreUpdates);
254
+ await configMerger.writeConfig(gyreConfigTarget, gyreConfigMerged);
255
+ changes.push(`Updated Gyre config.yaml to v${version}`);
256
+ if (verbose) console.log(` Updated Gyre config.yaml to v${version}`);
257
+ }
258
+
259
+ // Copy Gyre README
260
+ const gyreReadmeSource = path.join(packageGyre, 'README.md');
261
+ const gyreReadmeTarget = path.join(targetGyre, 'README.md');
262
+ if (!isSameRoot && fs.existsSync(gyreReadmeSource)) {
263
+ await fs.copy(gyreReadmeSource, gyreReadmeTarget, { overwrite: true });
264
+ changes.push('Refreshed Gyre README.md');
265
+ if (verbose) console.log(' Refreshed Gyre README.md');
266
+ }
267
+ }
268
+
93
269
  // 3. Update config.yaml (merge, preserving user prefs)
94
270
  const configPath = path.join(targetVortex, 'config.yaml');
95
271
  await fs.ensureDir(path.dirname(configPath));
@@ -172,35 +348,45 @@ async function refreshInstallation(projectRoot, options = {}) {
172
348
  isV610 = true;
173
349
  }
174
350
 
175
- // Build fresh bme rows matching the detected schema
351
+ // Build fresh bme rows matching the detected schema (Vortex + Gyre agents)
352
+ function buildAgentRow610(a, submodule) {
353
+ const p = a.persona;
354
+ return [
355
+ csvEscape(a.name), // name
356
+ csvEscape(''), // displayName
357
+ csvEscape(a.title), // title
358
+ csvEscape(a.icon), // icon
359
+ csvEscape(''), // capabilities
360
+ csvEscape(p.role), // role
361
+ csvEscape(p.identity), // identity
362
+ csvEscape(p.communication_style), // communicationStyle
363
+ csvEscape(p.expertise), // principles
364
+ csvEscape('bme'), // module
365
+ csvEscape(`_bmad/bme/${submodule}/agents/${a.id}.md`), // path
366
+ csvEscape(`bmad-agent-bme-${a.id}`), // canonicalId
367
+ ].join(',');
368
+ }
369
+
370
+ function buildAgentRowLegacy(a, submodule) {
371
+ const p = a.persona;
372
+ return [
373
+ a.id, a.name, a.title, a.icon,
374
+ p.role, p.identity, p.communication_style, p.expertise,
375
+ 'bme', `_bmad/bme/${submodule}/agents/${a.id}.md`,
376
+ ].map(csvEscape).join(',');
377
+ }
378
+
176
379
  let bmeRows;
177
380
  if (isV610) {
178
- bmeRows = AGENTS.map(a => {
179
- const p = a.persona;
180
- return [
181
- csvEscape(a.name), // name
182
- csvEscape(''), // displayName
183
- csvEscape(a.title), // title
184
- csvEscape(a.icon), // icon
185
- csvEscape(''), // capabilities
186
- csvEscape(p.role), // role
187
- csvEscape(p.identity), // identity
188
- csvEscape(p.communication_style), // communicationStyle
189
- csvEscape(p.expertise), // principles
190
- csvEscape('bme'), // module
191
- csvEscape(`_bmad/bme/_vortex/agents/${a.id}.md`), // path
192
- csvEscape(`bmad-agent-bme-${a.id}`), // canonicalId
193
- ].join(',');
194
- });
381
+ bmeRows = [
382
+ ...AGENTS.map(a => buildAgentRow610(a, '_vortex')),
383
+ ...GYRE_AGENTS.map(a => buildAgentRow610(a, '_gyre')),
384
+ ];
195
385
  } else {
196
- bmeRows = AGENTS.map(a => {
197
- const p = a.persona;
198
- return [
199
- a.id, a.name, a.title, a.icon,
200
- p.role, p.identity, p.communication_style, p.expertise,
201
- 'bme', `_bmad/bme/_vortex/agents/${a.id}.md`,
202
- ].map(csvEscape).join(',');
203
- });
386
+ bmeRows = [
387
+ ...AGENTS.map(a => buildAgentRowLegacy(a, '_vortex')),
388
+ ...GYRE_AGENTS.map(a => buildAgentRowLegacy(a, '_gyre')),
389
+ ];
204
390
  }
205
391
 
206
392
  const allRows = [...preservedRows, ...bmeRows].join('\n') + '\n';
@@ -250,7 +436,10 @@ async function refreshInstallation(projectRoot, options = {}) {
250
436
  const skillsDir = path.join(projectRoot, '.claude', 'skills');
251
437
 
252
438
  // Remove stale skill directories (agents no longer in registry)
253
- const currentSkillDirs = new Set(AGENTS.map(a => `bmad-agent-bme-${a.id}`));
439
+ const currentSkillDirs = new Set([
440
+ ...AGENTS.map(a => `bmad-agent-bme-${a.id}`),
441
+ ...GYRE_AGENTS.map(a => `bmad-agent-bme-${a.id}`),
442
+ ]);
254
443
  if (fs.existsSync(skillsDir)) {
255
444
  const existingSkills = (await fs.readdir(skillsDir)).filter(d => d.startsWith('bmad-agent-bme-'));
256
445
  for (const dir of existingSkills) {
@@ -286,6 +475,78 @@ You must fully embody this agent's persona and follow all activation instruction
286
475
  if (verbose) console.log(` Refreshed skill: bmad-agent-bme-${agent.id}/SKILL.md`);
287
476
  }
288
477
 
478
+ // 6b. Generate .claude/skills/ for Gyre agents
479
+ for (const agent of GYRE_AGENTS) {
480
+ const skillDir = path.join(skillsDir, `bmad-agent-bme-${agent.id}`);
481
+ await fs.ensureDir(skillDir);
482
+ const content = `---
483
+ name: bmad-agent-bme-${agent.id}
484
+ description: ${agent.id} agent
485
+ ---
486
+
487
+ You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
488
+
489
+ <agent-activation CRITICAL="TRUE">
490
+ 1. LOAD the FULL agent file from {project-root}/_bmad/bme/_gyre/agents/${agent.id}.md
491
+ 2. READ its entire contents - this contains the complete agent persona, menu, and instructions
492
+ 3. FOLLOW every step in the <activation> section precisely
493
+ 4. DISPLAY the welcome/greeting as instructed
494
+ 5. PRESENT the numbered menu
495
+ 6. WAIT for user input before proceeding
496
+ </agent-activation>
497
+ `;
498
+ await fs.writeFile(path.join(skillDir, 'SKILL.md'), content, 'utf8');
499
+ changes.push(`Refreshed skill: bmad-agent-bme-${agent.id}/SKILL.md`);
500
+ if (verbose) console.log(` Refreshed skill: bmad-agent-bme-${agent.id}/SKILL.md`);
501
+ }
502
+
503
+ // 6c. Copy Enhance workflow skill wrappers and register in manifests
504
+ if (enhanceConfig && !isSameRoot) {
505
+ for (const workflow of enhanceConfig.workflows || []) {
506
+ const canonicalId = `bmad-enhance-${workflow.name}`;
507
+ const skillDir = path.join(skillsDir, canonicalId);
508
+ await fs.ensureDir(skillDir);
509
+
510
+ // Copy source SKILL.md from package (shipped via npm, not generated)
511
+ const sourceSkillPath = path.join(packageRoot, '_bmad', 'bme', '_enhance', 'workflows', workflow.name, 'SKILL.md');
512
+ const targetSkillPath = path.join(skillDir, 'SKILL.md');
513
+ await fs.copy(sourceSkillPath, targetSkillPath, { overwrite: true });
514
+ changes.push(`Refreshed Enhance skill: ${canonicalId}/SKILL.md`);
515
+ if (verbose) console.log(` Refreshed Enhance skill: ${canonicalId}/SKILL.md`);
516
+
517
+ // Append to workflow-manifest.csv if not already present
518
+ const wfManifestPath = path.join(projectRoot, '_bmad', '_config', 'workflow-manifest.csv');
519
+ if (fs.existsSync(wfManifestPath)) {
520
+ const wfCsv = fs.readFileSync(wfManifestPath, 'utf8');
521
+ if (!wfCsv.includes(`"${canonicalId}"`)) {
522
+ const wfRow = `\n"${workflow.name}","Manage RICE initiatives backlog — triage review findings, rescore existing items, or bootstrap new backlogs.","bme","_bmad/bme/_enhance/${workflow.entry}","${canonicalId}"`;
523
+ fs.appendFileSync(wfManifestPath, wfRow, 'utf8');
524
+ changes.push(`Added ${canonicalId} to workflow-manifest.csv`);
525
+ if (verbose) console.log(` Added ${canonicalId} to workflow-manifest.csv`);
526
+ }
527
+ } else {
528
+ if (verbose) console.log(' ⚠ workflow-manifest.csv not found — skipping manifest registration');
529
+ }
530
+
531
+ // Append to skill-manifest.csv if not already present
532
+ const skManifestPath = path.join(projectRoot, '_bmad', '_config', 'skill-manifest.csv');
533
+ if (fs.existsSync(skManifestPath)) {
534
+ const skCsv = fs.readFileSync(skManifestPath, 'utf8');
535
+ if (!skCsv.includes(`"${canonicalId}"`)) {
536
+ const skRow = `\n"${canonicalId}","${canonicalId}","Manage RICE initiatives backlog — triage review findings, rescore existing items, or bootstrap new backlogs.","bme","_bmad/bme/_enhance/workflows/${workflow.name}/SKILL.md","true"`;
537
+ fs.appendFileSync(skManifestPath, skRow, 'utf8');
538
+ changes.push(`Added ${canonicalId} to skill-manifest.csv`);
539
+ if (verbose) console.log(` Added ${canonicalId} to skill-manifest.csv`);
540
+ }
541
+ } else {
542
+ if (verbose) console.log(' ⚠ skill-manifest.csv not found — skipping manifest registration');
543
+ }
544
+ }
545
+ } else if (enhanceConfig && isSameRoot) {
546
+ changes.push('Skipped Enhance skill registration (dev environment — source files unchanged)');
547
+ if (verbose) console.log(' Skipped Enhance skill registration (dev environment)');
548
+ }
549
+
289
550
  // 7. Generate agent customize files (only if they don't already exist)
290
551
  const customizeDir = path.join(projectRoot, '_bmad', '_config', 'agents');
291
552
  await fs.ensureDir(customizeDir);
@@ -318,7 +579,7 @@ menu: []
318
579
  prompts: []
319
580
  `;
320
581
 
321
- for (const agent of AGENTS) {
582
+ for (const agent of [...AGENTS, ...GYRE_AGENTS]) {
322
583
  const filename = `bme-${agent.name.toLowerCase()}.customize.yaml`;
323
584
  const filePath = path.join(customizeDir, filename);
324
585
  if (!fs.existsSync(filePath)) {