feat: add custom agents and quick-flow workflows, remove tech-spec track

Major Changes:
- Add sample custom agents demonstrating installable agent system
  - commit-poet: Generates semantic commit messages (BMAD Method repo sample)
  - toolsmith: Development tooling expert with knowledge base covering bundlers, deployment, docs, installers, modules, and tests (BMAD Method repo sample)
  - Both agents demonstrate custom agent architecture and are installable to projects via BMAD installer system
  - Include comprehensive installation guides and sidecar knowledge bases

- Add bmad-quick-flow methodology for rapid development
  - create-tech-spec: Direct technical specification workflow
  - quick-dev: Flexible execution workflow supporting both tech-spec-driven and direct instruction development
  - quick-flow-solo-dev (Barry): 1 man show agent specialized in bmad-quick-flow methodology
  - Comprehensive documentation for quick-flow approach and solo development

- Remove deprecated tech-spec workflow track
  - Delete entire tech-spec workflow directory and templates
  - Remove quick-spec-flow.md documentation (replaced by quick-flow docs)
  - Clean up unused epic and story templates

- Fix custom agent installation across IDE installers
  - Repair antigravity and multiple IDE installers to properly support custom agents
  - Enable custom agent installation via quick installer, agent installer, regular installer, and special agent installer
  - All installation methods now accessible via npx with full documentation

Infrastructure:
- Update BMM module configurations and team setups
- Modify workflow status paths to support quick-flow integration
- Reorganize documentation with new agent and workflow guides
- Add custom/ directory for user customizations
- Update platform codes and installer configurations
This commit is contained in:
Brian Madison
2025-11-23 08:50:36 -06:00
parent 6907d44810
commit 4308b36d4d
63 changed files with 2556 additions and 3019 deletions

View File

