diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index e28eac969..fa136be49 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -6,7 +6,6 @@ on: - main paths: - "docs/**" - - "src/modules/*/docs/**" - "website/**" - "tools/build-docs.mjs" - ".github/workflows/docs.yaml" @@ -19,6 +18,7 @@ permissions: concurrency: group: "pages" + # No big win in setting this to true — risk of cancelling a deploy mid-flight. cancel-in-progress: false jobs: @@ -28,12 +28,13 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: + # Full history needed for Starlight's lastUpdated timestamps (git log) fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: "20" + node-version-file: ".nvmrc" cache: "npm" - name: Install dependencies diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml index 65194558f..78023e466 100644 --- a/.github/workflows/quality.yaml +++ b/.github/workflows/quality.yaml @@ -84,10 +84,8 @@ jobs: - name: Install dependencies run: npm ci - - name: Validate documentation links - run: npm run docs:validate-links - - name: Build documentation + # Note: build-docs.mjs runs link validation internally before building run: npm run docs:build validate: diff --git a/README.md b/README.md index 6e1f3a9b0..e36d6e36a 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Follow the installer prompts, then open your AI IDE (Claude Code, Cursor, Windsu npx bmad-method install --directory /path/to/project --modules bmm --tools claude-code --yes ``` -See [Non-Interactive Installation Guide](docs/non-interactive-installation.md) for all available options. +See [Non-Interactive Installation Guide](http://docs.bmad-method.org/how-to/non-interactive-installation/) for all available options. > **Not sure what to do?** Run `/bmad-help` — it tells you exactly what's next and what's optional. You can also ask it questions like: diff --git a/docs/404.md b/docs/404.md index b42841e9b..ccaea4eff 100644 --- a/docs/404.md +++ b/docs/404.md @@ -6,4 +6,4 @@ template: splash The page you're looking for doesn't exist or has been moved. -[Return to Home](/docs/index.md) +[Return to Home](./index.md) diff --git a/docs/bmgd/bmgd-logo.png b/docs/bmgd/bmgd-logo.png deleted file mode 100644 index 8dcdd1254..000000000 Binary files a/docs/bmgd/bmgd-logo.png and /dev/null differ diff --git a/docs/bmgd/game-types.md b/docs/bmgd/game-types.md deleted file mode 100644 index 87870ea10..000000000 --- a/docs/bmgd/game-types.md +++ /dev/null @@ -1,376 +0,0 @@ ---- -title: "Game Types Reference" -description: 24 game type templates with genre-specific GDD sections for BMGD -draft: true ---- - -BMGD supports 24 game type templates. Each adds genre-specific sections to your GDD. - -## Game Types - -### Action & Combat - -#### Action Platformer - -Side-scrolling or 3D platforming with combat mechanics. - -**Examples:** Hollow Knight, Mega Man, Celeste - -**GDD sections:** - -- Movement systems (jumps, dashes, wall mechanics) -- Combat mechanics (melee/ranged, combos) -- Level design patterns -- Boss design - -#### Shooter - -Projectile combat with aiming mechanics. - -**Examples:** Doom, Call of Duty, Splatoon - -**GDD sections:** - -- Weapon systems -- Aiming and accuracy -- Enemy AI patterns -- Level/arena design -- Multiplayer considerations - -#### Fighting - -1v1 combat with combos and frame data. - -**Examples:** Street Fighter, Tekken, Super Smash Bros. - -**GDD sections:** - -- Frame data systems -- Combo mechanics -- Character movesets -- Competitive balance -- Netcode requirements - -### Strategy & Tactics - -#### Strategy - -Resource management with tactical decisions. - -**Examples:** StarCraft, Civilization, Europa Universalis - -**GDD sections:** - -- Resource systems -- Unit/building design -- AI opponent behavior -- Map/scenario design -- Victory conditions - -#### Turn-Based Tactics - -Grid-based movement with turn order. - -**Examples:** XCOM, Fire Emblem, Into the Breach - -**GDD sections:** - -- Grid and movement systems -- Turn order mechanics -- Cover and positioning -- Unit progression -- Procedural mission generation - -#### Tower Defense - -Wave-based defense with tower placement. - -**Examples:** Bloons TD, Kingdom Rush, Plants vs. Zombies - -**GDD sections:** - -- Tower types and upgrades -- Wave design and pacing -- Economy systems -- Map design patterns -- Meta-progression - -### RPG & Progression - -#### RPG - -Character progression with stats, inventory, and quests. - -**Examples:** Final Fantasy, The Witcher, Baldur's Gate - -**GDD sections:** - -- Character stats and leveling -- Inventory and equipment -- Quest system design -- Combat system (action/turn-based) -- Skill trees and builds - -#### Roguelike - -Procedural generation with permadeath and run-based progression. - -**Examples:** Hades, Dead Cells, Spelunky - -**GDD sections:** - -- Procedural generation rules -- Permadeath and persistence -- Run structure and pacing -- Item/ability synergies -- Meta-progression systems - -#### Metroidvania - -Interconnected world with ability gating. - -**Examples:** Metroid, Castlevania: Symphony of the Night, Ori - -**GDD sections:** - -- World map connectivity -- Ability gating design -- Backtracking flow -- Secret and collectible placement -- Power-up progression - -### Narrative & Story - -#### Adventure - -Story-driven exploration with puzzle elements. - -**Examples:** Monkey Island, Myst, Life is Strange - -**GDD sections:** - -- Puzzle design -- Narrative delivery -- Exploration mechanics -- Dialogue systems -- Story branching - -#### Visual Novel - -Narrative choices with branching story. - -**Examples:** Doki Doki Literature Club, Phoenix Wright, Steins;Gate - -**GDD sections:** - -- Branching narrative structure -- Choice and consequence -- Character routes -- UI/presentation -- Save/load states - -#### Text-Based - -Text input/output games with parser or choice mechanics. - -**Examples:** Zork, 80 Days, Dwarf Fortress (adventure mode) - -**GDD sections:** - -- Parser or choice systems -- World model -- Narrative structure -- Text presentation -- Save state management - -### Simulation & Management - -#### Simulation - -Realistic systems with management and building. - -**Examples:** SimCity, RollerCoaster Tycoon, The Sims - -**GDD sections:** - -- Core simulation loops -- Economy modeling -- AI agents/citizens -- Building/construction -- Failure states - -#### Sandbox - -Creative freedom with building and minimal objectives. - -**Examples:** Minecraft, Terraria, Garry's Mod - -**GDD sections:** - -- Creation tools -- Physics/interaction systems -- Persistence and saving -- Sharing/community features -- Optional objectives - -### Sports & Racing - -#### Racing - -Vehicle control with tracks and lap times. - -**Examples:** Mario Kart, Forza, Need for Speed - -**GDD sections:** - -- Vehicle physics model -- Track design -- AI opponents -- Progression/career mode -- Multiplayer racing - -#### Sports - -Team-based or individual sports simulation. - -**Examples:** FIFA, NBA 2K, Tony Hawk's Pro Skater - -**GDD sections:** - -- Sport-specific rules -- Player/team management -- AI opponent behavior -- Season/career modes -- Multiplayer modes - -### Multiplayer - -#### MOBA - -Multiplayer team battles with hero selection. - -**Examples:** League of Legends, Dota 2, Smite - -**GDD sections:** - -- Hero/champion design -- Lane and map design -- Team composition -- Matchmaking -- Economy (gold/items) - -#### Party Game - -Local multiplayer with minigames. - -**Examples:** Mario Party, Jackbox, Overcooked - -**GDD sections:** - -- Minigame design patterns -- Controller support -- Round/game structure -- Scoring systems -- Player count flexibility - -### Horror & Survival - -#### Survival - -Resource gathering with crafting and persistent threats. - -**Examples:** Don't Starve, Subnautica, The Forest - -**GDD sections:** - -- Resource gathering -- Crafting systems -- Hunger/health/needs -- Threat systems -- Base building - -#### Horror - -Atmosphere and tension with limited resources. - -**Examples:** Resident Evil, Silent Hill, Amnesia - -**GDD sections:** - -- Fear mechanics -- Resource scarcity -- Sound design -- Lighting and visibility -- Enemy/threat design - -### Casual & Progression - -#### Puzzle - -Logic-based challenges and problem-solving. - -**Examples:** Tetris, Portal, The Witness - -**GDD sections:** - -- Puzzle mechanics -- Difficulty progression -- Hint systems -- Level structure -- Scoring/rating - -#### Idle/Incremental - -Passive progression with upgrades and automation. - -**Examples:** Cookie Clicker, Adventure Capitalist, Clicker Heroes - -**GDD sections:** - -- Core loop design -- Prestige systems -- Automation unlocks -- Number scaling -- Offline progress - -#### Card Game - -Deck building with card mechanics. - -**Examples:** Slay the Spire, Hearthstone, Magic: The Gathering Arena - -**GDD sections:** - -- Card design framework -- Deck building rules -- Mana/resource systems -- Rarity and collection -- Competitive balance - -### Rhythm - -#### Rhythm - -Music synchronization with timing-based gameplay. - -**Examples:** Guitar Hero, Beat Saber, Crypt of the NecroDancer - -**GDD sections:** - -- Note/beat mapping -- Scoring systems -- Difficulty levels -- Music licensing -- Input methods - -## Hybrid Types - -Multiple game types can be combined. GDD sections from all selected types are included. - -| Hybrid | Components | Combined Sections | -|--------|------------|-------------------| -| Action RPG | Action Platformer + RPG | Movement, combat, stats, inventory | -| Survival Horror | Survival + Horror | Resources, crafting, atmosphere, fear | -| Roguelike Deckbuilder | Roguelike + Card Game | Run structure, procedural gen, cards | -| Tactical RPG | Turn-Based Tactics + RPG | Grid movement, stats, progression | -| Open World Survival | Sandbox + Survival | Building, crafting, exploration | diff --git a/docs/bmgd/index.md b/docs/bmgd/index.md deleted file mode 100644 index bd1565c12..000000000 --- a/docs/bmgd/index.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: "BMGD Quick Guide" -description: Quick reference for BMad Game Dev Studio -draft: true ---- - -![BMGD Logo](bmgd-logo.png) - -# BMGD Quick Guide - -BMad Game Dev Studio (BMGD) extends BMM with game-specific capabilities. Developed by game industry veterans, it guides you through product research, technical design, narrative design, and a full epic-driven production cycle. - -## Under Construction - -Documentation is under heavy construction catching up with the new beta release. We'll have complete documentation up as soon as possible. For now, please ask in the BMGD section of the Discord if you have any questions. - -![BMGD Workflow](workflow.jpg) - -## Quick Start - -**Install → Game Brief → GDD → (Narrative) → Architecture → Build** - -BMGD is an optional module installed via BMAD Method: `npx bmad-method install` - -See [How-To Reference](#how-to-reference) for commands. - -## Development Phases - -| Phase | Name | Key Activities | -|-------|------|----------------| -| 1 | **Preproduction** | Brainstorm Game, Game Brief, market research | -| 2 | **Design** | GDD creation, Narrative Design (for story-driven games) | -| 3 | **Technical** | Game Architecture (engine, systems, patterns) | -| 4 | **Production** | Sprint planning, story development, code review, testing | - -## BMGD Agents - -| Agent | Purpose | -|-------|---------| -| Game Designer | Game mechanics, balance, player psychology | -| Game Developer | Implementation with engine-specific patterns | -| Game Architect | Engine selection, systems design, technical structure | -| Game Scrum Master | Sprint planning and epic management | -| Game QA | Playtesting, engine-specific testing, performance profiling | -| Game Solo Dev | Full-stack game development for solo projects | - -## Key Documents - -| Document | Purpose | -|----------|---------| -| **Game Brief** | Vision, market positioning, fundamentals | -| **GDD** | Core loop, mechanics, progression, art/audio direction | -| **Narrative Design** | Story structure, characters, world-building, dialogue | -| **Architecture** | Engine, systems, patterns, project structure | - -## Game Type Templates - -BMGD includes 24 game type templates that auto-configure GDD sections: - -Action, Adventure, Puzzle, RPG, Strategy, Simulation, Sports, Racing, Fighting, Horror, Platformer, Shooter, and more. - -Each template provides genre-specific GDD sections, mechanics patterns, testing considerations, and common pitfalls to avoid. - -## Explanation: BMGD vs BMM - -### When to Use Each - -| Use BMGD for | Use BMM for | -|--------------|-------------| -| Video games | Web applications | -| Interactive experiences | APIs and services | -| Game prototyping | Mobile apps (non-game) | -| Game jams | General software projects | - -### Phase Mapping - -| BMM Phase | BMGD Phase | Key Difference | -|-----------|------------|----------------| -| Analysis | Preproduction | Game concepts, Game Brief instead of Product Brief | -| Planning | Design | GDD instead of PRD; optional Narrative Design | -| Solutioning | Technical | Focus on engine selection, game-specific patterns | -| Implementation | Production | Game QA replaces TEA; engine-specific testing | - -### Document Differences - -| BMM | BMGD | Notes | -|-----|------|-------| -| Product Brief | Game Brief | Captures vision, market, fundamentals | -| PRD | GDD | Includes mechanics, balance, player experience | -| N/A | Narrative Design | Story, characters, world (story-driven games) | -| Architecture | Architecture | BMGD version includes engine-specific patterns and considerations | - -### Testing Differences - -**BMM (TEA):** Web-focused testing with Playwright, Cypress, API testing, E2E for web apps. - -**BMGD (Game QA):** Engine-specific frameworks (Unity, Unreal, Godot), gameplay testing, performance profiling, playtest planning, balance validation. - -## How-To Reference - -| I need to... | Action | -|--------------|--------------------------------------------------------------------------------------------------------| -| Install BMGD | Run `npx bmad-method install` and select BMGD during module installation | -| Start a new game | Run `/bmad-gds-brainstorm-game`, then `/bmad:gds:create-game-brief` | -| Design my game | Run `/bmad-gds-create-gdd`; add `/bmad:gds:narrative` if story-heavy | -| Plan architecture | Run `/bmad-gds-game-architecture` with Game Architect | -| Build my game | Use Phase 4 production workflows - Run `/bmad-help` to see what's next | -| Test an idea quickly | Use [Quick-Flow](quick-flow-workflows.md) for rapid prototyping | - -## Further Reading - -- [Game Types Guide](game-types.md) -- [Quick-Flow Guide](quick-flow-workflows.md) diff --git a/docs/bmgd/quick-flow-workflows.md b/docs/bmgd/quick-flow-workflows.md deleted file mode 100644 index 239f263a6..000000000 --- a/docs/bmgd/quick-flow-workflows.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -title: "Quick Flow Workflows" -description: Create tech specs and execute implementations with BMGD Quick Flow -draft: true ---- - -How to create tech specs and execute implementations with Quick Flow. - -## Choosing a Workflow - -| Situation | Workflow | Command | -|-----------|----------|---------| -| Need to document before implementing | Quick-Spec | `/bmad-gds-quick-spec` | -| Multiple approaches to evaluate | Quick-Spec | `/bmad-gds-quick-spec` | -| Have a completed tech-spec | Quick-Dev | `/bmad-gds-quick-dev path/to/spec.md` | -| Have clear, direct instructions | Quick-Dev | `/bmad-gds-quick-dev` | -| Building complete game system | Full GDS | `/bmad-gds-workflow-init` | -| Epic-level features | Full GDS | `/bmad-gds-workflow-init` | - ---- - -## How to Create a Tech Spec (Quick-Spec) - -### Step 1: Start the workflow - -```bash -/bmad-gds-quick-spec -``` - -### Step 2: Describe your requirement - -Provide your feature request. The agent scans the codebase and asks clarifying questions. - -**Checkpoint options:** -- `[a]` Advanced Elicitation - explore requirements deeper -- `[c]` Continue to investigation -- `[p]` Party Mode - consult expert agents - -### Step 3: Review investigation findings - -The agent analyzes the codebase for patterns, constraints, and similar implementations. Review the findings. - -**Checkpoint options:** -- `[c]` Continue to spec generation -- `[p]` Party Mode - get technical review - -### Step 4: Review generated spec - -The agent creates an ordered task list with file paths and acceptance criteria. Verify completeness. - -**Checkpoint options:** -- `[c]` Continue to final review -- `[p]` Party Mode - technical review - -### Step 5: Finalize - -Confirm the spec meets these standards: -- Every task has a file path and specific action -- Tasks ordered by dependency -- Acceptance criteria in Given/When/Then format -- No placeholders or TBD sections - -**Options:** -- `[d]` Start Quick-Dev immediately -- `[done]` Save spec and exit - -**Output:** `{planning_artifacts}/tech-spec-{slug}.md` - ---- - -## How to Execute Implementation (Quick-Dev) - -### With a Tech-Spec - -```bash -/bmad-gds-quick-dev path/to/tech-spec-feature.md -``` - -The agent: -1. Captures baseline git commit -2. Loads and validates the spec -3. Executes tasks in order -4. Runs self-check -5. Performs adversarial review -6. Resolves findings -7. Validates against acceptance criteria - -### With Direct Instructions - -```bash -/bmad-gds-quick-dev -``` - -Then describe what you want implemented: -1. Captures baseline git commit -2. Evaluates complexity (may suggest planning) -3. Gathers context from codebase -4. Executes implementation -5. Runs self-check and adversarial review -6. Resolves findings - -**Escalation:** If the agent detects complexity (multiple components, system-level scope, uncertainty), it offers: -- `[t]` Create tech-spec first -- `[w]` Use full GDS workflow -- `[e]` Execute anyway - ---- - -## Troubleshooting - -### Spec has placeholders or TBD sections - -Return to investigation step. Complete missing research, inline all findings, re-run review. - -### Workflow lost context mid-step - -Check frontmatter for `stepsCompleted`. Resume from last completed step. - -### Agent suggested planning but you want to execute - -You can override with `[e]`, but document your assumptions. Escalation heuristics exist because planning saves time on complex tasks. - -### Tests failing after implementation - -Return to the resolve-findings step. Review failures, fix issues, ensure test expectations are correct, re-run full suite. - -### Need help - -```bash -/bmad-help -``` - ---- - -## Reference - -### File Locations - -| File | Location | -|------|----------| -| Work in progress | `{implementation_artifacts}/tech-spec-wip.md` | -| Completed specs | `{planning_artifacts}/tech-spec-{slug}.md` | -| Archived specs | `{implementation_artifacts}/tech-spec-{slug}-archived-{date}.md` | -| Workflow files | `_bmad/gds/workflows/gds-quick-flow/` | - -### Validation Criteria - -**Self-check (before adversarial review):** -- All tasks/instructions completed -- Tests written and passing -- Follows existing patterns -- No obvious bugs -- Acceptance criteria met -- Code is readable - -**Adversarial review:** -- Correctness -- Security -- Performance -- Maintainability -- Test coverage -- Error handling diff --git a/docs/bmgd/workflow.jpg b/docs/bmgd/workflow.jpg deleted file mode 100644 index 5761f085e..000000000 Binary files a/docs/bmgd/workflow.jpg and /dev/null differ diff --git a/docs/explanation/advanced-elicitation.md b/docs/explanation/advanced-elicitation.md index c7ca5bcf1..15888e51c 100644 --- a/docs/explanation/advanced-elicitation.md +++ b/docs/explanation/advanced-elicitation.md @@ -1,11 +1,17 @@ --- title: "Advanced Elicitation" description: Push the LLM to rethink its work using structured reasoning methods +sidebar: + order: 6 --- Make the LLM reconsider what it just generated. You pick a reasoning method, it applies that method to its own output, you decide whether to keep the improvements. -Dozens of methods are built in - things like First Principles, Red Team vs Blue Team, Pre-mortem Analysis, Socratic Questioning, and more. +## What is Advanced Elicitation? + +A structured second pass. Instead of asking the AI to "try again" or "make it better," you select a specific reasoning method and the AI re-examines its own output through that lens. + +The difference matters. Vague requests produce vague revisions. A named method forces a particular angle of attack, surfacing insights that a generic retry would miss. ## When to Use It @@ -22,3 +28,22 @@ Workflows offer advanced elicitation at decision points - after the LLM has gene 2. You pick one (or reshuffle for different options) 3. Method is applied, improvements shown 4. Accept or discard, repeat or continue + +## Built-in Methods + +Dozens of reasoning methods are available. A few examples: + +- **Pre-mortem Analysis** - Assume the project already failed, work backward to find why +- **First Principles Thinking** - Strip away assumptions, rebuild from ground truth +- **Inversion** - Ask how to guarantee failure, then avoid those things +- **Red Team vs Blue Team** - Attack your own work, then defend it +- **Socratic Questioning** - Challenge every claim with "why?" and "how do you know?" +- **Constraint Removal** - Drop all constraints, see what changes, add them back selectively +- **Stakeholder Mapping** - Re-evaluate from each stakeholder's perspective +- **Analogical Reasoning** - Find parallels in other domains and apply their lessons + +And many more. The AI picks the most relevant options for your content - you choose which to run. + +:::tip[Start Here] +Pre-mortem Analysis is a good first pick for any spec or plan. It consistently finds gaps that a standard review misses. +::: diff --git a/docs/explanation/adversarial-review.md b/docs/explanation/adversarial-review.md index 4543616ec..85a8c600d 100644 --- a/docs/explanation/adversarial-review.md +++ b/docs/explanation/adversarial-review.md @@ -1,6 +1,8 @@ --- title: "Adversarial Review" description: Forced reasoning technique that prevents lazy "looks good" reviews +sidebar: + order: 5 --- Force deeper analysis by requiring problems to be found. @@ -24,7 +26,7 @@ Normal reviews suffer from confirmation bias. You skim the work, nothing jumps o ## Where It's Used -Adversarial review appears throughout BMAD workflows - code review, implementation readiness checks, spec validation, and others. Sometimes it's a required step, sometimes optional (like advanced elicitation or party mode). The pattern adapts to whatever artifact needs scrutiny. +Adversarial review appears throughout BMad workflows - code review, implementation readiness checks, spec validation, and others. Sometimes it's a required step, sometimes optional (like advanced elicitation or party mode). The pattern adapts to whatever artifact needs scrutiny. ## Human Filtering Required diff --git a/docs/explanation/brainstorming.md b/docs/explanation/brainstorming.md index f4301b2ff..51aa80e22 100644 --- a/docs/explanation/brainstorming.md +++ b/docs/explanation/brainstorming.md @@ -1,6 +1,8 @@ --- title: "Brainstorming" description: Interactive creative sessions using 60+ proven ideation techniques +sidebar: + order: 2 --- Unlock your creativity through guided exploration. diff --git a/docs/explanation/established-projects-faq.md b/docs/explanation/established-projects-faq.md index e940b4dbb..fe217fcdd 100644 --- a/docs/explanation/established-projects-faq.md +++ b/docs/explanation/established-projects-faq.md @@ -1,6 +1,8 @@ --- title: "Established Projects FAQ" description: Common questions about using BMad Method on established projects +sidebar: + order: 8 --- Quick answers to common questions about working on established projects with the BMad Method (BMM). diff --git a/docs/explanation/party-mode.md b/docs/explanation/party-mode.md index 5e9dbaa9e..fe25f197d 100644 --- a/docs/explanation/party-mode.md +++ b/docs/explanation/party-mode.md @@ -1,6 +1,8 @@ --- title: "Party Mode" description: Multi-agent collaboration - get all your AI agents in one conversation +sidebar: + order: 7 --- Get all your AI agents in one conversation. diff --git a/docs/explanation/preventing-agent-conflicts.md b/docs/explanation/preventing-agent-conflicts.md index 4516ef6c7..e611f1c3a 100644 --- a/docs/explanation/preventing-agent-conflicts.md +++ b/docs/explanation/preventing-agent-conflicts.md @@ -1,6 +1,8 @@ --- title: "Preventing Agent Conflicts" description: How architecture prevents conflicts when multiple agents implement a system +sidebar: + order: 4 --- When multiple AI agents implement different parts of a system, they can make conflicting technical decisions. Architecture documentation prevents this by establishing shared standards. @@ -69,7 +71,7 @@ Explicit documentation of: Think of architecture as the shared context that all agents read before implementing: -``` +```text PRD: "What to build" ↓ Architecture: "How to build it" diff --git a/docs/explanation/quick-flow.md b/docs/explanation/quick-flow.md index 9b6e4ea71..6751feee0 100644 --- a/docs/explanation/quick-flow.md +++ b/docs/explanation/quick-flow.md @@ -1,27 +1,73 @@ --- title: "Quick Flow" description: Fast-track for small changes - skip the full methodology +sidebar: + order: 1 --- -Quick Flow is for when you don't need the full BMad Method. Skip Product Brief, PRD, and Architecture - go straight to implementation. - -## How It Works - -1. **Run `quick-spec`** — generates a focused tech-spec -2. **Run `quick-dev`** — implements it - -That's it. +Skip the ceremony. Quick Flow takes you from idea to working code in two commands - no Product Brief, no PRD, no Architecture doc. ## When to Use It -- Bug fixes -- Refactoring -- Small features -- Prototyping +- Bug fixes and patches +- Refactoring existing code +- Small, well-understood features +- Prototyping and spikes +- Single-agent work where one developer can hold the full scope -## When to Use Full BMad Method Instead +## When NOT to Use It -- New products -- Major features -- Multiple teams involved -- Stakeholder alignment needed +- New products or platforms that need stakeholder alignment +- Major features spanning multiple components or teams +- Work that requires architectural decisions (database schema, API contracts, service boundaries) +- Anything where requirements are unclear or contested + +:::caution[Scope Creep] +If you start a Quick Flow and realize the scope is bigger than expected, `quick-dev` will detect this and offer to escalate. You can switch to a full PRD workflow at any point without losing your work. +::: + +## How It Works + +Quick Flow has two commands, each backed by a structured workflow. You can run them together or independently. + +### quick-spec: Plan + +Run `quick-spec` and Barry (the Quick Flow agent) walks you through a conversational discovery process: + +1. **Understand** - You describe what you want to build. Barry scans the codebase to ask informed questions, then captures a problem statement, solution approach, and scope boundaries. +2. **Investigate** - Barry reads relevant files, maps code patterns, identifies files to modify, and documents the technical context. +3. **Generate** - Produces a complete tech-spec with ordered implementation tasks (specific file paths and actions), acceptance criteria in Given/When/Then format, testing strategy, and dependencies. +4. **Review** - Presents the full spec for your sign-off. You can edit, ask questions, run adversarial review, or refine with advanced elicitation before finalizing. + +The output is a `tech-spec-{slug}.md` file saved to your project's implementation artifacts folder. It contains everything a fresh agent needs to implement the feature - no conversation history required. + +### quick-dev: Build + +Run `quick-dev` and Barry implements the work. It operates in two modes: + +- **Tech-spec mode** - Point it at a spec file (`quick-dev tech-spec-auth.md`) and it executes every task in order, writes tests, and verifies acceptance criteria. +- **Direct mode** - Give it instructions directly (`quick-dev "refactor the auth middleware"`) and it gathers context, builds a mental plan, and executes. + +After implementation, `quick-dev` runs a self-check audit against all tasks and acceptance criteria, then triggers an adversarial code review of the diff. Findings are presented for you to resolve before wrapping up. + +:::tip[Fresh Context] +For best results, run `quick-dev` in a new conversation after finishing `quick-spec`. This gives the implementation agent clean context focused solely on building. +::: + +## What Quick Flow Skips + +The full BMad Method produces a Product Brief, PRD, Architecture doc, and Epic/Story breakdown before any code is written. Quick Flow replaces all of that with a single tech-spec. This works because Quick Flow targets changes where: + +- The product direction is already established +- Architecture decisions are already made +- A single developer can reason about the full scope +- Requirements fit in one conversation + +## Escalating to Full BMad Method + +Quick Flow includes built-in guardrails for scope detection. When you run `quick-dev` with a direct request, it evaluates signals like multi-component mentions, system-level language, and uncertainty about approach. If it detects the work is bigger than a quick flow: + +- **Light escalation** - Recommends running `quick-spec` first to create a plan +- **Heavy escalation** - Recommends switching to the full BMad Method PRD process + +You can also escalate manually at any time. Your tech-spec work carries forward - it becomes input for the broader planning process rather than being discarded. diff --git a/docs/explanation/why-solutioning-matters.md b/docs/explanation/why-solutioning-matters.md index cb37b7c5e..c1aa5ba67 100644 --- a/docs/explanation/why-solutioning-matters.md +++ b/docs/explanation/why-solutioning-matters.md @@ -1,6 +1,8 @@ --- title: "Why Solutioning Matters" description: Understanding why the solutioning phase is critical for multi-epic projects +sidebar: + order: 3 --- @@ -8,7 +10,7 @@ Phase 3 (Solutioning) translates **what** to build (from Planning) into **how** ## The Problem Without Solutioning -``` +```text Agent 1 implements Epic 1 using REST API Agent 2 implements Epic 2 using GraphQL Result: Inconsistent API design, integration nightmare @@ -18,7 +20,7 @@ When multiple agents implement different parts of a system without shared archit ## The Solution With Solutioning -``` +```text architecture workflow decides: "Use GraphQL for all APIs" All agents follow architecture decisions Result: Consistent implementation, no conflicts diff --git a/docs/how-to/customize-bmad.md b/docs/how-to/customize-bmad.md index 3c356373f..9ebb7884f 100644 --- a/docs/how-to/customize-bmad.md +++ b/docs/how-to/customize-bmad.md @@ -1,34 +1,35 @@ --- -title: "BMad Method Customization Guide" +title: "How to Customize BMad" description: Customize agents, workflows, and modules while preserving update compatibility +sidebar: + order: 7 --- -The ability to customize the BMad Method and its core to your needs, while still being able to get updates and enhancements is a critical idea within the BMad Ecosystem. +Use the `.customize.yaml` files to tailor agent behavior, personas, and menus while preserving your changes across updates. -The Customization Guidance outlined here, while targeted at understanding BMad Method customization, applies to any other module use within the BMad Method. +## When to Use This -## Types of Customization +- You want to change an agent's name, personality, or communication style +- You need agents to remember project-specific context +- You want to add custom menu items that trigger your own workflows or prompts +- You want agents to perform specific actions every time they start up -Customization includes Agent Customization, Workflow/Skill customization, the addition of new MCPs or Skills to be used by existing agents. Aside from all of this, a whole other realm of customization involves creating / adding your own relevant BMad Builder workflows, skills, agents and maybe even your own net new modules to compliment the BMad Method Module. +:::note[Prerequisites] +- BMad installed in your project (see [How to Install BMad](./install-bmad.md)) +- A text editor for YAML files +::: -Warning: The reason for customizing as this guide will prescribe will allow you to continue getting updates without worrying about losing your customization changes. And by continuing to get updates as BMad modules advance, you will be able to continue to evolve as the system improves. +:::caution[Keep Your Customizations Safe] +Always use the `.customize.yaml` files described here rather than editing agent files directly. The installer overwrites agent files during updates, but preserves your `.customize.yaml` changes. +::: -## Agent Customization +## Steps -### Agent Customization Areas +### 1. Locate Customization Files -- Change agent names, personas or manner of speech -- Add project-specific memories or context -- Add custom menu items to custom or inline prompts, skills or custom BMad workflows -- Define critical actions that occur agent startup for consistent behavior +After installation, find one `.customize.yaml` file per agent in: -## How to customize an agent. - -**1. Locate Customization Files** - -After installation, find agent customization files in: - -``` +```text _bmad/_config/agents/ ├── core-bmad-master.customize.yaml ├── bmm-dev.customize.yaml @@ -36,28 +37,22 @@ _bmad/_config/agents/ └── ... (one file per installed agent) ``` -**2. Edit Any Agent** +### 2. Edit the Customization File -Open the `.customize.yaml` file for the agent you want to modify. All sections are optional - customize only what you need. +Open the `.customize.yaml` file for the agent you want to modify. Every section is optional -- customize only what you need. -**3. Rebuild the Agent** +| Section | Behavior | Purpose | +| ------------------- | ------------ | ---------------------------------------------- | +| `agent.metadata` | Replaces | Override the agent's display name | +| `persona` | Replaces | Set role, identity, style, and principles | +| `memories` | Appends | Add persistent context the agent always recalls | +| `menu` | Appends | Add custom menu items for workflows or prompts | +| `critical_actions` | Appends | Define startup instructions for the agent | +| `prompts` | Appends | Create reusable prompts for menu actions | -After editing, IT IS CRITICAL to rebuild the agent to apply changes: +Sections marked **Replaces** overwrite the agent's defaults entirely. Sections marked **Appends** add to the existing configuration. -```bash -npx bmad-method install -``` - -You can either then: - -- Select `Quick Update` - This will also ensure all packages are up to date AND compile all agents to include any updates or customizations -- Select `Rebuild Agents` - This will only rebuild and apply customizations to agents, without pulling the latest - -There will be additional tools shortly after beta launch to allow install of individual agents, workflows, skills and modules without the need for using the full bmad installer. - -### What Agent Properties Can Be Customized? - -#### Agent Name +**Agent Name** Change how the agent introduces itself: @@ -67,7 +62,7 @@ agent: name: 'Spongebob' # Default: "Amelia" ``` -#### Persona +**Persona** Replace the agent's personality, role, and communication style: @@ -81,9 +76,9 @@ persona: - 'Favor composition over inheritance' ``` -**Note:** The persona section replaces the entire default persona (not merged). +The `persona` section replaces the entire default persona, so include all four fields if you set it. -#### Memories +**Memories** Add persistent context the agent will always remember: @@ -91,12 +86,12 @@ Add persistent context the agent will always remember: memories: - 'Works at Krusty Krab' - 'Favorite Celebrity: David Hasslehoff' - - 'Learned in Epic 1 that its not cool to just pretend that tests have passed' + - 'Learned in Epic 1 that it is not cool to just pretend that tests have passed' ``` -### Custom Menu Items +**Menu Items** -Any custom items you add here will be included in the agents display menu. +Add custom entries to the agent's display menu. Each item needs a `trigger`, a target (`workflow` path or `action` reference), and a `description`: ```yaml menu: @@ -108,18 +103,18 @@ menu: description: Deploy to production ``` -### Critical Actions +**Critical Actions** -Add instructions that execute before the agent starts: +Define instructions that run when the agent starts up: ```yaml critical_actions: - 'Check the CI Pipelines with the XYZ Skill and alert user on wake if anything is urgently needing attention' ``` -### Custom Prompts +**Custom Prompts** -Define reusable prompts for `action="#id"` menu handlers: +Create reusable prompts that menu items can reference with `action="#id"`: ```yaml prompts: @@ -131,29 +126,47 @@ prompts: 3. Execute deployment script ``` +### 3. Apply Your Changes + +After editing, recompile the agent to apply changes: + +```bash +npx bmad-method install +``` + +The installer detects the existing installation and offers these options: + +| Option | What It Does | +| --------------------- | ------------------------------------------------------------------- | +| **Quick Update** | Updates all modules to the latest version and recompiles all agents | +| **Recompile Agents** | Applies customizations only, without updating module files | +| **Modify BMad Installation** | Full installation flow for adding or removing modules | + +For customization-only changes, **Recompile Agents** is the fastest option. + ## Troubleshooting **Changes not appearing?** -- Make sure you ran `npx bmad-method build ` after editing -- Check YAML syntax is valid (indentation matters!) -- Verify the agent name matches the file name pattern +- Run `npx bmad-method install` and select **Recompile Agents** to apply changes +- Check that your YAML syntax is valid (indentation matters) +- Verify you edited the correct `.customize.yaml` file for the agent **Agent not loading?** -- Check for YAML syntax errors -- Ensure required fields aren't left empty if you uncommented them -- Try reverting to the template and rebuilding +- Check for YAML syntax errors using an online YAML validator +- Ensure you did not leave fields empty after uncommenting them +- Try reverting to the original template and rebuilding -**Need to reset?** +**Need to reset an agent?** -- Remove content from the `.customize.yaml` file (or delete the file) -- Run `npx bmad-method build ` to regenerate defaults +- Clear or delete the agent's `.customize.yaml` file +- Run `npx bmad-method install` and select **Recompile Agents** to restore defaults ## Workflow Customization -Information about customizing existing BMad Method workflows and skills are coming soon. +Customization of existing BMad Method workflows and skills is coming soon. ## Module Customization -Information on how to build expansion modules that augment BMad, or make other existing module customizations are coming soon. \ No newline at end of file +Guidance on building expansion modules and customizing existing modules is coming soon. diff --git a/docs/how-to/established-projects.md b/docs/how-to/established-projects.md index 2f362d0b6..5f1066a51 100644 --- a/docs/how-to/established-projects.md +++ b/docs/how-to/established-projects.md @@ -1,6 +1,8 @@ --- title: "Established Projects" description: How to use BMad Method on existing codebases +sidebar: + order: 6 --- Use BMad Method effectively when working on existing projects and legacy codebases, sometimes also referred to as brownfield projects. @@ -44,8 +46,8 @@ You have two primary options depending on the scope of changes: | Scope | Recommended Approach | | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | -| **Small updates or additions** | Use `quick-flow-solo-dev` to create a tech-spec and implement the change. The full four-phase BMad method is likely overkill. | -| **Major changes or additions** | Start with the BMad method, applying as much or as little rigor as needed. | +| **Small updates or additions** | Use `quick-flow-solo-dev` to create a tech-spec and implement the change. The full four-phase BMad Method is likely overkill. | +| **Major changes or additions** | Start with the BMad Method, applying as much or as little rigor as needed. | ### During PRD Creation @@ -76,5 +78,5 @@ Pay close attention here to prevent reinventing the wheel or making decisions th ## More Information -- **[Quick Fixes](/docs/how-to/quick-fixes.md)** - Bug fixes and ad-hoc changes -- **[Established Projects FAQ](/docs/explanation/established-projects-faq.md)** - Common questions about working on established projects +- **[Quick Fixes](./quick-fixes.md)** - Bug fixes and ad-hoc changes +- **[Established Projects FAQ](../explanation/established-projects-faq.md)** - Common questions about working on established projects diff --git a/docs/how-to/get-answers-about-bmad.md b/docs/how-to/get-answers-about-bmad.md index e85069be1..7e1c57ca1 100644 --- a/docs/how-to/get-answers-about-bmad.md +++ b/docs/how-to/get-answers-about-bmad.md @@ -1,6 +1,8 @@ --- title: "How to Get Answers About BMad" description: Use an LLM to quickly answer your own BMad questions +sidebar: + order: 4 --- If you have successfully installed BMad and the BMad Method (+ other modules as needed) - the first step in getting answers is `/bmad-help`. This will answer upwards of 80% of all questions and is available to you in the IDE as you are working. @@ -38,10 +40,11 @@ The `_bmad` folder is created when you install BMad. If you don't have it yet, c Fetch `llms-full.txt` into your session: -``` +```text https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt ``` + ### 3. Ask Your Question :::note[Example] diff --git a/docs/how-to/install-bmad.md b/docs/how-to/install-bmad.md index 4127bd8b2..20a20bab3 100644 --- a/docs/how-to/install-bmad.md +++ b/docs/how-to/install-bmad.md @@ -1,11 +1,13 @@ --- title: "How to Install BMad" description: Step-by-step guide to installing BMad in your project +sidebar: + order: 1 --- Use the `npx bmad-method install` command to set up BMad in your project with your choice of modules and AI tools. -If you want to use a non interactive installer and provide all install options on the command line, [this guide](/docs/non-interactive-installation.md). +If you want to use a non interactive installer and provide all install options on the command line, see [this guide](./non-interactive-installation.md). ## When to Use This @@ -27,6 +29,13 @@ If you want to use a non interactive installer and provide all install options o npx bmad-method install ``` +:::tip[Bleeding edge] +To install the latest from the main branch (may be unstable): +```bash +npx github:bmad-code-org/BMAD-METHOD install +``` +::: + ### 2. Choose Installation Location The installer will ask where to install BMad files: @@ -56,7 +65,7 @@ The installer guides you through the rest — custom content, settings, etc. ## What You Get -``` +```text your-project/ ├── _bmad/ │ ├── bmm/ # Your selected modules @@ -72,15 +81,8 @@ your-project/ Run the `help` workflow (`/bmad-help` on most platforms) to verify everything works and see what to do next. -**Latest from main branch:** -```bash -npx github:bmad-code-org/BMAD-METHOD install -``` - -Use these if you want the newest features before they're officially released. Things might break. - ## Troubleshooting **Installer throws an error** — Copy-paste the output into your AI assistant and let it figure it out. -**Installer worked but something doesn't work later** — Your AI needs BMad context to help. See [How to Get Answers About BMad](/docs/how-to/get-answers-about-bmad.md) for how to point your AI at the right sources. +**Installer worked but something doesn't work later** — Your AI needs BMad context to help. See [How to Get Answers About BMad](./get-answers-about-bmad.md) for how to point your AI at the right sources. diff --git a/docs/how-to/non-interactive-installation.md b/docs/how-to/non-interactive-installation.md new file mode 100644 index 000000000..e9122ecdb --- /dev/null +++ b/docs/how-to/non-interactive-installation.md @@ -0,0 +1,171 @@ +--- +title: Non-Interactive Installation +description: Install BMad using command-line flags for CI/CD pipelines and automated deployments +sidebar: + order: 2 +--- + +Use command-line flags to install BMad non-interactively. This is useful for: + +## When to Use This + +- Automated deployments and CI/CD pipelines +- Scripted installations +- Batch installations across multiple projects +- Quick installations with known configurations + +:::note[Prerequisites] +Requires [Node.js](https://nodejs.org) v20+ and `npx` (included with npm). +::: + +## Available Flags + +### Installation Options + +| Flag | Description | Example | +|------|-------------|---------| +| `--directory ` | Installation directory | `--directory ~/projects/myapp` | +| `--modules ` | Comma-separated module IDs | `--modules bmm,bmb` | +| `--tools ` | Comma-separated tool/IDE IDs (use `none` to skip) | `--tools claude-code,cursor` or `--tools none` | +| `--custom-content ` | Comma-separated paths to custom modules | `--custom-content ~/my-module,~/another-module` | +| `--action ` | Action for existing installations: `install` (default), `update`, `quick-update`, or `compile-agents` | `--action quick-update` | + +### Core Configuration + +| Flag | Description | Default | +|------|-------------|---------| +| `--user-name ` | Name for agents to use | System username | +| `--communication-language ` | Agent communication language | English | +| `--document-output-language ` | Document output language | English | +| `--output-folder ` | Output folder path | _bmad-output | + +### Other Options + +| Flag | Description | +|------|-------------| +| `-y, --yes` | Accept all defaults and skip prompts | +| `-d, --debug` | Enable debug output for manifest generation | + +## Module IDs + +Available module IDs for the `--modules` flag: + +- `bmm` — BMad Method Master +- `bmb` — BMad Builder + +Check the [BMad registry](https://github.com/bmad-code-org) for available external modules. + +## Tool/IDE IDs + +Available tool IDs for the `--tools` flag: + +**Preferred:** `claude-code`, `cursor`, `windsurf` + +Run `npx bmad-method install` interactively once to see the full current list of supported tools, or check the [platform codes configuration](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/cli/installers/lib/ide/platform-codes.yaml). + +## Installation Modes + +| Mode | Description | Example | +|------|-------------|---------| +| Fully non-interactive | Provide all flags to skip all prompts | `npx bmad-method install --directory . --modules bmm --tools claude-code --yes` | +| Semi-interactive | Provide some flags; BMad prompts for the rest | `npx bmad-method install --directory . --modules bmm` | +| Defaults only | Accept all defaults with `-y` | `npx bmad-method install --yes` | +| Without tools | Skip tool/IDE configuration | `npx bmad-method install --modules bmm --tools none` | + +## Examples + +### CI/CD Pipeline Installation + +```bash +#!/bin/bash +# install-bmad.sh + +npx bmad-method install \ + --directory "${GITHUB_WORKSPACE}" \ + --modules bmm \ + --tools claude-code \ + --user-name "CI Bot" \ + --communication-language English \ + --document-output-language English \ + --output-folder _bmad-output \ + --yes +``` + +### Update Existing Installation + +```bash +npx bmad-method install \ + --directory ~/projects/myapp \ + --action update \ + --modules bmm,bmb,custom-module +``` + +### Quick Update (Preserve Settings) + +```bash +npx bmad-method install \ + --directory ~/projects/myapp \ + --action quick-update +``` + +### Installation with Custom Content + +```bash +npx bmad-method install \ + --directory ~/projects/myapp \ + --modules bmm \ + --custom-content ~/my-custom-module,~/another-module \ + --tools claude-code +``` + +## What You Get + +- A fully configured `_bmad/` directory in your project +- Compiled agents and workflows for your selected modules and tools +- A `_bmad-output/` folder for generated artifacts + +## Validation and Error Handling + +BMad validates all provided flags: + +- **Directory** — Must be a valid path with write permissions +- **Modules** — Warns about invalid module IDs (but won't fail) +- **Tools** — Warns about invalid tool IDs (but won't fail) +- **Custom Content** — Each path must contain a valid `module.yaml` file +- **Action** — Must be one of: `install`, `update`, `quick-update`, `compile-agents` + +Invalid values will either: +1. Show an error and exit (for critical options like directory) +2. Show a warning and skip (for optional items like custom content) +3. Fall back to interactive prompts (for missing required values) + +:::tip[Best Practices] +- Use absolute paths for `--directory` to avoid ambiguity +- Test flags locally before using in CI/CD pipelines +- Combine with `-y` for truly unattended installations +- Use `--debug` if you encounter issues during installation +::: + +## Troubleshooting + +### Installation fails with "Invalid directory" + +- The directory path must exist (or its parent must exist) +- You need write permissions +- The path must be absolute or correctly relative to the current directory + +### Module not found + +- Verify the module ID is correct +- External modules must be available in the registry + +### Custom content path invalid + +Ensure each custom content path: +- Points to a directory +- Contains a `module.yaml` file in the root +- Has a `code` field in the `module.yaml` + +:::note[Still stuck?] +Run with `--debug` for detailed output, try interactive mode to isolate the issue, or report at . +::: diff --git a/docs/how-to/quick-fixes.md b/docs/how-to/quick-fixes.md index 5b6cfe35c..4bb870908 100644 --- a/docs/how-to/quick-fixes.md +++ b/docs/how-to/quick-fixes.md @@ -1,76 +1,123 @@ --- title: "Quick Fixes" description: How to make quick fixes and ad-hoc changes +sidebar: + order: 5 --- -Use the **DEV agent** directly for bug fixes, refactorings, or small targeted changes that don't require the full BMad method or Quick Flow. +Use the **DEV agent** directly for bug fixes, refactorings, or small targeted changes that don't require the full BMad Method or Quick Flow. ## When to Use This -- Simple bug fixes -- Small refactorings and changes that don't need extensive ideation, planning, or architectural shifts -- Larger refactorings or improvement with built in tool planning and execution mode combination, or better yet use quick flow -- Learning about your codebase +- Bug fixes with a clear, known cause +- Small refactorings (rename, extract, restructure) contained within a few files +- Minor feature tweaks or configuration changes +- Exploratory work to understand an unfamiliar codebase + +:::note[Prerequisites] +- BMad Method installed (`npx bmad-method install`) +- An AI-powered IDE (Claude Code, Cursor, Windsurf, or similar) +::: + +## Choose Your Approach + +| Situation | Agent | Why | +| --- | --- | --- | +| Fix a specific bug or make a small, scoped change | **DEV agent** | Jumps straight into implementation without planning overhead | +| Change touches several files or you want a written plan first | **Quick Flow Solo Dev** | Creates a quick-spec before implementation so the agent stays aligned to your standards | + +If you are unsure, start with the DEV agent. You can always escalate to Quick Flow if the change grows. ## Steps -### 1. Load an Agent +### 1. Load the DEV Agent -For quick fixes, you can use: +Start a **fresh chat** in your AI IDE and load the DEV agent with its slash command: -- **DEV agent** - For implementation-focused work -- **Quick Flow Solo Dev** - For slightly larger changes that still need a quick-spec to keep the agent aligned to planning and standards +```text +/bmad-agent-bmm-dev +``` + +This loads the agent's persona and capabilities into the session. If you decide you need Quick Flow instead, load the **Quick Flow Solo Dev** agent in a fresh chat: + +```text +/bmad-agent-bmm-quick-flow-solo-dev +``` + +Once the Solo Dev agent is loaded, describe your change and ask it to create a **quick-spec**. The agent drafts a lightweight spec capturing what you want to change and how. After you approve the quick-spec, tell the agent to start the **Quick Flow dev cycle** -- it will implement the change, run tests, and perform a self-review, all guided by the spec you just approved. + +:::tip[Fresh Chats] +Always start a new chat session when loading an agent. Reusing a session from a previous workflow can cause context conflicts. +::: ### 2. Describe the Change -Simply tell the agent what you need: +Tell the agent what you need in plain language. Be specific about the problem and, if you know it, where the relevant code lives. -``` -Fix the login validation bug that allows empty passwords -``` +:::note[Example Prompts] +**Bug fix** -- "Fix the login validation bug that allows empty passwords. The validation logic is in `src/auth/validate.ts`." -or +**Refactoring** -- "Refactor the UserService to use async/await instead of callbacks." -``` -Refactor the UserService to use async/await instead of callbacks -``` +**Configuration change** -- "Update the CI pipeline to cache node_modules between runs." + +**Dependency update** -- "Upgrade the express dependency to the latest v5 release and fix any breaking changes." +::: + +You don't need to provide every detail. The agent will read the relevant source files and ask clarifying questions when needed. ### 3. Let the Agent Work The agent will: -- Analyze the relevant code -- Propose a solution -- Implement the change -- Run tests (if available) +- Read and analyze the relevant source files +- Propose a solution and explain its reasoning +- Implement the change across the affected files +- Run your project's test suite if one exists -### 4. Review and Commit +If your project has tests, the agent runs them automatically after making changes and iterates until tests pass. For projects without a test suite, verify the change manually (run the app, hit the endpoint, check the output). -Review the changes made and commit when satisfied. +### 4. Review and Verify + +Before committing, review what changed: + +- Read through the diff to confirm the change matches your intent +- Run the application or tests yourself to double-check +- If something looks wrong, tell the agent what to fix -- it can iterate in the same session + +Once satisfied, commit the changes with a clear message describing the fix. + +:::caution[If Something Breaks] +If a committed change causes unexpected issues, use `git revert HEAD` to undo the last commit cleanly. Then start a fresh chat with the DEV agent to try a different approach. +::: ## Learning Your Codebase -This approach is also excellent for exploring unfamiliar code: +The DEV agent is also useful for exploring unfamiliar code. Load it in a fresh chat and ask questions: -``` -Explain how the authentication system works in this codebase -``` +:::note[Example Prompts] +"Explain how the authentication system works in this codebase." -``` -Show me where error handling happens in the API layer -``` +"Show me where error handling happens in the API layer." -LLMs are excellent at interpreting and analyzing code, whether it was AI-generated or not. Use the agent to: +"What does the `ProcessOrder` function do and what calls it?" +::: -- Learn about your project -- Understand how things are built -- Explore unfamiliar parts of the codebase +Use the agent to learn about your project, understand how components connect, and explore unfamiliar areas before making changes. + +## What You Get + +- Modified source files with the fix or refactoring applied +- Passing tests (if your project has a test suite) +- A clean commit describing the change + +No planning artifacts are produced -- that's the point of this approach. ## When to Upgrade to Formal Planning -Consider using Quick Flow or full BMad Method when: +Consider using [Quick Flow](../explanation/quick-flow.md) or the full BMad Method when: -- The change affects multiple files or systems -- You're unsure about the scope -- The fix keeps growing in complexity -- You need documentation for the change +- The change affects multiple systems or requires coordinated updates across many files +- You are unsure about the scope and need a spec to think it through +- The fix keeps growing in complexity as you work on it +- You need documentation or architectural decisions recorded for the team diff --git a/docs/how-to/shard-large-documents.md b/docs/how-to/shard-large-documents.md index 45925e5c6..e58e37946 100644 --- a/docs/how-to/shard-large-documents.md +++ b/docs/how-to/shard-large-documents.md @@ -1,15 +1,19 @@ --- title: "Document Sharding Guide" description: Split large markdown files into smaller organized files for better context management +sidebar: + order: 8 --- Use the `shard-doc` tool if you need to split large markdown files into smaller, organized files for better context management. -This is no longer recommended, and soon with updated workflows and most major llms and tools supporting sub processes this will be unnecessary. +:::caution[Deprecated] +This is no longer recommended, and soon with updated workflows and most major LLMs and tools supporting subprocesses this will be unnecessary. +::: ## When to Use This -Only use this if you notice your chosen tool / model combination are failing to load and read all the documents as input when needed. +Only use this if you notice your chosen tool / model combination is failing to load and read all the documents as input when needed. ## What is Document Sharding? @@ -17,7 +21,7 @@ Document sharding splits large markdown files into smaller, organized files base ### Architecture -``` +```text Before Sharding: docs/ └── PRD.md (large 50k token file) @@ -37,12 +41,12 @@ docs/ ### 1. Run the Shard-Doc Tool ```bash -/bmad:core:tools:shard-doc +/bmad-shard-doc ``` ### 2. Follow the Interactive Process -``` +```text Agent: Which document would you like to shard? User: docs/PRD.md diff --git a/docs/how-to/upgrade-to-v6.md b/docs/how-to/upgrade-to-v6.md index e8d13a5e8..882640a69 100644 --- a/docs/how-to/upgrade-to-v6.md +++ b/docs/how-to/upgrade-to-v6.md @@ -1,6 +1,8 @@ --- title: "How to Upgrade to v6" description: Migrate from BMad v4 to v6 +sidebar: + order: 3 --- Use the BMad installer to upgrade from v4 to v6, which includes automatic detection of legacy installations and migration assistance. @@ -20,7 +22,7 @@ Use the BMad installer to upgrade from v4 to v6, which includes automatic detect ### 1. Run the Installer -Follow the [Installer Instructions](/docs/how-to/install-bmad.md). +Follow the [Installer Instructions](./install-bmad.md). ### 2. Handle Legacy Installation @@ -29,7 +31,7 @@ When v4 is detected, you can: - Allow the installer to back up and remove `.bmad-method` - Exit and handle cleanup manually -If you named your bmad method folder something else - you will need to manual remove the folder yourself. +If you named your bmad method folder something else - you will need to manually remove the folder yourself. ### 3. Clean Up IDE Commands @@ -63,16 +65,16 @@ If you have stories created or implemented: **v6 unified structure:** -``` +```text your-project/ -└── _bmad/ # Single installation folder - ├── _config/ # Your customizations - │ └── agents/ # Agent customization files - ├── core/ # Universal core framework - ├── bmm/ # BMad Method module - ├── bmb/ # BMad Builder - └── cis/ # Creative Intelligence Suite -├── _bmad-output/ # Output folder (was doc folder in v4) +├── _bmad/ # Single installation folder +│ ├── _config/ # Your customizations +│ │ └── agents/ # Agent customization files +│ ├── core/ # Universal core framework +│ ├── bmm/ # BMad Method module +│ ├── bmb/ # BMad Builder +│ └── cis/ # Creative Intelligence Suite +└── _bmad-output/ # Output folder (was doc folder in v4) ``` ## Module Migration diff --git a/docs/index.md b/docs/index.md index ae3be92e5..ddcb421e8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,14 +7,12 @@ The BMad Method (**B**reakthrough **M**ethod of **A**gile AI **D**riven Developm If you're comfortable working with AI coding assistants like Claude, Cursor, or GitHub Copilot, you're ready to get started. ---- - ## New Here? Start with a Tutorial The fastest way to understand BMad is to try it. -- **[Get Started with BMad](/docs/tutorials/getting-started.md)** — Install and understand how BMad works -- **[Workflow Map](/docs/reference/workflow-map.md)** — Visual overview of BMM phases, workflows, and context management. +- **[Get Started with BMad](./tutorials/getting-started.md)** — Install and understand how BMad works +- **[Workflow Map](./reference/workflow-map.md)** — Visual overview of BMM phases, workflows, and context management. ## How to Use These Docs @@ -27,8 +25,6 @@ These docs are organized into four sections based on what you're trying to do: | **Explanation** | Understanding-oriented. Deep dives into concepts and architecture. Read when you want to know *why*. | | **Reference** | Information-oriented. Technical specifications for agents, workflows, and configuration. | ---- - ## What You'll Need BMad works with any AI coding assistant that supports custom system prompts or project context. Popular options include: @@ -41,8 +37,6 @@ BMad works with any AI coding assistant that supports custom system prompts or p You should be comfortable with basic software development concepts like version control, project structure, and agile workflows. No prior experience with BMad-style agent systems is required—that's what these docs are for. ---- - ## Join the Community Get help, share what you're building, or contribute to BMad: @@ -51,8 +45,6 @@ Get help, share what you're building, or contribute to BMad: - **[GitHub](https://github.com/bmad-code-org/BMAD-METHOD)** — Source code, issues, and contributions - **[YouTube](https://www.youtube.com/@BMadCode)** — Video tutorials and walkthroughs ---- - ## Next Step -Ready to dive in? **[Get Started with BMad](/docs/tutorials/getting-started.md)** and build your first project. +Ready to dive in? **[Get Started with BMad](./tutorials/getting-started.md)** and build your first project. diff --git a/docs/non-interactive-installation.md b/docs/non-interactive-installation.md deleted file mode 100644 index 7541ecc20..000000000 --- a/docs/non-interactive-installation.md +++ /dev/null @@ -1,314 +0,0 @@ ---- -title: Non-Interactive Installation -description: Install BMAD using command-line flags for CI/CD pipelines and automated deployments ---- - -# Non-Interactive Installation - -BMAD now supports non-interactive installation through command-line flags. This is particularly useful for: - -- Automated deployments and CI/CD pipelines -- Scripted installations -- Batch installations across multiple projects -- Quick installations with known configurations - -## Installation Modes - -### 1. Fully Interactive (Default) - -Run without any flags to use the traditional interactive prompts: - -```bash -npx bmad-method install -``` - -### 2. Fully Non-Interactive - -Provide all required flags to skip all prompts: - -```bash -npx bmad-method install \ - --directory /path/to/project \ - --modules bmm,bmb \ - --tools claude-code,cursor \ - --user-name "John Doe" \ - --communication-language English \ - --document-output-language English \ - --output-folder _bmad-output -``` - -### 3. Semi-Interactive (Graceful Fallback) - -Provide some flags and let BMAD prompt for the rest: - -```bash -npx bmad-method install \ - --directory /path/to/project \ - --modules bmm -``` - -In this case, BMAD will: -- Use the provided directory and modules -- Prompt for tool selection -- Prompt for core configuration - -### 4. Quick Install with Defaults - -Use the `-y` or `--yes` flag to accept all defaults: - -```bash -npx bmad-method install --yes -``` - -This will: -- Install to the current directory -- Skip custom content prompts -- Use default values for all configuration -- Use previously configured tools (or skip tool configuration if none exist) - -### 5. Install Without Tools - -To skip tool/IDE configuration entirely: - -**Option 1: Use --tools none** -```bash -npx bmad-method install --directory ~/myapp --modules bmm --tools none -``` - -**Option 2: Use --yes flag (if no tools were previously configured)** -```bash -npx bmad-method install --yes -``` - -**Option 3: Omit --tools and select "None" in the interactive prompt** -```bash -npx bmad-method install --directory ~/myapp --modules bmm -# Then select "⚠ None - I am not installing any tools" when prompted -``` - -## Available Flags - -### Installation Options - -| Flag | Description | Example | -|------|-------------|---------| -| `--directory ` | Installation directory | `--directory ~/projects/myapp` | -| `--modules ` | Comma-separated module IDs | `--modules bmm,bmb` | -| `--tools ` | Comma-separated tool/IDE IDs (use "none" to skip) | `--tools claude-code,cursor` or `--tools none` | -| `--custom-content ` | Comma-separated paths to custom modules | `--custom-content ~/my-module,~/another-module` | -| `--action ` | Action for existing installations | `--action quick-update` | - -### Core Configuration - -| Flag | Description | Default | -|------|-------------|---------| -| `--user-name ` | Name for agents to use | System username | -| `--communication-language ` | Agent communication language | English | -| `--document-output-language ` | Document output language | English | -| `--output-folder ` | Output folder path | _bmad-output | - -### Other Options - -| Flag | Description | -|------|-------------| -| `-y, --yes` | Accept all defaults and skip prompts | -| `-d, --debug` | Enable debug output for manifest generation | - -## Action Types - -When working with existing installations, use the `--action` flag: - -- `install` - Fresh installation (default for new directories) -- `update` - Modify existing installation (change modules/config) -- `quick-update` - Refresh installation without changing configuration -- `compile-agents` - Recompile agents with customizations only - -Example: - -```bash -npx bmad-method install --action quick-update -``` - -## Module IDs - -Available module IDs for the `--modules` flag: - -### Core Modules -- `bmm` - BMad Method Master -- `bmb` - BMad Builder - -### External Modules -Check the [BMad registry](https://github.com/bmad-code-org) for available external modules. - -## Tool/IDE IDs - -Available tool IDs for the `--tools` flag: - -- `claude-code` - Claude Code CLI -- `cursor` - Cursor IDE -- `windsurf` - Windsurf IDE -- `vscode` - Visual Studio Code -- `jetbrains` - JetBrains IDEs -- And more... - -Run the interactive installer once to see all available tools. - -## Examples - -### Basic Installation - -Install BMM module with Claude Code: - -```bash -npx bmad-method install \ - --directory ~/projects/myapp \ - --modules bmm \ - --tools claude-code \ - --user-name "Development Team" -``` - -### Installation Without Tools - -Install without configuring any tools/IDEs: - -```bash -npx bmad-method install \ - --directory ~/projects/myapp \ - --modules bmm \ - --tools none \ - --user-name "Development Team" -``` - -### Full Installation with Multiple Modules - -```bash -npx bmad-method install \ - --directory ~/projects/myapp \ - --modules bmm,bmb \ - --tools claude-code,cursor \ - --user-name "John Doe" \ - --communication-language English \ - --document-output-language English \ - --output-folder _output -``` - -### Update Existing Installation - -```bash -npx bmad-method install \ - --directory ~/projects/myapp \ - --action update \ - --modules bmm,bmb,custom-module -``` - -### Quick Update (Preserve Settings) - -```bash -npx bmad-method install \ - --directory ~/projects/myapp \ - --action quick-update -``` - -### Installation with Custom Content - -```bash -npx bmad-method install \ - --directory ~/projects/myapp \ - --modules bmm \ - --custom-content ~/my-custom-module,~/another-module \ - --tools claude-code -``` - -### CI/CD Pipeline Installation - -```bash -#!/bin/bash -# install-bmad.sh - -npx bmad-method install \ - --directory "${GITHUB_WORKSPACE}" \ - --modules bmm \ - --tools claude-code \ - --user-name "CI Bot" \ - --communication-language English \ - --document-output-language English \ - --output-folder _bmad-output \ - --yes -``` - -## Environment-Specific Installations - -### Development Environment - -```bash -npx bmad-method install \ - --directory . \ - --modules bmm,bmb \ - --tools claude-code,cursor \ - --user-name "${USER}" -``` - -### Production Environment - -```bash -npx bmad-method install \ - --directory /opt/app \ - --modules bmm \ - --tools claude-code \ - --user-name "Production Team" \ - --output-folder /var/bmad-output -``` - -## Validation and Error Handling - -BMAD validates all provided flags: - -- **Directory**: Must be a valid path with write permissions -- **Modules**: Will warn about invalid module IDs (but won't fail) -- **Tools**: Will warn about invalid tool IDs (but won't fail) -- **Custom Content**: Each path must contain a valid `module.yaml` file -- **Action**: Must be one of: install, update, quick-update, compile-agents - -Invalid values will either: -1. Show an error and exit (for critical options like directory) -2. Show a warning and skip (for optional items like custom content) -3. Fall back to interactive prompts (for missing required values) - -## Tips and Best Practices - -1. **Use absolute paths** for `--directory` to avoid ambiguity -2. **Test flags locally** before using in CI/CD pipelines -3. **Combine with `-y`** for truly unattended installations -4. **Check module availability** by running the interactive installer once -5. **Use `--debug`** flag if you encounter issues during installation -6. **Skip tool configuration** with `--tools none` for server/CI environments where IDEs aren't needed -7. **Partial flags are OK** - Omit flags and let BMAD prompt for missing values interactively - -## Troubleshooting - -### Installation fails with "Invalid directory" - -Check that: -- The directory path exists or its parent exists -- You have write permissions -- The path is absolute or correctly relative to current directory - -### Module not found - -- Verify the module ID is correct (check available modules in interactive mode) -- External modules may need to be available in the registry - -### Custom content path invalid - -Ensure each custom content path: -- Points to a directory -- Contains a `module.yaml` file in the root -- Has a `code` field in the `module.yaml` - -## Feedback and Issues - -If you encounter any issues with non-interactive installation: - -1. Run with `--debug` flag for detailed output -2. Try the interactive mode to verify the issue -3. Report issues on GitHub: diff --git a/docs/reference/agents.md b/docs/reference/agents.md index 87a0927c3..779f0b96e 100644 --- a/docs/reference/agents.md +++ b/docs/reference/agents.md @@ -1,13 +1,18 @@ --- title: Agents description: Default BMM agents with their menu triggers and primary workflows +sidebar: + order: 2 --- -This page lists the default BMM (Agile suite) agents that install with BMAD Method, along with their menu triggers and primary workflows. +## Default Agents + +This page lists the default BMM (Agile suite) agents that install with BMad Method, along with their menu triggers and primary workflows. + +## Notes -Notes: - Triggers are the short menu codes (e.g., `CP`) and fuzzy matches shown in each agent menu. -- Slash commands are generated separately. See `docs/reference/commands.md` for the slash command list and where they are defined. +- Slash commands are generated separately. See [Commands](./commands.md) for the slash command list and where they are defined. - QA (Quinn) is the lightweight test automation agent in BMM. The full Test Architect (TEA) lives in its own module. | Agent | Triggers | Primary workflows | diff --git a/docs/reference/commands.md b/docs/reference/commands.md index 6a77b1a2c..1ecca7516 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -1,45 +1,131 @@ --- title: Commands -description: How BMAD commands are generated and where to find them. +description: Reference for BMad slash commands — what they are, how they work, and where to find them. +sidebar: + order: 3 --- -# Commands +Slash commands are pre-built prompts that load agents, run workflows, or execute tasks inside your IDE. The BMad installer generates them from your installed modules at install time. If you later add, remove, or change modules, re-run the installer to keep commands in sync (see [Troubleshooting](#troubleshooting)). -BMAD slash commands are generated by the installer for your IDE and **reflect the modules you have installed**. -That means the authoritative list lives **in your project**, not in a static docs page. +## Commands vs. Agent Menu Triggers -## How to Discover Commands (Recommended) +BMad offers two ways to start work, and they serve different purposes. -- Type `/bmad` in your IDE and use autocomplete to browse agents/workflows. -- Run `/bmad-help` to get guided next steps and context-aware recommendations. - -## Where Commands Are Generated - -The installer writes command files into your project. The location and format depend on your AI tool: - -| AI Tool | Location | File Reference Syntax | +| Mechanism | How you invoke it | What happens | | --- | --- | --- | -| Claude Code | `.claude/commands/` | `@path` references | -| Kiro | `.kiro/steering/` | `#[[file:path]]` references with `inclusion: manual` frontmatter | -| Cursor | `.cursor/commands/` | `@path` references | -| Windsurf | `.windsurf/workflows/` | `@{project-root}/path` references | +| **Slash command** | Type `/bmad-...` in your IDE | Directly loads an agent, runs a workflow, or executes a task | +| **Agent menu trigger** | Load an agent first, then type a short code (e.g. `DS`) | The agent interprets the code and starts the matching workflow while staying in character | -Example paths for Claude Code: +Agent menu triggers require an active agent session. Use slash commands when you know which workflow you want. Use triggers when you are already working with an agent and want to switch tasks without leaving the conversation. -- `.claude/commands/bmad//agents/` -- `.claude/commands/bmad//workflows/` +## How Commands Are Generated -All tools invoke the same underlying `_bmad/` workflows and agents — only the launcher format differs. +When you run `npx bmad-method install`, the installer reads the manifests for every selected module and writes one command file per agent, workflow, task, and tool. Each file is a short markdown prompt that instructs the AI to load the corresponding source file and follow its instructions. -These folders are the **canonical, project-specific command list**. +The installer uses templates for each command type: -## Common Commands +| Command type | What the generated file does | +| --- | --- | +| **Agent launcher** | Loads the agent persona file, activates its menu, and stays in character | +| **Workflow command** | Loads the workflow engine (`workflow.xml`) and passes the workflow config | +| **Task command** | Loads a standalone task file and follows its instructions | +| **Tool command** | Loads a standalone tool file and follows its instructions | -- `/bmad-help` - Interactive help and next-step guidance -- `/bmad::agents:` - Load an agent (e.g. `/bmad:bmm:agents:dev`) -- `/bmad::workflows:` - Run a workflow (e.g. `/bmad:bmm:workflows:create-prd`) +:::note[Re-running the installer] +If you add or remove modules, run the installer again. It regenerates all command files to match your current module selection. +::: -## Why This Page Is Short +## Where Command Files Live -BMAD is modular, so the exact commands vary by install. -Use your IDE's autocomplete or the generated command folders above to see *everything* available. +The installer writes command files into an IDE-specific directory inside your project. The exact path depends on which IDE you selected during installation. + +| IDE / CLI | Command directory | +| --- | --- | +| Claude Code | `.claude/commands/` | +| Cursor | `.cursor/commands/` | +| Windsurf | `.windsurf/workflows/` | +| Other IDEs | See the installer output for the target path | + +All IDEs receive a flat set of command files in their command directory. For example, a Claude Code installation looks like: + +```text +.claude/commands/ +├── bmad-agent-bmm-dev.md +├── bmad-agent-bmm-pm.md +├── bmad-bmm-create-prd.md +├── bmad-editorial-review-prose.md +├── bmad-help.md +└── ... +``` + +The filename determines the slash command name in your IDE. For example, the file `bmad-agent-bmm-dev.md` registers the command `/bmad-agent-bmm-dev`. + +## How to Discover Your Commands + +Type `/bmad` in your IDE and use autocomplete to browse available commands. + +Run `/bmad-help` for context-aware guidance on your next step. + +:::tip[Quick discovery] +The generated command folders in your project are the canonical list. Open them in your file explorer to see every command with its description. +::: + +## Command Categories + +### Agent Commands + +Agent commands load a specialized AI persona with a defined role, communication style, and menu of workflows. Once loaded, the agent stays in character and responds to menu triggers. + +| Example command | Agent | Role | +| --- | --- | --- | +| `/bmad-agent-bmm-dev` | Amelia (Developer) | Implements stories with strict adherence to specs | +| `/bmad-agent-bmm-pm` | John (Product Manager) | Creates and validates PRDs | +| `/bmad-agent-bmm-architect` | Winston (Architect) | Designs system architecture | +| `/bmad-agent-bmm-sm` | Bob (Scrum Master) | Manages sprints and stories | + +See [Agents](./agents.md) for the full list of default agents and their triggers. + +### Workflow Commands + +Workflow commands run a structured, multi-step process without loading an agent persona first. They load the workflow engine and pass a specific workflow configuration. + +| Example command | Purpose | +| --- | --- | +| `/bmad-bmm-create-prd` | Create a Product Requirements Document | +| `/bmad-bmm-create-architecture` | Design system architecture | +| `/bmad-bmm-dev-story` | Implement a story | +| `/bmad-bmm-code-review` | Run a code review | +| `/bmad-bmm-quick-spec` | Define an ad-hoc change (Quick Flow) | + +See [Workflow Map](./workflow-map.md) for the complete workflow reference organized by phase. + +### Task and Tool Commands + +Tasks and tools are standalone operations that do not require an agent or workflow context. + +| Example command | Purpose | +| --- | --- | +| `/bmad-help` | Context-aware guidance and next-step recommendations | +| `/bmad-shard-doc` | Split a large markdown file into smaller sections | +| `/bmad-index-docs` | Index project documentation | +| `/bmad-editorial-review-prose` | Review document prose quality | + +## Naming Convention + +Command names follow a predictable pattern. + +| Pattern | Meaning | Example | +| --- | --- | --- | +| `bmad-agent--` | Agent launcher | `bmad-agent-bmm-dev` | +| `bmad--` | Workflow command | `bmad-bmm-create-prd` | +| `bmad-` | Core task or tool | `bmad-help` | + +Module codes: `bmm` (Agile suite), `bmb` (Builder), `tea` (Test Architect), `cis` (Creative Intelligence), `gds` (Game Dev Studio). See [Modules](./modules.md) for descriptions. + +## Troubleshooting + +**Commands not appearing after install.** Restart your IDE or reload the window. Some IDEs cache the command list and require a refresh to pick up new files. + +**Expected commands are missing.** The installer only generates commands for modules you selected. Run `npx bmad-method install` again and verify your module selection. Check that the command files exist in the expected directory. + +**Commands from a removed module still appear.** The installer does not delete old command files automatically. Remove the stale files from your IDE's command directory, or delete the entire command directory and re-run the installer for a clean set. diff --git a/docs/reference/modules.md b/docs/reference/modules.md index a0f6fdd6f..6bdc64190 100644 --- a/docs/reference/modules.md +++ b/docs/reference/modules.md @@ -1,6 +1,8 @@ --- title: Official Modules description: Add-on modules for building custom agents, creative intelligence, game development, and testing +sidebar: + order: 4 --- BMad extends through official modules that you select during installation. These add-on modules provide specialized agents, workflows, and tasks for specific domains beyond the built-in core and BMM (Agile suite). diff --git a/docs/reference/testing.md b/docs/reference/testing.md index 86af5294b..4063ddfe1 100644 --- a/docs/reference/testing.md +++ b/docs/reference/testing.md @@ -1,22 +1,106 @@ --- title: Testing Options -description: Built-in QA agent and the standalone Test Architect module for advanced testing +description: Comparing the built-in QA agent (Quinn) with the Test Architect (TEA) module for test automation. +sidebar: + order: 5 --- -# Testing Options +BMad provides two testing paths: a built-in QA agent for fast test generation and an installable Test Architect module for enterprise-grade test strategy. -BMad provides a built-in QA agent for quick test automation and a separate Test Architect (TEA) module for advanced testing. +## Which Should You Use? -## Built-in QA (Quinn) +| Factor | Quinn (Built-in QA) | TEA Module | +| --- | --- | --- | +| **Best for** | Small-medium projects, quick coverage | Large projects, regulated or complex domains | +| **Setup** | Nothing to install -- included in BMM | Install separately via `npx bmad-method install` | +| **Approach** | Generate tests fast, iterate later | Plan first, then generate with traceability | +| **Test types** | API and E2E tests | API, E2E, ATDD, NFR, and more | +| **Strategy** | Happy path + critical edge cases | Risk-based prioritization (P0-P3) | +| **Workflow count** | 1 (Automate) | 9 (design, ATDD, automate, review, trace, and others) | -Use the built-in QA agent for fast, straightforward test coverage: +:::tip[Start with Quinn] +Most projects should start with Quinn. If you later need test strategy, quality gates, or requirements traceability, install TEA alongside it. +::: -- Trigger: `QA` or `bmad-bmm-qa-automate` -- Best for: small projects, quick coverage, standard patterns +## Built-in QA Agent (Quinn) + +Quinn is the built-in QA agent in the BMM (Agile suite) module. It generates working tests quickly using your project's existing test framework -- no configuration or additional installation required. + +**Trigger:** `QA` or `bmad-bmm-qa-automate` + +### What Quinn Does + +Quinn runs a single workflow (Automate) that walks through five steps: + +1. **Detect test framework** -- scans `package.json` and existing test files for your framework (Jest, Vitest, Playwright, Cypress, or any standard runner). If none exists, analyzes the project stack and suggests one. +2. **Identify features** -- asks what to test or auto-discovers features in the codebase. +3. **Generate API tests** -- covers status codes, response structure, happy path, and 1-2 error cases. +4. **Generate E2E tests** -- covers user workflows with semantic locators and visible-outcome assertions. +5. **Run and verify** -- executes the generated tests and fixes failures immediately. + +Quinn produces a test summary saved to your project's implementation artifacts folder. + +### Test Patterns + +Generated tests follow a "simple and maintainable" philosophy: + +- **Standard framework APIs only** -- no external utilities or custom abstractions +- **Semantic locators** for UI tests (roles, labels, text rather than CSS selectors) +- **Independent tests** with no order dependencies +- **No hardcoded waits or sleeps** +- **Clear descriptions** that read as feature documentation + +:::note[Scope] +Quinn generates tests only. For code review and story validation, use the Code Review workflow (`CR`) instead. +::: + +### When to Use Quinn + +- Quick test coverage for a new or existing feature +- Beginner-friendly test automation without advanced setup +- Standard test patterns that any developer can read and maintain +- Small-medium projects where comprehensive test strategy is unnecessary ## Test Architect (TEA) Module -TEA is a standalone module with advanced testing workflows (test design, ATDD, automate, review, trace, NFR assessment). +TEA is a standalone module that provides an expert agent (Murat) and nine structured workflows for enterprise-grade testing. It goes beyond test generation into test strategy, risk-based planning, quality gates, and requirements traceability. -- Documentation: -- Install: `npx bmad-method@alpha install` and select the TEA module +- **Documentation:** [TEA Module Docs](https://bmad-code-org.github.io/bmad-method-test-architecture-enterprise/) +- **Install:** `npx bmad-method install` and select the TEA module +- **npm:** [`bmad-method-test-architecture-enterprise`](https://www.npmjs.com/package/bmad-method-test-architecture-enterprise) + +### What TEA Provides + +| Workflow | Purpose | +| --- | --- | +| Test Design | Create a comprehensive test strategy tied to requirements | +| ATDD | Acceptance-test-driven development with stakeholder criteria | +| Automate | Generate tests with advanced patterns and utilities | +| Test Review | Validate test quality and coverage against strategy | +| Traceability | Map tests back to requirements for audit and compliance | +| NFR Assessment | Evaluate non-functional requirements (performance, security) | +| CI Setup | Configure test execution in continuous integration pipelines | +| Framework Scaffolding | Set up test infrastructure and project structure | +| Release Gate | Make data-driven go/no-go release decisions | + +TEA also supports P0-P3 risk-based prioritization and optional integrations with Playwright Utils and MCP tooling. + +### When to Use TEA + +- Projects that require requirements traceability or compliance documentation +- Teams that need risk-based test prioritization across many features +- Enterprise environments with formal quality gates before release +- Complex domains where test strategy must be planned before tests are written +- Projects that have outgrown Quinn's single-workflow approach + +## How Testing Fits into Workflows + +Quinn's Automate workflow appears in Phase 4 (Implementation) of the BMad Method workflow map. A typical sequence: + +1. Implement a story with the Dev workflow (`DS`) +2. Generate tests with Quinn (`QA`) or TEA's Automate workflow +3. Validate implementation with Code Review (`CR`) + +Quinn works directly from source code without loading planning documents (PRD, architecture). TEA workflows can integrate with upstream planning artifacts for traceability. + +For more on where testing fits in the overall process, see the [Workflow Map](./workflow-map.md). diff --git a/docs/reference/workflow-map.md b/docs/reference/workflow-map.md index 0df3d3ec8..fc38b69ee 100644 --- a/docs/reference/workflow-map.md +++ b/docs/reference/workflow-map.md @@ -1,19 +1,23 @@ --- title: "Workflow Map" description: Visual reference for BMad Method workflow phases and outputs +sidebar: + order: 1 --- The BMad Method (BMM) is a module in the BMad Ecosystem, targeted at following the best practices of context engineering and planning. AI agents work best with clear, structured context. The BMM system builds that context progressively across 4 distinct phases - each phase, and multiple workflows optionally within each phase, produce documents that inform the next, so agents always know what to build and why. The rationale and concepts come from agile methodologies that have been used across the industry with great success as a mental framework. -If at anytime you are unsure what to do, the `/bmad-help` command will help you stay on track or know what to do next. You can always refer to this for reference also - but /bmad-help is fully interactive and much quicker if you have already installed the BMadMethod. Additionally, if you are using different modules that have extended the BMad Method or added other complimentary non extension modules - the /bmad-help evolves to know all that is available to give you the best in the moment advice. +If at any time you are unsure what to do, the `/bmad-help` command will help you stay on track or know what to do next. You can always refer to this for reference also - but /bmad-help is fully interactive and much quicker if you have already installed the BMad Method. Additionally, if you are using different modules that have extended the BMad Method or added other complementary non-extension modules - the /bmad-help evolves to know all that is available to give you the best in-the-moment advice. Final important note: Every workflow below can be run directly with your tool of choice via slash command or by loading an agent first and using the entry from the agents menu. - + -*[Interactive diagram - hover over outputs to see artifact flows]* +

