From d9b10490b4486679ae51f8569167d2694b98e327 Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Thu, 27 Nov 2025 09:46:16 -0700 Subject: [PATCH 01/11] fix: Clear all npm config env vars before calling AgentVibes installer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When BMAD is invoked with --prefix flag, npm sets many npm_config_* and npm_package_* environment variables. These caused npx agentvibes to look for files in the wrong directory (/prefix/lib instead of cwd). Changes: - tools/cli/commands/install.js: Filter out ALL npm_config_* and npm_package_* env vars before calling npx agentvibes - tools/cli/installers/lib/core/installer.js: Add AgentVibes prompt to Quick Update flow so existing installations can enable TTS - tools/cli/installers/lib/core/manifest-generator.js: Track agentVibes configuration in manifest.yaml This ensures AgentVibes runs in a clean environment regardless of how BMAD was invoked (with or without --prefix flag). šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- tools/cli/commands/install.js | 8 +++++ tools/cli/installers/lib/core/installer.js | 33 +++++++++++++++++++ .../installers/lib/core/manifest-generator.js | 4 +++ 3 files changed, 45 insertions(+) diff --git a/tools/cli/commands/install.js b/tools/cli/commands/install.js index d5742cf7..4ada1489 100644 --- a/tools/cli/commands/install.js +++ b/tools/cli/commands/install.js @@ -90,10 +90,18 @@ module.exports = { // Run AgentVibes installer const { execSync } = require('node:child_process'); try { + // Clear ALL npm config env vars to prevent inheritance issues + // when BMAD is invoked with --prefix flag + // npm sets many npm_config_* and npm_package_* vars that can interfere + const cleanEnv = Object.fromEntries( + Object.entries(process.env).filter(([key]) => !key.startsWith('npm_config_') && !key.startsWith('npm_package_')), + ); + execSync('npx agentvibes@latest install', { cwd: result.projectDir, stdio: 'inherit', shell: true, + env: cleanEnv, }); console.log(chalk.green('\nāœ“ AgentVibes installation complete')); } catch { diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index f113c141..4abe6eb5 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -824,6 +824,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: const manifestStats = await manifestGen.generateManifests(bmadDir, config.modules || [], this.installedFiles, { ides: config.ides || [], preservedModules: config._preserveModules || [], // Scan these from installed bmad/ dir + agentVibes: { enabled: this.enableAgentVibes || false }, // Track AgentVibes TTS configuration }); spinner.succeed( @@ -1966,6 +1967,37 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: } } + // Check for AgentVibes TTS - prompt if not previously configured + // Read existing manifest to check if AgentVibes was previously set + const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); + let agentVibesEnabled = false; + let agentVibesPreviouslyConfigured = false; + + try { + const manifestContent = await fs.readFile(manifestPath, 'utf8'); + const yaml = require('js-yaml'); + const manifest = yaml.load(manifestContent); + // Check if AgentVibes was previously configured (exists in manifest) + if (manifest.agentVibes !== undefined) { + agentVibesPreviouslyConfigured = true; + agentVibesEnabled = manifest.agentVibes?.enabled || false; + } + } catch { + // Manifest doesn't exist or can't be read - treat as not configured + } + + // If AgentVibes wasn't previously configured, prompt the user + if (!agentVibesPreviouslyConfigured) { + const { UI } = require('../../../lib/ui'); + const ui = new UI(); + const agentVibesConfig = await ui.promptAgentVibes(projectDir); + + if (agentVibesConfig.enableTts) { + agentVibesEnabled = true; + promptedForNewFields = true; + } + } + if (!promptedForNewFields) { console.log(chalk.green('āœ“ All configuration is up to date, no new options to configure')); } @@ -2003,6 +2035,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: _quickUpdate: true, // Flag to skip certain prompts _preserveModules: skippedModules, // Preserve these in manifest even though we didn't update them _savedIdeConfigs: savedIdeConfigs, // Pass saved IDE configs to installer + enableAgentVibes: agentVibesEnabled, // AgentVibes TTS configuration }; // Call the standard install method diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/cli/installers/lib/core/manifest-generator.js index f10d0deb..8612a0b4 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/cli/installers/lib/core/manifest-generator.js @@ -54,6 +54,9 @@ class ManifestGenerator { // Filter out any undefined/null values from IDE list this.selectedIdes = resolvedIdes.filter((ide) => ide && typeof ide === 'string'); + // Store AgentVibes configuration for manifest + this.agentVibes = options.agentVibes || null; + // Collect workflow data await this.collectWorkflows(selectedModules); @@ -446,6 +449,7 @@ class ManifestGenerator { }, modules: this.modules, ides: this.selectedIdes, + agentVibes: this.agentVibes, // Track AgentVibes TTS configuration }; const yamlStr = yaml.dump(manifest, { From 08aaf5e2f3c8e863e1a049e45ffba9810e385c94 Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Thu, 27 Nov 2025 09:54:17 -0700 Subject: [PATCH 02/11] feat: Swap bmad-master and pm voice assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - bmad-master: en_US-ryan-high → en_US-lessac-medium - pm (john): en_US-lessac-medium → en_US-ryan-high šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .bmad/_cfg/agent-voice-map.csv | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .bmad/_cfg/agent-voice-map.csv diff --git a/.bmad/_cfg/agent-voice-map.csv b/.bmad/_cfg/agent-voice-map.csv new file mode 100644 index 00000000..18a20fe4 --- /dev/null +++ b/.bmad/_cfg/agent-voice-map.csv @@ -0,0 +1,11 @@ +agent,voice +bmad-master,en_US-lessac-medium +analyst,en_US-kristin-medium +architect,en_GB-alan-medium +dev,en_US-joe-medium +pm,en_US-ryan-high +sm,en_US-amy-medium +tea,en_US-kusal-medium +tech-writer,jenny +ux-designer,kristin +frame-expert,en_GB-alan-medium From fe79f7776803f4fb4f3ded45135933f693bf4f61 Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Thu, 27 Nov 2025 10:04:00 -0700 Subject: [PATCH 03/11] feat: Move AgentVibes prompt after tool selection with smart defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move AgentVibes TTS prompt to after IDE/tool selection - Default to Y if Claude Code is selected (since AgentVibes only works with Claude Code) - Default to N if Claude Code is not selected - Remove mid-install warning about AgentVibes not being installed (handled at end) - Pass configured IDEs to quick update flow for consistent behavior šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- tools/cli/installers/lib/core/installer.js | 3 ++- tools/cli/lib/ui.js | 24 ++++++++++++---------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 4abe6eb5..562b0731 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -1987,10 +1987,11 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: } // If AgentVibes wasn't previously configured, prompt the user + // Use configuredIdes from line 1904 for smart default (Y if Claude Code is selected) if (!agentVibesPreviouslyConfigured) { const { UI } = require('../../../lib/ui'); const ui = new UI(); - const agentVibesConfig = await ui.promptAgentVibes(projectDir); + const agentVibesConfig = await ui.promptAgentVibes(projectDir, configuredIdes); if (agentVibesConfig.enableTts) { agentVibesEnabled = true; diff --git a/tools/cli/lib/ui.js b/tools/cli/lib/ui.js index 4c5b3379..f5db8520 100644 --- a/tools/cli/lib/ui.js +++ b/tools/cli/lib/ui.js @@ -119,13 +119,14 @@ class UI { const moduleChoices = await this.getModuleChoices(installedModuleIds); const selectedModules = await this.selectModules(moduleChoices); - // Prompt for AgentVibes TTS integration - const agentVibesConfig = await this.promptAgentVibes(confirmedDirectory); - // Collect IDE tool selection AFTER configuration prompts (fixes Windows/PowerShell hang) // This allows text-based prompts to complete before the checkbox prompt const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules); + // Prompt for AgentVibes TTS integration AFTER tool selection + // Default to Y if Claude Code is selected (since AgentVibes only works with Claude Code) + const agentVibesConfig = await this.promptAgentVibes(confirmedDirectory, toolSelection.ides); + // No more screen clearing - keep output flowing return { @@ -753,7 +754,7 @@ class UI { * - Markers: src/core/workflows/party-mode/instructions.md:101, src/modules/bmm/agents/*.md * - GitHub Issue: paulpreibisch/AgentVibes#36 */ - async promptAgentVibes(projectDir) { + async promptAgentVibes(projectDir, selectedIdes = []) { CLIUtils.displaySection('šŸŽ¤ Voice Features', 'Enable TTS for multi-agent conversations'); // Check if AgentVibes is already installed @@ -765,20 +766,21 @@ class UI { console.log(chalk.dim(' AgentVibes not detected')); } + // Default to Y if Claude Code is selected (AgentVibes only works with Claude Code) + const claudeCodeSelected = selectedIdes.includes('claude-code'); + const defaultValue = claudeCodeSelected; + const answers = await inquirer.prompt([ { type: 'confirm', name: 'enableTts', - message: 'Enable Agents to Speak Out loud (powered by Agent Vibes? Claude Code only currently)', - default: false, // Default to yes - recommended for best experience + message: 'Enable Agents to Speak Out loud (powered by AgentVibes, Claude Code only)', + default: defaultValue, }, ]); - if (answers.enableTts && !agentVibesInstalled) { - console.log(chalk.yellow('\n āš ļø AgentVibes not installed')); - console.log(chalk.dim(' Install AgentVibes separately to enable TTS:')); - console.log(chalk.dim(' https://github.com/paulpreibisch/AgentVibes\n')); - } + // Note: AgentVibes installer runs at end of BMAD install if enabled and not already installed + // No need to show warning here - the installer will handle it return { enabled: answers.enableTts, From 6e0b36f0e02012197268e0a938b6699dc608f85e Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Thu, 27 Nov 2025 11:00:01 -0700 Subject: [PATCH 04/11] feat: Add voice map generation with agent intros for party mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Generate _cfg/agent-voice-map.csv during BMAD install with voice and intro columns - Update party mode instructions to have 3-4 agents introduce themselves on activation - Each agent speaks their personalized intro message via TTS šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/core/workflows/party-mode/workflow.md | 20 ++++- .../installers/lib/core/manifest-generator.js | 75 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/core/workflows/party-mode/workflow.md b/src/core/workflows/party-mode/workflow.md index 38f2ce82..1c580dfa 100644 --- a/src/core/workflows/party-mode/workflow.md +++ b/src/core/workflows/party-mode/workflow.md @@ -38,6 +38,7 @@ Load config from `{project-root}/{bmad_folder}/bmm/config.yaml` and resolve: - `installed_path` = `{project-root}/{bmad_folder}/core/workflows/party-mode` - `agent_manifest_path` = `{project-root}/{bmad_folder}/_cfg/agent-manifest.csv` +- `agent_voice_map_path` = `{project-root}/{bmad_folder}/_cfg/agent-voice-map.csv` - `standalone_mode` = `true` (party mode is an interactive workflow) --- @@ -63,6 +64,16 @@ Parse CSV manifest to extract agent entries with complete information: Build complete agent roster with merged personalities for conversation orchestration. +### Voice Map Loading (Optional) + +If `agent_voice_map_path` exists, load agent voice configuration: + +- **agent** (agent identifier matching manifest name) +- **voice** (TTS voice name for the agent) +- **intro** (introduction message the agent uses when joining party mode) + +Merge voice map data with agent roster for TTS integration and personalized introductions. + --- ## EXECUTION @@ -81,7 +92,14 @@ Welcome {{user_name}}! All BMAD agents are here and ready for a dynamic group di **Let me introduce our collaborating agents:** -[Load agent roster and display 2-3 most diverse agents as examples] +[Load agent roster and display all agents with their icons and titles] + +**Agent Introductions (if voice map with intros is available):** + +For each agent in the roster, if they have an intro message from the voice map: +- Have the agent speak their intro message in-character +- Use TTS to voice the introduction with their assigned voice +- Format: `Bash: .claude/hooks/bmad-speak.sh "[Agent Name]" "[Their intro message]"` **What would you like to discuss with the team today?**" diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/cli/installers/lib/core/manifest-generator.js index 8612a0b4..141fb45a 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/cli/installers/lib/core/manifest-generator.js @@ -74,6 +74,7 @@ class ManifestGenerator { await this.writeMainManifest(cfgDir), await this.writeWorkflowManifest(cfgDir), await this.writeAgentManifest(cfgDir), + await this.writeVoiceMap(cfgDir), await this.writeTaskManifest(cfgDir), await this.writeToolManifest(cfgDir), await this.writeFilesManifest(cfgDir), @@ -585,6 +586,80 @@ class ManifestGenerator { return csvPath; } + /** + * Write agent voice map CSV for AgentVibes TTS integration + * Maps agent IDs to default Piper TTS voices and intro messages + * AgentVibes will use this if present, otherwise falls back to its own defaults + * @returns {string} Path to the voice map file + */ + async writeVoiceMap(cfgDir) { + const csvPath = path.join(cfgDir, 'agent-voice-map.csv'); + + // Default voice assignments and intros for BMAD agents + // These can be customized by editing the generated CSV + const agentDefaults = { + 'bmad-master': { + voice: 'en_US-lessac-medium', + intro: 'Greetings! The BMad Master is here to orchestrate and guide you through any workflow.', + }, + analyst: { + voice: 'en_US-kristin-medium', + intro: "Hi there! I'm Mary, your Business Analyst. I'll help uncover the real requirements.", + }, + architect: { + voice: 'en_GB-alan-medium', + intro: "Hello! Winston here, your Architect. I'll ensure we build something scalable and pragmatic.", + }, + dev: { + voice: 'en_US-joe-medium', + intro: 'Hey! Amelia here, your Developer. Ready to turn specs into working code.', + }, + pm: { + voice: 'en_US-ryan-high', + intro: "Hey team! John here, your Product Manager. Let's make sure we're building the right thing.", + }, + sm: { + voice: 'en_US-amy-medium', + intro: "Hi everyone! Bob here, your Scrum Master. I'll keep us focused and moving forward.", + }, + tea: { + voice: 'en_US-kusal-medium', + intro: 'Hello! Murat here, your Test Architect. Quality is my obsession.', + }, + 'tech-writer': { + voice: 'jenny', + intro: "Hi! I'm Paige, your Technical Writer. I'll make sure everything is documented clearly.", + }, + 'ux-designer': { + voice: 'kristin', + intro: 'Hey! Sally here, your UX Designer. The user experience is my top priority.', + }, + 'frame-expert': { + voice: 'en_GB-alan-medium', + intro: "Hello! Saif here, your Visual Design Expert. I'll help visualize your ideas.", + }, + }; + + // Fallback values for agents not in the default map + const fallbackVoice = 'en_US-lessac-medium'; + const fallbackIntro = 'Hello! Ready to help with the discussion.'; + + let csv = 'agent,voice,intro\n'; + + // Add voice mapping and intro for each discovered agent + for (const agent of this.agents) { + const defaults = agentDefaults[agent.name] || {}; + const voice = defaults.voice || fallbackVoice; + const intro = defaults.intro || fallbackIntro; + // Escape quotes in intro for CSV + const escapedIntro = intro.replaceAll('"', '""'); + csv += `${agent.name},${voice},"${escapedIntro}"\n`; + } + + await fs.writeFile(csvPath, csv); + return csvPath; + } + /** * Write task manifest CSV * @returns {string} Path to the manifest file From ba2d6c5cad6f6728ae55945f84e3a5b31def1ed3 Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Thu, 27 Nov 2025 14:28:32 -0700 Subject: [PATCH 05/11] fix: Always run AgentVibes installer when enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, BMAD would skip the AgentVibes installer if it detected existing hook files (.claude/hooks/bmad-speak.sh and play-tts.sh). This prevented users from getting AgentVibes updates. Now when user says "Yes" to AgentVibes, it always runs the installer, ensuring users get the latest version with new features and fixes. šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- tools/cli/installers/lib/core/installer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 562b0731..1e67cf43 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -1059,7 +1059,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: path: bmadDir, modules: config.modules, ides: config.ides, - needsAgentVibes: this.enableAgentVibes && !config.agentVibesInstalled, + needsAgentVibes: this.enableAgentVibes, // Always run installer if enabled - handles updates too projectDir: projectDir, }; } catch (error) { From bb2942ef0b1097ebe140bce0f4f3016732714d8b Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Sat, 6 Dec 2025 12:51:50 -0700 Subject: [PATCH 06/11] fix: Apply Prettier formatting to workflow.md --- src/core/workflows/party-mode/workflow.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/workflows/party-mode/workflow.md b/src/core/workflows/party-mode/workflow.md index 1c580dfa..1e54125b 100644 --- a/src/core/workflows/party-mode/workflow.md +++ b/src/core/workflows/party-mode/workflow.md @@ -97,6 +97,7 @@ Welcome {{user_name}}! All BMAD agents are here and ready for a dynamic group di **Agent Introductions (if voice map with intros is available):** For each agent in the roster, if they have an intro message from the voice map: + - Have the agent speak their intro message in-character - Use TTS to voice the introduction with their assigned voice - Format: `Bash: .claude/hooks/bmad-speak.sh "[Agent Name]" "[Their intro message]"` From 961c50f752be4c8e5f82337df05fcb6e46be0739 Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Sat, 6 Dec 2025 13:04:14 -0700 Subject: [PATCH 07/11] fix: Remove agent-voice-map.csv from tracking (user-specific file) --- .bmad/_cfg/agent-voice-map.csv | 11 ----------- .gitignore | 3 +++ 2 files changed, 3 insertions(+), 11 deletions(-) delete mode 100644 .bmad/_cfg/agent-voice-map.csv diff --git a/.bmad/_cfg/agent-voice-map.csv b/.bmad/_cfg/agent-voice-map.csv deleted file mode 100644 index 18a20fe4..00000000 --- a/.bmad/_cfg/agent-voice-map.csv +++ /dev/null @@ -1,11 +0,0 @@ -agent,voice -bmad-master,en_US-lessac-medium -analyst,en_US-kristin-medium -architect,en_GB-alan-medium -dev,en_US-joe-medium -pm,en_US-ryan-high -sm,en_US-amy-medium -tea,en_US-kusal-medium -tech-writer,jenny -ux-designer,kristin -frame-expert,en_GB-alan-medium diff --git a/.gitignore b/.gitignore index 47a82e6e..bdd6c859 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,6 @@ z*/ .agentvibes/ .kiro/ .roo + +# Generated voice map (user-specific) +.bmad/_cfg/agent-voice-map.csv From 5f0db3fd279f5e9fdeb8fbc3ab4206dbd291a08b Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Sun, 7 Dec 2025 00:12:26 -0700 Subject: [PATCH 08/11] feat: Add declarative TTS voice configuration in agent YAML files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add optional `tts` section to agent schema with intro and voices - Update manifest-generator.js to read TTS from YAML and generate provider-aware CSV - Add TTS configuration to all 9 agent YAML files with Piper and macOS voices - Voice map CSV now auto-generated from agent YAML instead of hardcoded - Provider-aware: auto-selects correct voice based on active TTS (Piper/macOS) Benefits: - Declarative: voice config lives with agent definition - Loose coupling: AgentVibes reads CSV, no YAML dependency - Extensible: new agents automatically get voice mapping Related: - Created comprehensive test suite in AgentVibes repo (test/unit/bmad-voice-map.bats) - All 10 tests passing (8 pass, 2 skip future features) - Validates BMAD → AgentVibes voice configuration pipeline šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/core/agents/bmad-master.agent.yaml | 6 ++ src/modules/bmm/agents/analyst.agent.yaml | 6 ++ src/modules/bmm/agents/architect.agent.yaml | 6 ++ src/modules/bmm/agents/dev.agent.yaml | 6 ++ src/modules/bmm/agents/pm.agent.yaml | 6 ++ src/modules/bmm/agents/sm.agent.yaml | 6 ++ src/modules/bmm/agents/tea.agent.yaml | 6 ++ src/modules/bmm/agents/tech-writer.agent.yaml | 6 ++ src/modules/bmm/agents/ux-designer.agent.yaml | 6 ++ .../installers/lib/core/manifest-generator.js | 98 ++++++++++--------- tools/schema/agent.js | 29 ++++++ 11 files changed, 133 insertions(+), 48 deletions(-) diff --git a/src/core/agents/bmad-master.agent.yaml b/src/core/agents/bmad-master.agent.yaml index bba8be22..83e4286f 100644 --- a/src/core/agents/bmad-master.agent.yaml +++ b/src/core/agents/bmad-master.agent.yaml @@ -21,6 +21,12 @@ agent: - "Remember the users name is {user_name}" - "ALWAYS communicate in {communication_language}" + tts: + intro: "Greetings! The BMad Master is here to orchestrate and guide you through any workflow." + voices: + - piper: en_US-lessac-medium + - mac: Samantha + # Agent menu items menu: - trigger: "list-tasks" diff --git a/src/modules/bmm/agents/analyst.agent.yaml b/src/modules/bmm/agents/analyst.agent.yaml index eb0bc7c4..cf00d663 100644 --- a/src/modules/bmm/agents/analyst.agent.yaml +++ b/src/modules/bmm/agents/analyst.agent.yaml @@ -17,6 +17,12 @@ agent: - Articulate requirements with absolute precision. Ensure all stakeholder voices heard. - Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md` + tts: + intro: "Hi there! I'm Mary, your Business Analyst. I'll help uncover the real requirements." + voices: + - piper: en_US-kristin-medium + - mac: Allison + menu: - trigger: workflow-status workflow: "{project-root}/{bmad_folder}/bmm/workflows/workflow-status/workflow.yaml" diff --git a/src/modules/bmm/agents/architect.agent.yaml b/src/modules/bmm/agents/architect.agent.yaml index 07d9ad3a..3b0a676c 100644 --- a/src/modules/bmm/agents/architect.agent.yaml +++ b/src/modules/bmm/agents/architect.agent.yaml @@ -17,6 +17,12 @@ agent: - Design simple solutions that scale when needed. Developer productivity is architecture. Connect every decision to business value and user impact. - Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md` + tts: + intro: "Hello! Winston here, your Architect. I'll ensure we build something scalable and pragmatic." + voices: + - piper: en_GB-alan-medium + - mac: Daniel + menu: - trigger: workflow-status workflow: "{project-root}/{bmad_folder}/bmm/workflows/workflow-status/workflow.yaml" diff --git a/src/modules/bmm/agents/dev.agent.yaml b/src/modules/bmm/agents/dev.agent.yaml index 3e3fdc2d..fe0ef415 100644 --- a/src/modules/bmm/agents/dev.agent.yaml +++ b/src/modules/bmm/agents/dev.agent.yaml @@ -34,6 +34,12 @@ agent: - "Update File List with ALL changed files after each task completion" - "NEVER lie about tests being written or passing - tests must actually exist and pass 100%" + tts: + intro: "Hey! Amelia here, your Developer. Ready to turn specs into working code." + voices: + - piper: en_US-amy-medium + - mac: Samantha + menu: - trigger: develop-story workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/dev-story/workflow.yaml" diff --git a/src/modules/bmm/agents/pm.agent.yaml b/src/modules/bmm/agents/pm.agent.yaml index 40dcf7d0..39fe7120 100644 --- a/src/modules/bmm/agents/pm.agent.yaml +++ b/src/modules/bmm/agents/pm.agent.yaml @@ -18,6 +18,12 @@ agent: - Align efforts with measurable business impact. Back all claims with data and user insights. - Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md` + tts: + intro: "Hey team! John here, your Product Manager. Let's make sure we're building the right thing." + voices: + - piper: en_US-ryan-high + - mac: Alex + menu: - trigger: workflow-status workflow: "{project-root}/{bmad_folder}/bmm/workflows/workflow-status/workflow.yaml" diff --git a/src/modules/bmm/agents/sm.agent.yaml b/src/modules/bmm/agents/sm.agent.yaml index 8be3ee66..77dbe60a 100644 --- a/src/modules/bmm/agents/sm.agent.yaml +++ b/src/modules/bmm/agents/sm.agent.yaml @@ -23,6 +23,12 @@ agent: - "When running *create-story, always run as *yolo. Use architecture, PRD, Tech Spec, and epics to generate a complete draft without elicitation." - "Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md`" + tts: + intro: "Hi everyone! Bob here, your Scrum Master. I'll keep us focused and moving forward." + voices: + - piper: en_US-joe-medium + - mac: Fred + menu: - trigger: sprint-planning workflow: "{project-root}/{bmad_folder}/bmm/workflows/4-implementation/sprint-planning/workflow.yaml" diff --git a/src/modules/bmm/agents/tea.agent.yaml b/src/modules/bmm/agents/tea.agent.yaml index df18b836..dfaed39f 100644 --- a/src/modules/bmm/agents/tea.agent.yaml +++ b/src/modules/bmm/agents/tea.agent.yaml @@ -27,6 +27,12 @@ agent: - "Cross-check recommendations with the current official Playwright, Cypress, Pact, and CI platform documentation" - "Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md`" + tts: + intro: "Hello! Murat here, your Test Architect. Quality is my obsession." + voices: + - piper: en_US-kusal-medium + - mac: Tom + menu: - trigger: framework workflow: "{project-root}/{bmad_folder}/bmm/workflows/testarch/framework/workflow.yaml" diff --git a/src/modules/bmm/agents/tech-writer.agent.yaml b/src/modules/bmm/agents/tech-writer.agent.yaml index 6911c581..af791ead 100644 --- a/src/modules/bmm/agents/tech-writer.agent.yaml +++ b/src/modules/bmm/agents/tech-writer.agent.yaml @@ -20,6 +20,12 @@ agent: - "CRITICAL: Load COMPLETE file {project-root}/{bmad_folder}/bmm/data/documentation-standards.md into permanent memory and follow ALL rules within" - "Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md`" + tts: + intro: "Hi! I'm Paige, your Technical Writer. I'll make sure everything is documented clearly." + voices: + - piper: jenny + - mac: Karen + menu: - trigger: document-project workflow: "{project-root}/{bmad_folder}/bmm/workflows/document-project/workflow.yaml" diff --git a/src/modules/bmm/agents/ux-designer.agent.yaml b/src/modules/bmm/agents/ux-designer.agent.yaml index 04ba4c86..777f2c19 100644 --- a/src/modules/bmm/agents/ux-designer.agent.yaml +++ b/src/modules/bmm/agents/ux-designer.agent.yaml @@ -22,6 +22,12 @@ agent: critical_actions: - "Find if this exists, if it does, always treat it as the bible I plan and execute against: `**/project-context.md`" + tts: + intro: "Hey! Sally here, your UX Designer. The user experience is my top priority." + voices: + - piper: kristin + - mac: Victoria + menu: - trigger: create-ux-design exec: "{project-root}/{bmad_folder}/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md" diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/cli/installers/lib/core/manifest-generator.js index 141fb45a..924f357f 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/cli/installers/lib/core/manifest-generator.js @@ -269,6 +269,21 @@ class ManifestGenerator { .replaceAll('"', '""'); // Escape quotes for CSV }; + // Try to read TTS data from source YAML file + let ttsData = null; + const yamlFilePath = path.join(dirPath, `${agentName}.agent.yaml`); + if (await fs.pathExists(yamlFilePath)) { + try { + const yamlContent = await fs.readFile(yamlFilePath, 'utf8'); + const agentYaml = yaml.load(yamlContent); + if (agentYaml?.agent?.tts) { + ttsData = agentYaml.agent.tts; + } + } catch { + // Silently skip if YAML parsing fails + } + } + agents.push({ name: agentName, displayName: nameMatch ? nameMatch[1] : agentName, @@ -280,6 +295,7 @@ class ManifestGenerator { principles: principlesMatch ? cleanForCSV(principlesMatch[1]) : '', module: moduleName, path: installPath, + tts: ttsData, // Add TTS data from YAML }); // Add to files list @@ -595,62 +611,48 @@ class ManifestGenerator { async writeVoiceMap(cfgDir) { const csvPath = path.join(cfgDir, 'agent-voice-map.csv'); - // Default voice assignments and intros for BMAD agents - // These can be customized by editing the generated CSV - const agentDefaults = { - 'bmad-master': { - voice: 'en_US-lessac-medium', - intro: 'Greetings! The BMad Master is here to orchestrate and guide you through any workflow.', - }, - analyst: { - voice: 'en_US-kristin-medium', - intro: "Hi there! I'm Mary, your Business Analyst. I'll help uncover the real requirements.", - }, - architect: { - voice: 'en_GB-alan-medium', - intro: "Hello! Winston here, your Architect. I'll ensure we build something scalable and pragmatic.", - }, - dev: { - voice: 'en_US-joe-medium', - intro: 'Hey! Amelia here, your Developer. Ready to turn specs into working code.', - }, - pm: { - voice: 'en_US-ryan-high', - intro: "Hey team! John here, your Product Manager. Let's make sure we're building the right thing.", - }, - sm: { - voice: 'en_US-amy-medium', - intro: "Hi everyone! Bob here, your Scrum Master. I'll keep us focused and moving forward.", - }, - tea: { - voice: 'en_US-kusal-medium', - intro: 'Hello! Murat here, your Test Architect. Quality is my obsession.', - }, - 'tech-writer': { - voice: 'jenny', - intro: "Hi! I'm Paige, your Technical Writer. I'll make sure everything is documented clearly.", - }, - 'ux-designer': { - voice: 'kristin', - intro: 'Hey! Sally here, your UX Designer. The user experience is my top priority.', - }, - 'frame-expert': { - voice: 'en_GB-alan-medium', - intro: "Hello! Saif here, your Visual Design Expert. I'll help visualize your ideas.", - }, + // Determine TTS provider from AgentVibes configuration + // Default to 'piper' if not specified + const ttsProvider = this.agentVibes?.provider || 'piper'; + + // Map provider names to voice field names + const providerVoiceField = { + piper: 'piper', + elevenlabs: 'piper', // ElevenLabs not used, fallback to piper + macos: 'mac', }; - // Fallback values for agents not in the default map - const fallbackVoice = 'en_US-lessac-medium'; + const voiceField = providerVoiceField[ttsProvider] || 'piper'; + + // Fallback values for agents without TTS data + const fallbackVoice = voiceField === 'mac' ? 'Samantha' : 'en_US-lessac-medium'; const fallbackIntro = 'Hello! Ready to help with the discussion.'; let csv = 'agent,voice,intro\n'; // Add voice mapping and intro for each discovered agent for (const agent of this.agents) { - const defaults = agentDefaults[agent.name] || {}; - const voice = defaults.voice || fallbackVoice; - const intro = defaults.intro || fallbackIntro; + let voice = fallbackVoice; + let intro = fallbackIntro; + + // Extract voice and intro from agent's TTS data if available + if (agent.tts) { + // Get intro + if (agent.tts.intro) { + intro = agent.tts.intro; + } + + // Get voice for the selected provider + if (agent.tts.voices && Array.isArray(agent.tts.voices)) { + for (const voiceEntry of agent.tts.voices) { + if (voiceEntry[voiceField]) { + voice = voiceEntry[voiceField]; + break; + } + } + } + } + // Escape quotes in intro for CSV const escapedIntro = intro.replaceAll('"', '""'); csv += `${agent.name},${voice},"${escapedIntro}"\n`; diff --git a/tools/schema/agent.js b/tools/schema/agent.js index 99438f6a..dcebd08c 100644 --- a/tools/schema/agent.js +++ b/tools/schema/agent.js @@ -126,6 +126,7 @@ function buildAgentSchema(expectedModule) { metadata: buildMetadataSchema(expectedModule), persona: buildPersonaSchema(), critical_actions: z.array(createNonEmptyString('agent.critical_actions[]')).optional(), + tts: buildTTSSchema().optional(), menu: z.array(buildMenuItemSchema()).min(1, { message: 'agent.menu must include at least one entry' }), prompts: z.array(buildPromptSchema()).optional(), webskip: z.boolean().optional(), @@ -195,6 +196,34 @@ function buildPersonaSchema() { .strict(); } +function buildTTSSchema() { + return z + .object({ + intro: createNonEmptyString('agent.tts.intro'), + voices: z + .array( + z.object({ + piper: createNonEmptyString('agent.tts.voices[].piper').optional(), + mac: createNonEmptyString('agent.tts.voices[].mac').optional(), + }), + ) + .min(1, { message: 'agent.tts.voices must include at least one voice mapping' }) + .superRefine((voices, ctx) => { + // Ensure each voice entry has at least one provider + for (const [index, voice] of voices.entries()) { + if (!voice.piper && !voice.mac) { + ctx.addIssue({ + code: 'custom', + path: [index], + message: 'agent.tts.voices[] must include at least one voice provider (piper or mac)', + }); + } + } + }), + }) + .strict(); +} + function buildPromptSchema() { return z .object({ From 169e983e622d770b47cbfd15f25f5dc6f23d0f92 Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Sun, 7 Dec 2025 00:17:38 -0700 Subject: [PATCH 09/11] refactor: Remove deprecated ElevenLabs provider mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove 'elevenlabs' fallback from providerVoiceField mapping - ElevenLabs is no longer supported in AgentVibes - Only Piper and macOS providers remain šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- tools/cli/installers/lib/core/manifest-generator.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/cli/installers/lib/core/manifest-generator.js index 924f357f..c0e68569 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/cli/installers/lib/core/manifest-generator.js @@ -618,7 +618,6 @@ class ManifestGenerator { // Map provider names to voice field names const providerVoiceField = { piper: 'piper', - elevenlabs: 'piper', // ElevenLabs not used, fallback to piper macos: 'mac', }; From 9a36a00b175864f673762a6f3c443c2f11bcb52d Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Sun, 7 Dec 2025 15:16:38 -0700 Subject: [PATCH 10/11] fix: Remove '(Optional)' from Voice Map Loading section header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses code review feedback - removing (Optional) prevents agents from skipping the section without evaluating the conditional logic within. šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/core/workflows/party-mode/workflow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/workflows/party-mode/workflow.md b/src/core/workflows/party-mode/workflow.md index 1e54125b..798f11a8 100644 --- a/src/core/workflows/party-mode/workflow.md +++ b/src/core/workflows/party-mode/workflow.md @@ -64,7 +64,7 @@ Parse CSV manifest to extract agent entries with complete information: Build complete agent roster with merged personalities for conversation orchestration. -### Voice Map Loading (Optional) +### Voice Map Loading If `agent_voice_map_path` exists, load agent voice configuration: From 6f95e04df7619039d779df17983d50875b1c2972 Mon Sep 17 00:00:00 2001 From: Paul Preibisch Date: Sun, 7 Dec 2025 15:39:17 -0700 Subject: [PATCH 11/11] feat: Add --with-audio flag for first-time AgentVibes installations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automatically includes --with-audio parameter when installing AgentVibes for the first time (detects by checking if .agentvibes directory exists). This ensures new users get audio tracks downloaded automatically. Updates skip --with-audio to avoid re-downloading existing audio files. šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- tools/cli/commands/install.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/cli/commands/install.js b/tools/cli/commands/install.js index 76bbde0b..9b403478 100644 --- a/tools/cli/commands/install.js +++ b/tools/cli/commands/install.js @@ -84,6 +84,9 @@ module.exports = { // Run AgentVibes installer const { execSync } = require('node:child_process'); + const fs = require('node:fs'); + const path = require('node:path'); + try { // Clear ALL npm config env vars to prevent inheritance issues // when BMAD is invoked with --prefix flag @@ -92,7 +95,12 @@ module.exports = { Object.entries(process.env).filter(([key]) => !key.startsWith('npm_config_') && !key.startsWith('npm_package_')), ); - execSync('npx agentvibes@latest install', { + // Check if this is first-time AgentVibes installation + const agentvibesDir = path.join(result.projectDir, '.agentvibes'); + const isFirstTime = !fs.existsSync(agentvibesDir); + const installCmd = isFirstTime ? 'npx agentvibes@latest install --with-audio' : 'npx agentvibes@latest install'; + + execSync(installCmd, { cwd: result.projectDir, stdio: 'inherit', shell: true,