convoke-agents 2.1.0 → 2.2.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [2.2.0] - 2026-03-14
11
+
12
+ ### Changed
13
+
14
+ - **Agent activation migrated from commands to skills** — `.claude/commands/bmad-agent-bme-*.md` replaced by `.claude/skills/bmad-agent-bme-{id}/SKILL.md` (BMAD v6.1.0 format)
15
+ - **Agent manifest uses v6.1.0 12-column schema** — BME agents now populate all fields including `canonicalId`, `module`, `communicationStyle`, `capabilities`
16
+ - **Removed redundant `createAgentManifest()`** from installer — `refreshInstallation()` is now the single code path for manifest generation
17
+
18
+ ### Added
19
+
20
+ - **`src/module.yaml`** — External module spec definition for future BMAD registration
21
+ - **Agent customize files** — `_bmad/_config/agents/bme-{name}.customize.yaml` generated on install (never overwritten)
22
+ - **Legacy command cleanup** — Automatically removes `.claude/commands/bmad-agent-bme-*` files from prior installs
23
+
24
+ ### Removed
25
+
26
+ - **`_bmad/bme/_config/module.yaml`** — Stale legacy file with deprecated agent references deleted
27
+
28
+ ---
29
+
10
30
  ## [2.0.0] - 2026-03-07
11
31
 
12
32
  ### Changed
package/README.md CHANGED
@@ -155,7 +155,7 @@ Open `_bmad/bme/_vortex/config.yaml` and replace `{user}` with your name. Agents
155
155
 
156
156
  #### Activate an Agent
157
157
 
158
- **Claude Code (slash commands)**
158
+ **Claude Code (skills)**
159
159
 
160
160
  ```
161
161
  /bmad-agent-bme-contextualization-expert # Emma 🎯
@@ -33,7 +33,7 @@ workflows:
33
33
  - learning-card
34
34
  - pivot-patch-persevere
35
35
  - vortex-navigation
36
- version: 1.6.2
36
+ version: 2.2.0
37
37
  user_name: '{user}'
38
38
  communication_language: en
39
39
  party_mode_enabled: true
@@ -56,9 +56,9 @@ cat _bmad/bme/_vortex/agents/contextualization-expert.md
56
56
 
57
57
  ---
58
58
 
59
- ### Method 2: Slash Command (BMAD Environments Only)
59
+ ### Method 2: Skill Activation (BMAD Environments Only)
60
60
 
61
- If your environment supports BMAD slash commands:
61
+ If your environment supports BMAD skills:
62
62
 
63
63
  ```
64
64
  /bmad-agent-bme-contextualization-expert
@@ -45,9 +45,9 @@ cat _bmad/bme/_vortex/agents/discovery-empathy-expert.md
45
45
 
46
46
  ---
47
47
 
48
- ### Method 2: Slash Command (BMAD Environments Only)
48
+ ### Method 2: Skill Activation (BMAD Environments Only)
49
49
 
50
- If your environment supports BMAD slash commands:
50
+ If your environment supports BMAD skills:
51
51
 
52
52
  ```
53
53
  /bmad-agent-bme-discovery-empathy-expert
@@ -57,9 +57,9 @@ cat _bmad/bme/_vortex/agents/hypothesis-engineer.md
57
57
 
58
58
  ---
59
59
 
60
- ### Method 2: Slash Command (BMAD Environments Only)
60
+ ### Method 2: Skill Activation (BMAD Environments Only)
61
61
 
62
- If your environment supports BMAD slash commands:
62
+ If your environment supports BMAD skills:
63
63
 
64
64
  ```
65
65
  /bmad-agent-bme-hypothesis-engineer
@@ -44,9 +44,9 @@ cat _bmad/bme/_vortex/agents/learning-decision-expert.md
44
44
 
45
45
  ---
46
46
 
47
- ### Method 2: Slash Command (BMAD Environments Only)
47
+ ### Method 2: Skill Activation (BMAD Environments Only)
48
48
 
49
- If your environment supports BMAD slash commands:
49
+ If your environment supports BMAD skills:
50
50
 
51
51
  ```
52
52
  /bmad-agent-bme-learning-decision-expert
@@ -56,9 +56,9 @@ cat _bmad/bme/_vortex/agents/research-convergence-specialist.md
56
56
 
57
57
  ---
58
58
 
59
- ### Method 2: Slash Command (BMAD Environments Only)
59
+ ### Method 2: Skill Activation (BMAD Environments Only)
60
60
 
61
- If your environment supports BMAD slash commands:
61
+ If your environment supports BMAD skills:
62
62
 
63
63
  ```
