From c42002f1ea1f96d46208999a3ba11784135f00b5 Mon Sep 17 00:00:00 2001 From: Davor Racic Date: Sat, 12 Jul 2025 16:55:12 +0200 Subject: [PATCH] refactor(gemini-cli): change agent storage from multiple files to single (#308) * refactor(gemini-cli): change agent storage from multiple files to single concatenated file - Update configuration to use .gemini/bmad-method/ directory instead of .gemini/agents/ - Implement new logic to concatenate all agent files into single GEMINI.md - Add backward compatibility for existing settings.json - Remove old agents directory and update related documentation - Ensure all agent settings are properly loaded * fix(ide-setup): change agent trigger symbol from @ to * The change was made to standardize the agent trigger symbol across the system and avoid confusion with other special characters. * docs: update gemini cli syntax and file structure - Change agent mention syntax from @ to * in docs and config - Update file structure documentation from .gemini/agents/ to .gemini/bmad-method/ - Add gemini cli syntax to workflow guide * fix(ide-setup): remove redundant contextFileNames handling --- docs/agentic-tools/gemini-cli-guide.md | 13 ++- docs/bmad-workflow-guide.md | 1 + tools/installer/config/install.config.yaml | 11 +- tools/installer/lib/ide-setup.js | 118 ++++++++++++++------- 4 files changed, 94 insertions(+), 49 deletions(-) diff --git a/docs/agentic-tools/gemini-cli-guide.md b/docs/agentic-tools/gemini-cli-guide.md index 8e029459..4de658a2 100644 --- a/docs/agentic-tools/gemini-cli-guide.md +++ b/docs/agentic-tools/gemini-cli-guide.md @@ -6,23 +6,22 @@ For the complete workflow, see the [BMad Workflow Guide](../bmad-workflow-guide. When running `npx bmad-method install`, select **Gemini CLI** as your IDE. This creates: -- `.gemini/agents/` directory with all agent context files -- `.gemini/settings.json` configured to load all agents automatically +- `.gemini/bmad-method/` directory with all agent context in GEMINI.md file ## Using BMad Agents with Gemini CLI Simply mention the agent in your prompt: -- "As @dev, implement the login feature" -- "Acting as @architect, review this system design" -- "@sm, create the next story for our project" +- "As \*dev, implement the login feature" +- "Acting as \*architect, review this system design" +- "\*sm, create the next story for our project" The Gemini CLI automatically loads the appropriate agent context. ## Gemini CLI-Specific Features -- **Context files**: All agents loaded as context in `.gemini/agents/` -- **Automatic loading**: Settings.json ensures agents are always available +- **Context files**: All agents loaded as context in `.gemini/bmad-method/GEMINI.md` +- **Automatic loading**: GEMINI.md ensures agents are always available - **Natural language**: No special syntax needed, just mention the agent ## Tips for Gemini CLI Users diff --git a/docs/bmad-workflow-guide.md b/docs/bmad-workflow-guide.md index d8ae6b84..c1253c08 100644 --- a/docs/bmad-workflow-guide.md +++ b/docs/bmad-workflow-guide.md @@ -111,6 +111,7 @@ Follow the SM → Dev cycle for systematic story development: - **Claude Code**: `/agent-name` (e.g., `/bmad-master`) - **Cursor**: `@agent-name` (e.g., `@bmad-master`) +- **Gemini CLI**: `*agent-name` (e.g., `*bmad-master`) - **Windsurf**: `@agent-name` (e.g., `@bmad-master`) - **Trae**: `@agent-name` (e.g., `@bmad-master`) - **Roo Code**: Select mode from mode selector (e.g., `bmad-bmad-master`) diff --git a/tools/installer/config/install.config.yaml b/tools/installer/config/install.config.yaml index 5da5aa8c..f3b8831d 100644 --- a/tools/installer/config/install.config.yaml +++ b/tools/installer/config/install.config.yaml @@ -68,13 +68,14 @@ ide-configurations: # 4. Rules are stored in .clinerules/ directory in your project gemini: name: Gemini CLI - rule-dir: .gemini/agents/ - format: context-files + rule-dir: .gemini/bmad-method/ + format: single-file + command-suffix: .md instructions: | # To use BMad agents with the Gemini CLI: - # 1. The installer creates a .gemini/ directory in your project. - # 2. It also configures .gemini/settings.json to load all agent files. - # 3. Simply mention the agent in your prompt (e.g., "As @dev, ..."). + # 1. The installer creates a .gemini/bmad-method/ directory in your project. + # 2. It concatenates all agent files into a single GEMINI.md file. + # 3. Simply mention the agent in your prompt (e.g., "As *dev, ..."). # 4. The Gemini CLI will automatically have the context for that agent. github-copilot: name: Github Copilot diff --git a/tools/installer/lib/ide-setup.js b/tools/installer/lib/ide-setup.js index 04fa7d81..b6a29598 100644 --- a/tools/installer/lib/ide-setup.js +++ b/tools/installer/lib/ide-setup.js @@ -512,12 +512,53 @@ class IdeSetup { async setupGeminiCli(installDir, selectedAgent) { await initializeModules(); const geminiDir = path.join(installDir, ".gemini"); - const agentsContextDir = path.join(geminiDir, "agents"); - await fileManager.ensureDirectory(agentsContextDir); + const bmadMethodDir = path.join(geminiDir, "bmad-method"); + await fileManager.ensureDirectory(bmadMethodDir); + + // Update logic for existing settings.json + const settingsPath = path.join(geminiDir, "settings.json"); + if (await fileManager.pathExists(settingsPath)) { + try { + const settingsContent = await fileManager.readFile(settingsPath); + const settings = JSON.parse(settingsContent); + let updated = false; + + // Handle contextFileName property + if (settings.contextFileName && Array.isArray(settings.contextFileName)) { + const originalLength = settings.contextFileName.length; + settings.contextFileName = settings.contextFileName.filter( + (fileName) => !fileName.startsWith("agents/") + ); + if (settings.contextFileName.length !== originalLength) { + updated = true; + } + } + + if (updated) { + await fileManager.writeFile( + settingsPath, + JSON.stringify(settings, null, 2) + ); + console.log(chalk.green("✓ Updated .gemini/settings.json - removed agent file references")); + } + } catch (error) { + console.warn( + chalk.yellow("Could not update .gemini/settings.json"), + error + ); + } + } + + // Remove old agents directory + const agentsDir = path.join(geminiDir, "agents"); + if (await fileManager.pathExists(agentsDir)) { + await fileManager.removeDirectory(agentsDir); + console.log(chalk.green("✓ Removed old .gemini/agents directory")); + } // Get all available agents const agents = await this.getAllAgentIds(installDir); - const agentContextFiles = []; + let concatenatedContent = ""; for (const agentId of agents) { // Find the source agent file @@ -525,43 +566,46 @@ class IdeSetup { if (agentPath) { const agentContent = await fileManager.readFile(agentPath); - const contextFilePath = path.join(agentsContextDir, `${agentId}.md`); - - // Copy the agent content directly into its own context file - await fileManager.writeFile(contextFilePath, agentContent); - - // Store the relative path for settings.json - const relativePath = path.relative(geminiDir, contextFilePath); - agentContextFiles.push(relativePath.replace(/\\/g, '/')); // Ensure forward slashes for consistency - console.log(chalk.green(`✓ Created context file for @${agentId}`)); + + // Create properly formatted agent rule content (similar to trae) + let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`; + agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle( + agentId, + installDir + )} agent persona.\n\n`; + agentRuleContent += "## Agent Activation\n\n"; + agentRuleContent += + "CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n"; + agentRuleContent += "```yaml\n"; + // Extract just the YAML content from the agent file + const yamlContent = extractYamlFromAgent(agentContent); + if (yamlContent) { + agentRuleContent += yamlContent; + } + else { + // If no YAML found, include the whole content minus the header + agentRuleContent += agentContent.replace(/^#.*$/m, "").trim(); + } + agentRuleContent += "\n```\n\n"; + agentRuleContent += "## File Reference\n\n"; + const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/'); + agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`; + agentRuleContent += "## Usage\n\n"; + agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle( + agentId, + installDir + )} persona and follow all instructions defined in the YAML configuration above.\n`; + + // Add to concatenated content with separator + concatenatedContent += agentRuleContent + "\n\n---\n\n"; + console.log(chalk.green(`✓ Added context for @${agentId}`)); } } - console.log(chalk.green(`\n✓ Created individual agent context files in ${agentsContextDir}`)); - - // Add GEMINI.md to the context files array - agentContextFiles.push("GEMINI.md"); - - // Create or update settings.json - const settingsPath = path.join(geminiDir, "settings.json"); - let settings = {}; - - if (await fileManager.pathExists(settingsPath)) { - try { - const existingSettings = await fileManager.readFile(settingsPath); - settings = JSON.parse(existingSettings); - console.log(chalk.yellow("Found existing .gemini/settings.json. Merging settings...")); - } catch (e) { - console.error(chalk.red("Error parsing existing settings.json. It will be overwritten."), e); - settings = {}; - } - } - - // Set contextFileName to our new array of files - settings.contextFileName = agentContextFiles; - - await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2)); - console.log(chalk.green(`✓ Configured .gemini/settings.json to load all agent context files.`)); + // Write the concatenated content to GEMINI.md + const geminiMdPath = path.join(bmadMethodDir, "GEMINI.md"); + await fileManager.writeFile(geminiMdPath, concatenatedContent); + console.log(chalk.green(`\n✓ Created GEMINI.md in ${bmadMethodDir}`)); return true; }