diff --git a/.github/FORK_GUIDE.md b/.github/FORK_GUIDE.md
new file mode 100644
index 00000000..d7ed2bd4
--- /dev/null
+++ b/.github/FORK_GUIDE.md
@@ -0,0 +1,106 @@
+# Fork Guide - CI/CD Configuration
+
+## CI/CD in Forks
+
+By default, CI/CD workflows are **disabled in forks** to conserve GitHub Actions resources and provide a cleaner fork experience.
+
+### Why This Approach?
+
+- **Resource efficiency**: Prevents unnecessary GitHub Actions usage across 1,600+ forks
+- **Clean fork experience**: No failed workflow notifications in your fork
+- **Full control**: Enable CI/CD only when you actually need it
+- **PR validation**: Your changes are still fully tested when submitting PRs to the main repository
+
+## Enabling CI/CD in Your Fork
+
+If you need to run CI/CD workflows in your fork, follow these steps:
+
+1. Navigate to your fork's **Settings** tab
+2. Go to **Secrets and variables** β **Actions** β **Variables**
+3. Click **New repository variable**
+4. Create a new variable:
+ - **Name**: `ENABLE_CI_IN_FORK`
+ - **Value**: `true`
+5. Click **Add variable**
+
+That's it! CI/CD workflows will now run in your fork.
+
+## Disabling CI/CD Again
+
+To disable CI/CD workflows in your fork, you can either:
+
+- **Delete the variable**: Remove the `ENABLE_CI_IN_FORK` variable entirely, or
+- **Set to false**: Change the `ENABLE_CI_IN_FORK` value to `false`
+
+## Alternative Testing Options
+
+You don't always need to enable CI/CD in your fork. Here are alternatives:
+
+### Local Testing
+
+Run tests locally before pushing:
+
+```bash
+# Install dependencies
+npm ci
+
+# Run linting
+npm run lint
+
+# Run format check
+npm run format:check
+
+# Run validation
+npm run validate
+
+# Build the project
+npm run build
+```
+
+### Pull Request CI
+
+When you open a Pull Request to the main repository:
+
+- All CI/CD workflows automatically run
+- You get full validation of your changes
+- No configuration needed
+
+### GitHub Codespaces
+
+Use GitHub Codespaces for a full development environment:
+
+- All tools pre-configured
+- Same environment as CI/CD
+- No local setup required
+
+## Frequently Asked Questions
+
+### Q: Will my PR be tested even if CI is disabled in my fork?
+
+**A:** Yes! When you open a PR to the main repository, all CI/CD workflows run automatically, regardless of your fork's settings.
+
+### Q: Can I selectively enable specific workflows?
+
+**A:** The `ENABLE_CI_IN_FORK` variable enables all workflows. For selective control, you'd need to modify individual workflow files.
+
+### Q: Do I need to enable CI in my fork to contribute?
+
+**A:** No! Most contributors never need to enable CI in their forks. Local testing and PR validation are sufficient for most contributions.
+
+### Q: Will disabling CI affect my ability to merge PRs?
+
+**A:** No! PR merge requirements are based on CI runs in the main repository, not your fork.
+
+### Q: Why was this implemented?
+
+**A:** With over 1,600 forks of BMAD-METHOD, this saves thousands of GitHub Actions minutes monthly while maintaining code quality standards.
+
+## Need Help?
+
+- Join our [Discord Community](https://discord.gg/gk8jAdXWmj) for support
+- Check the [Contributing Guide](../README.md#contributing) for more information
+- Open an issue if you encounter any problems
+
+---
+
+> π‘ **Pro Tip**: This fork-friendly approach is particularly valuable for projects using AI/LLM tools that create many experimental commits, as it prevents unnecessary CI runs while maintaining code quality standards.
diff --git a/.github/workflows/discord.yaml b/.github/workflows/discord.yaml
index 0d3eda6f..d66903a7 100644
--- a/.github/workflows/discord.yaml
+++ b/.github/workflows/discord.yaml
@@ -14,6 +14,7 @@ name: Discord Notification
jobs:
notify:
runs-on: ubuntu-latest
+ if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
steps:
- name: Notify Discord
uses: sarisia/actions-status-discord@v1
diff --git a/.github/workflows/format-check.yaml b/.github/workflows/format-check.yaml
index 78525659..1b9b319d 100644
--- a/.github/workflows/format-check.yaml
+++ b/.github/workflows/format-check.yaml
@@ -7,6 +7,7 @@ name: format-check
jobs:
prettier:
runs-on: ubuntu-latest
+ if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -25,6 +26,7 @@ jobs:
eslint:
runs-on: ubuntu-latest
+ if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
diff --git a/.github/workflows/manual-release.yaml b/.github/workflows/manual-release.yaml
index f5df668a..fc03a100 100644
--- a/.github/workflows/manual-release.yaml
+++ b/.github/workflows/manual-release.yaml
@@ -20,6 +20,7 @@ permissions:
jobs:
release:
runs-on: ubuntu-latest
+ if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
diff --git a/.github/workflows/pr-validation.yaml b/.github/workflows/pr-validation.yaml
new file mode 100644
index 00000000..5bacb4f0
--- /dev/null
+++ b/.github/workflows/pr-validation.yaml
@@ -0,0 +1,55 @@
+name: PR Validation
+
+on:
+ pull_request:
+ branches: [main]
+ types: [opened, synchronize, reopened]
+
+jobs:
+ validate:
+ runs-on: ubuntu-latest
+ if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == 'true'
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "20"
+ cache: npm
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Run validation
+ run: npm run validate
+
+ - name: Check formatting
+ run: npm run format:check
+
+ - name: Run linter
+ run: npm run lint
+
+ - name: Run tests (if available)
+ run: npm test --if-present
+
+ - name: Comment on PR if checks fail
+ if: failure()
+ uses: actions/github-script@v7
+ with:
+ script: |
+ github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: `β **PR Validation Failed**
+
+ This PR has validation errors that must be fixed before merging:
+ - Run \`npm run validate\` to check agent/team configs
+ - Run \`npm run format:check\` to check formatting (fix with \`npm run format\`)
+ - Run \`npm run lint\` to check linting issues (fix with \`npm run lint:fix\`)
+
+ Please fix these issues and push the changes.`
+ })
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index fe988154..2ad976dc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,6 +17,47 @@ Also note, we use the discussions feature in GitHub to have a community to discu
By participating in this project, you agree to abide by our Code of Conduct. Please read it before participating.
+## Before Submitting a PR
+
+**IMPORTANT**: All PRs must pass validation checks before they can be merged.
+
+### Required Checks
+
+Before submitting your PR, run these commands locally:
+
+```bash
+# Run all validation checks
+npm run pre-release
+
+# Or run them individually:
+npm run validate # Validate agent/team configs
+npm run format:check # Check code formatting
+npm run lint # Check for linting issues
+```
+
+### Fixing Issues
+
+If any checks fail, use these commands to fix them:
+
+```bash
+# Fix all issues automatically
+npm run fix
+
+# Or fix individually:
+npm run format # Fix formatting issues
+npm run lint:fix # Fix linting issues
+```
+
+### Setup Git Hooks (Optional but Recommended)
+
+To catch issues before committing:
+
+```bash
+# Run this once after cloning
+chmod +x tools/setup-hooks.sh
+./tools/setup-hooks.sh
+```
+
## How to Contribute
### Reporting Bugs
diff --git a/README.md b/README.md
index 41060958..c22292f6 100644
--- a/README.md
+++ b/README.md
@@ -212,6 +212,26 @@ The generated XML file contains your project's text-based source files in a stru
π **[Read CONTRIBUTING.md](CONTRIBUTING.md)** - Complete guide to contributing, including guidelines, process, and requirements
+### Working with Forks
+
+When you fork this repository, CI/CD workflows are **disabled by default** to save resources. This is intentional and helps keep your fork clean.
+
+#### Need CI/CD in Your Fork?
+
+See our [Fork CI/CD Guide](.github/FORK_GUIDE.md) for instructions on enabling workflows in your fork.
+
+#### Contributing Workflow
+
+1. **Fork the repository** - Click the Fork button on GitHub
+2. **Clone your fork** - `git clone https://github.com/YOUR-USERNAME/BMAD-METHOD.git`
+3. **Create a feature branch** - `git checkout -b feature/amazing-feature`
+4. **Make your changes** - Test locally with `npm test`
+5. **Commit your changes** - `git commit -m 'feat: add amazing feature'`
+6. **Push to your fork** - `git push origin feature/amazing-feature`
+7. **Open a Pull Request** - CI/CD will run automatically on the PR
+
+Your contributions are tested when you submit a PR - no need to enable CI in your fork!
+
## License
MIT License - see [LICENSE](LICENSE) for details.
@@ -223,3 +243,19 @@ BMADβ’ and BMAD-METHODβ’ are trademarks of BMad Code, LLC. All rights reserved
[](https://github.com/bmadcode/bmad-method/graphs/contributors)
Built with β€οΈ for the AI-assisted development community
+
+#### Codex (CLI & Web)
+
+- Two modes are supported:
+ - Codex (local only): `npx bmad-method install -f -i codex -d .` β keeps `.bmad-core/` ignored via `.gitignore` for local development.
+ - Codex Web Enabled: `npx bmad-method install -f -i codex-web -d .` β ensures `.bmad-core/` is tracked (not ignored) so it can be committed for Codex Web.
+- For Codex Web, commit both `.bmad-core/` and `AGENTS.md` to the repository.
+- Codex CLI: run `codex` at your project root; reference agents naturally, e.g., βAs dev, implement β¦β.
+- Codex Web: open your repo in Codex and prompt the same way β it reads `AGENTS.md` automatically.
+- Refresh after changes: rerun the appropriate install command (`codex` or `codex-web`) to regenerate the BMAD section inside `AGENTS.md`.
+
+If a `package.json` exists in your project, the installer will add helpful scripts:
+
+- `bmad:refresh` β `bmad-method install -f -i codex`
+- `bmad:list` β `bmad-method list:agents`
+- `bmad:validate` β `bmad-method validate`
diff --git a/bmad-core/agents/bmad-master.md b/bmad-core/agents/bmad-master.md
index 3aeb3b63..7dcb19fc 100644
--- a/bmad-core/agents/bmad-master.md
+++ b/bmad-core/agents/bmad-master.md
@@ -11,16 +11,16 @@ CRITICAL: Read the full YAML BLOCK that FOLLOWS IN THIS FILE to understand your
```yaml
IDE-FILE-RESOLUTION:
- FOR LATER USE ONLY - NOT FOR ACTIVATION, when executing commands that reference dependencies
- - Dependencies map to root/type/name
+ - Dependencies map to {root}/{type}/{name}
- type=folder (tasks|templates|checklists|data|utils|etc...), name=file-name
- - Example: create-doc.md β root/tasks/create-doc.md
+ - Example: create-doc.md β {root}/tasks/create-doc.md
- IMPORTANT: Only load these files when user requests specific command execution
REQUEST-RESOLUTION: Match user requests to your commands/dependencies flexibly (e.g., "draft story"β*createβcreate-next-story task, "make a new prd" would be dependencies->tasks->create-doc combined with the dependencies->templates->prd-tmpl.md), ALWAYS ask for clarification if no clear match.
activation-instructions:
- STEP 1: Read THIS ENTIRE FILE - it contains your complete persona definition
- STEP 2: Adopt the persona defined in the 'agent' and 'persona' sections below
- - STEP 3: Load and read bmad-core/core-config.yaml (project configuration) before any greeting
- - STEP 4: Greet user with your name/role and immediately run *help to display available commands
+ - STEP 3: Load and read `bmad-core/core-config.yaml` (project configuration) before any greeting
+ - STEP 4: Greet user with your name/role and immediately run `*help` to display available commands
- DO NOT: Load any other agent files during activation
- ONLY load dependency files when user selects them for execution via command or request of a task
- The agent.customization field ALWAYS takes precedence over any conflicting instructions
diff --git a/bmad-core/agents/dev.md b/bmad-core/agents/dev.md
index f04c438c..6362a303 100644
--- a/bmad-core/agents/dev.md
+++ b/bmad-core/agents/dev.md
@@ -49,6 +49,7 @@ persona:
core_principles:
- CRITICAL: Story has ALL info you will need aside from what you loaded during the startup commands. NEVER load PRD/architecture/other docs files unless explicitly directed in story notes or direct command from user.
+ - CRITICAL: ALWAYS check current folder structure before starting your story tasks, don't create new working directory if it already exists. Create new one when you're sure it's a brand new project.
- CRITICAL: ONLY update story file Dev Agent Record sections (checkboxes/Debug Log/Completion Notes/Change Log)
- CRITICAL: FOLLOW THE develop-story command when the user tells you to implement the story
- Numbered Options - Always use numbered lists when presenting choices to the user
diff --git a/bmad-core/workflows/brownfield-fullstack.yaml b/bmad-core/workflows/brownfield-fullstack.yaml
index 6a7d7d87..a696b0a8 100644
--- a/bmad-core/workflows/brownfield-fullstack.yaml
+++ b/bmad-core/workflows/brownfield-fullstack.yaml
@@ -160,7 +160,7 @@ workflow:
- Dev Agent (New Chat): Address remaining items
- Return to QA for final approval
- - repeat_development_cycle:
+ - step: repeat_development_cycle
action: continue_for_all_stories
notes: |
Repeat story cycle (SM β Dev β QA) for all epic stories
@@ -177,7 +177,7 @@ workflow:
- Validate epic was completed correctly
- Document learnings and improvements
- - workflow_end:
+ - step: workflow_end
action: project_complete
notes: |
All stories implemented and reviewed!
diff --git a/bmad-core/workflows/brownfield-service.yaml b/bmad-core/workflows/brownfield-service.yaml
index e2af23de..6c8148cd 100644
--- a/bmad-core/workflows/brownfield-service.yaml
+++ b/bmad-core/workflows/brownfield-service.yaml
@@ -106,7 +106,7 @@ workflow:
- Dev Agent (New Chat): Address remaining items
- Return to QA for final approval
- - repeat_development_cycle:
+ - step: repeat_development_cycle
action: continue_for_all_stories
notes: |
Repeat story cycle (SM β Dev β QA) for all epic stories
@@ -123,7 +123,7 @@ workflow:
- Validate epic was completed correctly
- Document learnings and improvements
- - workflow_end:
+ - step: workflow_end
action: project_complete
notes: |
All stories implemented and reviewed!
diff --git a/bmad-core/workflows/brownfield-ui.yaml b/bmad-core/workflows/brownfield-ui.yaml
index 4a9ffd76..9e249f4e 100644
--- a/bmad-core/workflows/brownfield-ui.yaml
+++ b/bmad-core/workflows/brownfield-ui.yaml
@@ -113,7 +113,7 @@ workflow:
- Dev Agent (New Chat): Address remaining items
- Return to QA for final approval
- - repeat_development_cycle:
+ - step: repeat_development_cycle
action: continue_for_all_stories
notes: |
Repeat story cycle (SM β Dev β QA) for all epic stories
@@ -130,7 +130,7 @@ workflow:
- Validate epic was completed correctly
- Document learnings and improvements
- - workflow_end:
+ - step: workflow_end
action: project_complete
notes: |
All stories implemented and reviewed!
diff --git a/bmad-core/workflows/greenfield-fullstack.yaml b/bmad-core/workflows/greenfield-fullstack.yaml
index 1425d9f2..1fa8a6a8 100644
--- a/bmad-core/workflows/greenfield-fullstack.yaml
+++ b/bmad-core/workflows/greenfield-fullstack.yaml
@@ -65,12 +65,12 @@ workflow:
condition: po_checklist_issues
notes: "If PO finds issues, return to relevant agent to fix and re-export updated documents to docs/ folder."
- - project_setup_guidance:
+ - step: project_setup_guidance
action: guide_project_structure
condition: user_has_generated_ui
notes: "If user generated UI with v0/Lovable: For polyrepo setup, place downloaded project in separate frontend repo alongside backend repo. For monorepo, place in apps/web or packages/frontend directory. Review architecture document for specific guidance."
- - development_order_guidance:
+ - step: development_order_guidance
action: guide_development_sequence
notes: "Based on PRD stories: If stories are frontend-heavy, start with frontend project/directory first. If backend-heavy or API-first, start with backend. For tightly coupled features, follow story sequence in monorepo setup. Reference sharded PRD epics for development order."
@@ -138,7 +138,7 @@ workflow:
- Dev Agent (New Chat): Address remaining items
- Return to QA for final approval
- - repeat_development_cycle:
+ - step: repeat_development_cycle
action: continue_for_all_stories
notes: |
Repeat story cycle (SM β Dev β QA) for all epic stories
@@ -155,7 +155,7 @@ workflow:
- Validate epic was completed correctly
- Document learnings and improvements
- - workflow_end:
+ - step: workflow_end
action: project_complete
notes: |
All stories implemented and reviewed!
diff --git a/bmad-core/workflows/greenfield-service.yaml b/bmad-core/workflows/greenfield-service.yaml
index c30c0132..c8339678 100644
--- a/bmad-core/workflows/greenfield-service.yaml
+++ b/bmad-core/workflows/greenfield-service.yaml
@@ -114,7 +114,7 @@ workflow:
- Dev Agent (New Chat): Address remaining items
- Return to QA for final approval
- - repeat_development_cycle:
+ - step: repeat_development_cycle
action: continue_for_all_stories
notes: |
Repeat story cycle (SM β Dev β QA) for all epic stories
@@ -131,7 +131,7 @@ workflow:
- Validate epic was completed correctly
- Document learnings and improvements
- - workflow_end:
+ - step: workflow_end
action: project_complete
notes: |
All stories implemented and reviewed!
diff --git a/bmad-core/workflows/greenfield-ui.yaml b/bmad-core/workflows/greenfield-ui.yaml
index 2b3e5f46..14678458 100644
--- a/bmad-core/workflows/greenfield-ui.yaml
+++ b/bmad-core/workflows/greenfield-ui.yaml
@@ -64,7 +64,7 @@ workflow:
condition: po_checklist_issues
notes: "If PO finds issues, return to relevant agent to fix and re-export updated documents to docs/ folder."
- - project_setup_guidance:
+ - step: project_setup_guidance
action: guide_project_structure
condition: user_has_generated_ui
notes: "If user generated UI with v0/Lovable: For polyrepo setup, place downloaded project in separate frontend repo. For monorepo, place in apps/web or frontend/ directory. Review architecture document for specific guidance."
@@ -133,7 +133,7 @@ workflow:
- Dev Agent (New Chat): Address remaining items
- Return to QA for final approval
- - repeat_development_cycle:
+ - step: repeat_development_cycle
action: continue_for_all_stories
notes: |
Repeat story cycle (SM β Dev β QA) for all epic stories
@@ -150,7 +150,7 @@ workflow:
- Validate epic was completed correctly
- Document learnings and improvements
- - workflow_end:
+ - step: workflow_end
action: project_complete
notes: |
All stories implemented and reviewed!
diff --git a/docs/user-guide.md b/docs/user-guide.md
index 43c2daf6..117b08b4 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -187,6 +187,32 @@ If you want to do the planning on the web with Claude (Sonnet 4 or Opus), Gemini
npx bmad-method install
```
+### Codex (CLI & Web)
+
+BMAD integrates with OpenAI Codex via `AGENTS.md` and committed core agent files.
+
+- Two installation modes:
+ - Codex (local only): keeps `.bmad-core/` ignored for local dev.
+ - `npx bmad-method install -f -i codex -d .`
+ - Codex Web Enabled: ensures `.bmad-core/` is tracked so you can commit it for Codex Web.
+ - `npx bmad-method install -f -i codex-web -d .`
+
+- What gets generated:
+ - `AGENTS.md` at the project root with a BMAD section containing
+ - How-to-use with Codex (CLI & Web)
+ - Agent Directory (Title, ID, When To Use)
+ - Detailed perβagent sections with source path, when-to-use, activation phrasing, and YAML
+ - Tasks with quick usage notes
+ - If a `package.json` exists, helpful scripts are added:
+ - `bmad:refresh`, `bmad:list`, `bmad:validate`
+
+- Using Codex:
+ - CLI: run `codex` in the project root and prompt naturally, e.g., βAs dev, implement β¦β.
+ - Web: commit `.bmad-core/` and `AGENTS.md`, then open the repo in Codex and prompt the same way.
+
+- Refresh after changes:
+ - Re-run the appropriate install mode (`codex` or `codex-web`) to update the BMAD block in `AGENTS.md`.
+
## Special Agents
There are two BMad agents β in the future they'll be consolidated into a single BMad-Master.
diff --git a/implement-fork-friendly-ci.sh b/implement-fork-friendly-ci.sh
new file mode 100755
index 00000000..da8e61b0
--- /dev/null
+++ b/implement-fork-friendly-ci.sh
@@ -0,0 +1,229 @@
+#!/bin/bash
+
+# Fork-Friendly CI/CD Implementation Script
+# Usage: ./implement-fork-friendly-ci.sh
+#
+# This script automates the implementation of fork-friendly CI/CD
+# by adding fork detection conditions to all GitHub Actions workflows
+
+set -e
+
+echo "π Implementing Fork-Friendly CI/CD..."
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# 1. Check if .github/workflows directory exists
+if [ ! -d ".github/workflows" ]; then
+ echo -e "${RED}β${NC} No .github/workflows directory found"
+ echo "This script must be run from the repository root"
+ exit 1
+fi
+
+# 2. Backup existing workflows
+echo "π¦ Backing up workflows..."
+backup_dir=".github/workflows.backup.$(date +%Y%m%d_%H%M%S)"
+cp -r .github/workflows "$backup_dir"
+echo -e "${GREEN}β${NC} Workflows backed up to $backup_dir"
+
+# 3. Count workflow files and jobs
+WORKFLOW_COUNT=$(ls -1 .github/workflows/*.yml .github/workflows/*.yaml 2>/dev/null | wc -l)
+echo "π Found ${WORKFLOW_COUNT} workflow files"
+
+# 4. Process each workflow file
+UPDATED_FILES=0
+MANUAL_REVIEW_NEEDED=0
+
+for file in .github/workflows/*.yml .github/workflows/*.yaml; do
+ if [ -f "$file" ]; then
+ filename=$(basename "$file")
+ echo -n "Processing ${filename}... "
+
+ # Create temporary file
+ temp_file="${file}.tmp"
+
+ # Track if file needs manual review
+ needs_review=0
+
+ # Process the file with awk
+ awk '
+ BEGIN {
+ in_jobs = 0
+ job_count = 0
+ modified = 0
+ }
+
+ /^jobs:/ {
+ in_jobs = 1
+ print
+ next
+ }
+
+ # Match job definitions (2 spaces + name + colon)
+ in_jobs && /^ [a-z][a-z0-9_-]*:/ {
+ job_name = $0
+ print job_name
+ job_count++
+
+ # Look ahead for existing conditions
+ getline next_line
+
+ # Check if next line is already an if condition
+ if (next_line ~ /^ if:/) {
+ # Job already has condition - combine with fork detection
+ existing_condition = next_line
+ sub(/^ if: /, "", existing_condition)
+
+ # Check if fork condition already exists
+ if (existing_condition !~ /github\.event\.repository\.fork/) {
+ print " # Fork-friendly CI: Combined with existing condition"
+ print " if: (" existing_condition ") && (github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == '\''true'\'')"
+ modified++
+ } else {
+ # Already has fork detection
+ print next_line
+ }
+ } else if (next_line ~ /^ runs-on:/) {
+ # No condition exists, add before runs-on
+ print " if: github.event.repository.fork != true || vars.ENABLE_CI_IN_FORK == '\''true'\''"
+ print next_line
+ modified++
+ } else {
+ # Some other configuration, preserve as-is
+ print next_line
+ }
+ next
+ }
+
+ # Reset when leaving jobs section
+ /^[a-z]/ && in_jobs {
+ in_jobs = 0
+ }
+
+ # Print all other lines
+ {
+ if (!in_jobs) print
+ }
+
+ END {
+ if (modified > 0) {
+ exit 0 # Success - file was modified
+ } else {
+ exit 1 # No modifications needed
+ }
+ }
+ ' "$file" > "$temp_file"
+
+ # Check if modifications were made
+ if [ $? -eq 0 ]; then
+ mv "$temp_file" "$file"
+ echo -e "${GREEN}β${NC} Updated"
+ ((UPDATED_FILES++))
+ else
+ rm -f "$temp_file"
+ echo -e "${YELLOW}β${NC} No changes needed"
+ fi
+
+ # Check for complex conditions that might need manual review
+ if grep -q "needs:" "$file" || grep -q "strategy:" "$file"; then
+ echo " β οΈ Complex workflow detected - manual review recommended"
+ ((MANUAL_REVIEW_NEEDED++))
+ fi
+ fi
+done
+
+echo -e "${GREEN}β${NC} Updated ${UPDATED_FILES} workflow files"
+
+# 5. Create Fork Guide if it doesn't exist
+if [ ! -f ".github/FORK_GUIDE.md" ]; then
+ echo "π Creating Fork Guide documentation..."
+ cat > .github/FORK_GUIDE.md << 'EOF'
+# Fork Guide - CI/CD Configuration
+
+## CI/CD in Forks
+
+By default, CI/CD workflows are **disabled in forks** to conserve GitHub Actions resources.
+
+### Enabling CI/CD in Your Fork
+
+If you need to run CI/CD workflows in your fork:
+
+1. Navigate to **Settings** β **Secrets and variables** β **Actions** β **Variables**
+2. Click **New repository variable**
+3. Create variable:
+ - **Name**: `ENABLE_CI_IN_FORK`
+ - **Value**: `true`
+4. Click **Add variable**
+
+### Disabling CI/CD Again
+
+Either:
+- Delete the `ENABLE_CI_IN_FORK` variable, or
+- Set its value to `false`
+
+### Alternative Testing Options
+
+- **Local testing**: Run tests locally before pushing
+- **Pull Request CI**: Workflows automatically run when you open a PR
+- **GitHub Codespaces**: Full development environment
+EOF
+ echo -e "${GREEN}β${NC} Fork Guide created"
+else
+ echo "βΉοΈ Fork Guide already exists"
+fi
+
+# 6. Validate YAML files (if yamllint is available)
+if command -v yamllint &> /dev/null; then
+ echo "π Validating YAML syntax..."
+ VALIDATION_ERRORS=0
+ for file in .github/workflows/*.yml .github/workflows/*.yaml; do
+ if [ -f "$file" ]; then
+ filename=$(basename "$file")
+ if yamllint -d relaxed "$file" &>/dev/null; then
+ echo -e " ${GREEN}β${NC} ${filename}"
+ else
+ echo -e " ${RED}β${NC} ${filename} - YAML validation failed"
+ ((VALIDATION_ERRORS++))
+ fi
+ fi
+ done
+
+ if [ $VALIDATION_ERRORS -gt 0 ]; then
+ echo -e "${YELLOW}β ${NC} ${VALIDATION_ERRORS} files have YAML errors"
+ fi
+else
+ echo "βΉοΈ yamllint not found - skipping YAML validation"
+ echo " Install with: pip install yamllint"
+fi
+
+# 7. Summary
+echo ""
+echo "βββββββββββββββββββββββββββββββββββββββ"
+echo " Fork-Friendly CI/CD Summary"
+echo "βββββββββββββββββββββββββββββββββββββββ"
+echo " π Files updated: ${UPDATED_FILES}"
+echo " π Total workflows: ${WORKFLOW_COUNT}"
+echo " π Fork Guide: .github/FORK_GUIDE.md"
+if [ $MANUAL_REVIEW_NEEDED -gt 0 ]; then
+ echo " β οΈ Files needing review: ${MANUAL_REVIEW_NEEDED}"
+fi
+echo ""
+echo "Next steps:"
+echo "1. Review the changes: git diff"
+echo "2. Test workflows locally (if possible)"
+echo "3. Commit changes: git commit -m 'feat: implement fork-friendly CI/CD'"
+echo "4. Push and create PR"
+echo ""
+echo "Remember to update README.md with fork information!"
+echo "βββββββββββββββββββββββββββββββββββββββ"
+
+# Exit with appropriate code
+if [ $UPDATED_FILES -gt 0 ]; then
+ exit 0
+else
+ echo "No files were updated - workflows may already be fork-friendly"
+ exit 1
+fi
\ No newline at end of file
diff --git a/package.json b/package.json
index 3bbd7627..8033b6a8 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"build": "node tools/cli.js build",
"build:agents": "node tools/cli.js build --agents-only",
"build:teams": "node tools/cli.js build --teams-only",
+ "fix": "npm run format && npm run lint:fix",
"flatten": "node tools/flattener/main.js",
"format": "prettier --write \"**/*.{js,cjs,mjs,json,md,yaml}\"",
"format:check": "prettier --check \"**/*.{js,cjs,mjs,json,md,yaml}\"",
@@ -34,12 +35,14 @@
"lint": "eslint . --ext .js,.cjs,.mjs,.yaml --max-warnings=0",
"lint:fix": "eslint . --ext .js,.cjs,.mjs,.yaml --fix",
"list:agents": "node tools/cli.js list:agents",
+ "pre-release": "npm run validate && npm run format:check && npm run lint",
"prepare": "husky",
"preview:release": "node tools/preview-release-notes.js",
"release:major": "gh workflow run \"Manual Release\" -f version_bump=major",
"release:minor": "gh workflow run \"Manual Release\" -f version_bump=minor",
"release:patch": "gh workflow run \"Manual Release\" -f version_bump=patch",
"release:watch": "gh run watch",
+ "setup:hooks": "chmod +x tools/setup-hooks.sh && ./tools/setup-hooks.sh",
"validate": "node tools/cli.js validate",
"version:all": "node tools/bump-all-versions.js",
"version:all:major": "node tools/bump-all-versions.js major",
diff --git a/test.md b/test.md
new file mode 100644
index 00000000..8ae05696
--- /dev/null
+++ b/test.md
@@ -0,0 +1 @@
+# Test
diff --git a/tools/installer/bin/bmad.js b/tools/installer/bin/bmad.js
index 9457c8ac..705ad133 100755
--- a/tools/installer/bin/bmad.js
+++ b/tools/installer/bin/bmad.js
@@ -49,7 +49,7 @@ program
.option('-d, --directory ', 'Installation directory')
.option(
'-i, --ide ',
- 'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, iflow-cli, windsurf, trae, roo, kilo, cline, gemini, qwen-code, github-copilot, other)',
+ 'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, trae, roo, kilo, cline, gemini, qwen-code, github-copilot, codex, codex-web, iflow-cli, other)',
)
.option(
'-e, --expansion-packs ',
diff --git a/tools/installer/config/install.config.yaml b/tools/installer/config/install.config.yaml
index e8aa823e..fdadca10 100644
--- a/tools/installer/config/install.config.yaml
+++ b/tools/installer/config/install.config.yaml
@@ -130,3 +130,25 @@ ide-configurations:
# 2. It concatenates all agent files into a single QWEN.md file.
# 3. Simply mention the agent in your prompt (e.g., "As *dev, ...").
# 4. The Qwen Code CLI will automatically have the context for that agent.
+
+ codex:
+ name: Codex CLI
+ format: project-memory
+ file: AGENTS.md
+ instructions: |
+ # To use BMAD agents with Codex CLI:
+ # 1. The installer updates/creates AGENTS.md at your project root with BMAD agents and tasks.
+ # 2. Run `codex` in your project. Codex automatically reads AGENTS.md as project memory.
+ # 3. Mention agents in your prompt (e.g., "As dev, please implement ...") or reference tasks.
+ # 4. You can further customize global Codex behavior via ~/.codex/config.toml.
+
+ codex-web:
+ name: Codex Web Enabled
+ format: project-memory
+ file: AGENTS.md
+ instructions: |
+ # To enable BMAD agents for Codex Web (cloud):
+ # 1. The installer updates/creates AGENTS.md and ensures `.bmad-core` is NOT ignored by git.
+ # 2. Commit `.bmad-core/` and `AGENTS.md` to your repository.
+ # 3. Open the repo in Codex Web and reference agents naturally (e.g., "As dev, ...").
+ # 4. Re-run this installer to refresh agent sections when the core changes.
diff --git a/tools/installer/lib/ide-setup.js b/tools/installer/lib/ide-setup.js
index 5ca70575..a6525c48 100644
--- a/tools/installer/lib/ide-setup.js
+++ b/tools/installer/lib/ide-setup.js
@@ -77,6 +77,12 @@ class IdeSetup extends BaseIdeSetup {
case 'qwen-code': {
return this.setupQwenCode(installDir, selectedAgent);
}
+ case 'codex': {
+ return this.setupCodex(installDir, selectedAgent, { webEnabled: false });
+ }
+ case 'codex-web': {
+ return this.setupCodex(installDir, selectedAgent, { webEnabled: true });
+ }
default: {
console.log(chalk.yellow(`\nIDE ${ide} not yet supported`));
return false;
@@ -84,6 +90,175 @@ class IdeSetup extends BaseIdeSetup {
}
}
+ async setupCodex(installDir, selectedAgent, options) {
+ options = options ?? { webEnabled: false };
+ // Codex reads AGENTS.md at the project root as project memory (CLI & Web).
+ // Inject/update a BMAD section with guidance, directory, and details.
+ const filePath = path.join(installDir, 'AGENTS.md');
+ const startMarker = '';
+ const endMarker = '';
+
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
+ const tasks = await this.getAllTaskIds(installDir);
+
+ // Build BMAD section content
+ let section = '';
+ section += `${startMarker}\n`;
+ section += `# BMAD-METHOD Agents and Tasks\n\n`;
+ section += `This section is auto-generated by BMAD-METHOD for Codex. Codex merges this AGENTS.md into context.\n\n`;
+ section += `## How To Use With Codex\n\n`;
+ section += `- Codex CLI: run \`codex\` in this project. Reference an agent naturally, e.g., "As dev, implement ...".\n`;
+ section += `- Codex Web: open this repo and reference roles the same way; Codex reads \`AGENTS.md\`.\n`;
+ section += `- Commit \`.bmad-core\` and this \`AGENTS.md\` file to your repo so Codex (Web/CLI) can read full agent definitions.\n`;
+ section += `- Refresh this section after agent updates: \`npx bmad-method install -f -i codex\`.\n\n`;
+
+ section += `### Helpful Commands\n\n`;
+ section += `- List agents: \`npx bmad-method list:agents\`\n`;
+ section += `- Reinstall BMAD core and regenerate AGENTS.md: \`npx bmad-method install -f -i codex\`\n`;
+ section += `- Validate configuration: \`npx bmad-method validate\`\n\n`;
+
+ // Agents directory table
+ section += `## Agents\n\n`;
+ section += `### Directory\n\n`;
+ section += `| Title | ID | When To Use |\n|---|---|---|\n`;
+ const agentSummaries = [];
+ for (const agentId of agents) {
+ const agentPath = await this.findAgentPath(agentId, installDir);
+ if (!agentPath) continue;
+ const raw = await fileManager.readFile(agentPath);
+ const yamlMatch = raw.match(/```ya?ml\r?\n([\s\S]*?)```/);
+ const yamlBlock = yamlMatch ? yamlMatch[1].trim() : null;
+ const title = await this.getAgentTitle(agentId, installDir);
+ const whenToUse = yamlBlock?.match(/whenToUse:\s*"?([^\n"]+)"?/i)?.[1]?.trim() || '';
+ agentSummaries.push({ agentId, title, whenToUse, yamlBlock, raw, path: agentPath });
+ section += `| ${title} | ${agentId} | ${whenToUse || 'β'} |\n`;
+ }
+ section += `\n`;
+
+ // Detailed agent sections
+ for (const { agentId, title, whenToUse, yamlBlock, raw, path: agentPath } of agentSummaries) {
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
+ section += `### ${title} (id: ${agentId})\n`;
+ section += `Source: ${relativePath}\n\n`;
+ if (whenToUse) section += `- When to use: ${whenToUse}\n`;
+ section += `- How to activate: Mention "As ${agentId}, ..." or "Use ${title} to ..."\n\n`;
+ if (yamlBlock) {
+ section += '```yaml\n' + yamlBlock + '\n```\n\n';
+ } else {
+ section += '```md\n' + raw.trim() + '\n```\n\n';
+ }
+ }
+
+ // Tasks
+ if (tasks && tasks.length > 0) {
+ section += `## Tasks\n\n`;
+ section += `These are reusable task briefs you can reference directly in Codex.\n\n`;
+ for (const taskId of tasks) {
+ const taskPath = await this.findTaskPath(taskId, installDir);
+ if (!taskPath) continue;
+ const raw = await fileManager.readFile(taskPath);
+ const relativePath = path.relative(installDir, taskPath).replaceAll('\\', '/');
+ section += `### Task: ${taskId}\n`;
+ section += `Source: ${relativePath}\n`;
+ section += `- How to use: "Use task ${taskId} with the appropriate agent" and paste relevant parts as needed.\n\n`;
+ section += '```md\n' + raw.trim() + '\n```\n\n';
+ }
+ }
+
+ section += `${endMarker}\n`;
+
+ // Write or update AGENTS.md
+ let finalContent = '';
+ if (await fileManager.pathExists(filePath)) {
+ const existing = await fileManager.readFile(filePath);
+ if (existing.includes(startMarker) && existing.includes(endMarker)) {
+ // Replace existing BMAD block
+ const pattern = String.raw`${startMarker}[\s\S]*?${endMarker}`;
+ const replaced = existing.replace(new RegExp(pattern, 'm'), section);
+ finalContent = replaced;
+ } else {
+ // Append BMAD block to existing file
+ finalContent = existing.trimEnd() + `\n\n` + section;
+ }
+ } else {
+ // Create fresh AGENTS.md with a small header and BMAD block
+ finalContent += '# Project Agents\n\n';
+ finalContent += 'This file provides guidance and memory for Codex CLI.\n\n';
+ finalContent += section;
+ }
+
+ await fileManager.writeFile(filePath, finalContent);
+ console.log(chalk.green('β Created/updated AGENTS.md for Codex CLI integration'));
+ console.log(
+ chalk.dim(
+ 'Codex reads AGENTS.md automatically. Run `codex` in this project to use BMAD agents.',
+ ),
+ );
+
+ // Optionally add helpful npm scripts if a package.json exists
+ try {
+ const pkgPath = path.join(installDir, 'package.json');
+ if (await fileManager.pathExists(pkgPath)) {
+ const pkgRaw = await fileManager.readFile(pkgPath);
+ const pkg = JSON.parse(pkgRaw);
+ pkg.scripts = pkg.scripts || {};
+ const updated = { ...pkg.scripts };
+ if (!updated['bmad:refresh']) updated['bmad:refresh'] = 'bmad-method install -f -i codex';
+ if (!updated['bmad:list']) updated['bmad:list'] = 'bmad-method list:agents';
+ if (!updated['bmad:validate']) updated['bmad:validate'] = 'bmad-method validate';
+ const changed = JSON.stringify(updated) !== JSON.stringify(pkg.scripts);
+ if (changed) {
+ const newPkg = { ...pkg, scripts: updated };
+ await fileManager.writeFile(pkgPath, JSON.stringify(newPkg, null, 2) + '\n');
+ console.log(chalk.green('β Added npm scripts: bmad:refresh, bmad:list, bmad:validate'));
+ }
+ }
+ } catch {
+ console.log(
+ chalk.yellow('β οΈ Skipped adding npm scripts (package.json not writable or invalid)'),
+ );
+ }
+
+ // Adjust .gitignore behavior depending on Codex mode
+ try {
+ const gitignorePath = path.join(installDir, '.gitignore');
+ const ignoreLines = ['# BMAD (local only)', '.bmad-core/', '.bmad-*/'];
+ const exists = await fileManager.pathExists(gitignorePath);
+ if (options.webEnabled) {
+ if (exists) {
+ let gi = await fileManager.readFile(gitignorePath);
+ // Remove lines that ignore BMAD dot-folders
+ const updated = gi
+ .split(/\r?\n/)
+ .filter((l) => !/^\s*\.bmad-core\/?\s*$/.test(l) && !/^\s*\.bmad-\*\/?\s*$/.test(l))
+ .join('\n');
+ if (updated !== gi) {
+ await fileManager.writeFile(gitignorePath, updated.trimEnd() + '\n');
+ console.log(chalk.green('β Updated .gitignore to include .bmad-core in commits'));
+ }
+ }
+ } else {
+ // Local-only: add ignores if missing
+ let base = exists ? await fileManager.readFile(gitignorePath) : '';
+ const haveCore = base.includes('.bmad-core/');
+ const haveStar = base.includes('.bmad-*/');
+ if (!haveCore || !haveStar) {
+ const sep = base.endsWith('\n') || base.length === 0 ? '' : '\n';
+ const add = [!haveCore || !haveStar ? ignoreLines.join('\n') : '']
+ .filter(Boolean)
+ .join('\n');
+ const out = base + sep + add + '\n';
+ await fileManager.writeFile(gitignorePath, out);
+ console.log(chalk.green('β Added .bmad-core/* to .gitignore for local-only Codex setup'));
+ }
+ }
+ } catch {
+ console.log(chalk.yellow('β οΈ Could not update .gitignore (skipping)'));
+ }
+
+ return true;
+ }
+
async setupCursor(installDir, selectedAgent) {
const cursorRulesDir = path.join(installDir, '.cursor', 'rules', 'bmad');
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
diff --git a/tools/setup-hooks.sh b/tools/setup-hooks.sh
new file mode 100755
index 00000000..f8838508
--- /dev/null
+++ b/tools/setup-hooks.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# Setup script for git hooks
+echo "Setting up git hooks..."
+
+# Install husky
+npm install --save-dev husky
+
+# Initialize husky
+npx husky init
+
+# Create pre-commit hook
+cat > .husky/pre-commit << 'EOF'
+#!/usr/bin/env sh
+. "$(dirname -- "$0")/_/husky.sh"
+
+# Run validation checks before commit
+echo "Running pre-commit checks..."
+
+npm run validate
+npm run format:check
+npm run lint
+
+if [ $? -ne 0 ]; then
+ echo "β Pre-commit checks failed. Please fix the issues before committing."
+ echo " Run 'npm run format' to fix formatting issues"
+ echo " Run 'npm run lint:fix' to fix some lint issues"
+ exit 1
+fi
+
+echo "β
Pre-commit checks passed!"
+EOF
+
+chmod +x .husky/pre-commit
+
+echo "β
Git hooks setup complete!"
+echo "Now commits will be validated before they're created."
\ No newline at end of file