+ Open diagram in new tab ↗ +

## Phase 1: Analysis (Optional) @@ -21,7 +25,7 @@ Explore the problem space and validate ideas before committing to planning. | Workflow | Purpose | Produces | | ---------------------- | -------------------------------------------------------------------------- | ------------------------- | -| `brainstorm` | Brainstorm Project Ideas with guided facilitation of a brainstorming coach | `brainstorming-report.md` | +| `brainstorming` | Brainstorm Project Ideas with guided facilitation of a brainstorming coach | `brainstorming-report.md` | | `research` | Validate market, technical, or domain assumptions | Research findings | | `create-product-brief` | Capture strategic vision | `product-brief.md` | diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index 54a9b240d..f8dbdad2f 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -37,7 +37,7 @@ BMad helps you build software through guided workflows with specialized AI agent | 3 | Solutioning | Design architecture *(BMad Method/Enterprise only)* | | 4 | Implementation | Build epic by epic, story by story | -**[Open the Workflow Map](/docs/reference/workflow-map.md)** to explore phases, workflows, and context management. +**[Open the Workflow Map](../reference/workflow-map.md)** to explore phases, workflows, and context management. Based on your project's complexity, BMad offers three planning tracks: @@ -153,7 +153,7 @@ You've learned the foundation of building with BMad: Your project now has: -``` +```text your-project/ ├── _bmad/ # BMad configuration ├── _bmad-output/ diff --git a/eslint.config.mjs b/eslint.config.mjs index 90dbf1553..d6c20f329 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -83,7 +83,7 @@ export default [ // CLI scripts under tools/** and test/** { - files: ['tools/**/*.js', 'tools/**/*.mjs', 'test/**/*.js'], + files: ['tools/**/*.js', 'tools/**/*.mjs', 'test/**/*.js', 'test/**/*.mjs'], rules: { // Allow CommonJS patterns for Node CLI scripts 'unicorn/prefer-module': 'off', diff --git a/package.json b/package.json index 030a3a026..404548897 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,11 @@ }, "scripts": { "bmad:install": "node tools/cli/bmad-cli.js install", - "bundle": "node tools/cli/bundlers/bundle-web.js all", "docs:build": "node tools/build-docs.mjs", "docs:dev": "astro dev --root website", "docs:fix-links": "node tools/fix-doc-links.js", "docs:preview": "astro preview --root website", "docs:validate-links": "node tools/validate-doc-links.js", - "flatten": "node tools/flattener/main.js", "format:check": "prettier --check \"**/*.{js,cjs,mjs,json,yaml}\"", "format:fix": "prettier --write \"**/*.{js,cjs,mjs,json,yaml}\"", "format:fix:staged": "prettier --write", diff --git a/test/test-rehype-plugins.mjs b/test/test-rehype-plugins.mjs new file mode 100644 index 000000000..47559a658 --- /dev/null +++ b/test/test-rehype-plugins.mjs @@ -0,0 +1,1050 @@ +/** + * Rehype Plugin Tests + * + * Tests for rehype-markdown-links and rehype-base-paths plugins: + * - findFirstDelimiter helper + * - detectContentDir helper + * - Transformer skip conditions + * - Path resolution + * - Index handling + * - Query/hash preservation + * - Base path prefixing + * - Element rewriting + * - Raw HTML rewriting + * - Integration (both plugins together) + * + * Usage: node test/test-rehype-plugins.mjs + */ + +import rehypeMarkdownLinks, { findFirstDelimiter, detectContentDir } from '../website/src/rehype-markdown-links.js'; +import rehypeBasePaths from '../website/src/rehype-base-paths.js'; + +// ANSI colors +const colors = { + reset: '\u001B[0m', + green: '\u001B[32m', + red: '\u001B[31m', + yellow: '\u001B[33m', + cyan: '\u001B[36m', + dim: '\u001B[2m', +}; + +let passed = 0; +let failed = 0; + +/** + * Test helper: Assert condition + */ +function assert(condition, testName, errorMessage = '') { + if (condition) { + console.log(`${colors.green}\u2713${colors.reset} ${testName}`); + passed++; + } else { + console.log(`${colors.red}\u2717${colors.reset} ${testName}`); + if (errorMessage) { + console.log(` ${colors.dim}${errorMessage}${colors.reset}`); + } + failed++; + } +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +const CONTENT_DIR = '/project/src/content/docs'; +const STD_FILE = { path: '/project/src/content/docs/guide/intro.md' }; +const STD_OPTS = { contentDir: CONTENT_DIR }; +const BASE = '/BMAD-METHOD/'; + +function transform(tree, file, options = {}) { + const plugin = rehypeMarkdownLinks(options); + plugin(tree, file); + return tree; +} + +function transformBase(tree, options = {}) { + const plugin = rehypeBasePaths(options); + plugin(tree); + return tree; +} + +function makeAnchorTree(href) { + return { + type: 'root', + children: [ + { + type: 'element', + tagName: 'a', + properties: { href }, + children: [{ type: 'text', value: 'link' }], + }, + ], + }; +} + +function makeElementTree(tagName, properties) { + return { + type: 'root', + children: [ + { + type: 'element', + tagName, + properties: { ...properties }, + children: [], + }, + ], + }; +} + +function getHref(tree) { + return tree.children[0].properties.href; +} + +function getSrc(tree) { + return tree.children[0].properties.src; +} + +function getRawValue(tree) { + return tree.children[0].value; +} + +// --------------------------------------------------------------------------- +// Test Suite +// --------------------------------------------------------------------------- + +function runTests() { + console.log(`${colors.cyan}========================================`); + console.log('Rehype Plugin Tests'); + console.log(`========================================${colors.reset}\n`); + + // ============================================================ + // findFirstDelimiter helper + // ============================================================ + console.log(`${colors.yellow}findFirstDelimiter helper (8 tests)${colors.reset}\n`); + + assert(findFirstDelimiter('page') === -1, 'No delimiters returns -1', `Expected -1, got ${findFirstDelimiter('page')}`); + + assert(findFirstDelimiter('page.md?v=1') === 7, 'Only ? returns its index (7)', `Expected 7, got ${findFirstDelimiter('page.md?v=1')}`); + + assert(findFirstDelimiter('page.md#sec') === 7, 'Only # returns its index (7)', `Expected 7, got ${findFirstDelimiter('page.md#sec')}`); + + assert( + findFirstDelimiter('page.md?v=1#sec') === 7, + '? before # returns index of ?', + `Expected 7, got ${findFirstDelimiter('page.md?v=1#sec')}`, + ); + + assert( + findFirstDelimiter('page.md#sec?v=1') === 7, + '# before ? returns index of #', + `Expected 7, got ${findFirstDelimiter('page.md#sec?v=1')}`, + ); + + assert(findFirstDelimiter('') === -1, 'Empty string returns -1', `Expected -1, got ${findFirstDelimiter('')}`); + + assert(findFirstDelimiter('#top') === 0, '# at position 0 returns 0', `Expected 0, got ${findFirstDelimiter('#top')}`); + + assert(findFirstDelimiter('?q=1') === 0, '? at position 0 returns 0', `Expected 0, got ${findFirstDelimiter('?q=1')}`); + + console.log(''); + + // ============================================================ + // detectContentDir helper + // ============================================================ + console.log(`${colors.yellow}detectContentDir helper (6 tests)${colors.reset}\n`); + + assert( + detectContentDir('/project/src/content/docs/guide/intro.md') === '/project/src/content/docs', + 'Standard path finds content dir', + `Got ${detectContentDir('/project/src/content/docs/guide/intro.md')}`, + ); + + assert( + detectContentDir('/some/random/path/file.md') === null, + 'No match returns null', + `Got ${detectContentDir('/some/random/path/file.md')}`, + ); + + assert(detectContentDir('/src/content') === null, 'Too few segments returns null', `Got ${detectContentDir('/src/content')}`); + + assert( + detectContentDir('/src/content/docs') === '/src/content/docs', + 'Exactly 3 matching segments returns match', + `Got ${detectContentDir('/src/content/docs')}`, + ); + + assert( + detectContentDir('/a/src/content/docs/nested/src/content/docs/deep/file.md') === '/a/src/content/docs/nested/src/content/docs', + 'Nested double match finds innermost', + `Got ${detectContentDir('/a/src/content/docs/nested/src/content/docs/deep/file.md')}`, + ); + + assert(detectContentDir('') === null, 'Empty string returns null', `Got ${detectContentDir('')}`); + + console.log(''); + + // ============================================================ + // Transformer skip conditions + // ============================================================ + console.log(`${colors.yellow}Transformer skip conditions (21 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('https://example.com'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === 'https://example.com', 'External https URL unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('http://example.com'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === 'http://example.com', 'External http URL unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('//cdn.example.com/path'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '//cdn.example.com/path', 'Protocol-relative // unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('mailto:user@example.com'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === 'mailto:user@example.com', 'mailto: unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('tel:+15551234567'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === 'tel:+15551234567', 'tel: unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('./page.html'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === './page.html', '.html unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('./doc.pdf'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === './doc.pdf', '.pdf unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('./page.mdx'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === './page.mdx', '.mdx unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('#section'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '#section', '#section unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('?page=2'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '?page=2', '?page=2 unchanged', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree(''); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '', 'Empty href unchanged', `Got ${getHref(tree)}`); + } + + { + // Non-anchor element (div) unchanged + const tree = { + type: 'root', + children: [ + { + type: 'element', + tagName: 'div', + properties: { href: 'page.md' }, + children: [], + }, + ], + }; + transform(tree, STD_FILE, STD_OPTS); + assert(tree.children[0].properties.href === 'page.md', 'Non-anchor element (div) unchanged', `Got ${tree.children[0].properties.href}`); + } + + { + // Anchor without properties (no crash) + const tree = { + type: 'root', + children: [{ type: 'element', tagName: 'a', children: [] }], + }; + let threw = false; + try { + transform(tree, STD_FILE, STD_OPTS); + } catch { + threw = true; + } + assert(!threw, 'Anchor without properties unchanged (no crash)'); + } + + { + // Anchor with numeric href + const tree = { + type: 'root', + children: [ + { + type: 'element', + tagName: 'a', + properties: { href: 42 }, + children: [], + }, + ], + }; + transform(tree, STD_FILE, STD_OPTS); + assert(tree.children[0].properties.href === 42, 'Anchor with numeric href unchanged', `Got ${tree.children[0].properties.href}`); + } + + { + // Anchor with null href + const tree = { + type: 'root', + children: [ + { + type: 'element', + tagName: 'a', + properties: { href: null }, + children: [], + }, + ], + }; + transform(tree, STD_FILE, STD_OPTS); + assert(tree.children[0].properties.href === null, 'Anchor with null href unchanged', `Got ${tree.children[0].properties.href}`); + } + + { + // Anchor with undefined href + const tree = { + type: 'root', + children: [ + { + type: 'element', + tagName: 'a', + properties: { href: undefined }, + children: [], + }, + ], + }; + transform(tree, STD_FILE, STD_OPTS); + assert( + tree.children[0].properties.href === undefined, + 'Anchor with undefined href unchanged', + `Got ${tree.children[0].properties.href}`, + ); + } + + { + // Target outside content root unchanged + const tree = makeAnchorTree('../../../../../../outside.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '../../../../../../outside.md', 'Target outside content root unchanged', `Got ${getHref(tree)}`); + } + + { + // No file path -> no processing + const tree = makeAnchorTree('sibling.md'); + transform(tree, { path: undefined }, STD_OPTS); + assert(getHref(tree) === 'sibling.md', 'No file path -> no processing', `Got ${getHref(tree)}`); + } + + { + // Empty string path -> no processing + const tree = makeAnchorTree('sibling.md'); + transform(tree, { path: '' }, STD_OPTS); + assert(getHref(tree) === 'sibling.md', 'Empty string path -> no processing', `Got ${getHref(tree)}`); + } + + { + // page.MD (uppercase) unchanged + const tree = makeAnchorTree('page.MD'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === 'page.MD', 'page.MD (uppercase) unchanged', `Got ${getHref(tree)}`); + } + + { + // page.Md (mixed case) unchanged + const tree = makeAnchorTree('page.Md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === 'page.Md', 'page.Md (mixed case) unchanged', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // Error conditions + // ============================================================ + console.log(`${colors.yellow}Error conditions (1 test)${colors.reset}\n`); + + { + // No content dir + no contentDir option -> throws + const tree = makeAnchorTree('sibling.md'); + const file = { path: '/some/random/path/file.md' }; + let threw = false; + let errorMsg = ''; + try { + transform(tree, file, {}); + } catch (error) { + threw = true; + errorMsg = error.message; + } + assert( + threw && errorMsg.includes('Could not detect content directory'), + 'No content dir + no contentDir option throws', + `threw=${threw}, msg=${errorMsg}`, + ); + } + + console.log(''); + + // ============================================================ + // Path resolution + // ============================================================ + console.log(`${colors.yellow}Path resolution (7 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('sibling.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/sibling/', 'Bare relative sibling.md -> /guide/sibling/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('./sibling.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/sibling/', 'Dot-slash ./sibling.md -> /guide/sibling/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('../other/page.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/other/page/', 'Parent ../other/page.md -> /other/page/', `Got ${getHref(tree)}`); + } + + { + // Use a file two levels deep so ../../ still stays inside content root + const deepFile = { + path: '/project/src/content/docs/guide/sub/intro.md', + }; + const tree = makeAnchorTree('../../root-level.md'); + transform(tree, deepFile, STD_OPTS); + assert(getHref(tree) === '/root-level/', 'Deep parent ../../root-level.md -> /root-level/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('./sub/deep/page.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/sub/deep/page/', 'Into subdir ./sub/deep/page.md -> /guide/sub/deep/page/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/docs/guide/page.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/page/', 'Absolute /docs/guide/page.md -> /guide/page/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/guide/page.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/page/', 'Absolute /guide/page.md -> /guide/page/', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // Index handling + // ============================================================ + console.log(`${colors.yellow}Index handling (5 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('index.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/', 'index.md -> /guide/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('./sub/index.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/sub/', './sub/index.md -> /guide/sub/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('../index.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/', '../index.md -> /', `Got ${getHref(tree)}`); + } + + { + // Root index.md: file at content root + const rootFile = { + path: '/project/src/content/docs/intro.md', + }; + const tree = makeAnchorTree('index.md'); + transform(tree, rootFile, STD_OPTS); + assert(getHref(tree) === '/', 'Root index.md -> /', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/docs/index.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/', '/docs/index.md -> /', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // Query/hash preservation + // ============================================================ + console.log(`${colors.yellow}Query/hash preservation (5 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('page.md#section'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/page/#section', 'page.md#section -> /guide/page/#section', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('page.md?foo=bar'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/page/?foo=bar', 'page.md?foo=bar -> /guide/page/?foo=bar', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('page.md?foo=bar#section'); + transform(tree, STD_FILE, STD_OPTS); + assert( + getHref(tree) === '/guide/page/?foo=bar#section', + 'page.md?foo=bar#section -> /guide/page/?foo=bar#section', + `Got ${getHref(tree)}`, + ); + } + + { + const tree = makeAnchorTree('page.md#section?foo=bar'); + transform(tree, STD_FILE, STD_OPTS); + assert( + getHref(tree) === '/guide/page/#section?foo=bar', + 'page.md#section?foo=bar -> /guide/page/#section?foo=bar', + `Got ${getHref(tree)}`, + ); + } + + { + const tree = makeAnchorTree('index.md#top'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/#top', 'index.md#top -> /guide/#top', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // Base path + // ============================================================ + console.log(`${colors.yellow}Base path (4 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('page.md'); + transform(tree, STD_FILE, { ...STD_OPTS, base: '/' }); + assert(getHref(tree) === '/guide/page/', 'Base / -> /guide/page/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('page.md'); + transform(tree, STD_FILE, { ...STD_OPTS, base: '/BMAD-METHOD/' }); + assert(getHref(tree) === '/BMAD-METHOD/guide/page/', 'Base /BMAD-METHOD/ -> /BMAD-METHOD/guide/page/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('page.md'); + transform(tree, STD_FILE, { ...STD_OPTS, base: '/BMAD-METHOD' }); + assert(getHref(tree) === '/BMAD-METHOD/guide/page/', 'Base /BMAD-METHOD (no trailing slash) -> same result', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('page.md'); + transform(tree, STD_FILE, { ...STD_OPTS, base: '/org/repo/docs/' }); + assert(getHref(tree) === '/org/repo/docs/guide/page/', 'Base /org/repo/docs/ -> /org/repo/docs/guide/page/', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // Normalization + // ============================================================ + console.log(`${colors.yellow}Normalization (3 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('page.md'); + transform(tree, STD_FILE, { ...STD_OPTS, base: '/' }); + assert(!getHref(tree).includes('//'), 'No // in output for root base', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('page.md'); + transform(tree, STD_FILE, { ...STD_OPTS, base: '/BMAD-METHOD/' }); + assert(!getHref(tree).includes('//'), 'No // in output for subpath base', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('page.md#section'); + transform(tree, STD_FILE, STD_OPTS); + const href = getHref(tree); + const hashIndex = href.indexOf('#'); + assert(href[hashIndex - 1] === '/', 'Trailing slash before suffix', `Got ${href}`); + } + + console.log(''); + + // ============================================================ + // Edge cases + // ============================================================ + console.log(`${colors.yellow}Edge cases (5 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('v2.0.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/v2.0/', 'v2.0.md -> /guide/v2.0/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('file.test.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/file.test/', 'file.test.md -> /guide/file.test/', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('markdown-guide/foo.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/markdown-guide/foo/', 'markdown-guide/foo.md -> /guide/markdown-guide/foo/', `Got ${getHref(tree)}`); + } + + { + // .md bare -> processes (not left as ".md") + const tree = makeAnchorTree('.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) !== '.md', '.md bare -> processes (not left as ".md")', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('\u00FCber-guide.md'); + transform(tree, STD_FILE, STD_OPTS); + assert(getHref(tree) === '/guide/\u00FCber-guide/', '\u00FCber-guide.md -> /guide/\u00FCber-guide/', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // rehype-base-paths: Option handling + // ============================================================ + console.log(`${colors.yellow}rehype-base-paths: Option handling (5 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('/page/'); + transformBase(tree, {}); + assert(getHref(tree) === '/page/', 'Default no-op for absolute href', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/page/'); + transformBase(tree, { base: '/BMAD-METHOD/' }); + assert(getHref(tree) === '/BMAD-METHOD/page/', 'Base /BMAD-METHOD/ prefixes', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/page/'); + transformBase(tree, { base: '/BMAD-METHOD' }); + assert(getHref(tree) === '/BMAD-METHOD/page/', 'Base /BMAD-METHOD normalizes (adds trailing slash)', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/page/'); + transformBase(tree, { base: '' }); + assert(getHref(tree) === '/page/', 'Empty string falls back to / (no-op)', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/page/'); + transformBase(tree, { base: '/' }); + assert(getHref(tree) === '/page/', 'Root / is no-op', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // rehype-base-paths: Element rewriting + // ============================================================ + console.log(`${colors.yellow}rehype-base-paths: Element rewriting (9 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('/page/'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '/BMAD-METHOD/page/', 'a[href] prefixed', `Got ${getHref(tree)}`); + } + + { + const tree = makeElementTree('img', { src: '/img/logo.png' }); + transformBase(tree, { base: BASE }); + assert(getSrc(tree) === '/BMAD-METHOD/img/logo.png', 'img[src] prefixed', `Got ${getSrc(tree)}`); + } + + { + const tree = makeElementTree('link', { href: '/styles/main.css' }); + transformBase(tree, { base: BASE }); + assert( + tree.children[0].properties.href === '/BMAD-METHOD/styles/main.css', + 'link[href] prefixed', + `Got ${tree.children[0].properties.href}`, + ); + } + + { + const tree = makeElementTree('script', { src: '/js/app.js' }); + transformBase(tree, { base: BASE }); + assert(getSrc(tree) === '/js/app.js', 'script[src] NOT prefixed (not in tag list)', `Got ${getSrc(tree)}`); + } + + { + const tree = makeElementTree('video', { src: '/media/intro.mp4' }); + transformBase(tree, { base: BASE }); + assert(getSrc(tree) === '/BMAD-METHOD/media/intro.mp4', 'video[src] prefixed', `Got ${getSrc(tree)}`); + } + + { + const tree = makeElementTree('audio', { src: '/media/clip.mp3' }); + transformBase(tree, { base: BASE }); + assert(getSrc(tree) === '/BMAD-METHOD/media/clip.mp3', 'audio[src] prefixed', `Got ${getSrc(tree)}`); + } + + { + const tree = makeElementTree('iframe', { src: '/embed/widget' }); + transformBase(tree, { base: BASE }); + assert(getSrc(tree) === '/BMAD-METHOD/embed/widget', 'iframe[src] prefixed', `Got ${getSrc(tree)}`); + } + + { + const tree = makeElementTree('area', { href: '/map/region' }); + transformBase(tree, { base: BASE }); + assert( + tree.children[0].properties.href === '/map/region', + 'area[href] NOT prefixed (not in tag list)', + `Got ${tree.children[0].properties.href}`, + ); + } + + { + const tree = makeElementTree('source', { src: '/media/alt.mp4' }); + transformBase(tree, { base: BASE }); + assert(getSrc(tree) === '/BMAD-METHOD/media/alt.mp4', 'source[src] prefixed', `Got ${getSrc(tree)}`); + } + + console.log(''); + + // ============================================================ + // rehype-base-paths: No-op base / + // ============================================================ + console.log(`${colors.yellow}rehype-base-paths: No-op base / (2 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('/page/'); + transformBase(tree, { base: '/' }); + assert(getHref(tree) === '/page/', 'a[href] unchanged with base /', `Got ${getHref(tree)}`); + } + + { + const tree = makeElementTree('img', { src: '/img/logo.png' }); + transformBase(tree, { base: '/' }); + assert(getSrc(tree) === '/img/logo.png', 'img[src] unchanged with base /', `Got ${getSrc(tree)}`); + } + + console.log(''); + + // ============================================================ + // rehype-base-paths: Skip conditions + // ============================================================ + console.log(`${colors.yellow}rehype-base-paths: Skip conditions (10 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('//cdn.example.com/path'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '//cdn.example.com/path', 'Protocol-relative skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('https://example.com'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === 'https://example.com', 'External https skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('http://example.com'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === 'http://example.com', 'External http skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('data:text/html,hello'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === 'data:text/html,hello', 'data: URI skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('#section'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '#section', '#section skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree(''); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '', 'Empty href skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/BMAD-METHOD/page/'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '/BMAD-METHOD/page/', 'Already prefixed skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('relative/path'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === 'relative/path', 'Relative path skipped', `Got ${getHref(tree)}`); + } + + { + // Non-target element (button with href-like attribute via properties) + const tree = makeElementTree('button', { href: '/page/' }); + transformBase(tree, { base: BASE }); + assert(tree.children[0].properties.href === '/page/', 'Non-target element skipped', `Got ${tree.children[0].properties.href}`); + } + + { + // Non-target attribute (data-url on an img) + const tree = makeElementTree('img', { + src: '/img/logo.png', + 'data-url': '/some/path', + }); + transformBase(tree, { base: BASE }); + assert( + tree.children[0].properties['data-url'] === '/some/path', + 'Non-target attribute (data-url) skipped', + `Got ${tree.children[0].properties['data-url']}`, + ); + } + + console.log(''); + + // ============================================================ + // rehype-base-paths: Anchor .md handling + // ============================================================ + console.log(`${colors.yellow}rehype-base-paths: Anchor .md handling (4 tests)${colors.reset}\n`); + + { + const tree = makeAnchorTree('/docs/guide/page.md'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '/docs/guide/page.md', '.md href skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/docs/guide/page.md#section'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '/docs/guide/page.md#section', '.md#section skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/docs/guide/page.md?v=1'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '/docs/guide/page.md?v=1', '.md?v=1 skipped', `Got ${getHref(tree)}`); + } + + { + const tree = makeAnchorTree('/docs/index.md'); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '/docs/index.md', 'index.md skipped', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // rehype-base-paths: srcset + // ============================================================ + console.log(`${colors.yellow}rehype-base-paths: srcset (1 test)${colors.reset}\n`); + + { + const tree = makeElementTree('img', { + src: '/img/logo.png', + srcset: '/img/logo-2x.png 2x', + }); + transformBase(tree, { base: BASE }); + assert( + tree.children[0].properties.srcset === '/img/logo-2x.png 2x', + 'srcset not handled by plugin', + `Got ${tree.children[0].properties.srcset}`, + ); + } + + console.log(''); + + // ============================================================ + // rehype-base-paths: Raw HTML + // ============================================================ + console.log(`${colors.yellow}rehype-base-paths: Raw HTML (7 tests)${colors.reset}\n`); + + { + const tree = { + type: 'root', + children: [{ type: 'raw', value: '' }], + }; + transformBase(tree, { base: BASE }); + assert(getRawValue(tree) === '', 'Raw img src rewritten', `Got ${getRawValue(tree)}`); + } + + { + const tree = { + type: 'root', + children: [{ type: 'raw', value: 'link' }], + }; + transformBase(tree, { base: BASE }); + assert(getRawValue(tree) === 'link', 'Raw a href rewritten', `Got ${getRawValue(tree)}`); + } + + { + const tree = { + type: 'root', + children: [{ type: 'raw', value: '' }], + }; + transformBase(tree, { base: BASE }); + assert(getRawValue(tree) === '', 'Raw protocol-relative unchanged', `Got ${getRawValue(tree)}`); + } + + { + const tree = { + type: 'root', + children: [ + { + type: 'raw', + value: '', + }, + ], + }; + transformBase(tree, { base: BASE }); + assert(getRawValue(tree) === '', 'Raw already prefixed unchanged', `Got ${getRawValue(tree)}`); + } + + { + const tree = { + type: 'root', + children: [ + { + type: 'raw', + value: '', + }, + ], + }; + transformBase(tree, { base: BASE }); + assert( + getRawValue(tree) === '', + 'Raw multiple attributes rewritten', + `Got ${getRawValue(tree)}`, + ); + } + + { + const tree = { + type: 'root', + children: [ + { + type: 'raw', + value: 'external', + }, + ], + }; + transformBase(tree, { base: BASE }); + assert(getRawValue(tree) === 'external', 'Raw external URL unchanged', `Got ${getRawValue(tree)}`); + } + + { + // Base / skips raw visit entirely + const tree = { + type: 'root', + children: [{ type: 'raw', value: '' }], + }; + transformBase(tree, { base: '/' }); + assert(getRawValue(tree) === '', 'Base / skips raw visit', `Got ${getRawValue(tree)}`); + } + + console.log(''); + + // ============================================================ + // Integration: both plugins together + // ============================================================ + console.log(`${colors.yellow}Integration: both plugins together (4 tests)${colors.reset}\n`); + + { + // ./sibling.md through both -> no double prefix + const tree = makeAnchorTree('./sibling.md'); + transform(tree, STD_FILE, { ...STD_OPTS, base: BASE }); + transformBase(tree, { base: BASE }); + const href = getHref(tree); + assert(href === '/BMAD-METHOD/guide/sibling/', './sibling.md through both -> no double prefix', `Got ${href}`); + } + + { + // img /img/logo.png -> only base-paths prefixes + const tree = makeElementTree('img', { src: '/img/logo.png' }); + // markdown-links doesn't touch img elements, so just run base-paths + transformBase(tree, { base: BASE }); + assert(getSrc(tree) === '/BMAD-METHOD/img/logo.png', 'img /img/logo.png -> only base-paths prefixes', `Got ${getSrc(tree)}`); + } + + { + // External -> both skip + const tree = makeAnchorTree('https://example.com'); + transform(tree, STD_FILE, { ...STD_OPTS, base: BASE }); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === 'https://example.com', 'External -> both skip', `Got ${getHref(tree)}`); + } + + { + // /page/ (non-.md) -> only base-paths prefixes + const tree = makeAnchorTree('/page/'); + transform(tree, STD_FILE, { ...STD_OPTS, base: BASE }); + transformBase(tree, { base: BASE }); + assert(getHref(tree) === '/BMAD-METHOD/page/', '/page/ (non-.md) -> only base-paths prefixes', `Got ${getHref(tree)}`); + } + + console.log(''); + + // ============================================================ + // Summary + // ============================================================ + console.log(`${colors.cyan}========================================`); + console.log('Test Results:'); + console.log(` Passed: ${colors.green}${passed}${colors.reset}`); + console.log(` Failed: ${colors.red}${failed}${colors.reset}`); + console.log(`========================================${colors.reset}\n`); + + if (failed === 0) { + console.log(`${colors.green}All rehype plugin tests passed!${colors.reset}\n`); + process.exit(0); + } else { + console.log(`${colors.red}Some rehype plugin tests failed${colors.reset}\n`); + process.exit(1); + } +} + +// Run tests +try { + runTests(); +} catch (error) { + console.error(`${colors.red}Test runner failed:${colors.reset}`, error.message); + console.error(error.stack); + process.exit(1); +} diff --git a/tools/build-docs.mjs b/tools/build-docs.mjs index fac767c42..bf04eb911 100644 --- a/tools/build-docs.mjs +++ b/tools/build-docs.mjs @@ -52,6 +52,12 @@ const LLM_EXCLUDE_PATTERNS = [ */ async function main() { + if (process.platform === 'win32') { + console.error('Error: The docs build pipeline does not support Windows.'); + console.error('Please build on Linux, macOS, or WSL.'); + process.exit(1); + } + console.log(); printBanner('BMAD Documentation Build Pipeline'); console.log(); @@ -118,9 +124,6 @@ function buildAstroSite() { runAstroBuild(); copyArtifactsToSite(artifactsDir, siteDir); - // No longer needed: Inject AI agents banner into every HTML page - // injectAgentBanner(siteDir); - console.log(); console.log(` \u001B[32m✓\u001B[0m Astro build complete`); @@ -152,20 +155,18 @@ function generateLlmsTxt(outputDir) { '', '## Quick Start', '', - `- **[Quick Start](${siteUrl}/docs/modules/bmm/quick-start)** - Get started with BMAD Method`, - `- **[Installation](${siteUrl}/docs/getting-started/installation)** - Installation guide`, + `- **[Getting Started](${siteUrl}/tutorials/getting-started/)** - Tutorial: install and learn how BMad works`, + `- **[Installation](${siteUrl}/how-to/install-bmad/)** - How to install BMad Method`, '', '## Core Concepts', '', - `- **[Scale Adaptive System](${siteUrl}/docs/modules/bmm/scale-adaptive-system)** - Understand BMAD scaling`, - `- **[Quick Flow](${siteUrl}/docs/modules/bmm/bmad-quick-flow)** - Fast development workflow`, - `- **[Party Mode](${siteUrl}/docs/modules/bmm/party-mode)** - Multi-agent collaboration`, + `- **[Quick Flow](${siteUrl}/explanation/quick-flow/)** - Fast development workflow`, + `- **[Party Mode](${siteUrl}/explanation/party-mode/)** - Multi-agent collaboration`, + `- **[Workflow Map](${siteUrl}/reference/workflow-map/)** - Visual overview of phases and workflows`, '', '## Modules', '', - `- **[BMM - Method](${siteUrl}/docs/modules/bmm/quick-start)** - Core methodology module`, - `- **[BMB - Builder](${siteUrl}/docs/modules/bmb/)** - Agent and workflow builder`, - `- **[BMGD - Game Dev](${siteUrl}/docs/modules/bmgd/quick-start)** - Game development module`, + `- **[Official Modules](${siteUrl}/reference/modules/)** - BMM, BMB, BMGD, and more`, '', '---', '', @@ -401,32 +402,6 @@ function formatFileSize(bytes) { return `${bytes}B`; } -// ============================================================================= -// Post-build Injection -/** - * Recursively collects all files with the given extension under a directory. - * - * @param {string} dir - Root directory to search. - * @param {string} ext - File extension to match (include the leading dot, e.g. ".md"). - * @returns {string[]} An array of file paths for files ending with `ext` found under `dir`. - */ - -function getAllFilesByExtension(dir, ext) { - const result = []; - const entries = fs.readdirSync(dir, { withFileTypes: true }); - - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - result.push(...getAllFilesByExtension(fullPath, ext)); - } else if (entry.name.endsWith(ext)) { - result.push(fullPath); - } - } - - return result; -} - // ============================================================================= // File System Utilities /** @@ -444,33 +419,6 @@ function cleanBuildDirectory() { fs.mkdirSync(BUILD_DIR, { recursive: true }); } -/** - * Recursively copies all files and subdirectories from one directory to another, creating the destination if needed. - * - * @param {string} src - Path to the source directory to copy from. - * @param {string} dest - Path to the destination directory to copy to. - * @param {string[]} [exclude=[]] - List of file or directory names (not paths) to skip while copying. - * @returns {boolean} `true` if the source existed and copying proceeded, `false` if the source did not exist. - */ -function copyDirectory(src, dest, exclude = []) { - if (!fs.existsSync(src)) return false; - fs.mkdirSync(dest, { recursive: true }); - - for (const entry of fs.readdirSync(src, { withFileTypes: true })) { - if (exclude.includes(entry.name)) continue; - - const srcPath = path.join(src, entry.name); - const destPath = path.join(dest, entry.name); - - if (entry.isDirectory()) { - copyDirectory(srcPath, destPath, exclude); - } else { - fs.copyFileSync(srcPath, destPath); - } - } - return true; -} - // ============================================================================= // Console Output Formatting // ============================================================================= @@ -496,7 +444,7 @@ function printBanner(title) { /** * Verify internal documentation links by running the link-checking script. * - * Executes the Node script tools/check-doc-links.js from the project root and + * Executes the Node script tools/validate-doc-links.js from the project root and * exits the process with code 1 if the check fails. */ diff --git a/tools/fix-doc-links.js b/tools/fix-doc-links.js index dbfcc8620..e2ae6bdf7 100644 --- a/tools/fix-doc-links.js +++ b/tools/fix-doc-links.js @@ -20,11 +20,8 @@ const path = require('node:path'); const DOCS_ROOT = path.resolve(__dirname, '../docs'); const DRY_RUN = !process.argv.includes('--write'); -// Regex to match markdown links: -// - [text](path.md) or [text](path.md#anchor) - existing .md links -// - [text](/path/to/page/) or [text](/path/to/page/#anchor) - site-relative links to convert -const MARKDOWN_LINK_REGEX = /\[([^\]]*)\]\(([^)]+(?:\.md|\/))(?:#[^)]*)?(?:\?[^)]*)?\)/g; -// Simpler approach: match all markdown links and filter in the handler +// Match all markdown links; filtering (external, anchors, assets) happens in convertToRepoRelative. +// This intentionally matches broadly so the handler can make context-aware decisions. const ALL_MARKDOWN_LINKS_REGEX = /\[([^\]]*)\]\(([^)]+)\)/g; /** @@ -64,8 +61,8 @@ function getMarkdownFiles(dir) { * @returns {string|null} - Repo-relative path (e.g., "/docs/path/to/file.md"), or null if shouldn't be converted */ function convertToRepoRelative(href, currentFilePath) { - // Skip external links - if (href.includes('://') || href.startsWith('mailto:') || href.startsWith('tel:')) { + // Skip external links (including protocol-relative URLs like //cdn.example.com) + if (href.includes('://') || href.startsWith('//') || href.startsWith('mailto:') || href.startsWith('tel:')) { return null; } diff --git a/tools/validate-doc-links.js b/tools/validate-doc-links.js index f6f514cc0..f8ce4c478 100644 --- a/tools/validate-doc-links.js +++ b/tools/validate-doc-links.js @@ -21,8 +21,8 @@ const path = require('node:path'); const DOCS_ROOT = path.resolve(__dirname, '../docs'); const DRY_RUN = !process.argv.includes('--write'); -// Regex to match markdown links with site-relative paths -const LINK_REGEX = /\[([^\]]*)\]\((\/[^)]+)\)/g; +// Regex to match markdown links with site-relative paths or bare .md references +const LINK_REGEX = /\[([^\]]*)\]\(((?:\.{1,2}\/|\/)[^)]+|[\w][^)\s]*\.md(?:[?#][^)]*)?)\)/g; // File extensions that are static assets, not markdown docs const STATIC_ASSET_EXTENSIONS = ['.zip', '.txt', '.pdf', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico']; @@ -108,11 +108,27 @@ function extractAnchors(content) { * /docs/how-to/installation/install-bmad.md -> docs/how-to/installation/install-bmad.md * /how-to/installation/install-bmad/ -> docs/how-to/installation/install-bmad.md or .../index.md */ -function resolveLink(siteRelativePath) { +function resolveLink(siteRelativePath, sourceFile) { // Strip anchor and query let checkPath = siteRelativePath.split('#')[0].split('?')[0]; - // Strip /docs/ prefix if present (repo-relative links) + // Handle relative paths (including bare .md): resolve from source file's directory + if (checkPath.startsWith('./') || checkPath.startsWith('../') || (!checkPath.startsWith('/') && checkPath.endsWith('.md'))) { + const sourceDir = path.dirname(sourceFile); + const resolved = path.resolve(sourceDir, checkPath); + // Ensure the resolved path stays within DOCS_ROOT + if (!resolved.startsWith(DOCS_ROOT + path.sep) && resolved !== DOCS_ROOT) return null; + if (fs.existsSync(resolved) && fs.statSync(resolved).isFile()) return resolved; + if (fs.existsSync(resolved + '.md')) return resolved + '.md'; + // Directory: check for index.md + if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) { + const indexFile = path.join(resolved, 'index.md'); + if (fs.existsSync(indexFile)) return indexFile; + } + return null; + } + + // Strip /docs/ prefix if present (legacy absolute links) if (checkPath.startsWith('/docs/')) { checkPath = checkPath.slice(5); // Remove '/docs' but keep leading '/' } @@ -129,12 +145,18 @@ function resolveLink(siteRelativePath) { // Direct path (e.g., /path/file.md) const direct = path.join(DOCS_ROOT, checkPath); - if (fs.existsSync(direct)) return direct; + if (fs.existsSync(direct) && fs.statSync(direct).isFile()) return direct; // Try with .md extension const withMd = direct + '.md'; if (fs.existsSync(withMd)) return withMd; + // Directory without trailing slash: check for index.md + if (fs.existsSync(direct) && fs.statSync(direct).isDirectory()) { + const indexFile = path.join(direct, 'index.md'); + if (fs.existsSync(indexFile)) return indexFile; + } + return null; } @@ -144,7 +166,7 @@ function resolveLink(siteRelativePath) { function findFileWithContext(brokenPath) { // Extract filename and parent directory from the broken path // e.g., /tutorials/getting-started/foo/ -> parent: getting-started, file: foo.md - const cleanPath = brokenPath.replace(/\/$/, '').replace(/^\//, ''); + const cleanPath = brokenPath.replace(/\/$/, '').replace(/^(\.\.\/|\.\/|\/)+/, ''); const parts = cleanPath.split('/'); const fileName = parts.at(-1) + '.md'; const parentDir = parts.length > 1 ? parts.at(-2) : null; @@ -219,7 +241,7 @@ function processFile(filePath) { } // Validate the link target exists - const targetFile = resolveLink(linkPath); + const targetFile = resolveLink(linkPath, filePath); if (!targetFile) { // Link is broken - try to find the file diff --git a/website/public/img/logo.svg b/website/public/img/logo.svg deleted file mode 100644 index 1dbba3c17..000000000 --- a/website/public/img/logo.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - B - diff --git a/website/public/img/workflow-map.png b/website/public/img/workflow-map.png deleted file mode 100644 index 61e0ab4a3..000000000 Binary files a/website/public/img/workflow-map.png and /dev/null differ diff --git a/website/src/components/Banner.astro b/website/src/components/Banner.astro index d0c94e5dc..00944d669 100644 --- a/website/src/components/Banner.astro +++ b/website/src/components/Banner.astro @@ -4,17 +4,16 @@ import { getSiteUrl } from '../lib/site-url.mjs'; const llmsFullUrl = `${getSiteUrl()}/llms-full.txt`; --- -
+
🤖 Consolidated, AI-optimized BMAD docs: llms-full.txt. Fetch this plain text file for complete context.