Compare commits
6 Commits
a65ff90b44
...
38e65abd83
| Author | SHA1 | Date |
|---|---|---|
|
|
38e65abd83 | |
|
|
ff9a085dd0 | |
|
|
d5c687d99d | |
|
|
b68e5c0225 | |
|
|
987f81ff64 | |
|
|
0c2afdd2bb |
|
|
@ -0,0 +1,36 @@
|
|||
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
|
||||
|
||||
language: "en-US"
|
||||
early_access: true
|
||||
reviews:
|
||||
profile: chill
|
||||
high_level_summary: true
|
||||
request_changes_workflow: false
|
||||
review_status: true
|
||||
collapse_walkthrough: false
|
||||
poem: false
|
||||
auto_review:
|
||||
enabled: false # must be manually triggered with @coderabbit review
|
||||
drafts: true # Can review drafts. Since it's manually triggered, it's fine.
|
||||
auto_incremental_review: false # always review the whole PR, not just new commits
|
||||
base_branches:
|
||||
- main
|
||||
path_filters:
|
||||
- "!**/node_modules/**"
|
||||
path_instructions:
|
||||
- path: "**/*"
|
||||
instructions: |
|
||||
Focus on inconsistencies, contradictions, edge cases and serious issues.
|
||||
Avoid commenting on minor issues such as linting, formatting and style issues.
|
||||
When providing code suggestions, use GitHub's suggestion format:
|
||||
```suggestion
|
||||
<code changes>
|
||||
```
|
||||
- path: "**/*.js"
|
||||
instructions: |
|
||||
CLI tooling code. Check for: missing error handling on fs operations,
|
||||
path.join vs string concatenation, proper cleanup in error paths.
|
||||
Flag any process.exit() without error message.
|
||||
chat:
|
||||
auto_reply: true # Response to mentions in comments, a la @coderabbit review
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ representative at an online or offline event.
|
|||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
the official BMAD Discord server (https://discord.com/invite/gk8jAdXWmj) - DM a moderator or flag a post.
|
||||
the official BMAD Discord server (<https://discord.com/invite/gk8jAdXWmj>) - DM a moderator or flag a post.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
|
|
@ -116,7 +116,7 @@ the community.
|
|||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
<https://www.contributor-covenant.org/version/2/0/code_of_conduct.html>.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
|
@ -124,5 +124,5 @@ enforcement ladder](https://github.com/mozilla/diversity).
|
|||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
<https://www.contributor-covenant.org/faq>. Translations are available at
|
||||
<https://www.contributor-covenant.org/translations>.
|
||||
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
## AI-Driven Agile Development That Scales From Bug Fixes to Enterprise
|
||||
|
||||
**Build More, Architect Dreams** (BMAD) with **19 specialized AI agents** and **50+ guided workflows** that adapt to your project's complexity—from quick bug fixes to enterprise platforms.
|
||||
**Build More, Architect Dreams** (BMAD) with **21 specialized AI agents** across 4 official modules, and **50+ guided workflows** that adapt to your project's complexity—from quick bug fixes to enterprise platforms, and new step file workflows that allow for incredibly long workflows to stay on the rails longer than ever before!
|
||||
|
||||
Additionally - when we say 'Build More, Architect Dreams' - we mean it! The BMad Builder has landed, and now as of Alpha.15 is fully supported in the installation flow via NPX - custom stand along agents, workflows and the modules of your dreams! The community forge will soon open, endless possibility awaits!
|
||||
|
||||
> **🚀 v6 is a MASSIVE upgrade from v4!** Complete architectural overhaul, scale-adaptive intelligence, visual workflows, and the powerful BMad Core framework. v4 users: this changes everything. [See what's new →](#whats-new-in-v6)
|
||||
|
||||
|
|
@ -154,6 +156,7 @@ Each agent brings deep expertise and can be customized to match your team's styl
|
|||
- **[GitHub Issues](https://github.com/bmad-code-org/BMAD-METHOD/issues)** - Report bugs, request features
|
||||
- **[YouTube Channel](https://www.youtube.com/@BMadCode)** - Video tutorials and demos
|
||||
- **[Web Bundles](https://bmad-code-org.github.io/bmad-bundles/)** - Pre-built agent bundles
|
||||
- **[Code of Conduct](.github/CODE_OF_CONDUCT.md)** - Community guidelines
|
||||
|
||||
## 🛠️ Development
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,137 +0,0 @@
|
|||
# Custom Agent Installation
|
||||
|
||||
BMAD agents and workflows are now installed through the main CLI installer using a `custom.yaml` configuration file or by having an installer file.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Create a `custom.yaml` file in the root of your agent/workflow folder:
|
||||
|
||||
```yaml
|
||||
code: my-custom-agent
|
||||
name: 'My Custom Agent'
|
||||
default_selected: true
|
||||
```
|
||||
|
||||
Then run the BMAD installer from your project directory:
|
||||
|
||||
```bash
|
||||
npx bmad-method install
|
||||
```
|
||||
|
||||
Or if you have bmad-cli installed globally:
|
||||
|
||||
```bash
|
||||
bmad install
|
||||
```
|
||||
|
||||
## Installation Methods
|
||||
|
||||
### Method 1: Stand-alone Folder with custom.yaml
|
||||
|
||||
Place your agent or workflow in a folder with a `custom.yaml` file at the root:
|
||||
|
||||
```
|
||||
my-agent/
|
||||
├── custom.yaml # Required configuration file
|
||||
├── my-agent.agent.yaml
|
||||
└── sidecar/ # Optional
|
||||
└── instructions.md
|
||||
```
|
||||
|
||||
### Method 2: Installer File
|
||||
|
||||
For more complex installations, include an `installer.js` or `installer.yaml` file in your agent/workflow folder:
|
||||
|
||||
```
|
||||
my-workflow/
|
||||
├── workflow.md
|
||||
└── installer.yaml # Custom installation logic
|
||||
```
|
||||
|
||||
## What It Does
|
||||
|
||||
1. **Discovers** available agents and workflows from folders with `custom.yaml`
|
||||
2. **Installs** to your project's `.bmad/custom/` directory
|
||||
3. **Creates** IDE commands for all your configured IDEs (Claude Code, Codex, Cursor, etc.)
|
||||
4. **Registers** the agent/workflow in the BMAD system
|
||||
|
||||
## Example custom.yaml
|
||||
|
||||
```yaml
|
||||
code: my-custom-agent
|
||||
name: 'My Custom Agent'
|
||||
default_selected: true
|
||||
```
|
||||
|
||||
## Installing Reference Agents
|
||||
|
||||
The BMAD source includes example agents you can install. **You must copy them to your project first.**
|
||||
|
||||
### Step 1: Copy the Agent Template
|
||||
|
||||
**For simple agents** (single file):
|
||||
|
||||
```bash
|
||||
# From your project root
|
||||
mkdir -p .bmad/custom/agents/my-agent
|
||||
cp node_modules/bmad-method/src/modules/bmb/reference/agents/stand-alone/commit-poet.agent.yaml \
|
||||
.bmad/custom/agents/my-agent/
|
||||
```
|
||||
|
||||
**For expert agents** (folder with sidecar files):
|
||||
|
||||
```bash
|
||||
# Copy the entire folder
|
||||
cp -r node_modules/bmad-method/src/modules/bmb/reference/agents/agent-with-memory/journal-keeper \
|
||||
.bmad/custom/agents/
|
||||
```
|
||||
|
||||
### Step 2: Create custom.yaml
|
||||
|
||||
```bash
|
||||
# In the agent folder, create custom.yaml
|
||||
cat > .bmad/custom/agents/my-agent/custom.yaml << EOF
|
||||
code: my-agent
|
||||
name: "My Custom Agent"
|
||||
default_selected: true
|
||||
EOF
|
||||
```
|
||||
|
||||
### Step 3: Install
|
||||
|
||||
```bash
|
||||
npx bmad-method install
|
||||
# or: bmad install (if BMAD installed locally)
|
||||
```
|
||||
|
||||
The installer will:
|
||||
|
||||
1. Find the agent with its `custom.yaml`
|
||||
2. Install it to the appropriate location
|
||||
3. Create IDE commands for immediate use
|
||||
|
||||
### Available Reference Agents
|
||||
|
||||
**Simple (standalone file):**
|
||||
|
||||
- `commit-poet.agent.yaml` - Commit message artisan with style preferences
|
||||
|
||||
**Expert (folder with sidecar):**
|
||||
|
||||
- `journal-keeper/` - Personal journal companion with memory and pattern recognition
|
||||
|
||||
Find these in the BMAD source:
|
||||
|
||||
```
|
||||
src/modules/bmb/reference/agents/
|
||||
├── stand-alone/
|
||||
│ └── commit-poet.agent.yaml
|
||||
└── agent-with-memory/
|
||||
└── journal-keeper/
|
||||
├── journal-keeper.agent.yaml
|
||||
└── journal-keeper-sidecar/
|
||||
```
|
||||
|
||||
## Creating Your Own
|
||||
|
||||
Use the BMB agent builder to craft your agents. Once ready to use, place your `.agent.yaml` files or folders with `custom.yaml` in `.bmad/custom/agents/` or `.bmad/custom/workflows/`.
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
# Custom Content Installation
|
||||
|
||||
This guide explains how to create and install custom BMAD content including agents, workflows, and modules. Custom content allows you to extend BMAD's functionality with your own specialized tools and workflows that can be shared across projects or teams.
|
||||
|
||||
## Types of Custom Content
|
||||
|
||||
### 1. Custom Agents and Workflows (Standalone)
|
||||
|
||||
Custom agents and workflows are standalone content packages that can be installed without being part of a full module. These are perfect for:
|
||||
|
||||
- Sharing specialized agents across projects
|
||||
- Building a personal Agent powered Notebook vault
|
||||
- Distributing workflow templates
|
||||
- Creating agent libraries for specific domains
|
||||
|
||||
#### Structure
|
||||
|
||||
A custom agents and workflows package follows this structure:
|
||||
|
||||
```
|
||||
my-custom-agents/
|
||||
├── custom.yaml # Package configuration
|
||||
├── agents/ # Agent definitions
|
||||
│ └── my-agent/
|
||||
│ └── agent.md
|
||||
└── workflows/ # Workflow definitions
|
||||
└── my-workflow/
|
||||
└── workflow.md
|
||||
```
|
||||
|
||||
#### Configuration
|
||||
|
||||
Create a `custom.yaml` file in your package root:
|
||||
|
||||
```yaml
|
||||
code: my-custom-agents
|
||||
name: 'My Custom Agents and Workflows'
|
||||
default_selected: true
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
See `/example-custom-content` for a working example of a folder with multiple random custom agents and workflows. Technically its also just a module, but you will be able to further pick and choose from this folders contents of what you do and do not want to include in a destination folder. This way, you can store all custom content source in one location and easily install it to different locations.
|
||||
|
||||
```bash
|
||||
# The example is ready to use - just rename the config file:
|
||||
mv example-custom-content/custom.bak example-custom-content/custom.yaml
|
||||
```
|
||||
|
||||
### 2. Custom Modules
|
||||
|
||||
Custom modules are complete BMAD modules that can include their own configuration, documentation, along with agents and workflows that all compliment each other. Additionally they will have their own installation scripts, data, and potentially other tools. Modules can be used for:
|
||||
|
||||
- Domain-specific functionality (e.g., industry-specific workflows, entertainment, education and training, medical, etc...)
|
||||
- Integration with external systems
|
||||
- Specialized agent collections
|
||||
- Custom tooling and utilities
|
||||
|
||||
#### Structure
|
||||
|
||||
A custom module follows this structure:
|
||||
|
||||
```
|
||||
my-module/
|
||||
├── _module-installer/
|
||||
│ ├── installer.js # optional, when it exists it will run with module installation
|
||||
│ └── install-config.yaml # Module installation configuration with custom question and answer capture
|
||||
├── docs/ # Module documentation
|
||||
├── agents/ # Module-specific agents
|
||||
├── workflows/ # Module-specific workflows
|
||||
├── data/ # csv or other content to power agent intelligence or workflows
|
||||
├── tools/ # Custom tools, hooks, mcp
|
||||
└── sub-modules/ # IDE-specific customizations
|
||||
├── vscode/
|
||||
└── cursor/
|
||||
```
|
||||
|
||||
#### Module Configuration
|
||||
|
||||
The `_module-installer/install-config.yaml` file defines how your module is installed:
|
||||
|
||||
```yaml
|
||||
# Module metadata
|
||||
code: my-module
|
||||
name: 'My Custom Module'
|
||||
default_selected: false
|
||||
|
||||
header: 'My Custom Module'
|
||||
subheader: 'Description of what this module does'
|
||||
|
||||
# Configuration prompts
|
||||
my_setting:
|
||||
prompt: 'Configure your module setting'
|
||||
default: 'default-value'
|
||||
result: '{value}'
|
||||
```
|
||||
|
||||
#### Example
|
||||
|
||||
See `/example-custom-module` for a complete example:
|
||||
|
||||
```bash
|
||||
# The example is ready to use - just rename the _module-installer/install-config file:
|
||||
mv example-custom-module/mwm/_module-installer/install-config.bak \
|
||||
example-custom-module/mwm/_module-installer/install-config.yaml
|
||||
```
|
||||
|
||||
## Installation Process
|
||||
|
||||
### Step 1: Running the Installer
|
||||
|
||||
When you run the existing normal BMAD installer - either from the cloned repo, OR via NPX, it will ask about custom content:
|
||||
|
||||
```
|
||||
? Do you have custom content to install?
|
||||
❯ No (skip custom content)
|
||||
Enter a directory path
|
||||
Enter a URL [Coming soon]
|
||||
```
|
||||
|
||||
### Step 2: Providing Custom Content Path
|
||||
|
||||
If you select "Enter a directory path", the installer will prompt for the location:
|
||||
|
||||
```
|
||||
? Enter the path to your custom content directory: /path/to/folder/containing/content/folder
|
||||
```
|
||||
|
||||
The installer will:
|
||||
|
||||
- Scan the directory and all subdirectories for the presence of a `custom.yaml` file (standalone content such as agents and workflows)
|
||||
- Scan for `_module-installer/install-config.yaml` files (modules)
|
||||
- Display an indication of how many installable folders it has found. Note that a project with stand along agents and workflows all under a single folder like the example will just list the count as 1 for that directory.
|
||||
|
||||
### Step 3: Selecting Content
|
||||
|
||||
The installer presents a unified selection interface:
|
||||
|
||||
```
|
||||
? Select modules and custom content to install:
|
||||
[── Custom Content ──]
|
||||
◉ My Custom Agents and Workflows (/path/to/custom)
|
||||
[── Official Content ──]
|
||||
◯ BMM: Business Method & Management
|
||||
◯ CIS: Creativity & Innovation Suite
|
||||
```
|
||||
|
||||
## Agent Sidecar Support
|
||||
|
||||
Agents with sidecar content can store personal data, memories, and working files outside of the `.bmad` directory. This separation keeps personal content separate from BMAD's core files.
|
||||
|
||||
### What is Sidecar Content?
|
||||
|
||||
Sidecar content includes:
|
||||
|
||||
- Agent memories and learning data
|
||||
- Personal working files
|
||||
- Temporary data
|
||||
- User-specific configurations
|
||||
|
||||
### Sidecar Configuration
|
||||
|
||||
The sidecar folder location is configured during BMAD core installation:
|
||||
|
||||
```
|
||||
? Where should users' agent sidecar memory folders be stored?
|
||||
❯ .bmad-user-memory
|
||||
```
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Agent Declaration**: Agents declare `hasSidecar: true` in their metadata
|
||||
2. **Sidecar Detection**: The installer automatically detects folders with "sidecar" in the name
|
||||
3. **Installation**: Sidecar content is copied to the configured location
|
||||
4. **Path Replacement**: The `{agent_sidecar_folder}` placeholder in agent configurations is replaced with the actual path to the installed instance of the sidecar folder. Now when you use the agent, depending on its design, will use the content in sidecar to record interactions, remember things you tell it, or serve a host of many other issues.
|
||||
|
||||
### Example Structure
|
||||
|
||||
```
|
||||
my-agent/
|
||||
├── agent.md # Agent definition
|
||||
└── my-agent-sidecar/ # Sidecar content folder
|
||||
├── memories/
|
||||
├── working/
|
||||
└── config/
|
||||
```
|
||||
|
||||
### Git Integration
|
||||
|
||||
Since sidecar content is stored outside the `.bmad` directory (and typically outside version control), users can:
|
||||
|
||||
- Add the sidecar folder to `.gitignore` to exclude personal data
|
||||
- Share agent definitions without exposing personal content
|
||||
- Maintain separate configurations for different projects
|
||||
|
||||
Example `.gitignore` entry:
|
||||
|
||||
```
|
||||
# Exclude agent personal data
|
||||
.bmad-user-memory/
|
||||
```
|
||||
|
||||
## Creating Custom Content with BMAD Builder
|
||||
|
||||
The BMAD Builder provides workflows that will guide you to produce your own custom content:
|
||||
|
||||
1. **Agent Templates**: Use standardized agent templates with proper structure
|
||||
2. **Workflow Templates**: Create workflows using proven patterns
|
||||
3. **Validation Tools**: Validate your content before distribution
|
||||
4. **Package Generation**: Generate properly structured packages
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Use Clear Naming**: Make your content codes and names descriptive
|
||||
2. **Provide Documentation**: Include clear setup and usage instructions
|
||||
3. **Test Installation**: Test your content in a clean environment
|
||||
4. **Version Management**: Use semantic versioning for updates
|
||||
5. **Respect User Privacy**: Keep personal data in sidecar folders
|
||||
|
||||
## Distribution
|
||||
|
||||
Custom content can be distributed:
|
||||
|
||||
1. **File System**: Copy folders directly to users
|
||||
2. **Git Repositories**: Clone or download from version control
|
||||
3. **Package Managers**: [Coming soon] npm package support
|
||||
4. **URL Installation**: [Coming soon] Direct URL installation, including an official community vetted module forge
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Custom Content Found
|
||||
|
||||
- Ensure your `custom.yaml` or `install-config.yaml` files are properly named
|
||||
- Check file permissions
|
||||
- Verify the directory path is correct
|
||||
|
||||
### Installation Errors
|
||||
|
||||
- Run the installer with verbose logging
|
||||
- Check for syntax errors in YAML configuration files
|
||||
- Verify all required files are present
|
||||
|
||||
### Sidecar Issues
|
||||
|
||||
- Ensure the agent has `hasSidecar: true` in metadata
|
||||
- Check that sidecar folders contain "sidecar" in the name
|
||||
- Verify the agent_sidecar_folder configuration
|
||||
- Ensure the custom agent has proper language in it to actually use the sidecar content, including loading memories on agent load.
|
||||
|
||||
## Support
|
||||
|
||||
For help with custom content creation or installation:
|
||||
|
||||
1. Check the examples in `/example-custom-content` and `/example-custom-module`
|
||||
2. Review the BMAD documentation
|
||||
3. Create an issue in the BMAD repository
|
||||
4. Join the BMAD community discussions on discord
|
||||
|
|
@ -96,9 +96,9 @@ Instructions for loading agents and running workflows in your development enviro
|
|||
|
||||
## 🔧 Advanced Topics
|
||||
|
||||
### Custom Agents
|
||||
### Custom Agents, Workflow and Modules
|
||||
|
||||
- **[Custom Agent Installation](./custom-agent-installation.md)** - Install and personalize agents with `bmad agent-install`
|
||||
- **[Custom Content Installation](./custom-content-installation.md)** - Install and personalize agents, workflows and modules with the default bmad-method installer!
|
||||
- [Agent Customization Guide](./agent-customization-guide.md) - Customize agent behavior and responses
|
||||
|
||||
### Installation & Bundling
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ web-bundles/
|
|||
|
||||
**Create a Gem:**
|
||||
|
||||
1. Go to [Google AI Studio](https://aistudio.google.com/)
|
||||
1. Go to [Gemini Gem manager](https://gemini.google.com/gems/view)
|
||||
2. Click "New Gem" or "Create Gem"
|
||||
3. Give your Gem a name (e.g., "BMad PM Agent")
|
||||
4. **Enable "Code execution" for best results with document generation**
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
- @/docs/v6-open-items.md - Known issues and open items
|
||||
- @/docs/document-sharding-guide.md - Guide for sharding large documents
|
||||
- @/docs/agent-customization-guide.md - How to customize agents
|
||||
- @/docs/custom-agent-installation.md - Custom agent installation guide
|
||||
- @/docs/custom-content-installation.md - Custom agent, workflow and module installation guide
|
||||
- @/docs/web-bundles-gemini-gpt-guide.md - Web bundle usage for AI platforms
|
||||
- @/docs/BUNDLE_DISTRIBUTION_SETUP.md - Bundle distribution setup
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ Production-ready examples in `/src/modules/bmb/reference/agents/`:
|
|||
|
||||
For installing standalone simple and expert agents, see:
|
||||
|
||||
- [Custom Agent Installation](/docs/custom-agent-installation.md)
|
||||
- [Custom Agent Installation](/docs/custom-content-installation.md)
|
||||
|
||||
## Key Concepts
|
||||
|
||||
|
|
|
|||
|
|
@ -798,6 +798,53 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|||
}
|
||||
}
|
||||
|
||||
// Install custom content if provided AND selected
|
||||
if (
|
||||
config.customContent &&
|
||||
config.customContent.hasCustomContent &&
|
||||
config.customContent.customPath &&
|
||||
config.customContent.selected &&
|
||||
config.customContent.selectedFiles
|
||||
) {
|
||||
spinner.start('Installing custom content...');
|
||||
const { CustomHandler } = require('../custom/handler');
|
||||
const customHandler = new CustomHandler();
|
||||
|
||||
// Use the selected files instead of finding all files
|
||||
const customFiles = config.customContent.selectedFiles;
|
||||
|
||||
if (customFiles.length > 0) {
|
||||
console.log(chalk.cyan(`\n Found ${customFiles.length} custom content file(s):`));
|
||||
for (const customFile of customFiles) {
|
||||
const customInfo = await customHandler.getCustomInfo(customFile, projectDir);
|
||||
if (customInfo) {
|
||||
console.log(chalk.dim(` • ${customInfo.name} (${customInfo.relativePath})`));
|
||||
|
||||
// Install the custom content
|
||||
const result = await customHandler.install(
|
||||
customInfo.path,
|
||||
bmadDir,
|
||||
{ ...config.coreConfig, ...customInfo.config },
|
||||
(filePath) => {
|
||||
// Track installed files
|
||||
this.installedFiles.push(filePath);
|
||||
},
|
||||
);
|
||||
|
||||
if (result.errors.length > 0) {
|
||||
console.log(chalk.yellow(` ⚠️ ${result.errors.length} error(s) occurred`));
|
||||
for (const error of result.errors) {
|
||||
console.log(chalk.dim(` - ${error}`));
|
||||
}
|
||||
} else {
|
||||
console.log(chalk.green(` ✓ Installed ${result.agentsInstalled} agents, ${result.workflowsInstalled} workflows`));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
spinner.succeed('Custom content installed');
|
||||
}
|
||||
|
||||
// Generate clean config.yaml files for each installed module
|
||||
spinner.start('Generating module configurations...');
|
||||
await this.generateModuleConfigs(bmadDir, moduleConfigs);
|
||||
|
|
|
|||
|
|
@ -68,9 +68,10 @@ class CustomHandler {
|
|||
/**
|
||||
* Get custom content info from a custom.yaml file
|
||||
* @param {string} customYamlPath - Path to custom.yaml file
|
||||
* @param {string} projectRoot - Project root directory for calculating relative paths
|
||||
* @returns {Object|null} Custom content info
|
||||
*/
|
||||
async getCustomInfo(customYamlPath) {
|
||||
async getCustomInfo(customYamlPath, projectRoot = null) {
|
||||
try {
|
||||
const configContent = await fs.readFile(customYamlPath, 'utf8');
|
||||
|
||||
|
|
@ -84,7 +85,9 @@ class CustomHandler {
|
|||
}
|
||||
|
||||
const customDir = path.dirname(customYamlPath);
|
||||
const relativePath = path.relative(process.cwd(), customDir);
|
||||
// Use provided projectRoot or fall back to process.cwd()
|
||||
const basePath = projectRoot || process.cwd();
|
||||
const relativePath = path.relative(basePath, customDir);
|
||||
|
||||
return {
|
||||
id: config.code || path.basename(customDir),
|
||||
|
|
@ -236,13 +239,20 @@ class CustomHandler {
|
|||
// Copy with placeholder replacement for text files
|
||||
const textExtensions = ['.md', '.yaml', '.yml', '.txt', '.json'];
|
||||
if (textExtensions.some((ext) => entry.name.endsWith(ext))) {
|
||||
await this.fileOps.copyFile(sourcePath, targetPath, {
|
||||
bmadFolder: config.bmad_folder || 'bmad',
|
||||
userName: config.user_name || 'User',
|
||||
communicationLanguage: config.communication_language || 'English',
|
||||
outputFolder: config.output_folder || 'docs',
|
||||
});
|
||||
// Read source content
|
||||
let content = await fs.readFile(sourcePath, 'utf8');
|
||||
|
||||
// Replace placeholders
|
||||
content = content.replaceAll('{bmad_folder}', config.bmad_folder || 'bmad');
|
||||
content = content.replaceAll('{user_name}', config.user_name || 'User');
|
||||
content = content.replaceAll('{communication_language}', config.communication_language || 'English');
|
||||
content = content.replaceAll('{output_folder}', config.output_folder || 'docs');
|
||||
|
||||
// Write to target
|
||||
await fs.ensureDir(path.dirname(targetPath));
|
||||
await fs.writeFile(targetPath, content, 'utf8');
|
||||
} else {
|
||||
// Copy binary files as-is
|
||||
await fs.copy(sourcePath, targetPath);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ class UI {
|
|||
await installer.handleLegacyV4Migration(confirmedDirectory, legacyV4);
|
||||
}
|
||||
|
||||
// Prompt for custom content location (separate from installation directory)
|
||||
const customContentConfig = await this.promptCustomContentLocation();
|
||||
|
||||
// Check if there's an existing BMAD installation
|
||||
const fs = require('fs-extra');
|
||||
const path = require('node:path');
|
||||
|
|
@ -85,9 +88,12 @@ class UI {
|
|||
|
||||
// Handle quick update separately
|
||||
if (actionType === 'quick-update') {
|
||||
// Even for quick update, ask about custom content
|
||||
const customContentConfig = await this.promptCustomContentLocation();
|
||||
return {
|
||||
actionType: 'quick-update',
|
||||
directory: confirmedDirectory,
|
||||
customContent: customContentConfig,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -125,8 +131,21 @@ class UI {
|
|||
console.log(chalk.cyan('\n📦 Keeping existing modules: ') + selectedModules.join(', '));
|
||||
} else {
|
||||
// Only show module selection for new installs
|
||||
const moduleChoices = await this.getModuleChoices(installedModuleIds);
|
||||
const moduleChoices = await this.getModuleChoices(installedModuleIds, customContentConfig);
|
||||
selectedModules = await this.selectModules(moduleChoices);
|
||||
|
||||
// Check which custom content items were selected
|
||||
const selectedCustomContent = selectedModules.filter((mod) => mod.startsWith('__CUSTOM_CONTENT__'));
|
||||
if (selectedCustomContent.length > 0) {
|
||||
customContentConfig.selected = true;
|
||||
customContentConfig.selectedFiles = selectedCustomContent.map((mod) => mod.replace('__CUSTOM_CONTENT__', ''));
|
||||
// Filter out custom content markers since they're not real modules
|
||||
selectedModules = selectedModules.filter((mod) => !mod.startsWith('__CUSTOM_CONTENT__'));
|
||||
} else if (customContentConfig.hasCustomContent) {
|
||||
// User provided custom content but didn't select any
|
||||
customContentConfig.selected = false;
|
||||
customContentConfig.selectedFiles = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Prompt for AgentVibes TTS integration
|
||||
|
|
@ -147,7 +166,9 @@ class UI {
|
|||
ides: toolSelection.ides,
|
||||
skipIde: toolSelection.skipIde,
|
||||
coreConfig: coreConfig, // Pass collected core config to installer
|
||||
enableAgentVibes: agentVibesConfig.enabled, // AgentVibes TTS integration
|
||||
// Custom content configuration
|
||||
customContent: customContentConfig,
|
||||
enableAgentVibes: agentVibesConfig.enabled,
|
||||
agentVibesInstalled: agentVibesConfig.alreadyInstalled,
|
||||
};
|
||||
}
|
||||
|
|
@ -483,19 +504,50 @@ class UI {
|
|||
/**
|
||||
* Get module choices for selection
|
||||
* @param {Set} installedModuleIds - Currently installed module IDs
|
||||
* @param {Object} customContentConfig - Custom content configuration
|
||||
* @returns {Array} Module choices for inquirer
|
||||
*/
|
||||
async getModuleChoices(installedModuleIds) {
|
||||
async getModuleChoices(installedModuleIds, customContentConfig = null) {
|
||||
const moduleChoices = [];
|
||||
const isNewInstallation = installedModuleIds.size === 0;
|
||||
|
||||
// Add custom content items first if found
|
||||
if (customContentConfig && customContentConfig.hasCustomContent && customContentConfig.customPath) {
|
||||
// Add separator before custom content
|
||||
moduleChoices.push(new inquirer.Separator('── Custom Content ──'));
|
||||
|
||||
// Get the custom content info to display proper names
|
||||
const { CustomHandler } = require('../installers/lib/custom/handler');
|
||||
const customHandler = new CustomHandler();
|
||||
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
||||
|
||||
for (const customFile of customFiles) {
|
||||
const customInfo = await customHandler.getCustomInfo(customFile);
|
||||
if (customInfo) {
|
||||
moduleChoices.push({
|
||||
name: `${chalk.cyan('✓')} ${customInfo.name} ${chalk.gray(`(${customInfo.relativePath})`)}`,
|
||||
value: `__CUSTOM_CONTENT__${customFile}`, // Unique value for each custom content
|
||||
checked: true, // Default to selected since user chose to provide custom content
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add separator for official content
|
||||
moduleChoices.push(new inquirer.Separator('── Official Content ──'));
|
||||
}
|
||||
|
||||
// Add official modules
|
||||
const { ModuleManager } = require('../installers/lib/modules/manager');
|
||||
const moduleManager = new ModuleManager();
|
||||
const availableModules = await moduleManager.listAvailable();
|
||||
|
||||
const isNewInstallation = installedModuleIds.size === 0;
|
||||
const moduleChoices = availableModules.map((mod) => ({
|
||||
name: mod.isCustom ? `${mod.name} ${chalk.red('(Custom)')}` : mod.name,
|
||||
value: mod.id,
|
||||
checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id),
|
||||
}));
|
||||
for (const mod of availableModules) {
|
||||
moduleChoices.push({
|
||||
name: mod.name,
|
||||
value: mod.id,
|
||||
checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id),
|
||||
});
|
||||
}
|
||||
|
||||
return moduleChoices;
|
||||
}
|
||||
|
|
@ -574,6 +626,111 @@ class UI {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt for custom content location
|
||||
* @returns {Object} Custom content configuration
|
||||
*/
|
||||
async promptCustomContentLocation() {
|
||||
try {
|
||||
CLIUtils.displaySection('Custom Content', 'Optional: Add custom agents and workflows');
|
||||
|
||||
const { hasCustomContent } = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'hasCustomContent',
|
||||
message: 'Do you have custom content to install?',
|
||||
choices: [
|
||||
{ name: 'No (skip custom content)', value: 'none' },
|
||||
{ name: 'Enter a directory path', value: 'directory' },
|
||||
{ name: 'Enter a URL', value: 'url' },
|
||||
],
|
||||
default: 'none',
|
||||
},
|
||||
]);
|
||||
|
||||
if (hasCustomContent === 'none') {
|
||||
return { hasCustomContent: false };
|
||||
}
|
||||
|
||||
if (hasCustomContent === 'url') {
|
||||
console.log(chalk.yellow('\nURL-based custom content installation is coming soon!'));
|
||||
console.log(chalk.cyan('For now, please download your custom content and choose "Enter a directory path".\n'));
|
||||
return { hasCustomContent: false };
|
||||
}
|
||||
|
||||
if (hasCustomContent === 'directory') {
|
||||
let customPath;
|
||||
while (!customPath) {
|
||||
let expandedPath;
|
||||
const { directory } = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'directory',
|
||||
message: 'Enter the path to your custom content directory:',
|
||||
default: process.cwd(), // Use actual current working directory
|
||||
validate: async (input) => {
|
||||
if (!input || input.trim() === '') {
|
||||
return 'Please enter a directory path';
|
||||
}
|
||||
|
||||
try {
|
||||
expandedPath = this.expandUserPath(input.trim());
|
||||
} catch (error) {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
// Check if the path exists
|
||||
const pathExists = await fs.pathExists(expandedPath);
|
||||
if (!pathExists) {
|
||||
return 'Directory does not exist';
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
// Now expand the path for use after the prompt
|
||||
expandedPath = this.expandUserPath(directory.trim());
|
||||
|
||||
// Check if directory has custom content
|
||||
const { CustomHandler } = require('../installers/lib/custom/handler');
|
||||
const customHandler = new CustomHandler();
|
||||
const customFiles = await customHandler.findCustomContent(expandedPath);
|
||||
|
||||
if (customFiles.length === 0) {
|
||||
console.log(chalk.yellow(`\nNo custom.yaml files found in ${expandedPath}`));
|
||||
|
||||
const { tryAgain } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'tryAgain',
|
||||
message: 'Try a different directory?',
|
||||
default: true,
|
||||
},
|
||||
]);
|
||||
|
||||
if (tryAgain) {
|
||||
continue;
|
||||
} else {
|
||||
return { hasCustomContent: false };
|
||||
}
|
||||
}
|
||||
|
||||
customPath = expandedPath;
|
||||
console.log(chalk.green(`\n✓ Found ${customFiles.length} custom content file(s)`));
|
||||
}
|
||||
|
||||
return { hasCustomContent: true, customPath };
|
||||
}
|
||||
|
||||
return { hasCustomContent: false };
|
||||
} catch (error) {
|
||||
console.error(chalk.red('Error in custom content prompt:'), error);
|
||||
return { hasCustomContent: false };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm directory selection
|
||||
* @param {string} directory - The directory path
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
# Raven's Verdict - Deep PR Review Tool
|
||||
|
||||
Adversarial code review for GitHub PRs. Works with any LLM agent.
|
||||
|
||||
> **Status: Experimental.** We're still figuring out how to use this effectively. Expect the workflow to evolve.
|
||||
|
||||
## How It Works
|
||||
|
||||
Point your agent at `review-pr.md` and ask it to review a specific PR:
|
||||
|
||||
> "Read tools/maintainer/review-pr.md and apply it to PR #123"
|
||||
|
||||
The tool will:
|
||||
|
||||
1. Check out the PR branch locally
|
||||
2. Run an adversarial review (find at least 5 issues)
|
||||
3. Transform findings into professional tone
|
||||
4. Preview the review and ask before posting
|
||||
|
||||
See `review-pr.md` for full prompt structure, severity ratings, and sandboxing rules.
|
||||
|
||||
## When to Use
|
||||
|
||||
**Good candidates:**
|
||||
|
||||
- PRs with meaningful logic changes
|
||||
- Refactors touching multiple files
|
||||
- New features or architectural changes
|
||||
|
||||
**Skip it for:**
|
||||
|
||||
- Trivial PRs (typo fixes, version bumps, single-line changes)
|
||||
- PRs you've already reviewed manually
|
||||
- PRs where you haven't agreed on the approach yet — fix the direction before the implementation
|
||||
|
||||
## Workflow Tips
|
||||
|
||||
**Always review before posting.** The preview step exists for a reason:
|
||||
|
||||
- **[y] Yes** — Post as-is (only if you're confident)
|
||||
- **[e] Edit** — Modify findings before posting
|
||||
- **[s] Save only** — Write to file, don't post
|
||||
|
||||
The save option is useful when you want to:
|
||||
|
||||
- Hand-edit the review before posting
|
||||
- Use the findings as input for a second opinion ("Hey Claude, here's what Raven found — what do you think?")
|
||||
- Cherry-pick specific findings
|
||||
|
||||
**Trust but verify.** LLM reviews can miss context or flag non-issues. Skim the findings before they hit the PR.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `gh` CLI installed and authenticated (`gh auth status`)
|
||||
- Any LLM agent capable of running bash commands
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
# Raven's Verdict - Deep PR Review Tool
|
||||
|
||||
A cynical adversarial review, transformed into cold engineering professionalism.
|
||||
|
||||
<orientation>
|
||||
CRITICAL: Sandboxed Execution Rules
|
||||
|
||||
Before proceeding, you MUST verify:
|
||||
|
||||
- [ ] PR number or URL was EXPLICITLY provided in the user's message
|
||||
- [ ] You are NOT inferring the PR from conversation history
|
||||
- [ ] You are NOT looking at git branches, recent commits, or local state
|
||||
- [ ] You are NOT guessing or assuming any PR numbers
|
||||
|
||||
**If no explicit PR number/URL was provided, STOP immediately and ask:**
|
||||
"What PR number or URL should I review?"
|
||||
</orientation>
|
||||
|
||||
<preflight-checks>
|
||||
|
||||
## Preflight Checks
|
||||
|
||||
### 0.1 Parse PR Input
|
||||
|
||||
Extract PR number from user input. Examples of valid formats:
|
||||
|
||||
- `123` (just the number)
|
||||
- `#123` (with hash)
|
||||
- `https://github.com/owner/repo/pull/123` (full URL)
|
||||
|
||||
If a URL specifies a different repository than the current one:
|
||||
|
||||
```bash
|
||||
# Check current repo
|
||||
gh repo view --json nameWithOwner -q '.nameWithOwner'
|
||||
```
|
||||
|
||||
If mismatch detected, ask user:
|
||||
|
||||
> "This PR is from `{detected_repo}` but we're in `{current_repo}`. Proceed with reviewing `{detected_repo}#123`? (y/n)"
|
||||
|
||||
If user confirms, store `{REPO}` for use in all subsequent `gh` commands.
|
||||
|
||||
### 0.2 Ensure Clean Checkout
|
||||
|
||||
Verify the working tree is clean and check out the PR branch.
|
||||
|
||||
```bash
|
||||
# Check for uncommitted changes
|
||||
git status --porcelain
|
||||
```
|
||||
|
||||
If output is non-empty, STOP and tell user:
|
||||
|
||||
> "You have uncommitted changes. Please commit or stash them before running a PR review."
|
||||
|
||||
If clean, fetch and checkout the PR branch:
|
||||
|
||||
```bash
|
||||
# Fetch and checkout PR branch
|
||||
# For cross-repo PRs, include --repo {REPO}
|
||||
gh pr checkout {PR_NUMBER} [--repo {REPO}]
|
||||
```
|
||||
|
||||
If checkout fails, STOP and report the error.
|
||||
|
||||
Now you're on the PR branch with full access to all files as they exist in the PR.
|
||||
|
||||
### 0.3 Check PR Size
|
||||
|
||||
```bash
|
||||
# For cross-repo PRs, include --repo {REPO}
|
||||
gh pr view {PR_NUMBER} [--repo {REPO}] --json additions,deletions,changedFiles -q '{"additions": .additions, "deletions": .deletions, "files": .changedFiles}'
|
||||
```
|
||||
|
||||
**Size thresholds:**
|
||||
|
||||
| Metric | Warning Threshold |
|
||||
| ------------- | ----------------- |
|
||||
| Files changed | > 50 |
|
||||
| Lines changed | > 5000 |
|
||||
|
||||
If thresholds exceeded, ask user:
|
||||
|
||||
> "This PR has {X} files and {Y} line changes. That's large.
|
||||
>
|
||||
> **[f] Focus** - Pick specific files or directories to review
|
||||
> **[p] Proceed** - Review everything (may be slow/expensive)
|
||||
> **[a] Abort** - Stop here"
|
||||
|
||||
### 0.4 Note Binary Files
|
||||
|
||||
```bash
|
||||
# For cross-repo PRs, include --repo {REPO}
|
||||
gh pr diff {PR_NUMBER} [--repo {REPO}] --name-only | grep -E '\.(png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|pdf|zip|tar|gz|bin|exe|dll|so|dylib)$' || echo "No binary files detected"
|
||||
```
|
||||
|
||||
Store list of binary files to skip. Note them in final output.
|
||||
|
||||
</preflight-checks>
|
||||
|
||||
<adversarial-review>
|
||||
|
||||
### 1.1 Run Cynical Review
|
||||
|
||||
**INTERNAL PERSONA - Never post this directly:**
|
||||
|
||||
Task: You are a cynical, jaded code reviewer with zero patience for sloppy work. This PR was submitted by a clueless weasel and you expect to find problems. Find at least five issues to fix or improve in it. Number them. Be skeptical of everything. Ultrathink.
|
||||
|
||||
Output format:
|
||||
|
||||
```markdown
|
||||
### [NUMBER]. [FINDING TITLE] [likely]
|
||||
|
||||
**Severity:** [EMOJI] [LEVEL]
|
||||
|
||||
[DESCRIPTION - be specific, include file:line references]
|
||||
```
|
||||
|
||||
Severity scale:
|
||||
|
||||
| Level | Emoji | Meaning |
|
||||
| -------- | ----- | ------------------------------------------------------- |
|
||||
| Critical | 🔴 | Security issue, data loss risk, or broken functionality |
|
||||
| Moderate | 🟡 | Bug, performance issue, or significant code smell |
|
||||
| Minor | 🟢 | Style, naming, minor improvement opportunity |
|
||||
|
||||
Likely tag:
|
||||
|
||||
- Add `[likely]` to findings with high confidence, e.g. with direct evidence
|
||||
- Sort findings by severity (Critical → Moderate → Minor), not by confidence
|
||||
|
||||
</adversarial-review>
|
||||
|
||||
<tone-transformation>
|
||||
|
||||
**Transform the cynical output into cold engineering professionalism.**
|
||||
|
||||
**Transformation rules:**
|
||||
|
||||
1. Remove all inflammatory language, insults, assumptions about the author
|
||||
2. Keep all technical substance, file references, severity ratings and likely tag
|
||||
3. Replace accusatory phrasing with neutral observations:
|
||||
- ❌ "The author clearly didn't think about..."
|
||||
- ✅ "This implementation may not account for..."
|
||||
4. Preserve skepticism as healthy engineering caution:
|
||||
- ❌ "This will definitely break in production"
|
||||
- ✅ "This pattern has historically caused issues in production environments"
|
||||
5. Add the suggested fixes.
|
||||
6. Keep suggestions actionable and specific
|
||||
|
||||
Output format after transformation:
|
||||
|
||||
```markdown
|
||||
## PR Review: #{PR_NUMBER}
|
||||
|
||||
**Title:** {PR_TITLE}
|
||||
**Author:** @{AUTHOR}
|
||||
**Branch:** {HEAD} → {BASE}
|
||||
|
||||
---
|
||||
|
||||
### Findings
|
||||
|
||||
[TRANSFORMED FINDINGS HERE]
|
||||
|
||||
---
|
||||
|
||||
### Summary
|
||||
|
||||
**Critical:** {COUNT} | **Moderate:** {COUNT} | **Minor:** {COUNT}
|
||||
|
||||
[BINARY_FILES_NOTE if any]
|
||||
|
||||
---
|
||||
|
||||
_Review generated by Raven's Verdict. LLM-produced analysis - findings may be incorrect or lack context. Verify before acting._
|
||||
```
|
||||
|
||||
</tone-transformation>
|
||||
|
||||
<post-review>
|
||||
### 3.1 Preview
|
||||
|
||||
Display the complete transformed review to the user.
|
||||
|
||||
```
|
||||
══════════════════════════════════════════════════════
|
||||
PREVIEW - This will be posted to PR #{PR_NUMBER}
|
||||
══════════════════════════════════════════════════════
|
||||
|
||||
[FULL REVIEW CONTENT]
|
||||
|
||||
══════════════════════════════════════════════════════
|
||||
```
|
||||
|
||||
### 3.2 Confirm
|
||||
|
||||
Ask user for explicit confirmation:
|
||||
|
||||
> **Ready to post this review to PR #{PR_NUMBER}?**
|
||||
>
|
||||
> **[y] Yes** - Post as comment
|
||||
> **[n] No** - Abort, do not post
|
||||
> **[e] Edit** - Let me modify before posting
|
||||
> **[s] Save only** - Save locally, don't post
|
||||
|
||||
### 3.3 Post or Save
|
||||
|
||||
**Write review to a temp file, then post:**
|
||||
|
||||
1. Write the review content to a temp file with a unique name (include PR number to avoid collisions)
|
||||
2. Post using `gh pr comment {PR_NUMBER} [--repo {REPO}] --body-file {path}`
|
||||
3. Delete the temp file after successful post
|
||||
|
||||
Do NOT use heredocs or `echo` - Markdown code blocks will break shell parsing. Use your file writing tool instead.
|
||||
|
||||
**If auth fails or post fails:**
|
||||
|
||||
1. Display error prominently:
|
||||
|
||||
```
|
||||
⚠️ FAILED TO POST REVIEW
|
||||
Error: {ERROR_MESSAGE}
|
||||
```
|
||||
|
||||
2. Keep the temp file and tell the user where it is, so they can post manually with:
|
||||
`gh pr comment {PR_NUMBER} [--repo {REPO}] --body-file {path}`
|
||||
|
||||
**If save only (s):**
|
||||
|
||||
Keep the temp file and inform user of location.
|
||||
|
||||
</post-review>
|
||||
|
||||
<notes>
|
||||
- The "cynical asshole" phase is internal only - never posted
|
||||
- Tone transform MUST happen before any external output
|
||||
- When in doubt, ask the user - never assume
|
||||
- If you're unsure about severity, err toward higher severity
|
||||
- If you're unsure about confidence, be honest and use Medium or Low
|
||||
</notes>
|
||||
Loading…
Reference in New Issue