diff --git a/docs/sample-custom-modules/sample-unitary-module/agents/toolsmith/toolsmith-sidecar/knowledge/installers.md b/docs/sample-custom-modules/sample-unitary-module/agents/toolsmith/toolsmith-sidecar/knowledge/installers.md
index 71498d59..75c925f6 100644
--- a/docs/sample-custom-modules/sample-unitary-module/agents/toolsmith/toolsmith-sidecar/knowledge/installers.md
+++ b/docs/sample-custom-modules/sample-unitary-module/agents/toolsmith/toolsmith-sidecar/knowledge/installers.md
@@ -49,8 +49,7 @@
- @/tools/cli/lib/xml-handler.js - XML processing
- @/tools/cli/lib/yaml-format.js - YAML formatting
- @/tools/cli/lib/file-ops.js - File operations
-- @/tools/cli/lib/agent/compiler.js - Agent YAML to XML compilation
-- @/tools/cli/lib/agent/installer.js - Agent installation
+- @/tools/cli/lib/agent/yaml-xml-builder.js - Agent YAML to XML compilation
- @/tools/cli/lib/agent/template-engine.js - Template processing
## IDE Handler Registry (16 IDEs)
diff --git a/src/modules/bmb/docs/agents/agent-compilation.md b/src/modules/bmb/docs/agents/agent-compilation.md
index 32af63fd..b960bb5f 100644
--- a/src/modules/bmb/docs/agents/agent-compilation.md
+++ b/src/modules/bmb/docs/agents/agent-compilation.md
@@ -8,7 +8,7 @@ What the compiler auto-injects. **DO NOT duplicate these in your YAML.**
agent.yaml ā Handlebars processing ā XML generation ā frontmatter.md
```
-Source: `tools/cli/lib/agent/compiler.js`
+Source: `tools/cli/lib/agent/yaml-xml-builder.js`
## File Naming Convention
diff --git a/src/modules/bmb/docs/agents/index.md b/src/modules/bmb/docs/agents/index.md
index a1dd92e3..ac476161 100644
--- a/src/modules/bmb/docs/agents/index.md
+++ b/src/modules/bmb/docs/agents/index.md
@@ -52,4 +52,4 @@ Agents are authored in YAML with Handlebars templating. The compiler auto-inject
**Critical:** See [Agent Compilation](./agent-compilation.md) to avoid duplicating auto-injected content.
-Source: `tools/cli/lib/agent/compiler.js`
+Source: `tools/cli/lib/agent/yaml-xml-builder.js`
diff --git a/src/modules/bmb/docs/agents/simple-agent-architecture.md b/src/modules/bmb/docs/agents/simple-agent-architecture.md
index e68a3c56..d7f35f44 100644
--- a/src/modules/bmb/docs/agents/simple-agent-architecture.md
+++ b/src/modules/bmb/docs/agents/simple-agent-architecture.md
@@ -178,7 +178,7 @@ Content when false
## What Gets Injected at Compile Time
-The `tools/cli/lib/agent/compiler.js` automatically adds:
+The `tools/cli/lib/agent/yaml-xml-builder.js` automatically adds:
1. **YAML Frontmatter**
diff --git a/src/modules/bmb/workflows/create-agent/templates/simple-agent.template.md b/src/modules/bmb/workflows/create-agent/templates/simple-agent.template.md
index e68a3c56..d7f35f44 100644
--- a/src/modules/bmb/workflows/create-agent/templates/simple-agent.template.md
+++ b/src/modules/bmb/workflows/create-agent/templates/simple-agent.template.md
@@ -178,7 +178,7 @@ Content when false
## What Gets Injected at Compile Time
-The `tools/cli/lib/agent/compiler.js` automatically adds:
+The `tools/cli/lib/agent/yaml-xml-builder.js` automatically adds:
1. **YAML Frontmatter**
diff --git a/test/test-installation-components.js b/test/test-installation-components.js
index 1f9c99dd..41775e6b 100644
--- a/test/test-installation-components.js
+++ b/test/test-installation-components.js
@@ -13,7 +13,7 @@
const path = require('node:path');
const fs = require('fs-extra');
-const { YamlXmlBuilder } = require('../tools/cli/lib/yaml-xml-builder');
+const { YamlXmlBuilder } = require('../tools/cli/lib/agent/yaml-xml-builder');
const { ManifestGenerator } = require('../tools/cli/installers/lib/core/manifest-generator');
// ANSI colors
diff --git a/tools/cli/commands/build.js b/tools/cli/commands/build.js
index 467fcd65..50c12b83 100644
--- a/tools/cli/commands/build.js
+++ b/tools/cli/commands/build.js
@@ -1,7 +1,7 @@
const chalk = require('chalk');
const path = require('node:path');
const fs = require('fs-extra');
-const { YamlXmlBuilder } = require('../lib/yaml-xml-builder');
+const { YamlXmlBuilder } = require('../lib/agent/yaml-xml-builder');
const { getProjectRoot } = require('../lib/project-root');
const builder = new YamlXmlBuilder();
diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js
index 5b403972..8e6f5a4b 100644
--- a/tools/cli/installers/lib/core/installer.js
+++ b/tools/cli/installers/lib/core/installer.js
@@ -9,7 +9,7 @@ const { ModuleManager } = require('../modules/manager');
const { IdeManager } = require('../ide/manager');
const { FileOps } = require('../../../lib/file-ops');
const { Config } = require('../../../lib/config');
-const { XmlHandler } = require('../../../lib/xml-handler');
+const { XmlHandler } = require('../../../lib/agent/xml-handler');
const { DependencyResolver } = require('./dependency-resolver');
const { ConfigCollector } = require('./config-collector');
const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
diff --git a/tools/cli/installers/lib/custom/handler.js b/tools/cli/installers/lib/custom/handler.js
index c8aa52ee..41d8f0ac 100644
--- a/tools/cli/installers/lib/custom/handler.js
+++ b/tools/cli/installers/lib/custom/handler.js
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
const chalk = require('chalk');
const yaml = require('yaml');
const { FileOps } = require('../../../lib/file-ops');
-const { XmlHandler } = require('../../../lib/xml-handler');
+const { XmlHandler } = require('../../../lib/agent/xml-handler');
/**
* Handler for custom content (custom.yaml)
@@ -311,7 +311,7 @@ class CustomHandler {
// Read and compile the YAML
try {
const yamlContent = await fs.readFile(agentFile, 'utf8');
- const { compileAgent } = require('../../../lib/agent/compiler');
+ const { compileAgent } = require('../../../lib/agent/yaml-xml-builder');
// Create customize template if it doesn't exist
if (!(await fs.pathExists(customizePath))) {
diff --git a/tools/cli/installers/lib/ide/_base-ide.js b/tools/cli/installers/lib/ide/_base-ide.js
index b53eb977..1aedceb7 100644
--- a/tools/cli/installers/lib/ide/_base-ide.js
+++ b/tools/cli/installers/lib/ide/_base-ide.js
@@ -1,7 +1,7 @@
const path = require('node:path');
const fs = require('fs-extra');
const chalk = require('chalk');
-const { XmlHandler } = require('../../../lib/xml-handler');
+const { XmlHandler } = require('../../../lib/agent/xml-handler');
const { getSourcePath } = require('../../../lib/project-root');
/**
diff --git a/tools/cli/installers/lib/modules/manager.js b/tools/cli/installers/lib/modules/manager.js
index 4844f243..c2acb34a 100644
--- a/tools/cli/installers/lib/modules/manager.js
+++ b/tools/cli/installers/lib/modules/manager.js
@@ -2,9 +2,9 @@ const path = require('node:path');
const fs = require('fs-extra');
const yaml = require('yaml');
const chalk = require('chalk');
-const { XmlHandler } = require('../../../lib/xml-handler');
+const { XmlHandler } = require('../../../lib/agent/xml-handler');
const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
-const { filterCustomizationData } = require('../../../lib/agent/compiler');
+const { filterCustomizationData } = require('../../../lib/agent/yaml-xml-builder');
/**
* Manages the installation, updating, and removal of BMAD modules.
@@ -757,7 +757,7 @@ class ModuleManager {
// Read and compile the YAML
try {
const yamlContent = await fs.readFile(sourceYamlPath, 'utf8');
- const { compileAgent } = require('../../../lib/agent/compiler');
+ const { compileAgent } = require('../../../lib/agent/yaml-xml-builder');
// Create customize template if it doesn't exist
if (!(await fs.pathExists(customizePath))) {
diff --git a/tools/cli/lib/activation-builder.js b/tools/cli/lib/agent/activation-builder.js
similarity index 99%
rename from tools/cli/lib/activation-builder.js
rename to tools/cli/lib/agent/activation-builder.js
index 9b91c2a9..e45447fb 100644
--- a/tools/cli/lib/activation-builder.js
+++ b/tools/cli/lib/agent/activation-builder.js
@@ -1,6 +1,6 @@
const fs = require('fs-extra');
const path = require('node:path');
-const { getSourcePath } = require('./project-root');
+const { getSourcePath } = require('../project-root');
/**
* Builds activation blocks from fragments based on agent profile
diff --git a/tools/cli/lib/agent-analyzer.js b/tools/cli/lib/agent/agent-analyzer.js
similarity index 100%
rename from tools/cli/lib/agent-analyzer.js
rename to tools/cli/lib/agent/agent-analyzer.js
diff --git a/tools/cli/lib/agent/compiler.js b/tools/cli/lib/agent/compiler.js
deleted file mode 100644
index 0d805451..00000000
--- a/tools/cli/lib/agent/compiler.js
+++ /dev/null
@@ -1,554 +0,0 @@
-/**
- * BMAD Agent Compiler
- * Transforms agent YAML to compiled XML (.md) format
- * Uses the existing BMAD builder infrastructure for proper formatting
- */
-
-const yaml = require('yaml');
-const fs = require('node:fs');
-const path = require('node:path');
-const { processAgentYaml, extractInstallConfig, stripInstallConfig, getDefaultValues } = require('./template-engine');
-const { escapeXml } = require('../../../lib/xml-utils');
-const { ActivationBuilder } = require('../activation-builder');
-const { AgentAnalyzer } = require('../agent-analyzer');
-
-/**
- * Build frontmatter for agent
- * @param {Object} metadata - Agent metadata
- * @param {string} agentName - Final agent name
- * @returns {string} YAML frontmatter
- */
-function buildFrontmatter(metadata, agentName) {
- const nameFromFile = agentName.replaceAll('-', ' ');
- const description = metadata.title || 'BMAD Agent';
-
- return `---
-name: "${nameFromFile}"
-description: "${description}"
----
-
-You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
-
-`;
-}
-
-// buildSimpleActivation function removed - replaced by ActivationBuilder for proper fragment loading from src/utility/agent-components/
-
-/**
- * Build persona XML section
- * @param {Object} persona - Persona object
- * @returns {string} Persona XML
- */
-function buildPersonaXml(persona) {
- if (!persona) return '';
-
- let xml = ' \n';
-
- if (persona.role) {
- const roleText = persona.role.trim().replaceAll(/\n+/g, ' ').replaceAll(/\s+/g, ' ');
- xml += ` ${escapeXml(roleText)}\n`;
- }
-
- if (persona.identity) {
- const identityText = persona.identity.trim().replaceAll(/\n+/g, ' ').replaceAll(/\s+/g, ' ');
- xml += ` ${escapeXml(identityText)}\n`;
- }
-
- if (persona.communication_style) {
- const styleText = persona.communication_style.trim().replaceAll(/\n+/g, ' ').replaceAll(/\s+/g, ' ');
- xml += ` ${escapeXml(styleText)}\n`;
- }
-
- if (persona.principles) {
- let principlesText;
- if (Array.isArray(persona.principles)) {
- principlesText = persona.principles.join(' ');
- } else {
- principlesText = persona.principles.trim().replaceAll(/\n+/g, ' ');
- }
- xml += ` ${escapeXml(principlesText)}\n`;
- }
-
- xml += ' \n';
-
- return xml;
-}
-
-/**
- * Build prompts XML section
- * @param {Array} prompts - Prompts array
- * @returns {string} Prompts XML
- */
-function buildPromptsXml(prompts) {
- if (!prompts || prompts.length === 0) return '';
-
- let xml = ' \n';
-
- for (const prompt of prompts) {
- xml += ` \n`;
- xml += ` \n`;
- // Don't escape prompt content - it's meant to be read as-is
- xml += `${prompt.content || ''}\n`;
- xml += ` \n`;
- xml += ` \n`;
- }
-
- xml += ' \n';
-
- return xml;
-}
-
-/**
- * Build memories XML section
- * @param {Array} memories - Memories array
- * @returns {string} Memories XML
- */
-function buildMemoriesXml(memories) {
- if (!memories || memories.length === 0) return '';
-
- let xml = ' \n';
-
- for (const memory of memories) {
- xml += ` ${escapeXml(String(memory))}\n`;
- }
-
- xml += ' \n';
-
- return xml;
-}
-
-/**
- * Build menu XML section
- * Supports both legacy and multi format menu items
- * Multi items display as a single menu item with nested handlers
- * @param {Array} menuItems - Menu items
- * @returns {string} Menu XML
- */
-function buildMenuXml(menuItems) {
- let xml = '
\n';
-
- return xml;
-}
-
-/**
- * Build nested handlers for multi format menu items
- * @param {Array} triggers - Triggers array from multi format
- * @returns {string} Handler XML
- */
-function buildNestedHandlers(triggers) {
- let xml = '';
-
- for (const triggerGroup of triggers) {
- for (const [triggerName, execArray] of Object.entries(triggerGroup)) {
- // Extract the relevant execution data
- const execData = processExecArray(execArray);
-
- // For nested handlers in multi items, we use match attribute for fuzzy matching
- const attrs = [`match="${escapeXml(execData.description || '')}"`];
-
- // Add handler attributes based on exec data
- if (execData.route) attrs.push(`exec="${execData.route}"`);
- if (execData.workflow) attrs.push(`workflow="${execData.workflow}"`);
- if (execData['validate-workflow']) attrs.push(`validate-workflow="${execData['validate-workflow']}"`);
- if (execData.action) attrs.push(`action="${execData.action}"`);
- if (execData.data) attrs.push(`data="${execData.data}"`);
- if (execData.tmpl) attrs.push(`tmpl="${execData.tmpl}"`);
- // Only add type if it's not 'exec' (exec is already implied by the exec attribute)
- if (execData.type && execData.type !== 'exec') attrs.push(`type="${execData.type}"`);
-
- xml += ` \n`;
- }
- }
-
- return xml;
-}
-
-/**
- * Process the execution array from multi format triggers
- * Extracts relevant data for XML attributes
- * @param {Array} execArray - Array of execution objects
- * @returns {Object} Processed execution data
- */
-function processExecArray(execArray) {
- const result = {
- description: '',
- route: null,
- workflow: null,
- data: null,
- action: null,
- type: null,
- };
-
- if (!Array.isArray(execArray)) {
- return result;
- }
-
- for (const exec of execArray) {
- if (exec.input) {
- // Use input as description if no explicit description is provided
- result.description = exec.input;
- }
-
- if (exec.route) {
- // Determine if it's a workflow or exec based on file extension or context
- if (exec.route.endsWith('.yaml') || exec.route.endsWith('.yml')) {
- result.workflow = exec.route;
- } else {
- result.route = exec.route;
- }
- }
-
- if (exec.data !== null && exec.data !== undefined) {
- result.data = exec.data;
- }
-
- if (exec.action) {
- result.action = exec.action;
- }
-
- if (exec.type) {
- result.type = exec.type;
- }
- }
-
- return result;
-}
-
-/**
- * Compile agent YAML to proper XML format
- * @param {Object} agentYaml - Parsed and processed agent YAML
- * @param {string} agentName - Final agent name (for ID and frontmatter)
- * @param {string} targetPath - Target path for agent ID
- * @returns {Promise} Compiled XML string with frontmatter
- */
-async function compileToXml(agentYaml, agentName = '', targetPath = '') {
- const agent = agentYaml.agent;
- const meta = agent.metadata;
-
- let xml = '';
-
- // Build frontmatter
- xml += buildFrontmatter(meta, agentName || meta.name || 'agent');
-
- // Start code fence
- xml += '```xml\n';
-
- // Agent opening tag
- const agentAttrs = [
- `id="${targetPath || meta.id || ''}"`,
- `name="${meta.name || ''}"`,
- `title="${meta.title || ''}"`,
- `icon="${meta.icon || 'š¤'}"`,
- ];
-
- xml += `\n`;
-
- // Activation block - use ActivationBuilder for proper fragment loading
- const activationBuilder = new ActivationBuilder();
- const analyzer = new AgentAnalyzer();
- const profile = analyzer.analyzeAgentObject(agentYaml);
- xml += await activationBuilder.buildActivation(
- profile,
- meta,
- agent.critical_actions || [],
- false, // forWebBundle - set to false for IDE deployment
- );
-
- // Persona section
- xml += buildPersonaXml(agent.persona);
-
- // Prompts section (if present)
- if (agent.prompts && agent.prompts.length > 0) {
- xml += buildPromptsXml(agent.prompts);
- }
-
- // Memories section (if present)
- if (agent.memories && agent.memories.length > 0) {
- xml += buildMemoriesXml(agent.memories);
- }
-
- // Menu section
- xml += buildMenuXml(agent.menu || []);
-
- // Closing agent tag
- xml += '\n';
-
- // Close code fence
- xml += '```\n';
-
- return xml;
-}
-
-/**
- * Full compilation pipeline
- * @param {string} yamlContent - Raw YAML string
- * @param {Object} answers - Answers from install_config questions (or defaults)
- * @param {string} agentName - Optional final agent name (user's custom persona name)
- * @param {string} targetPath - Optional target path for agent ID
- * @param {Object} options - Additional options including config
- * @returns {Promise