64
64
  /bmad-agent-bme-research-convergence-specialist
@@ -58,9 +58,9 @@ cat _bmad/bme/_vortex/agents/production-intelligence-specialist.md
58
58
 
59
59
  ---
60
60
 
61
- ### Method 2: Slash Command (BMAD Environments Only)
61
+ ### Method 2: Skill Activation (BMAD Environments Only)
62
62
 
63
- If your environment supports BMAD slash commands:
63
+ If your environment supports BMAD skills:
64
64
 
65
65
  ```
66
66
  /bmad-agent-bme-production-intelligence-specialist
@@ -57,9 +57,9 @@ cat _bmad/bme/_vortex/agents/lean-experiments-specialist.md
57
57
 
58
58
  ---
59
59
 
60
- ### Method 2: Slash Command (BMAD Environments Only)
60
+ ### Method 2: Skill Activation (BMAD Environments Only)
61
61
 
62
- If your environment supports BMAD slash commands:
62
+ If your environment supports BMAD skills:
63
63
 
64
64
  ```
65
65
  /bmad-agent-bme-lean-experiments-specialist
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "convoke-agents",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Agent teams for complex systems, compatible with BMad Method",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -11,7 +11,8 @@
11
11
  "UPDATE-GUIDE.md",
12
12
  "CHANGELOG.md",
13
13
  "LICENSE",
14
- "README.md"
14
+ "README.md",
15
+ "src/"
15
16
  ],