@@ -1629,14 +1629,9 @@ class Installer {
spinner.succeed('No custom agents found to rebuild');
}
// Regenerate manifests after compilation (including custom agents)
spinner.start('Regenerating manifests...');
const installedModules = entries
.filter((e) => e.isDirectory() && e.name !== '_cfg' && e.name !== 'docs' && e.name !== 'agents' && e.name !== 'core')
.map((e) => e.name);
const manifestGen = new ManifestGenerator();
// Get existing IDE list from manifest
// Skip full manifest regeneration during compileAgents to preserve custom agents
// Custom agents are already added to manifests during individual installation
// Only regenerate YAML manifest for IDE updates if needed
const existingManifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml');
let existingIdes = [];
if (await fs.pathExists(existingManifestPath)) {
@@ -1646,11 +1641,6 @@ class Installer {
existingIdes = manifest.ides || [];
}
await manifestGen.generateManifests(bmadDir, installedModules, [], {
ides: existingIdes,
});
spinner.succeed('Manifests regenerated');
// Update IDE configurations using the existing IDE list from manifest
if (existingIdes && existingIdes.length > 0) {
spinner.start('Updating IDE configurations...');
@@ -2369,8 +2359,16 @@ class Installer {
// Update manifest CSV
if (await fs.pathExists(manifestFile)) {
const manifestData = extractManifestData(xml, { ...metadata, name: finalAgentName }, relativePath, 'custom');
manifestData.name = finalAgentName;
// Preserve YAML metadata for persona name, but override id for filename
const manifestMetadata = {
...metadata,
id: relativePath, // Use the compiled agent path for id
name: metadata.name || finalAgentName, // Use YAML metadata.name (persona name) or fallback
title: metadata.title, // Use YAML title
icon: metadata.icon, // Use YAML icon
};
const manifestData = extractManifestData(xml, manifestMetadata, relativePath, 'custom');
manifestData.name = finalAgentName; // Use filename for the name field
manifestData.path = relativePath;
addToManifest(manifestFile, manifestData);
}

View File

@@ -1,4 +1,5 @@
const path = require('node:path');
const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
@@ -44,7 +45,6 @@ class AntigravitySetup extends BaseIdeSetup {
const injectionConfigPath = path.join(sourceModulesPath, moduleName, 'sub-modules', 'antigravity', 'injections.yaml');
if (await this.exists(injectionConfigPath)) {
const fs = require('fs-extra');
const yaml = require('js-yaml');
try {
@@ -88,7 +88,6 @@ class AntigravitySetup extends BaseIdeSetup {
* @param {string} projectDir - Project directory
*/
async cleanup(projectDir) {
const fs = require('fs-extra');
const bmadWorkflowsDir = path.join(projectDir, this.configDir, this.workflowsDir, 'bmad');
if (await fs.pathExists(bmadWorkflowsDir)) {
@@ -191,7 +190,6 @@ class AntigravitySetup extends BaseIdeSetup {
* Read and process file content
*/
async readAndProcess(filePath, metadata) {
const fs = require('fs-extra');
const content = await fs.readFile(filePath, 'utf8');
return this.processContent(content, metadata);
}
@@ -208,7 +206,6 @@ class AntigravitySetup extends BaseIdeSetup {
* Get agents from source modules (not installed location)
*/
async getAgentsFromSource(sourceDir, selectedModules) {
const fs = require('fs-extra');
const agents = [];
// Add core agents
@@ -387,7 +384,6 @@ class AntigravitySetup extends BaseIdeSetup {
* Inject content at specified point in file
*/
async injectContent(projectDir, injection, subagentChoices = null) {
const fs = require('fs-extra');
const targetPath = path.join(projectDir, injection.file);
if (await this.exists(targetPath)) {
@@ -413,7 +409,6 @@ class AntigravitySetup extends BaseIdeSetup {
* Copy selected subagents to appropriate Antigravity agents directory
*/
async copySelectedSubagents(projectDir, handlerBaseDir, subagentConfig, choices, location) {
const fs = require('fs-extra');
const os = require('node:os');
// Determine target directory based on user choice
@@ -468,10 +463,12 @@ class AntigravitySetup extends BaseIdeSetup {
* @returns {Object} Installation result
*/
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
// Create .agent/workflows/bmad directory structure (same as regular agents)
const agentDir = path.join(projectDir, this.configDir);
const workflowsDir = path.join(agentDir, this.workflowsDir);
const bmadWorkflowsDir = path.join(workflowsDir, 'bmad');
// Create .agent directory if it doesn't exist
await fs.ensureDir(agentDir);
await fs.ensureDir(bmadWorkflowsDir);
// Create custom agent launcher with same pattern as regular agents
const launcherContent = `name: '${agentName}'
@@ -493,7 +490,7 @@ usage: |
⚠️ **IMPORTANT**: Run @${agentPath} to load the complete agent before using this launcher!`;
const fileName = `bmad-custom-agents-${agentName}.md`;
const launcherPath = path.join(agentDir, fileName);
const launcherPath = path.join(bmadWorkflowsDir, fileName);
// Write the launcher file
await fs.writeFile(launcherPath, launcherContent, 'utf8');

View File

@@ -1,4 +1,5 @@
const path = require('node:path');
const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
@@ -187,9 +188,10 @@ BMAD ${workflow.module.toUpperCase()} module
// Auggie uses .augment/commands directory
const location = path.join(projectDir, '.augment', 'commands');
const bmadCommandsDir = path.join(location, 'bmad');
const agentsDir = path.join(bmadCommandsDir, 'agents');
// Create .augment/commands/bmad directory if it doesn't exist
await fs.ensureDir(bmadCommandsDir);
// Create .augment/commands/bmad/agents directory if it doesn't exist
await fs.ensureDir(agentsDir);
// Create custom agent launcher
const launcherContent = `---
@@ -213,7 +215,7 @@ BMAD Custom agent
`;
const fileName = `custom-${agentName.toLowerCase()}.md`;
const launcherPath = path.join(bmadCommandsDir, fileName);
const launcherPath = path.join(agentsDir, fileName);
// Write the launcher file
await fs.writeFile(launcherPath, launcherContent, 'utf8');

View File

@@ -1,4 +1,5 @@
const path = require('node:path');
const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
@@ -43,7 +44,6 @@ class ClaudeCodeSetup extends BaseIdeSetup {
const injectionConfigPath = path.join(sourceModulesPath, moduleName, 'sub-modules', 'claude-code', 'injections.yaml');
if (await this.exists(injectionConfigPath)) {
const fs = require('fs-extra');
const yaml = require('js-yaml');
try {
@@ -87,7 +87,6 @@ class ClaudeCodeSetup extends BaseIdeSetup {
* @param {string} projectDir - Project directory
*/
async cleanup(projectDir) {
const fs = require('fs-extra');
const bmadCommandsDir = path.join(projectDir, this.configDir, this.commandsDir, 'bmad');
if (await fs.pathExists(bmadCommandsDir)) {
@@ -199,7 +198,6 @@ class ClaudeCodeSetup extends BaseIdeSetup {
* Read and process file content
*/
async readAndProcess(filePath, metadata) {
const fs = require('fs-extra');
const content = await fs.readFile(filePath, 'utf8');
return this.processContent(content, metadata);
}
@@ -216,7 +214,6 @@ class ClaudeCodeSetup extends BaseIdeSetup {
* Get agents from source modules (not installed location)
*/
async getAgentsFromSource(sourceDir, selectedModules) {
const fs = require('fs-extra');
const agents = [];
// Add core agents
@@ -395,7 +392,6 @@ class ClaudeCodeSetup extends BaseIdeSetup {
* Inject content at specified point in file
*/
async injectContent(projectDir, injection, subagentChoices = null) {
const fs = require('fs-extra');
const targetPath = path.join(projectDir, injection.file);
if (await this.exists(targetPath)) {
@@ -421,7 +417,6 @@ class ClaudeCodeSetup extends BaseIdeSetup {
* Copy selected subagents to appropriate Claude agents directory
*/
async copySelectedSubagents(projectDir, handlerBaseDir, subagentConfig, choices, location) {
const fs = require('fs-extra');
const os = require('node:os');
// Determine target directory based on user choice

View File

@@ -354,7 +354,7 @@ class CodexSetup extends BaseIdeSetup {
* @returns {Object|null} Info about created command
*/
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
const destDir = this.getCodexPromptDir();
const destDir = this.getCodexPromptDir(projectDir, 'project');
await fs.ensureDir(destDir);
const launcherContent = `---
@@ -379,7 +379,7 @@ You must fully embody this agent's persona and follow all activation instruction
await fs.writeFile(launcherPath, launcherContent, 'utf8');
return {
path: launcherPath,
path: path.relative(projectDir, launcherPath),
command: `/${fileName.replace('.md', '')}`,
};
}

View File

@@ -1,4 +1,5 @@
const path = require('node:path');
const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');

View File

@@ -1,4 +1,5 @@
const path = require('node:path');
const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');

View File

@@ -1,4 +1,5 @@
const path = require('node:path');
const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { getAgentsFromBmad, getTasksFromBmad } = require('./shared/bmad-artifacts');

View File

@@ -1,4 +1,5 @@
const path = require('node:path');
const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');