16
17
  "bin": {
17
18
  "convoke-install-vortex": "scripts/install-vortex-agents.js",
@@ -522,13 +522,13 @@ async function runAudit(opts = {}) {
522
522
  const content = fs.readFileSync(absPath, 'utf8');
523
523
  allDocsContent.push(content);
524
524
 
525
- // Skip stale-reference checks for CHANGELOG — historical entries
526
- // (e.g., "Added 4 agents" in v1.0) are accurate for their time period
525
+ // Skip stale-reference and broken-path checks for CHANGELOG — historical entries
526
+ // reference files that may have been deleted or renamed in past versions
527
527
  if (relPath !== 'CHANGELOG.md') {
528
528
  allFindings.push(...checkStaleReferences(content, relPath));
529
+ allFindings.push(...checkBrokenPaths(content, relPath, projectRoot));
529
530
  }
530
531
  allFindings.push(...checkBrokenLinks(content, relPath, projectRoot));
531
- allFindings.push(...checkBrokenPaths(content, relPath, projectRoot));
532
532
  allFindings.push(...checkIncompleteAgentTables(content, relPath));
533
533
  allFindings.push(...checkInternalNamingLeaks(content, relPath));
534
534
  allFindings.push(...checkStaleBrandReferences(content, relPath));
@@ -29,7 +29,7 @@ function printBanner() {
29
29
  }
30
30
 
31
31
  function checkPrerequisites(projectRoot) {
32
- console.log(`${CYAN}[1/6]${RESET} Checking prerequisites...`);
32
+ console.log(`${CYAN}[1/5]${RESET} Checking prerequisites...`);
33
33
 
34
34
  const bmadDir = path.join(projectRoot, '_bmad');
35
35
 
@@ -53,7 +53,7 @@ function checkPrerequisites(projectRoot) {
53
53
  }
54
54
 
55
55
  function archiveDeprecatedWorkflows(projectRoot) {
56
- console.log(`${CYAN}[2/6]${RESET} Archiving deprecated workflows...`);
56
+ console.log(`${CYAN}[2/5]${RESET} Archiving deprecated workflows...`);
57
57
 
58
58
  const sourceDir = path.join(__dirname, '..', '_bmad', 'bme', '_vortex');
59
59
  const targetDir = path.join(projectRoot, '_bmad', 'bme', '_vortex');
@@ -94,32 +94,8 @@ function cleanupLegacyFiles(projectRoot) {
94
94
  console.log(`${GREEN} ✓${RESET} Legacy cleanup complete`);
95
95
  }
96
96
 
97
- function csvEscape(value) {
98
- return `"${String(value).replace(/"/g, '""')}"`;
99
- }
100
-
101
- function createAgentManifest(projectRoot) {
102
- console.log(`${CYAN}[3/6]${RESET} Creating agent manifest...`);
103
-
104
- const manifestPath = path.join(projectRoot, '_bmad', '_config', 'agent-manifest.csv');
105
- fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
106
-
107
- const header = '"agent_id","name","title","icon","role","identity","communication_style","expertise","submodule","path"\n';
108
- const rows = AGENTS.map(a => {
109
- const p = a.persona;
110
- return [
111
- a.id, a.name, a.title, a.icon,
112
- p.role, p.identity, p.communication_style, p.expertise,
113
- 'bme', `_bmad/bme/_vortex/agents/${a.id}.md`,
114
- ].map(csvEscape).join(',');
115
- }).join('\n') + '\n';
116
-
117
- fs.writeFileSync(manifestPath, header + rows);
118
- console.log(`${GREEN} ✓${RESET} Created agent-manifest.csv`);
119
- }
120
-
121
97
  function createOutputDirectory(projectRoot) {
122
- console.log(`${CYAN}[4/6]${RESET} Setting up output directory...`);
98
+ console.log(`${CYAN}[3/5]${RESET} Setting up output directory...`);
123
99
 
124
100
  const outputDir = path.join(projectRoot, '_bmad-output', 'vortex-artifacts');
125
101
  fs.mkdirSync(outputDir, { recursive: true });
@@ -128,11 +104,11 @@ function createOutputDirectory(projectRoot) {
128
104
  }
129
105
 
130
106
  function verifyInstallation(projectRoot) {
131
- console.log(`${CYAN}[6/6]${RESET} Verifying installation...`);
107
+ console.log(`${CYAN}[5/5]${RESET} Verifying installation...`);
132
108
 
133
109
  const checks = [
134
110
  ...AGENTS.map(a => ({ path: `_bmad/bme/_vortex/agents/${a.id}.md`, name: `${a.name} agent file` })),
135
- ...AGENTS.map(a => ({ path: `.claude/commands/bmad-agent-bme-${a.id}.md`, name: `${a.name} slash command` })),
111
+ ...AGENTS.map(a => ({ path: `.claude/skills/bmad-agent-bme-${a.id}/SKILL.md`, name: `${a.name} skill` })),
136
112
  { path: '_bmad/bme/_vortex/config.yaml', name: 'Configuration file' },
137
113
  ];
138
114
 
@@ -175,7 +151,7 @@ function printSuccess() {
175
151
  console.log(` ${YELLOW}1.${RESET} Personalize your config:`);
176
152
  console.log(` Edit ${CYAN}_bmad/bme/_vortex/config.yaml${RESET} and replace ${YELLOW}{user}${RESET} with your name`);
177
153
  console.log('');
178
- console.log(` ${YELLOW}2.${RESET} Activate an agent with a slash command (Claude Code):`);
154
+ console.log(` ${YELLOW}2.${RESET} Activate an agent (skill) in Claude Code:`);
179
155
  for (const agent of AGENTS) {
180
156
  console.log(` ${CYAN}/bmad-agent-bme-${agent.id}${RESET} (${agent.name})`);
181
157
  }
@@ -193,11 +169,10 @@ async function main() {
193
169
  printBanner();
194
170
  checkPrerequisites(projectRoot);
195
171
  archiveDeprecatedWorkflows(projectRoot);
196
- createAgentManifest(projectRoot);
197
172
  createOutputDirectory(projectRoot);
198
173
 
199
- // Use refreshInstallation for agents, workflows, config, and user guides
200
- console.log(`${CYAN}[5/6]${RESET} Installing agents, workflows, config, and guides...`);
174
+ // Use refreshInstallation for agents, workflows, config, guides, manifest, and skills
175
+ console.log(`${CYAN}[4/5]${RESET} Installing agents, workflows, config, and guides...`);
201
176
  await refreshInstallation(projectRoot, { backupGuides: false });
202
177
  console.log(`${GREEN} ✓${RESET} Installation refreshed`);
203
178
 
@@ -112,31 +112,96 @@ async function refreshInstallation(projectRoot, options = {}) {
112
112
  return `"${String(value).replace(/"/g, '""')}"`;
113
113
  }
114
114
 
115
- const header = '"agent_id","name","title","icon","role","identity","communication_style","expertise","submodule","path"';
115
+ function parseCSVRow(row) {
116
+ const fields = [];
117
+ let current = '';
118
+ let inQuotes = false;
119
+ for (let i = 0; i < row.length; i++) {
120
+ const ch = row[i];
121
+ if (inQuotes) {
122
+ if (ch === '"' && row[i + 1] === '"') {
123
+ current += '"';
124
+ i++;
125
+ } else if (ch === '"') {
126
+ inQuotes = false;
127
+ } else {
128
+ current += ch;
129
+ }
130
+ } else if (ch === '"') {
131
+ inQuotes = true;
132
+ } else if (ch === ',') {
133
+ fields.push(current);
134
+ current = '';
135
+ } else {
136
+ current += ch;
137
+ }
138
+ }
139
+ fields.push(current);
140
+ return fields;
141
+ }
116
142
 
117
- // Read existing non-bme rows to preserve them
143
+ const V610_HEADER = 'name,displayName,title,icon,capabilities,role,identity,communicationStyle,principles,module,path,canonicalId';
144
+ // Detect schema from existing manifest or default to v6.1.0
145
+ let header;
146
+ let isV610 = true;
118
147
  let preservedRows = [];
148
+
119
149
  if (fs.existsSync(manifestPath)) {
120
150
  const existing = (await fs.readFile(manifestPath, 'utf8')).trim().split('\n');
121
- // Skip header, keep rows where submodule is NOT bme
151
+ header = existing[0];
152
+ isV610 = header.startsWith('name,') || header.includes('canonicalId');
153
+
154
+ // Filter out bme rows, preserve everything else
122
155
  preservedRows = existing.slice(1).filter(row => {
123
- // submodule is the 9th field (index 8) in the CSV
124
- const fields = row.match(/"([^"]*(?:""[^"]*)*)"/g);
125
- if (!fields || fields.length < 9) return true; // keep unrecognised rows
126
- const submodule = fields[8].replace(/^"|"$/g, '');
127
- return submodule !== 'bme';
156
+ if (!row.trim()) return false;
157
+ if (isV610) {
158
+ // v6.1.0: module is column 10 (index 9) handle quoted CSV fields
159
+ const parsed = parseCSVRow(row);
160
+ if (!parsed || parsed.length < 10) return true;
161
+ return parsed[9] !== 'bme';
162
+ } else {
163
+ // Legacy: submodule is column 9 (index 8) — quoted CSV
164
+ const fields = row.match(/"([^"]*(?:""[^"]*)*)"/g);
165
+ if (!fields || fields.length < 9) return true;
166
+ const submodule = fields[8].replace(/^"|"$/g, '');
167
+ return submodule !== 'bme';
168
+ }
128
169
  });
170
+ } else {
171
+ header = V610_HEADER;
172
+ isV610 = true;
129
173
  }
130
174
 
131
- // Build fresh bme rows from registry
132
- const bmeRows = AGENTS.map(a => {
133
- const p = a.persona;
134
- return [
135
- a.id, a.name, a.title, a.icon,
136
- p.role, p.identity, p.communication_style, p.expertise,
137
- 'bme', `_bmad/bme/_vortex/agents/${a.id}.md`,
138
- ].map(csvEscape).join(',');
139
- });
175
+ // Build fresh bme rows matching the detected schema
176
+ let bmeRows;
177
+ 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
+ });
195
+ } 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
+ });
204
+ }
140
205
 
141
206
  const allRows = [...preservedRows, ...bmeRows].join('\n') + '\n';
142
207
  await fs.writeFile(manifestPath, header + '\n' + allRows, 'utf8');
@@ -171,26 +236,38 @@ async function refreshInstallation(projectRoot, options = {}) {
171
236
  if (verbose) console.log(' Skipped guide copy (dev environment)');
172
237
  }
173
238
 
174
- // 6. Generate .claude/commands/ slash command files for each agent
175
- const commandsTarget = path.join(projectRoot, '.claude', 'commands');
176
- await fs.ensureDir(commandsTarget);
177
-
178
- // Remove deprecated command files (agents no longer in registry)
179
- const currentCommandFiles = new Set(AGENTS.map(a => `bmad-agent-bme-${a.id}.md`));
180
- const existingCommands = (await fs.readdir(commandsTarget)).filter(f => f.startsWith('bmad-agent-bme-'));
181
- for (const file of existingCommands) {
182
- if (!currentCommandFiles.has(file)) {
183
- await fs.remove(path.join(commandsTarget, file));
184
- changes.push(`Removed deprecated command: ${file}`);
185
- if (verbose) console.log(` Removed deprecated command: ${file}`);
239
+ // 6. Clean up legacy .claude/commands/ and generate .claude/skills/ for each agent
240
+ const commandsDir = path.join(projectRoot, '.claude', 'commands');
241
+ if (fs.existsSync(commandsDir)) {
242
+ const legacyCommands = (await fs.readdir(commandsDir)).filter(f => f.startsWith('bmad-agent-bme-'));
243
+ for (const file of legacyCommands) {
244
+ await fs.remove(path.join(commandsDir, file));
245
+ changes.push(`Removed legacy command: ${file}`);
246
+ if (verbose) console.log(` Removed legacy command: ${file}`);
247
+ }
248
+ }
249
+
250
+ const skillsDir = path.join(projectRoot, '.claude', 'skills');
251
+
252
+ // Remove stale skill directories (agents no longer in registry)
253
+ const currentSkillDirs = new Set(AGENTS.map(a => `bmad-agent-bme-${a.id}`));
254
+ if (fs.existsSync(skillsDir)) {
255
+ const existingSkills = (await fs.readdir(skillsDir)).filter(d => d.startsWith('bmad-agent-bme-'));
256
+ for (const dir of existingSkills) {
257
+ if (!currentSkillDirs.has(dir)) {
258
+ await fs.remove(path.join(skillsDir, dir));
259
+ changes.push(`Removed stale skill: ${dir}`);
260
+ if (verbose) console.log(` Removed stale skill: ${dir}`);
261
+ }
186
262
  }
187
263
  }
188
264
 
189
265
  for (const agent of AGENTS) {
190
- const filename = `bmad-agent-bme-${agent.id}.md`;
266
+ const skillDir = path.join(skillsDir, `bmad-agent-bme-${agent.id}`);
267
+ await fs.ensureDir(skillDir);
191
268
  const content = `---
192
- name: '${agent.id}'
193
- description: '${agent.id} agent'
269
+ name: bmad-agent-bme-${agent.id}
270
+ description: ${agent.id} agent
194
271
  ---
195
272
 
196
273
  You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
@@ -204,9 +281,51 @@ You must fully embody this agent's persona and follow all activation instruction
204
281
  6. WAIT for user input before proceeding
205
282
  </agent-activation>
206
283
  `;
207
- await fs.writeFile(path.join(commandsTarget, filename), content, 'utf8');
208
- changes.push(`Refreshed command: ${filename}`);
209
- if (verbose) console.log(` Refreshed command: ${filename}`);
284
+ await fs.writeFile(path.join(skillDir, 'SKILL.md'), content, 'utf8');
285
+ changes.push(`Refreshed skill: bmad-agent-bme-${agent.id}/SKILL.md`);
286
+ if (verbose) console.log(` Refreshed skill: bmad-agent-bme-${agent.id}/SKILL.md`);
287
+ }
288
+
289
+ // 7. Generate agent customize files (only if they don't already exist)
290
+ const customizeDir = path.join(projectRoot, '_bmad', '_config', 'agents');
291
+ await fs.ensureDir(customizeDir);
292
+
293
+ const CUSTOMIZE_TEMPLATE = `# Agent Customization
294
+ # Customize any section below - all are optional
295
+
296
+ # Override agent name
297
+ agent:
298
+ metadata:
299
+ name: ""
300
+
301
+ # Replace entire persona (not merged)
302
+ persona:
303
+ role: ""
304
+ identity: ""
305
+ communication_style: ""
306
+ principles: []
307
+
308
+ # Add custom critical actions (appended after standard config loading)
309
+ critical_actions: []
310
+
311
+ # Add persistent memories for the agent
312
+ memories: []
313
+
314
+ # Add custom menu items (appended to base menu)
315
+ menu: []
316
+
317
+ # Add custom prompts (for action="#id" handlers)
318
+ prompts: []
319
+ `;
320
+
321
+ for (const agent of AGENTS) {
322
+ const filename = `bme-${agent.name.toLowerCase()}.customize.yaml`;
323
+ const filePath = path.join(customizeDir, filename);
324
+ if (!fs.existsSync(filePath)) {
325
+ await fs.writeFile(filePath, CUSTOMIZE_TEMPLATE, 'utf8');
326
+ changes.push(`Created customize file: ${filename}`);
327
+ if (verbose) console.log(` Created customize file: ${filename}`);
328
+ }
210
329
  }
211
330
 
212
331
  return changes;
@@ -0,0 +1,6 @@
1
+ code: bme
2
+ name: "Convoke: Vortex Discovery Framework"
3
+ header: "Convoke — Vortex Discovery Framework"
4
+ subheader: "7 AI agents for product discovery based on the Shiftup Innovation Vortex"
5
+ description: "Domain-specialized agent teams for structured product discovery: Contextualize, Empathize, Synthesize, Hypothesize, Externalize, Sensitize, Systematize"
6
+ default_selected: false