feat: convert docs to site-relative links and add validation tools

- Convert all relative links (./  ../) to site-relative paths (/path/)
- Strip .md extensions and use trailing slashes for Astro/Starlight
- Add fix-doc-links.js to convert relative links to site-relative
- Add validate-doc-links.js to check links point to existing files
- Remove old audit-doc-links.js and check-doc-links.js
- Update build-docs.js to use new validation script
- Add npm scripts: docs:fix-links, docs:validate-links
- Update style guide with validation steps

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
forcetrainer 2026-01-08 01:31:40 -05:00
parent bfc9c71077
commit 433967eec1
77 changed files with 933 additions and 1023 deletions

View File

@ -9,6 +9,27 @@ Internal guidelines for maintaining consistent, high-quality documentation acros
3. **Strategic visuals** — Use admonitions, tables, and diagrams purposefully
4. **Scannable content** — Headers, lists, and callouts help readers find what they need
## Validation Steps
Before submitting documentation changes, run these checks from the repo root:
1. **Fix link format** — Convert relative links (`./`, `../`) to site-relative paths (`/path/`)
```bash
npm run docs:fix-links # Preview changes
npm run docs:fix-links -- --write # Apply changes
```
2. **Validate links** — Check all links point to existing files
```bash
npm run docs:validate-links # Preview issues
npm run docs:validate-links -- --write # Auto-fix where possible
```
3. **Build the site** — Verify no build errors
```bash
npm run docs:build
```
## Tutorial Structure
Every tutorial should follow this structure:

View File

@ -0,0 +1,75 @@
# BMAD Method
[![Version](https://img.shields.io/npm/v/bmad-method?color=blue&label=version)](https://www.npmjs.com/package/bmad-method)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org)
[![Discord](https://img.shields.io/badge/Discord-Join%20Community-7289da?logo=discord&logoColor=white)](https://discord.gg/gk8jAdXWmj)
**Build More, Architect Dreams** — An AI-driven agile development framework with 21 specialized agents, 50+ guided workflows, and scale-adaptive intelligence that adjusts from bug fixes to enterprise systems.
## Why BMAD?
Traditional AI tools do the thinking for you, producing average results. BMAD agents act as expert collaborators who guide you through structured workflows to bring out your best thinking.
- **Scale-Adaptive**: Automatically adjusts planning depth based on project complexity (Level 0-4)
- **Structured Workflows**: Grounded in agile best practices across analysis, planning, architecture, and implementation
- **Specialized Agents**: 12+ domain experts (PM, Architect, Developer, UX, Scrum Master, and more)
- **Complete Lifecycle**: From brainstorming to deployment, with just-in-time documentation
## Quick Start
**Prerequisites**: [Node.js](https://nodejs.org) v20+
```bash
npx bmad-method@alpha install
```
Follow the installer prompts to configure your project. Then run:
```bash
*workflow-init
```
This analyzes your project and recommends a track:
| Track | Best For | Time to First Story |
| --------------- | ------------------------- | ------------------- |
| **Quick Flow** | Bug fixes, small features | ~5 minutes |
| **BMad Method** | Products and platforms | ~15 minutes |
| **Enterprise** | Compliance-heavy systems | ~30 minutes |
## Modules
| Module | Purpose |
| ------------------------------------- | -------------------------------------------------------- |
| **BMad Method (BMM)** | Core agile development with 34 workflows across 4 phases |
| **BMad Builder (BMB)** | Create custom agents and domain-specific modules |
| **Creative Intelligence Suite (CIS)** | Innovation, brainstorming, and problem-solving |
## Documentation
**[Full Documentation](http://docs.bmad-method.org)** — Tutorials, how-to guides, concepts, and reference
- [Getting Started Tutorial](TBD_GITHUB_PAGES_URL/tutorials/getting-started)
- [Upgrading from Previous Versions](TBD)
## Community
- [Discord](https://discord.gg/gk8jAdXWmj) — Get help, share ideas, collaborate
- [YouTube](https://www.youtube.com/@BMadCode) — Video tutorials and updates
- [GitHub Issues](https://github.com/bmad-code-org/BMAD-METHOD/issues) — Bug reports and feature requests
- [Discussions](https://github.com/bmad-code-org/BMAD-METHOD/discussions) — Community conversations
## Contributing
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
## License
MIT License — see [LICENSE](LICENSE) for details.
---
**BMAD** and **BMAD-METHOD** are trademarks of BMad Code, LLC.
[![Contributors](https://contrib.rocks/image?repo=bmad-code-org/BMAD-METHOD)](https://github.com/bmad-code-org/BMAD-METHOD/graphs/contributors)

View File

@ -310,11 +310,11 @@ Implement OAuth 2.0 authentication with JWT tokens and role-based access control
## Related Documentation
- **[Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md)** - Getting started with BMM
- **[Agents Guide](../../explanation/core-concepts/agent-roles.md)** - Complete agent reference
- **[Four Phases](../../explanation/architecture/four-phases.md)** - Understanding development tracks
- **[Workflow Implementation](../../how-to/workflows/run-sprint-planning.md)** - Implementation workflows
- **[Party Mode](../../explanation/features/party-mode.md)** - Multi-agent collaboration
- **[Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/)** - Getting started with BMM
- **[Agents Guide](/explanation/core-concepts/agent-roles/)** - Complete agent reference
- **[Four Phases](/explanation/architecture/four-phases/)** - Understanding development tracks
- **[Workflow Implementation](/how-to/workflows/run-sprint-planning/)** - Implementation workflows
- **[Party Mode](/explanation/features/party-mode/)** - Multi-agent collaboration
---

View File

@ -12,17 +12,17 @@ Comprehensive guides to BMAD's AI agents - their roles, capabilities, and how to
### BMM Agents
- **[Agent Roles](../core-concepts/agent-roles.md)** - Overview of all BMM agent roles and responsibilities
- **[Quick Flow Solo Dev (Barry)](./barry-quick-flow.md)** - The dedicated agent for rapid development
- **[Agent Roles](/explanation/core-concepts/agent-roles/)** - Overview of all BMM agent roles and responsibilities
- **[Quick Flow Solo Dev (Barry)](/explanation/agents/barry-quick-flow/)** - The dedicated agent for rapid development
### BMGD Agents
- **[Game Development Agents](../game-dev/agents.md)** - Complete guide to BMGD's specialized game dev agents
- **[Game Development Agents](/explanation/game-dev/agents/)** - Complete guide to BMGD's specialized game dev agents
---
## Related
- **[What Are Agents?](../core-concepts/what-are-agents.md)** - Core concept explanation
- **[Party Mode](../features/party-mode.md)** - Multi-agent collaboration
- **[Customize Agents](../../how-to/customization/customize-agents.md)** - How to customize agent behavior
- **[What Are Agents?](/explanation/core-concepts/what-are-agents/)** - Core concept explanation
- **[Party Mode](/explanation/features/party-mode/)** - Multi-agent collaboration
- **[Customize Agents](/how-to/customization/customize-agents/)** - How to customize agent behavior

View File

@ -121,6 +121,6 @@ Same as BMad Method with optional extended workflows.
## Related
- [Why Solutioning Matters](./why-solutioning-matters.md)
- [Preventing Agent Conflicts](./preventing-agent-conflicts.md)
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md)
- [Why Solutioning Matters](/explanation/architecture/why-solutioning-matters/)
- [Preventing Agent Conflicts](/explanation/architecture/preventing-agent-conflicts/)
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/)

View File

@ -133,6 +133,6 @@ Document written once, never updated
## Related
- [Why Solutioning Matters](./why-solutioning-matters.md)
- [Four Phases](./four-phases.md)
- [Create Architecture](../../how-to/workflows/create-architecture.md)
- [Why Solutioning Matters](/explanation/architecture/why-solutioning-matters/)
- [Four Phases](/explanation/architecture/four-phases/)
- [Create Architecture](/how-to/workflows/create-architecture/)

View File

@ -86,6 +86,6 @@ Catching alignment issues in solutioning is 10× faster than discovering them du
## Related
- [Four Phases](./four-phases.md) - Overview of all phases
- [Preventing Agent Conflicts](./preventing-agent-conflicts.md) - Detailed conflict prevention
- [Create Architecture](../../how-to/workflows/create-architecture.md) - How to do it
- [Four Phases](/explanation/architecture/four-phases/) - Overview of all phases
- [Preventing Agent Conflicts](/explanation/architecture/preventing-agent-conflicts/) - Detailed conflict prevention
- [Create Architecture](/how-to/workflows/create-architecture/) - How to do it

View File

@ -27,7 +27,7 @@ This flexibility transforms the platform beyond its current capabilities, enabli
Custom modules range from simple collections of related agents, workflows, and tools designed to work independently, to complex, expansive systems like the BMad Method or even larger applications.
Custom modules are [installable](../../how-to/installation/install-custom-modules.md) using the standard BMAD method and support advanced features:
Custom modules are [installable](/how-to/installation/install-custom-modules/) using the standard BMAD method and support advanced features:
- Optional user information collection during installation/updates
- Versioning and upgrade paths

View File

@ -10,7 +10,7 @@ Create custom agents, workflows, and modules for BMAD.
## Quick Start
- **[Agent Creation Guide](../../tutorials/advanced/create-custom-agent.md)** - Step-by-step guide to building your first agent
- **[Agent Creation Guide](/tutorials/advanced/create-custom-agent/)** - Step-by-step guide to building your first agent
---
@ -56,11 +56,11 @@ Production-ready examples available in the BMB reference folder:
## Installation Guide
For installing standalone simple and expert agents, see:
- [Install Custom Modules](../../how-to/installation/install-custom-modules.md)
- [Install Custom Modules](/how-to/installation/install-custom-modules/)
---
## Related
- [Custom Content Types](./custom-content-types.md) - Understanding content types
- [Create Custom Agent](../../tutorials/advanced/create-custom-agent.md) - Tutorial
- [Custom Content Types](/explanation/bmad-builder/custom-content-types/) - Understanding content types
- [Create Custom Agent](/tutorials/advanced/create-custom-agent/) - Tutorial

View File

@ -11,7 +11,7 @@ Complete guides for the BMad Method Module (BMM) - AI-powered agile development
**New to BMM?** Start here:
- **[Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md)** - Step-by-step guide to building your first project
- **[Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/)** - Step-by-step guide to building your first project
- Installation and setup
- Understanding the four phases
- Running your first workflows
@ -36,26 +36,26 @@ First know there is the full BMad Method Process and then there is a Quick Flow
- All 4 phases have optional steps in them, depending on how rigorous you want to go with planning, research ideation, validation, testing and traceability.
- While there is a lot here, know that even this can be distilled down to a simple PRD, Epic and Story list and then jump into the dev cycle. But if that is all you want, you might be better off with the BMad Quick Flow described next
- **[BMAD Quick Flow](../../explanation/features/quick-flow.md)** - Fast-track development workflow
- **[BMAD Quick Flow](/explanation/features/quick-flow/)** - Fast-track development workflow
- 3-step process: spec → dev → optional review
- Perfect for bug fixes and small features
- Rapid prototyping with production quality
- Implementation in minutes, not days
- Has a specialized single agent that does all of this: **[Quick Flow Solo Dev Agent](../agents/barry-quick-flow.md)**
- Has a specialized single agent that does all of this: **[Quick Flow Solo Dev Agent](/explanation/agents/barry-quick-flow/)**
- **TEA engagement (optional)** - Choose TEA engagement: none, TEA-only (standalone), or integrated by track. See **[Test Architect Guide](../../explanation/features/tea-overview.md)**.
- **TEA engagement (optional)** - Choose TEA engagement: none, TEA-only (standalone), or integrated by track. See **[Test Architect Guide](/explanation/features/tea-overview/)**.
## 🤖 Agents and Collaboration
Complete guide to BMM's AI agent team:
- **[Agents Guide](../../explanation/core-concepts/agent-roles.md)** - Comprehensive agent reference
- **[Agents Guide](/explanation/core-concepts/agent-roles/)** - Comprehensive agent reference
- 12 specialized BMM agents + BMad Master
- Agent roles, workflows, and when to use them
- Agent customization system
- Best practices and common patterns
- **[Party Mode Guide](../../explanation/features/party-mode.md)** - Multi-agent collaboration
- **[Party Mode Guide](/explanation/features/party-mode/)** - Multi-agent collaboration
- How party mode works (19+ agents collaborate in real-time)
- When to use it (strategic, creative, cross-functional, complex)
- Example party compositions
@ -67,7 +67,7 @@ Complete guide to BMM's AI agent team:
Comprehensive guide for brownfield development:
- **[Brownfield Development Guide](../../how-to/brownfield/index.md)** - Complete guide for existing codebases
- **[Brownfield Development Guide](/how-to/brownfield/)** - Complete guide for existing codebases
- Documentation phase strategies
- Track selection for brownfield
- Integration with existing patterns
@ -78,49 +78,49 @@ Comprehensive guide for brownfield development:
Essential reference materials:
- **[Glossary](../../reference/glossary/index.md)** - Key terminology and concepts
- **[FAQ](../faq/index.md)** - Frequently asked questions across all topics
- **[Glossary](/reference/glossary/)** - Key terminology and concepts
- **[FAQ](/explanation/faq/)** - Frequently asked questions across all topics
## 🎯 Choose Your Path
### I need to...
**Build something new (greenfield)**
→ Start with [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md)
→ Start with [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/)
**Fix a bug or add small feature**
→ Use the [Quick Flow Solo Dev](../agents/barry-quick-flow.md) directly with its dedicated stand alone [Quick Bmad Spec Flow](../features/quick-flow.md) process
→ Use the [Quick Flow Solo Dev](/explanation/agents/barry-quick-flow/) directly with its dedicated stand alone [Quick Bmad Spec Flow](/explanation/features/quick-flow/) process
**Work with existing codebase (brownfield)**
→ Read [Brownfield Development Guide](../../how-to/brownfield/index.md)
→ Read [Brownfield Development Guide](/how-to/brownfield/)
→ Pay special attention to documentation requirements for brownfield projects
## 📋 Workflow Guides
Comprehensive documentation for all BMM workflows organized by phase:
- **[Phase 1: Analysis Workflows](../../how-to/workflows/run-brainstorming-session.md)** - Optional exploration and research workflows (595 lines)
- **[Phase 1: Analysis Workflows](/how-to/workflows/run-brainstorming-session/)** - Optional exploration and research workflows (595 lines)
- brainstorm-project, product-brief, research, and more
- When to use analysis workflows
- Creative and strategic tools
- **[Phase 2: Planning Workflows](../../how-to/workflows/create-prd.md)** - Scale-adaptive planning (967 lines)
- **[Phase 2: Planning Workflows](/how-to/workflows/create-prd/)** - Scale-adaptive planning (967 lines)
- prd, tech-spec, gdd, narrative, ux
- Track-based planning approach (Quick Flow, BMad Method, Enterprise Method)
- Which planning workflow to use
- **[Phase 3: Solutioning Workflows](../../how-to/workflows/create-architecture.md)** - Architecture and validation (638 lines)
- **[Phase 3: Solutioning Workflows](/how-to/workflows/create-architecture/)** - Architecture and validation (638 lines)
- architecture, create-epics-and-stories, implementation-readiness
- V6: Epics created AFTER architecture for better quality
- Required for BMad Method and Enterprise Method tracks
- Preventing agent conflicts
- **[Phase 4: Implementation Workflows](../../how-to/workflows/run-sprint-planning.md)** - Sprint-based development (1,634 lines)
- **[Phase 4: Implementation Workflows](/how-to/workflows/run-sprint-planning/)** - Sprint-based development (1,634 lines)
- sprint-planning, create-story, dev-story, code-review
- Complete story lifecycle
- One-story-at-a-time discipline
- **[Testing & QA Workflows](../../explanation/features/tea-overview.md)** - Comprehensive quality assurance (1,420 lines)
- **[Testing & QA Workflows](/explanation/features/tea-overview/)** - Comprehensive quality assurance (1,420 lines)
- Test strategy, automation, quality gates
- TEA agent and test healing
@ -132,4 +132,4 @@ Comprehensive documentation for all BMM workflows organized by phase:
- **[GitHub Issues](https://github.com/bmad-code-org/BMAD-METHOD/issues)** - Report bugs or request features
- **[YouTube Channel](https://www.youtube.com/@BMadCode)** - Video tutorials and walkthroughs
**Ready to begin?** → [Start with the Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md)
**Ready to begin?** → [Start with the Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/)

View File

@ -199,6 +199,6 @@ Fast solo development without handoffs.
## Related
- [What Are Agents](./what-are-agents.md) - Foundational concepts
- [Agent Reference](../../reference/agents/index.md) - Complete command reference
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md)
- [What Are Agents](/explanation/core-concepts/what-are-agents/) - Foundational concepts
- [Agent Reference](/reference/agents/) - Complete command reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/)

View File

@ -9,32 +9,32 @@ Understanding the fundamental building blocks of the BMAD Method.
| Concept | Description | Guide |
|---------|-------------|-------|
| **Agents** | AI assistants with personas, capabilities, and menus | [Agents Guide](./what-are-agents.md) |
| **Workflows** | Structured processes for achieving specific outcomes | [Workflows Guide](./what-are-workflows.md) |
| **Modules** | Packaged collections of agents and workflows | [Modules Guide](./what-are-modules.md) |
| **Agents** | AI assistants with personas, capabilities, and menus | [Agents Guide](/explanation/core-concepts/what-are-agents/) |
| **Workflows** | Structured processes for achieving specific outcomes | [Workflows Guide](/explanation/core-concepts/what-are-workflows/) |
| **Modules** | Packaged collections of agents and workflows | [Modules Guide](/explanation/core-concepts/what-are-modules/) |
## Getting Started
### New to BMAD?
Start here to understand what BMAD is and how it works:
1. **[Agents Guide](./what-are-agents.md)** - Learn about Simple and Expert agents
2. **[Workflows Guide](./what-are-workflows.md)** - Understand how workflows orchestrate tasks
3. **[Modules Guide](./what-are-modules.md)** - See how modules organize functionality
1. **[Agents Guide](/explanation/core-concepts/what-are-agents/)** - Learn about Simple and Expert agents
2. **[Workflows Guide](/explanation/core-concepts/what-are-workflows/)** - Understand how workflows orchestrate tasks
3. **[Modules Guide](/explanation/core-concepts/what-are-modules/)** - See how modules organize functionality
### Installing BMAD
- **[Installation Guide](../../how-to/installation/index.md)** - Set up BMAD in your project
- **[Upgrading from v4](../../how-to/installation/upgrade-to-v6.md)** - Migrate from earlier versions
- **[Installation Guide](/how-to/installation/)** - Set up BMAD in your project
- **[Upgrading from v4](/how-to/installation/upgrade-to-v6/)** - Migrate from earlier versions
### Configuration
- **[BMAD Customization](../../how-to/customization/index.md)** - Personalize agents and workflows
- **[BMAD Customization](/how-to/customization/)** - Personalize agents and workflows
### Advanced
- **[Web Bundles](../features/web-bundles.md)** - Use BMAD in Gemini Gems and Custom GPTs
- **[Web Bundles](/explanation/features/web-bundles/)** - Use BMAD in Gemini Gems and Custom GPTs
---
**Next:** Read the [Agents Guide](./what-are-agents.md) to understand the core building block of BMAD.
**Next:** Read the [Agents Guide](/explanation/core-concepts/what-are-agents/) to understand the core building block of BMAD.

View File

@ -85,12 +85,12 @@ All agents share these building blocks:
## Creating Custom Agents
BMAD provides the **BMAD Builder (BMB)** module for creating your own agents. See the [Agent Creation Guide](../../tutorials/advanced/create-custom-agent.md) for step-by-step instructions.
BMAD provides the **BMAD Builder (BMB)** module for creating your own agents. See the [Agent Creation Guide](/tutorials/advanced/create-custom-agent/) for step-by-step instructions.
## Customizing Existing Agents
You can modify any agent's behavior without editing core files. See [BMAD Customization](../../how-to/customization/index.md) for details. It is critical to never modify an installed agents .md file directly and follow the customization process, this way future updates to the agent or module its part of will continue to be updated and recompiled with the installer tool, and your customizations will still be retained.
You can modify any agent's behavior without editing core files. See [BMAD Customization](/how-to/customization/) for details. It is critical to never modify an installed agents .md file directly and follow the customization process, this way future updates to the agent or module its part of will continue to be updated and recompiled with the installer tool, and your customizations will still be retained.
---
**Next:** Learn about [Workflows](./what-are-workflows.md) to see how agents accomplish complex tasks.
**Next:** Learn about [Workflows](/explanation/core-concepts/what-are-workflows/) to see how agents accomplish complex tasks.

View File

@ -72,8 +72,8 @@ Custom modules are installed the same way as official modules.
During BMAD installation, you choose which modules to install. You can also add or remove modules later by re-running the installer.
See [Installation Guide](../../how-to/installation/index.md) for details.
See [Installation Guide](/how-to/installation/) for details.
---
**Next:** Read the [Installation Guide](../../how-to/installation/index.md) to set up BMAD with the modules you need.
**Next:** Read the [Installation Guide](/how-to/installation/) to set up BMAD with the modules you need.

View File

@ -7,12 +7,12 @@ The Core Module is installed with all installations of BMAD modules and provides
## Core Module Components
- **[Global Core Config](../../reference/configuration/global-config.md)** — Inheritable configuration that impacts all modules and custom content
- **[Core Workflows](../../reference/workflows/core-workflows.md)** — Domain-agnostic workflows usable by any module
- [Party Mode](../../explanation/features/party-mode.md) — Multi-agent conversation orchestration
- [Brainstorming](../../explanation/features/brainstorming-techniques.md) — Structured creative sessions with 60+ techniques
- [Advanced Elicitation](../../explanation/features/advanced-elicitation.md) — LLM rethinking with 50+ reasoning methods
- **[Core Tasks](../../reference/configuration/core-tasks.md)** — Common tasks available across modules
- [Index Docs](../../reference/configuration/core-tasks.md#index-docs) — Generate directory index files
- [Adversarial Review](../../reference/configuration/core-tasks.md#adversarial-review-general) — Critical content review
- [Shard Document](../../reference/configuration/core-tasks.md#shard-document) — Split large documents into sections
- **[Global Core Config](/reference/configuration/global-config/)** — Inheritable configuration that impacts all modules and custom content
- **[Core Workflows](/reference/workflows/core-workflows/)** — Domain-agnostic workflows usable by any module
- [Party Mode](/explanation/features/party-mode/) — Multi-agent conversation orchestration
- [Brainstorming](/explanation/features/brainstorming-techniques/) — Structured creative sessions with 60+ techniques
- [Advanced Elicitation](/explanation/features/advanced-elicitation/) — LLM rethinking with 50+ reasoning methods
- **[Core Tasks](/reference/configuration/core-tasks/)** — Common tasks available across modules
- [Index Docs](/reference/configuration/core-tasks/#index-docs) — Generate directory index files
- [Adversarial Review](/reference/configuration/core-tasks/#adversarial-review-general) — Critical content review
- [Shard Document](/reference/configuration/core-tasks/#shard-document) — Split large documents into sections

View File

@ -117,5 +117,5 @@ CIS workflows integrate with:
## Related
- [Facilitation Over Generation](../philosophy/facilitation-over-generation.md) - Core philosophy
- [Brainstorming Techniques](../features/brainstorming-techniques.md) - Technique reference
- [Facilitation Over Generation](/explanation/philosophy/facilitation-over-generation/) - Core philosophy
- [Brainstorming Techniques](/explanation/features/brainstorming-techniques/) - Technique reference

View File

@ -71,9 +71,9 @@ BMM respects your choice - it won't force modernization, but it will offer it.
## Related Documentation
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Get started with BMM
- [Brownfield Guide](../../how-to/brownfield/index.md) - Existing codebase workflows
- [Glossary](../../reference/glossary/index.md) - Terminology reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Get started with BMM
- [Brownfield Guide](/how-to/brownfield/) - Existing codebase workflows
- [Glossary](/reference/glossary/) - Terminology reference
---

View File

@ -16,7 +16,7 @@ Quick answers to common questions about getting started with the BMad Method.
- Creates the tracking status file
- Routes you to the correct starting workflow
For experienced users: use the [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) to go directly to the right agent/workflow.
For experienced users: use the [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) to go directly to the right agent/workflow.
## Q: Why do I need fresh chats for each workflow?
@ -58,8 +58,8 @@ Quick workflows like status checks can reuse chats safely.
## Related Documentation
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Get started with BMM
- [Glossary](../../reference/glossary/index.md) - Terminology reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Get started with BMM
- [Glossary](/reference/glossary/) - Terminology reference
---

View File

@ -48,8 +48,8 @@ Don't wait until project end - run after each epic for continuous improvement.
## Related Documentation
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Get started with BMM
- [Glossary](../../reference/glossary/index.md) - Terminology reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Get started with BMM
- [Glossary](/reference/glossary/) - Terminology reference
---

View File

@ -8,10 +8,10 @@ Quick answers to common questions about the BMad Method, organized by topic.
## Topics
- [Getting Started](./getting-started-faq.md) - Questions about starting with BMM
- [Levels & Tracks](./levels-and-tracks-faq.md) - Choosing the right level
- [Workflows](./workflows-faq.md) - Workflow and phase questions
- [Planning](./planning-faq.md) - Planning document questions
- [Implementation](./implementation-faq.md) - Implementation questions
- [Brownfield](./brownfield-faq.md) - Existing codebase questions
- [Tools & Advanced](./tools-faq.md) - Tools, IDEs, and advanced topics
- [Getting Started](/explanation/faq/getting-started-faq/) - Questions about starting with BMM
- [Levels & Tracks](/explanation/faq/levels-and-tracks-faq/) - Choosing the right level
- [Workflows](/explanation/faq/workflows-faq/) - Workflow and phase questions
- [Planning](/explanation/faq/planning-faq/) - Planning document questions
- [Implementation](/explanation/faq/implementation-faq/) - Implementation questions
- [Brownfield](/explanation/faq/brownfield-faq/) - Existing codebase questions
- [Tools & Advanced](/explanation/faq/tools-faq/) - Tools, IDEs, and advanced topics

View File

@ -50,8 +50,8 @@ The overlap (5-10 stories) is intentional. Choose based on:
## Related Documentation
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Get started with BMM
- [Glossary](../../reference/glossary/index.md) - Terminology reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Get started with BMM
- [Glossary](/reference/glossary/) - Terminology reference
---

View File

@ -39,8 +39,8 @@ PRDs are for Level 2-4 projects with multiple features requiring product-level c
## Related Documentation
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Get started with BMM
- [Glossary](../../reference/glossary/index.md) - Terminology reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Get started with BMM
- [Glossary](/reference/glossary/) - Terminology reference
---

View File

@ -210,7 +210,7 @@ Trust your expertise - BMM supports your decisions.
**For complete documentation:**
👉 **[Party Mode Guide](../../explanation/features/party-mode.md)** - How it works, when to use it, example compositions, best practices
👉 **[Party Mode Guide](/explanation/features/party-mode/)** - How it works, when to use it, example compositions, best practices
---
@ -240,8 +240,8 @@ Please include:
## Related Documentation
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Get started with BMM
- [Glossary](../../reference/glossary/index.md) - Terminology reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Get started with BMM
- [Glossary](/reference/glossary/) - Terminology reference
---

View File

@ -60,8 +60,8 @@ If status file exists, use workflow-status. If not, use workflow-init.
## Related Documentation
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Get started with BMM
- [Glossary](../../reference/glossary/index.md) - Terminology reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Get started with BMM
- [Glossary](/reference/glossary/) - Terminology reference
---

View File

@ -103,9 +103,9 @@ _(Multiple perspectives reveal the right answer)_
## Related Documentation
- [Agents Reference](../../reference/agents/index.md) - Complete agent reference
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Getting started with BMM
- [Setup Party Mode](../../how-to/workflows/setup-party-mode.md) - How to use it
- [Agents Reference](/reference/agents/) - Complete agent reference
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Getting started with BMM
- [Setup Party Mode](/how-to/workflows/setup-party-mode/) - How to use it
---

View File

@ -164,6 +164,6 @@ Start with Quick Flow, but switch to BMad Method when:
## Related
- [Create Tech Spec](../../how-to/workflows/create-tech-spec.md) - How to use Quick Flow
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Getting started
- [Four Phases](../architecture/four-phases.md) - Understanding the full methodology
- [Create Tech Spec](/how-to/workflows/create-tech-spec/) - How to use Quick Flow
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Getting started
- [Four Phases](/explanation/architecture/four-phases/) - Understanding the full methodology

View File

@ -214,5 +214,5 @@ Epic/Release Gate → TEA: *nfr-assess, *trace Phase 2 (release decision)
## Related Documentation
- [Setup Test Framework](../../how-to/workflows/setup-test-framework.md) - How to set up testing infrastructure
- [Run Test Design](../../how-to/workflows/run-test-design.md) - Creating test plans
- [Setup Test Framework](/how-to/workflows/setup-test-framework/) - How to set up testing infrastructure
- [Run Test Design](/how-to/workflows/run-test-design/) - Creating test plans

View File

@ -405,6 +405,6 @@ The `project-context.md` file (if present) serves as the authoritative source fo
## Next Steps
- **[Quick Start Guide](../../tutorials/getting-started/quick-start-bmgd.md)** - Get started with BMGD
- **[Workflows Guide](../../reference/workflows/index.md)** - Detailed workflow reference
- **[Game Types Guide](../../explanation/game-dev/game-types.md)** - Game type templates
- **[Quick Start Guide](/tutorials/getting-started/quick-start-bmgd/)** - Get started with BMGD
- **[Workflows Guide](/reference/workflows/)** - Detailed workflow reference
- **[Game Types Guide](/explanation/game-dev/game-types/)** - Game type templates

View File

@ -145,6 +145,6 @@ This means you get all of BMM's implementation structure plus game-specific enha
## Related
- [BMGD Overview](./index.md) - Getting started with BMGD
- [Game Types Guide](./game-types.md) - Understanding game templates
- [Quick Start BMGD](../../tutorials/getting-started/quick-start-bmgd.md) - Tutorial
- [BMGD Overview](/explanation/game-dev/) - Getting started with BMGD
- [Game Types Guide](/explanation/game-dev/game-types/) - Understanding game templates
- [Quick Start BMGD](/tutorials/getting-started/quick-start-bmgd/) - Tutorial

View File

@ -501,6 +501,6 @@ When you select a game type, BMGD adds these GDD sections:
## Next Steps
- **[Quick Start Guide](../../tutorials/getting-started/quick-start-bmgd.md)** - Get started with BMGD
- **[Workflows Guide](../../reference/workflows/bmgd-workflows.md)** - GDD workflow details
- **[Glossary](../../reference/glossary/index.md)** - Game development terminology
- **[Quick Start Guide](/tutorials/getting-started/quick-start-bmgd/)** - Get started with BMGD
- **[Workflows Guide](/reference/workflows/bmgd-workflows/)** - GDD workflow details
- **[Glossary](/reference/glossary/)** - Game development terminology

View File

@ -12,7 +12,7 @@ Complete guides for the BMad Game Development Module (BMGD) - AI-powered workflo
**New to BMGD?** Start here:
- **[Quick Start Guide](../../tutorials/getting-started/quick-start-bmgd.md)** - Get started building your first game
- **[Quick Start Guide](/tutorials/getting-started/quick-start-bmgd/)** - Get started building your first game
- Installation and setup
- Understanding the game development phases
- Running your first workflows
@ -24,8 +24,8 @@ Complete guides for the BMad Game Development Module (BMGD) - AI-powered workflo
## Core Documentation
- **[Game Types Guide](./game-types.md)** - Selecting and using game type templates (24 supported types)
- **[BMGD vs BMM](./bmgd-vs-bmm.md)** - Understanding the differences
- **[Game Types Guide](/explanation/game-dev/game-types/)** - Selecting and using game type templates (24 supported types)
- **[BMGD vs BMM](/explanation/game-dev/bmgd-vs-bmm/)** - Understanding the differences
---
@ -58,7 +58,7 @@ BMGD follows four phases aligned with game development:
### I need to...
**Start a new game project**
→ Start with [Quick Start Guide](../../tutorials/getting-started/quick-start-bmgd.md)
→ Start with [Quick Start Guide](/tutorials/getting-started/quick-start-bmgd/)
→ Run `brainstorm-game` for ideation
→ Create a Game Brief with `create-brief`
@ -74,12 +74,12 @@ BMGD follows four phases aligned with game development:
→ Follow the sprint-based development cycle
**Quickly test an idea**
→ Use [Quick-Flow](../../how-to/workflows/bmgd-quick-flow.md) for rapid prototyping
→ Use [Quick-Flow](/how-to/workflows/bmgd-quick-flow/) for rapid prototyping
---
## Related
- [Game Types Guide](./game-types.md) - Understanding game type templates
- [BMGD vs BMM](./bmgd-vs-bmm.md) - Comparison with core method
- [Glossary](../../reference/glossary/index.md) - Terminology reference
- [Game Types Guide](/explanation/game-dev/game-types/) - Understanding game type templates
- [BMGD vs BMM](/explanation/game-dev/bmgd-vs-bmm/) - Comparison with core method
- [Glossary](/reference/glossary/) - Terminology reference

View File

@ -117,5 +117,5 @@ But the core creative work happens through facilitated discovery.
## Related
- [Creative Intelligence Suite](../creative-intelligence/index.md) - CIS overview
- [Brainstorming Techniques](../features/brainstorming-techniques.md) - Available techniques
- [Creative Intelligence Suite](/explanation/creative-intelligence/) - CIS overview
- [Brainstorming Techniques](/explanation/features/brainstorming-techniques/) - Available techniques

View File

@ -86,6 +86,6 @@ Follow the standard Phase 4 implementation workflows:
## Related
- [Brownfield Development Guide](./index.md)
- [Document Existing Project](./document-existing-project.md)
- [Quick Fix in Brownfield](./quick-fix-in-brownfield.md)
- [Brownfield Development Guide](/how-to/brownfield/)
- [Document Existing Project](/how-to/brownfield/document-existing-project/)
- [Quick Fix in Brownfield](/how-to/brownfield/quick-fix-in-brownfield/)

View File

@ -80,5 +80,5 @@ Review the documentation for:
## Related
- [Brownfield Development Guide](./index.md)
- [Add Feature to Existing Project](./add-feature-to-existing.md)
- [Brownfield Development Guide](/how-to/brownfield/)
- [Add Feature to Existing Project](/how-to/brownfield/add-feature-to-existing/)

View File

@ -89,14 +89,14 @@ Pay close attention here to prevent reinventing the wheel or making decisions th
## Next Steps
- **[Document Existing Project](../../how-to/brownfield/document-existing-project.md)** - How to document your brownfield codebase
- **[Add Feature to Existing Project](../../how-to/brownfield/add-feature-to-existing.md)** - Adding new functionality
- **[Quick Fix in Brownfield](../../how-to/brownfield/quick-fix-in-brownfield.md)** - Bug fixes and ad-hoc changes
- **[Brownfield FAQ](../../explanation/faq/brownfield-faq.md)** - Common questions about brownfield development
- **[Document Existing Project](/how-to/brownfield/document-existing-project/)** - How to document your brownfield codebase
- **[Add Feature to Existing Project](/how-to/brownfield/add-feature-to-existing/)** - Adding new functionality
- **[Quick Fix in Brownfield](/how-to/brownfield/quick-fix-in-brownfield/)** - Bug fixes and ad-hoc changes
- **[Brownfield FAQ](/explanation/faq/brownfield-faq/)** - Common questions about brownfield development
---
## Related Documentation
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Getting started with BMM
- [Quick Spec Flow](../../explanation/features/quick-flow.md) - Fast path for small changes
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Getting started with BMM
- [Quick Spec Flow](/explanation/features/quick-flow/) - Fast path for small changes

View File

@ -89,6 +89,6 @@ Consider using Quick Flow or full BMad Method when:
## Related
- [Brownfield Development Guide](./index.md)
- [Add Feature to Existing Project](./add-feature-to-existing.md)
- [Quick Spec Flow](../../explanation/features/quick-flow.md)
- [Brownfield Development Guide](/how-to/brownfield/)
- [Add Feature to Existing Project](/how-to/brownfield/add-feature-to-existing/)
- [Quick Spec Flow](/explanation/features/quick-flow/)

View File

@ -201,8 +201,8 @@ memories:
## Next Steps
- **[Learn about Agents](../../explanation/core-concepts/what-are-agents.md)** - Understand Simple vs Expert agents
- **[Agent Creation Guide](../../tutorials/advanced/create-custom-agent.md)** - Build completely custom agents
- **[BMM Complete Documentation](../../explanation/bmm/index.md)** - Full BMad Method reference
- **[Learn about Agents](/explanation/core-concepts/what-are-agents/)** - Understand Simple vs Expert agents
- **[Agent Creation Guide](/tutorials/advanced/create-custom-agent/)** - Build completely custom agents
- **[BMM Complete Documentation](/explanation/bmm/)** - Full BMad Method reference
[← Back to Customization](./index.md)
[← Back to Customization](/how-to/customization/)

View File

@ -23,11 +23,11 @@ Workflow customization will allow you to:
While workflow customization is in development, you can:
- **Create Custom Workflows** - Use the BMAD Builder to create entirely new workflows
- **Customize Agents** - Modify agent behavior using [Agent Customization](./customize-agents.md)
- **Customize Agents** - Modify agent behavior using [Agent Customization](/how-to/customization/customize-agents/)
- **Provide Feedback** - Share your workflow customization needs with the community
---
**In the meantime:** Learn how to [create custom workflows](../../explanation/bmad-builder/index.md) from scratch.
**In the meantime:** Learn how to [create custom workflows](/explanation/bmad-builder/) from scratch.
[← Back to Customization](./index.md)
[← Back to Customization](/how-to/customization/)

View File

@ -9,8 +9,8 @@ Personalize agents and workflows to match your needs.
| Guide | Description |
|-------|-------------|
| **[Agent Customization](./customize-agents.md)** | Modify agent behavior without editing core files |
| **[Workflow Customization](./customize-workflows.md)** | Customize and optimize workflows |
| **[Agent Customization](/how-to/customization/customize-agents/)** | Modify agent behavior without editing core files |
| **[Workflow Customization](/how-to/customization/customize-workflows/)** | Customize and optimize workflows |
## Overview
@ -24,4 +24,4 @@ Replace or extend workflow steps to create tailored processes. (Coming soon)
---
**Next:** Read the [Agent Customization Guide](./customize-agents.md) to start personalizing your agents.
**Next:** Read the [Agent Customization Guide](/how-to/customization/customize-agents/) to start personalizing your agents.

View File

@ -10,6 +10,6 @@ How-to guides for installing and configuring the BMad Method.
| Guide | Description |
|-------|-------------|
| **[Install BMad](./install-bmad.md)** | Step-by-step installation instructions |
| **[Install Custom Modules](./install-custom-modules.md)** | Add custom agents, workflows, and modules |
| **[Upgrade to v6](./upgrade-to-v6.md)** | Migrate from BMad v4 to v6 |
| **[Install BMad](/how-to/installation/install-bmad/)** | Step-by-step installation instructions |
| **[Install Custom Modules](/how-to/installation/install-custom-modules/)** | Add custom agents, workflows, and modules |
| **[Upgrade to v6](/how-to/installation/upgrade-to-v6/)** | Migrate from BMad v4 to v6 |

View File

@ -133,6 +133,6 @@ npx bmad-method install --verbose
## Related
- [Quick Start Guide](../../tutorials/getting-started/getting-started-bmadv6.md) - Getting started with BMM
- [Upgrade to V6](./upgrade-to-v6.md) - Upgrading from previous versions
- [Install Custom Modules](./install-custom-modules.md) - Adding custom content
- [Quick Start Guide](/tutorials/getting-started/getting-started-bmadv6/) - Getting started with BMM
- [Upgrade to V6](/how-to/installation/upgrade-to-v6/) - Upgrading from previous versions
- [Install Custom Modules](/how-to/installation/install-custom-modules/) - Adding custom content

View File

@ -5,7 +5,7 @@ title: "Custom Content Installation"
This guide explains how to create and install custom BMAD content including agents, workflows, and modules. Custom content extends BMAD's functionality with specialized tools and workflows that can be shared across projects or teams.
For detailed information about the different types of custom content available, see [Custom Content Types](../../explanation/bmad-builder/custom-content-types.md).
For detailed information about the different types of custom content available, see [Custom Content Types](/explanation/bmad-builder/custom-content-types/).
You can find example custom modules in the `samples/sample-custom-modules/` folder of the repository. Download either of the sample folders to try them out.

View File

@ -123,7 +123,7 @@ persona:
- Always upbeat and adventurous
```
There is a lot more that is possible with agent customization, which is covered in detail in the [Agent Customization Guide](../customization/customize-agents.md)
There is a lot more that is possible with agent customization, which is covered in detail in the [Agent Customization Guide](/how-to/customization/customize-agents/)
CRITICAL NOTE: After you modify the customization file, you need to run the npx installer against your installed location, and choose the option to rebuild all agents, or just do a quick update again. This always builds agents fresh and applies customizations.

View File

@ -256,6 +256,6 @@ When reporting issues, include:
## Next Steps
- **[Quick Start Guide](../../tutorials/getting-started/quick-start-bmgd.md)** - Getting started
- **[Workflows Guide](../../reference/workflows/index.md)** - Workflow reference
- **[Glossary](../../reference/glossary/index.md)** - Terminology
- **[Quick Start Guide](/tutorials/getting-started/quick-start-bmgd/)** - Getting started
- **[Workflows Guide](/reference/workflows/)** - Workflow reference
- **[Glossary](/reference/glossary/)** - Terminology

View File

@ -286,6 +286,6 @@ If quick-dev keeps expanding scope, stop and create proper stories.
## Next Steps
- **[Workflows Guide](../../reference/workflows/bmgd-workflows.md)** - Full workflow reference
- **[Agents Guide](../../explanation/game-dev/agents.md)** - Agent capabilities
- **[Quick Start Guide](../../tutorials/getting-started/quick-start-bmgd.md)** - Getting started with BMGD
- **[Workflows Guide](/reference/workflows/bmgd-workflows/)** - Full workflow reference
- **[Agents Guide](/explanation/game-dev/agents/)** - Agent capabilities
- **[Quick Start Guide](/tutorials/getting-started/quick-start-bmgd/)** - Getting started with BMGD

View File

@ -125,6 +125,6 @@ After research:
## Related
- [Run Brainstorming Session](./run-brainstorming-session.md) - Explore ideas before research
- [Create Product Brief](./create-product-brief.md) - Capture strategic vision
- [Create PRD](./create-prd.md) - Move to formal planning
- [Run Brainstorming Session](/how-to/workflows/run-brainstorming-session/) - Explore ideas before research
- [Create Product Brief](/how-to/workflows/create-product-brief/) - Capture strategic vision
- [Create PRD](/how-to/workflows/create-prd/) - Move to formal planning

View File

@ -141,7 +141,7 @@ After architecture:
## Related
- [Create PRD](./create-prd.md) - Requirements before architecture
- [Create Epics and Stories](./create-epics-and-stories.md) - Next step
- [Run Implementation Readiness](./run-implementation-readiness.md) - Gate check
- [Why Solutioning Matters](../../explanation/architecture/why-solutioning-matters.md)
- [Create PRD](/how-to/workflows/create-prd/) - Requirements before architecture
- [Create Epics and Stories](/how-to/workflows/create-epics-and-stories/) - Next step
- [Run Implementation Readiness](/how-to/workflows/run-implementation-readiness/) - Gate check
- [Why Solutioning Matters](/explanation/architecture/why-solutioning-matters/)

View File

@ -131,6 +131,6 @@ After creating epics and stories:
## Related
- [Create Architecture](./create-architecture.md) - Do this first
- [Run Implementation Readiness](./run-implementation-readiness.md) - Gate check
- [Run Sprint Planning](./run-sprint-planning.md) - Start implementation
- [Create Architecture](/how-to/workflows/create-architecture/) - Do this first
- [Run Implementation Readiness](/how-to/workflows/run-implementation-readiness/) - Gate check
- [Run Sprint Planning](/how-to/workflows/run-sprint-planning/) - Start implementation

View File

@ -125,6 +125,6 @@ After PRD:
## Related
- [Create Product Brief](./create-product-brief.md) - Input for PRD
- [Create UX Design](./create-ux-design.md) - Optional UX workflow
- [Create Architecture](./create-architecture.md) - Next step after PRD
- [Create Product Brief](/how-to/workflows/create-product-brief/) - Input for PRD
- [Create UX Design](/how-to/workflows/create-ux-design/) - Optional UX workflow
- [Create Architecture](/how-to/workflows/create-architecture/) - Next step after PRD

View File

@ -112,6 +112,6 @@ Planning workflows automatically load the product brief if it exists.
## Related
- [Run Brainstorming Session](./run-brainstorming-session.md) - Explore ideas first
- [Conduct Research](./conduct-research.md) - Validate ideas
- [Create PRD](./create-prd.md) - Next step after product brief
- [Run Brainstorming Session](/how-to/workflows/run-brainstorming-session/) - Explore ideas first
- [Conduct Research](/how-to/workflows/conduct-research/) - Validate ideas
- [Create PRD](/how-to/workflows/create-prd/) - Next step after product brief

View File

@ -114,6 +114,6 @@ Implement email verification flow for new user registrations.
## Related
- [Run Sprint Planning](./run-sprint-planning.md) - Initialize tracking
- [Implement Story](./implement-story.md) - Next step
- [Run Code Review](./run-code-review.md) - After implementation
- [Run Sprint Planning](/how-to/workflows/run-sprint-planning/) - Initialize tracking
- [Implement Story](/how-to/workflows/implement-story/) - Next step
- [Run Code Review](/how-to/workflows/run-code-review/) - After implementation

View File

@ -154,6 +154,6 @@ If your "single change" needs 3+ files, it might be a multi-story feature. Let t
## Related
- [Quick Flow](../../explanation/features/quick-flow.md) - Understanding Quick Spec Flow
- [Implement Story](./implement-story.md) - After tech spec
- [Create PRD](./create-prd.md) - For larger projects needing full BMad Method
- [Quick Flow](/explanation/features/quick-flow/) - Understanding Quick Spec Flow
- [Implement Story](/how-to/workflows/implement-story/) - After tech spec
- [Create PRD](/how-to/workflows/create-prd/) - For larger projects needing full BMad Method

View File

@ -112,6 +112,6 @@ The UX spec feeds into:
## Related
- [Create PRD](./create-prd.md) - Create requirements first
- [Create Architecture](./create-architecture.md) - Technical design
- [Create Epics and Stories](./create-epics-and-stories.md) - Work breakdown
- [Create PRD](/how-to/workflows/create-prd/) - Create requirements first
- [Create Architecture](/how-to/workflows/create-architecture/) - Technical design
- [Create Epics and Stories](/how-to/workflows/create-epics-and-stories/) - Work breakdown

View File

@ -122,6 +122,6 @@ A: Split the story and document the change.
## Related
- [Create Story](./create-story.md) - Prepare the story first
- [Run Code Review](./run-code-review.md) - After implementation
- [Run Sprint Planning](./run-sprint-planning.md) - Sprint organization
- [Create Story](/how-to/workflows/create-story/) - Prepare the story first
- [Run Code Review](/how-to/workflows/run-code-review/) - After implementation
- [Run Sprint Planning](/how-to/workflows/run-sprint-planning/) - Sprint organization

View File

@ -89,6 +89,6 @@ After brainstorming:
## Related
- [Conduct Research](./conduct-research.md) - Validate your ideas
- [Create Product Brief](./create-product-brief.md) - Capture strategic vision
- [Create PRD](./create-prd.md) - Move to formal planning
- [Conduct Research](/how-to/workflows/conduct-research/) - Validate your ideas
- [Create Product Brief](/how-to/workflows/create-product-brief/) - Capture strategic vision
- [Create PRD](/how-to/workflows/create-prd/) - Move to formal planning

View File

@ -136,6 +136,6 @@ Every story goes through code-review before being marked done. This ensures:
## Related
- [Implement Story](./implement-story.md) - Before code review
- [Create Story](./create-story.md) - Move to next story
- [Run Sprint Planning](./run-sprint-planning.md) - Sprint organization
- [Implement Story](/how-to/workflows/implement-story/) - Before code review
- [Create Story](/how-to/workflows/create-story/) - Move to next story
- [Run Sprint Planning](/how-to/workflows/run-sprint-planning/) - Sprint organization

View File

@ -157,6 +157,6 @@ E-commerce platform → CONCERNS ⚠️
## Related
- [Create Architecture](./create-architecture.md) - Architecture workflow
- [Create Epics and Stories](./create-epics-and-stories.md) - Work breakdown
- [Run Sprint Planning](./run-sprint-planning.md) - Start implementation
- [Create Architecture](/how-to/workflows/create-architecture/) - Architecture workflow
- [Create Epics and Stories](/how-to/workflows/create-epics-and-stories/) - Work breakdown
- [Run Sprint Planning](/how-to/workflows/run-sprint-planning/) - Start implementation

View File

@ -106,6 +106,6 @@ Stories move through these states in the sprint status file:
## Related
- [Create Story](./create-story.md) - Prepare stories for implementation
- [Implement Story](./implement-story.md) - Dev workflow
- [Run Code Review](./run-code-review.md) - Quality assurance
- [Create Story](/how-to/workflows/create-story/) - Prepare stories for implementation
- [Implement Story](/how-to/workflows/implement-story/) - Dev workflow
- [Run Code Review](/how-to/workflows/run-code-review/) - Quality assurance

View File

@ -123,6 +123,6 @@ TEA generates a comprehensive test design document.
## Related
- [TEA Overview](../../explanation/features/tea-overview.md) - Understanding the Test Architect
- [Setup Test Framework](./setup-test-framework.md) - Setting up testing infrastructure
- [Create Architecture](./create-architecture.md) - Architecture workflow
- [TEA Overview](/explanation/features/tea-overview/) - Understanding the Test Architect
- [Setup Test Framework](/how-to/workflows/setup-test-framework/) - Setting up testing infrastructure
- [Create Architecture](/how-to/workflows/create-architecture/) - Architecture workflow

View File

@ -113,5 +113,5 @@ Type "exit" or "done" to conclude the session. Participating agents will say per
## Related
- [Party Mode](../../explanation/features/party-mode.md) - Understanding Party Mode
- [Agent Roles](../../explanation/core-concepts/agent-roles.md) - Available agents
- [Party Mode](/explanation/features/party-mode/) - Understanding Party Mode
- [Agent Roles](/explanation/core-concepts/agent-roles/) - Available agents

View File

@ -108,6 +108,6 @@ Configure in your IDE's MCP settings.
## Related
- [TEA Overview](../../explanation/features/tea-overview.md) - Understanding the Test Architect
- [Run Test Design](./run-test-design.md) - Creating test plans
- [Create Architecture](./create-architecture.md) - Architecture workflow
- [TEA Overview](/explanation/features/tea-overview/) - Understanding the Test Architect
- [Run Test Design](/how-to/workflows/run-test-design/) - Creating test plans
- [Create Architecture](/how-to/workflows/create-architecture/) - Architecture workflow

View File

@ -12,10 +12,10 @@ If you're comfortable working with AI coding assistants like Claude, Cursor, or
The fastest way to understand BMad is to try it. Choose a tutorial to walk through your first project in about 10 minutes.
- **[Get Started with BMad](./tutorials/getting-started/getting-started-bmadv6.md)** — Latest features, still in active development
- **[Get Started with BMad](/tutorials/getting-started/getting-started-bmadv6/)** — Latest features, still in active development
:::tip[Already familiar with AI-assisted development?]
Feel free to skip around. Use the sidebar to jump to any topic, or check out [What Are Agents?](./explanation/core-concepts/what-are-agents.md) to understand how BMad organizes its AI personas.
Feel free to skip around. Use the sidebar to jump to any topic, or check out [What Are Agents?](/explanation/core-concepts/what-are-agents/) to understand how BMad organizes its AI personas.
:::
---
@ -60,4 +60,4 @@ Get help, share what you're building, or contribute to BMad:
Ready to dive in? Pick a tutorial and start building.
- **[Get Started with BMadv6](./tutorials/getting-started/getting-started-bmadv6.md)** — Explore the latest features
- **[Get Started with BMad](/tutorials/getting-started/getting-started-bmadv6/)** — Explore the latest features

View File

@ -137,5 +137,5 @@ Available to all agents:
## Related
- [Agent Roles](../../explanation/core-concepts/agent-roles.md) - Understanding agent responsibilities
- [What Are Agents](../../explanation/core-concepts/what-are-agents.md) - Foundational concepts
- [Agent Roles](/explanation/core-concepts/agent-roles/) - Understanding agent responsibilities
- [What Are Agents](/explanation/core-concepts/what-are-agents/) - Foundational concepts

View File

@ -262,7 +262,7 @@ Checks current project status across all phases. Shows completed documents, curr
## Quick-Flow Workflows
Fast-track workflows that skip full planning phases. See **[Quick-Flow Guide](../../how-to/workflows/bmgd-quick-flow.md)** for detailed usage.
Fast-track workflows that skip full planning phases. See **[Quick-Flow Guide](/how-to/workflows/bmgd-quick-flow/)** for detailed usage.
### Quick-Prototype
@ -460,7 +460,7 @@ This means:
## Next Steps
- **[Quick Start Guide](../../tutorials/getting-started/quick-start-bmgd.md)** - Get started with BMGD
- **[Quick-Flow Guide](../../how-to/workflows/bmgd-quick-flow.md)** - Rapid prototyping and development
- **[Agents Guide](../../explanation/game-dev/agents.md)** - Agent reference
- **[Game Types Guide](../../explanation/game-dev/game-types.md)** - Game type templates
- **[Quick Start Guide](/tutorials/getting-started/quick-start-bmgd/)** - Get started with BMGD
- **[Quick-Flow Guide](/how-to/workflows/bmgd-quick-flow/)** - Rapid prototyping and development
- **[Agents Guide](/explanation/game-dev/agents/)** - Agent reference
- **[Game Types Guide](/explanation/game-dev/game-types/)** - Game type templates

View File

@ -7,15 +7,15 @@ Core Workflows are domain-agnostic workflows that can be utilized by any BMAD-co
## Available Core Workflows
### [Party Mode](../../explanation/features/party-mode.md)
### [Party Mode](/explanation/features/party-mode/)
Orchestrate dynamic multi-agent conversations with your entire BMAD team. Engage with multiple specialized perspectives simultaneously—each agent maintaining their unique personality, expertise, and communication style.
### [Brainstorming](../../explanation/features/brainstorming-techniques.md)
### [Brainstorming](/explanation/features/brainstorming-techniques/)
Facilitate structured creative sessions using 60+ proven ideation techniques. The AI acts as coach and guide, using proven creativity methods to draw out ideas and insights that are already within you.
### [Advanced Elicitation](../../explanation/features/advanced-elicitation.md)
### [Advanced Elicitation](/explanation/features/advanced-elicitation/)
Push the LLM to rethink its work through 50+ reasoning methods—the inverse of brainstorming. The LLM applies sophisticated techniques to re-examine and enhance content it has just generated, essentially "LLM brainstorming" to find better approaches and uncover improvements.

View File

@ -70,5 +70,5 @@ The workflow can be interrupted and resumed without losing progress:
**Related Documentation:**
- [Brownfield Development Guide](../../how-to/brownfield/index.md)
- [Implementation Workflows](../../how-to/workflows/run-sprint-planning.md)
- [Brownfield Development Guide](/how-to/brownfield/)
- [Implementation Workflows](/how-to/workflows/run-sprint-planning/)

View File

@ -8,9 +8,9 @@ Complete reference documentation for all BMad Method workflows.
## Core Workflows
- [Core Workflows](./core-workflows.md) - Domain-agnostic workflows available to all modules
- [Document Project](./document-project.md) - Brownfield project documentation workflow
- [Core Workflows](/reference/workflows/core-workflows/) - Domain-agnostic workflows available to all modules
- [Document Project](/reference/workflows/document-project/) - Brownfield project documentation workflow
## Module-Specific Workflows
- [BMGD Workflows](./bmgd-workflows.md) - Game development workflows
- [BMGD Workflows](/reference/workflows/bmgd-workflows/) - Game development workflows

View File

@ -159,9 +159,9 @@ Study the reference agents in `src/modules/bmb/reference/agents/`:
## Further Reading
- **[What Are Agents](../../explanation/core-concepts/what-are-agents.md)** - Deep technical details on agent types
- **[Agent Customization](../../how-to/customization/customize-agents.md)** - Modify agents without editing core files
- **[Custom Content Installation](../../how-to/installation/install-custom-modules.md)** - Package and distribute your agents
- **[What Are Agents](/explanation/core-concepts/what-are-agents/)** - Deep technical details on agent types
- **[Agent Customization](/how-to/customization/customize-agents/)** - Modify agents without editing core files
- **[Custom Content Installation](/how-to/installation/install-custom-modules/)** - Package and distribute your agents
:::tip[Key Takeaways]
- **Start small** - Your first agent should solve one problem well

View File

@ -3,7 +3,7 @@ title: "Getting Started with the BMad Method"
description: Install BMad and build your first project
---
**Upgrading from previous versions?** See the [Upgrade Guide](../../how-to/installation/upgrade-to-v6.md) instead.
**Upgrading from previous versions?** See the [Upgrade Guide](/how-to/installation/upgrade-to-v6/) instead.
---
@ -83,7 +83,7 @@ your-project/
```
:::tip[Troubleshooting]
Having issues? See [Install BMad](../../how-to/installation/install-bmad.md) for common solutions.
Having issues? See [Install BMad](/how-to/installation/install-bmad/) for common solutions.
:::
## Step 1: Initialize Your Project
@ -230,7 +230,7 @@ Yes, once you learn the flow. Use the Quick Reference to go directly to needed w
- **During workflows** — Agents guide you with questions and explanations
- **Community** — [Discord](https://discord.gg/gk8jAdXWmj) (#bmad-method-help, #report-bugs-and-issues)
- **Documentation** — [BMM Workflow Reference](../../reference/workflows/index.md)
- **Documentation** — [BMM Workflow Reference](/reference/workflows/)
- **Video tutorials** — [BMad Code YouTube](https://www.youtube.com/@BMadCode)
## Key Takeaways

View File

@ -7,7 +7,7 @@ description: Build games with BMad's Game Development Module
Build games faster using AI-powered workflows with specialized game development agents that guide you through preproduction, design, architecture, and implementation.
:::note[Module Extension]
BMGD (BMad Game Development) is a module that extends BMad Method. You'll need BMad installed first—see the [BMad v6 tutorial](./getting-started-bmadv6.md) if you haven't installed it yet.
BMGD (BMad Game Development) is a module that extends BMad Method. You'll need BMad installed first—see the [BMad v6 tutorial](/tutorials/getting-started/getting-started-bmadv6/) if you haven't installed it yet.
:::
## What You'll Learn
@ -244,7 +244,7 @@ Yes. Documents are living artifacts—return to update them as your vision evolv
- **During workflows** — Agents guide you with questions and explanations
- **Community** — [Discord](https://discord.gg/gk8jAdXWmj) (#bmad-method-help, #report-bugs-and-issues)
- **Documentation** — [BMGD Workflow Reference](../../reference/workflows/bmgd-workflows.md)
- **Documentation** — [BMGD Workflow Reference](/reference/workflows/bmgd-workflows/)
- **Video tutorials** — [BMad Code YouTube](https://www.youtube.com/@BMadCode)
## Key Takeaways

View File

@ -27,9 +27,10 @@
"bmad:install": "node tools/cli/bmad-cli.js install",
"bundle": "node tools/cli/bundlers/bundle-web.js all",
"docs:build": "node tools/build-docs.js",
"docs:check-links": "node tools/check-doc-links.js",
"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}\"",

View File

@ -1,341 +0,0 @@
/**
* Documentation Link Auditor
*
* Scans markdown files in docs/ and:
* - Identifies broken relative links
* - Attempts to find where files may have moved
* - Generates a report with auto-fix suggestions
* - Outputs JSON for the fixer script to consume
*
* Usage: node tools/audit-doc-links.js
*/
const { readFileSync, writeFileSync, existsSync } = require('node:fs');
const { resolve, dirname, join, normalize, relative, basename } = require('node:path');
const { glob } = require('glob');
const DOCS_DIR = resolve(process.cwd(), 'docs');
const REPORT_PATH = resolve(__dirname, '.link-audit-report.json');
// Regex to match markdown links: [text](path)
const LINK_PATTERN = /\[([^\]]*)\]\(([^)]+)\)/g;
// Colors for console output
const colors = {
reset: '\u001B[0m',
red: '\u001B[31m',
green: '\u001B[32m',
yellow: '\u001B[33m',
cyan: '\u001B[36m',
dim: '\u001B[2m',
};
/**
* Determines whether a link should be ignored during validation.
*/
function shouldIgnoreLink(link) {
return (
link.startsWith('http://') ||
link.startsWith('https://') ||
link.startsWith('mailto:') ||
link.startsWith('tel:') ||
link.startsWith('/') || // Absolute paths handled by Astro routing
link.startsWith('#') // Same-file anchors
);
}
/**
* Remove fenced and inline code segments from Markdown content.
*/
function stripCodeBlocks(content) {
return content
.replaceAll(/```[\s\S]*?```/g, '')
.replaceAll(/~~~[\s\S]*?~~~/g, '')
.replaceAll(/`[^`\n]+`/g, '');
}
/**
* Parse link to extract path and anchor.
*/
function parseLink(link) {
const hashIndex = link.indexOf('#');
if (hashIndex === -1) {
return { path: link, anchor: null };
}
return {
path: link.slice(0, hashIndex) || null,
anchor: link.slice(hashIndex + 1),
};
}
/**
* Get line number for a character position in content.
*/
function getLineNumber(content, charIndex) {
const lines = content.slice(0, charIndex).split('\n');
return lines.length;
}
/**
* Extract links with their line numbers from markdown content.
*/
function extractLinksWithPositions(content, filePath) {
const strippedContent = stripCodeBlocks(content);
const links = [];
let match;
LINK_PATTERN.lastIndex = 0;
while ((match = LINK_PATTERN.exec(strippedContent)) !== null) {
const rawLink = match[2];
if (!shouldIgnoreLink(rawLink)) {
const lineNumber = getLineNumber(strippedContent, match.index);
links.push({
raw: rawLink,
text: match[1],
line: lineNumber,
fullMatch: match[0],
});
}
}
return links;
}
/**
* Resolve a relative link path to an absolute file path.
*/
function resolveLink(fromFile, linkPath) {
if (!linkPath) return fromFile;
const fromDir = dirname(fromFile);
let resolved = normalize(resolve(fromDir, linkPath));
// If link doesn't have extension, try .md
if (!resolved.endsWith('.md') && !resolved.endsWith('.mdx') && !existsSync(resolved)) {
const withMd = resolved + '.md';
if (existsSync(withMd)) {
return withMd;
}
// Try as directory with index.md
const asIndex = join(resolved, 'index.md');
if (existsSync(asIndex)) {
return asIndex;
}
}
return resolved;
}
/**
* Search for a file that may have moved.
* Uses multiple strategies to find the best match.
*
* @param {string} brokenPath - The original broken link path (e.g., "../tutorials/getting-started/foo.md")
* @returns {string[]} Array of matching absolute paths
*/
async function findMovedFile(brokenPath) {
const fileName = basename(brokenPath);
const searchName = fileName.endsWith('.md') ? fileName : `${fileName}.md`;
// Strategy 1: Try to match with directory context
// e.g., for "tutorials/getting-started/foo.md", look for "*/getting-started/foo.md"
const pathParts = brokenPath.replace(/^\.\.?\/?/, '').split('/');
if (pathParts.length >= 2) {
const parentDir = pathParts.at(-2);
const contextPattern = `**/${parentDir}/${searchName}`;
const contextMatches = await glob(contextPattern, {
cwd: DOCS_DIR,
absolute: true,
ignore: ['**/_*/**'],
});
if (contextMatches.length > 0) {
return contextMatches;
}
}
// Strategy 2: For non-index files, try filename-only match
// Skip this for index.md since it's too generic (exists in every directory)
if (searchName !== 'index.md') {
const matches = await glob(`**/${searchName}`, {
cwd: DOCS_DIR,
absolute: true,
ignore: ['**/_*/**'],
});
return matches;
}
// For index.md with no context match, return empty (truly missing)
return [];
}
/**
* Calculate the relative path from source file to target file.
*/
function calculateRelativePath(fromFile, toFile) {
const fromDir = dirname(fromFile);
let relativePath = relative(fromDir, toFile);
// Ensure path starts with ./ or ../
if (!relativePath.startsWith('.')) {
relativePath = './' + relativePath;
}
return relativePath;
}
/**
* Main audit function.
*/
async function main() {
console.log('\n Documentation Link Auditor');
console.log(' ==========================\n');
console.log(' Scanning for broken links and attempting auto-resolution...\n');
// Find all markdown files, excluding underscore directories
const files = await glob('**/*.{md,mdx}', {
cwd: DOCS_DIR,
absolute: true,
ignore: ['**/_*/**'],
});
console.log(` Found ${files.length} markdown files to scan.\n`);
const brokenLinks = [];
const autoFixable = [];
const needsReview = [];
const missing = [];
// Track all files for fast lookup
const allFiles = new Set(files);
for (const file of files) {
const content = readFileSync(file, 'utf-8');
const links = extractLinksWithPositions(content, file);
const relativePath = relative(DOCS_DIR, file);
for (const linkInfo of links) {
const { path: linkPath } = parseLink(linkInfo.raw);
if (!linkPath) continue; // Same-file anchor only
const targetFile = resolveLink(file, linkPath);
// Check if target exists
if (!existsSync(targetFile)) {
const fileName = basename(linkPath);
// Try to find the file elsewhere
const candidates = await findMovedFile(linkPath);
const brokenInfo = {
sourceFile: relativePath,
sourceFileAbsolute: file,
line: linkInfo.line,
linkText: linkInfo.text,
originalLink: linkInfo.raw,
expectedTarget: linkPath,
fullMatch: linkInfo.fullMatch,
};
if (candidates.length === 1) {
// Found exactly one match - auto-fixable
const newPath = calculateRelativePath(file, candidates[0]);
brokenInfo.suggestedFix = newPath;
brokenInfo.foundAt = relative(DOCS_DIR, candidates[0]);
brokenInfo.status = 'auto-fixable';
autoFixable.push(brokenInfo);
} else if (candidates.length > 1) {
// Multiple matches - needs manual review
brokenInfo.candidates = candidates.map((c) => relative(DOCS_DIR, c));
brokenInfo.status = 'needs-review';
needsReview.push(brokenInfo);
} else {
// No matches found
brokenInfo.status = 'missing';
missing.push(brokenInfo);
}
brokenLinks.push(brokenInfo);
}
}
}
// Generate report
const report = {
timestamp: new Date().toISOString(),
summary: {
totalFiles: files.length,
totalBroken: brokenLinks.length,
autoFixable: autoFixable.length,
needsReview: needsReview.length,
missing: missing.length,
},
autoFixable,
needsReview,
missing,
};
// Write JSON report
writeFileSync(REPORT_PATH, JSON.stringify(report, null, 2));
// Console output
console.log(' ' + '─'.repeat(50));
console.log('\n SUMMARY\n');
if (brokenLinks.length === 0) {
console.log(` ${colors.green}${colors.reset} No broken links found!\n`);
process.exit(0);
}
console.log(` Total broken links: ${colors.red}${brokenLinks.length}${colors.reset}`);
console.log(` ├─ Auto-fixable: ${colors.green}${autoFixable.length}${colors.reset}`);
console.log(` ├─ Needs review: ${colors.yellow}${needsReview.length}${colors.reset}`);
console.log(` └─ Missing: ${colors.red}${missing.length}${colors.reset}\n`);
// Show auto-fixable
if (autoFixable.length > 0) {
console.log(` ${colors.green}AUTO-FIXABLE${colors.reset} (file found elsewhere)\n`);
for (const item of autoFixable) {
console.log(` ${colors.cyan}${item.sourceFile}${colors.reset}:${item.line}`);
console.log(` ${colors.dim}Link:${colors.reset} ${item.originalLink}`);
console.log(` ${colors.dim}Fix:${colors.reset} ${item.suggestedFix}`);
console.log(` ${colors.dim}Found at:${colors.reset} ${item.foundAt}\n`);
}
}
// Show needs review
if (needsReview.length > 0) {
console.log(` ${colors.yellow}NEEDS REVIEW${colors.reset} (multiple matches found)\n`);
for (const item of needsReview) {
console.log(` ${colors.cyan}${item.sourceFile}${colors.reset}:${item.line}`);
console.log(` ${colors.dim}Link:${colors.reset} ${item.originalLink}`);
console.log(` ${colors.dim}Candidates:${colors.reset}`);
for (const candidate of item.candidates) {
console.log(` - ${candidate}`);
}
console.log();
}
}
// Show missing
if (missing.length > 0) {
console.log(` ${colors.red}MISSING${colors.reset} (file not found anywhere)\n`);
for (const item of missing) {
console.log(` ${colors.cyan}${item.sourceFile}${colors.reset}:${item.line}`);
console.log(` ${colors.dim}Link:${colors.reset} ${item.originalLink}\n`);
}
}
console.log(' ' + '─'.repeat(50));
console.log(`\n Report saved to: ${colors.dim}${relative(process.cwd(), REPORT_PATH)}${colors.reset}`);
console.log(`\n To fix auto-fixable links, run:`);
console.log(` node tools/fix-doc-links.js --apply\n`);
process.exit(1);
}
main().catch((error) => {
console.error('Error:', error.message);
process.exit(1);
});

View File

@ -548,7 +548,7 @@ function checkDocLinks() {
printHeader('Checking documentation links');
try {
execSync('node tools/check-doc-links.js', {
execSync('node tools/validate-doc-links.js', {
cwd: PROJECT_ROOT,
stdio: 'inherit',
});

View File

@ -1,286 +0,0 @@
/**
* Internal documentation link checker
* Scans markdown files in docs/ and verifies:
* - All relative links point to existing files
* - All anchor links (#section) point to valid headings
* - No duplicate/conflicting paths
*
* Exits with code 1 if broken links are found (fails the build).
*/
const { readFileSync, existsSync } = require('node:fs');
const { resolve, dirname, join, normalize, relative } = require('node:path');
const { glob } = require('glob');
const DOCS_DIR = resolve(process.cwd(), 'docs');
// Regex to match markdown links: [text](path) and reference-style [text]: path
const LINK_PATTERNS = [
/\[([^\]]*)\]\(([^)]+)\)/g, // [text](path)
/\[([^\]]+)\]:\s*(\S+)/g, // [text]: path
];
// Regex to extract headings for anchor validation
const HEADING_PATTERN = /^#{1,6}\s+(.+)$/gm;
/**
* Determines whether a link should be ignored during validation.
* @param {string} link - The link URL or path to test.
* @returns {boolean} `true` if the link is external, uses a special protocol (`http://`, `https://`, `mailto:`, `tel:`), or is an absolute path starting with `/`, `false` otherwise.
*/
function shouldIgnore(link) {
return (
link.startsWith('http://') ||
link.startsWith('https://') ||
link.startsWith('mailto:') ||
link.startsWith('tel:') ||
link.startsWith('/') // Absolute paths handled by Astro routing
);
}
/**
* Convert a markdown heading into the anchor slug used by common Markdown processors.
*
* Produces a lowercase slug with emojis and most punctuation removed, whitespace collapsed to single
* hyphens, consecutive hyphens collapsed, and leading/trailing hyphens trimmed.
* @param {string} heading - The heading text to convert.
* @returns {string} The resulting anchor slug.
*/
function headingToAnchor(heading) {
return heading
.toLowerCase()
.replaceAll(/[\u{1F300}-\u{1F9FF}]/gu, '') // Remove emojis
.replaceAll(/[^\w\s-]/g, '') // Remove special chars except hyphens
.replaceAll(/\s+/g, '-') // Spaces to hyphens
.replaceAll(/-+/g, '-') // Collapse multiple hyphens
.replaceAll(/^-+|-+$/g, ''); // Trim leading/trailing hyphens
}
/**
* Extracts anchor slugs from Markdown content by converting headings to their anchor form.
*
* Strips inline formatting (code spans, emphasis, bold, and inline links), processes
* Markdown headings (levels 16), and returns the resulting anchor slugs.
*
* @param {string} content - The Markdown text to scan for headings.
* @returns {Set<string>} A set of anchor slugs derived from the headings in `content`.
*/
function extractAnchors(content) {
const anchors = new Set();
let match;
HEADING_PATTERN.lastIndex = 0;
while ((match = HEADING_PATTERN.exec(content)) !== null) {
const headingText = match[1].trim();
// Remove inline code, bold, italic, links from heading
const cleanHeading = headingText
.replaceAll(/`[^`]+`/g, '')
.replaceAll(/\*\*([^*]+)\*\*/g, '$1')
.replaceAll(/\*([^*]+)\*/g, '$1')
.replaceAll(/\[([^\]]+)\]\([^)]+\)/g, '$1')
.trim();
anchors.add(headingToAnchor(cleanHeading));
}
return anchors;
}
/**
* Remove fenced and inline code segments from Markdown content.
*
* @param {string} content - Markdown text to sanitize.
* @returns {string} The input content with fenced code blocks (```...``` and ~~~...~~~) and inline code (backtick-enclosed) removed.
*/
function stripCodeBlocks(content) {
// Remove fenced code blocks (``` or ~~~)
return content
.replaceAll(/```[\s\S]*?```/g, '')
.replaceAll(/~~~[\s\S]*?~~~/g, '')
.replaceAll(/`[^`\n]+`/g, ''); // Also remove inline code
}
/**
* Extracts all non-external link targets from markdown content, ignoring links inside code blocks.
* @param {string} content - Markdown source to scan for link targets.
* @returns {string[]} Array of raw link strings (paths and optional anchors) found in the content; external or protocol-based links are excluded.
*/
function extractLinks(content) {
const strippedContent = stripCodeBlocks(content);
const links = [];
for (const pattern of LINK_PATTERNS) {
let match;
pattern.lastIndex = 0;
while ((match = pattern.exec(strippedContent)) !== null) {
const rawLink = match[2];
if (!shouldIgnore(rawLink)) {
links.push(rawLink);
}
}
}
return links;
}
/**
* Split a link into its path and anchor components.
* @param {string} link - The link string to parse; may include a `#` followed by an anchor.
* @returns {{path: string|null, anchor: string|null}} An object where `path` is the portion before `#` (or `null` when empty, indicating a same-file anchor), and `anchor` is the portion after `#` (or `null` when no `#` is present). Note: `anchor` may be an empty string if the link ends with `#`.
*/
function parseLink(link) {
const hashIndex = link.indexOf('#');
if (hashIndex === -1) {
return { path: link, anchor: null };
}
return {
path: link.slice(0, hashIndex) || null, // Empty path means same file
anchor: link.slice(hashIndex + 1),
};
}
/**
* Resolve a relative markdown link path from a source file to a concrete absolute file path.
* @param {string} fromFile - Absolute path of the file containing the link.
* @param {string|null} linkPath - Link target as written in markdown; may be `null` or empty for same-file anchors.
* @returns {string} The resolved absolute path. If `linkPath` is null/empty returns `fromFile`. If the resolved path has no extension, an existing `.md` file or an `index.md` inside a matching directory is preferred; otherwise the normalized resolved path is returned.
*/
function resolveLink(fromFile, linkPath) {
if (!linkPath) return fromFile; // Same file anchor
const fromDir = dirname(fromFile);
let resolved = normalize(resolve(fromDir, linkPath));
// If link doesn't have extension, try .md
if (!resolved.endsWith('.md') && !existsSync(resolved)) {
const withMd = resolved + '.md';
if (existsSync(withMd)) {
return withMd;
}
// Try as directory with index.md
const asIndex = join(resolved, 'index.md');
if (existsSync(asIndex)) {
return asIndex;
}
}
return resolved;
}
// Cache for file anchors to avoid re-reading files
const anchorCache = new Map();
/**
* Retrieve and cache the set of markdown anchor slugs for a given file.
*
* Reads the file at the provided path, extracts heading-based anchor slugs, stores them in an internal cache, and returns them.
* @param {string} filePath - Absolute or relative path to the markdown file.
* @returns {Set<string>} The set of anchor slugs present in the file.
*/
function getAnchorsForFile(filePath) {
if (anchorCache.has(filePath)) {
return anchorCache.get(filePath);
}
const content = readFileSync(filePath, 'utf-8');
const anchors = extractAnchors(content);
anchorCache.set(filePath, anchors);
return anchors;
}
/**
* Validate Markdown files in docs/ for broken relative links and anchor targets.
*
* Scans all `.md` and `.mdx` files under DOCS_DIR, checks that relative links resolve to existing
* files and that any `#anchor` references point to existing headings. Prints a grouped,
* colored report of issues to stdout and terminates the process with exit code `0` if no issues
* were found or `1` if any broken links or anchors are detected.
*/
async function main() {
console.log(' → Scanning for broken links and anchors...');
const files = await glob('**/*.{md,mdx}', {
cwd: DOCS_DIR,
absolute: true,
ignore: ['**/_*/**'], // Ignore underscore directories (archive, planning, etc.)
});
const errors = [];
// Track all resolved paths for duplicate detection
const pathRegistry = new Map(); // normalized path -> [source files]
for (const file of files) {
const content = readFileSync(file, 'utf-8');
const links = extractLinks(content);
const relativePath = relative(DOCS_DIR, file);
for (const rawLink of links) {
const { path: linkPath, anchor } = parseLink(rawLink);
// Resolve target file
const targetFile = resolveLink(file, linkPath);
const normalizedTarget = normalize(targetFile);
// Check if file exists (skip for same-file anchors)
if (linkPath && !existsSync(targetFile)) {
errors.push({
type: 'broken-link',
file: relativePath,
link: rawLink,
message: `File not found: ${linkPath}`,
});
continue;
}
// Check anchor if present
if (anchor) {
const anchors = getAnchorsForFile(targetFile);
if (!anchors.has(anchor)) {
errors.push({
type: 'broken-anchor',
file: relativePath,
link: rawLink,
message: `Anchor "#${anchor}" not found in ${linkPath || 'same file'}`,
});
}
}
// Track paths for duplicate detection
if (linkPath) {
if (!pathRegistry.has(normalizedTarget)) {
pathRegistry.set(normalizedTarget, []);
}
pathRegistry.get(normalizedTarget).push({ from: relativePath, link: rawLink });
}
}
}
// Report results
if (errors.length === 0) {
console.log(` \u001B[32m✓\u001B[0m Checked ${files.length} files - no broken links found.`);
process.exit(0);
}
console.log(`\n \u001B[31m✗\u001B[0m Found ${errors.length} issue(s):\n`);
// Group by file
const byFile = {};
for (const error of errors) {
if (!byFile[error.file]) byFile[error.file] = [];
byFile[error.file].push(error);
}
for (const [file, fileErrors] of Object.entries(byFile)) {
console.log(` \u001B[36m${file}\u001B[0m`);
for (const error of fileErrors) {
const icon = error.type === 'broken-link' ? '🔗' : '⚓';
console.log(` ${icon} ${error.link}`);
console.log(` └─ ${error.message}`);
}
console.log();
}
process.exit(1);
}
main().catch((error) => {
console.error('Error:', error.message);
process.exit(1);
});

View File

@ -1,172 +1,249 @@
/**
* Documentation Link Fixer
* Fix Documentation Links
*
* Reads the audit report generated by audit-doc-links.js and applies fixes
* to broken links where a single match was found.
* Converts relative markdown links to site-relative paths.
* - ./file.md /current/path/file/
* - ../other/file.md /resolved/path/file/
* - /absolute/file.md /absolute/file/
* - index.md parent directory (e.g., /path/index.md /path/)
*
* Usage:
* node tools/fix-doc-links.js # Dry-run (preview changes)
* node tools/fix-doc-links.js --apply # Apply changes
* node tools/fix-doc-links.js # Dry run (shows what would change)
* node tools/fix-doc-links.js --write # Actually write changes
*/
const { readFileSync, writeFileSync, existsSync } = require('node:fs');
const { resolve, relative } = require('node:path');
const fs = require('node:fs');
const path = require('node:path');
const REPORT_PATH = resolve(__dirname, '.link-audit-report.json');
const DOCS_ROOT = path.resolve(__dirname, '../docs');
const DRY_RUN = !process.argv.includes('--write');
// Colors for console output
const colors = {
reset: '\u001B[0m',
red: '\u001B[31m',
green: '\u001B[32m',
yellow: '\u001B[33m',
cyan: '\u001B[36m',
dim: '\u001B[2m',
};
// Regex to match markdown links: [text](path.md) or [text](path.md#anchor)
const MARKDOWN_LINK_REGEX = /\[([^\]]*)\]\(([^)]+\.md(?:#[^)]*)?(?:\?[^)]*)?)\)/g;
/**
* Load the audit report.
* Get all markdown files in docs directory, excluding _* directories/files
*/
function loadReport() {
if (!existsSync(REPORT_PATH)) {
console.error(`\n ${colors.red}Error:${colors.reset} No audit report found.`);
console.error(` Run 'node tools/audit-doc-links.js' first.\n`);
process.exit(1);
}
function getMarkdownFiles(dir) {
const files = [];
try {
const content = readFileSync(REPORT_PATH, 'utf-8');
return JSON.parse(content);
} catch (error) {
console.error(`\n ${colors.red}Error:${colors.reset} Failed to parse audit report.`);
console.error(` ${error.message}\n`);
process.exit(1);
}
}
function walk(currentDir) {
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
/**
* Apply a fix to a file by replacing the original link with the suggested fix.
*/
function applyFix(filePath, originalLink, suggestedFix) {
const content = readFileSync(filePath, 'utf-8');
for (const entry of entries) {
const fullPath = path.join(currentDir, entry.name);
// Create the replacement pattern - we need to match the exact link in markdown syntax
// Original might have anchor, so we need to handle that
const originalWithoutAnchor = originalLink.split('#')[0];
const suggestedWithoutAnchor = suggestedFix.split('#')[0];
// Also preserve any anchor from the original if the fix doesn't include one
let finalFix = suggestedFix;
if (originalLink.includes('#') && !suggestedFix.includes('#')) {
const anchor = originalLink.slice(originalLink.indexOf('#'));
finalFix = suggestedFix + anchor;
}
// Replace the link - be careful to only replace inside markdown link syntax
const linkPattern = new RegExp(`\\]\\(${escapeRegex(originalLink)}\\)`, 'g');
const newContent = content.replace(linkPattern, `](${finalFix})`);
if (newContent === content) {
return false; // No change made
}
writeFileSync(filePath, newContent);
return true;
}
/**
* Escape special regex characters in a string.
*/
function escapeRegex(string) {
return string.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
}
/**
* Main function.
*/
async function main() {
const args = process.argv.slice(2);
const applyChanges = args.includes('--apply');
console.log('\n Documentation Link Fixer');
console.log(' ========================\n');
if (applyChanges) {
console.log(` ${colors.green}APPLYING CHANGES${colors.reset}\n`);
} else {
console.log(` ${colors.yellow}DRY RUN${colors.reset} - No files will be modified.`);
console.log(` Use --apply to apply changes.\n`);
}
const report = loadReport();
if (report.autoFixable.length === 0) {
console.log(` ${colors.green}${colors.reset} No auto-fixable links found.\n`);
process.exit(0);
}
console.log(` Found ${report.autoFixable.length} auto-fixable link(s).\n`);
const fixed = [];
const failed = [];
// Group fixes by file for efficiency
const byFile = {};
for (const item of report.autoFixable) {
if (!byFile[item.sourceFileAbsolute]) {
byFile[item.sourceFileAbsolute] = [];
}
byFile[item.sourceFileAbsolute].push(item);
}
for (const [filePath, items] of Object.entries(byFile)) {
const displayPath = relative(process.cwd(), filePath);
console.log(` ${colors.cyan}${displayPath}${colors.reset}`);
for (const item of items) {
console.log(` Line ${item.line}:`);
console.log(` ${colors.dim}Old:${colors.reset} ${item.originalLink}`);
console.log(` ${colors.dim}New:${colors.reset} ${item.suggestedFix}`);
if (applyChanges) {
try {
const success = applyFix(filePath, item.originalLink, item.suggestedFix);
if (success) {
console.log(` ${colors.green}✓ Fixed${colors.reset}`);
fixed.push(item);
} else {
console.log(` ${colors.yellow}⚠ No match found (may have been fixed already)${colors.reset}`);
}
} catch (error) {
console.log(` ${colors.red}✗ Error: ${error.message}${colors.reset}`);
failed.push({ ...item, error: error.message });
}
// Skip underscore-prefixed entries
if (entry.name.startsWith('_')) {
continue;
}
if (entry.isDirectory()) {
walk(fullPath);
} else if (entry.isFile() && entry.name.endsWith('.md')) {
files.push(fullPath);
}
console.log();
}
}
// Summary
console.log(' ' + '─'.repeat(50));
console.log('\n SUMMARY\n');
if (applyChanges) {
console.log(` Fixed: ${colors.green}${fixed.length}${colors.reset}`);
if (failed.length > 0) {
console.log(` Failed: ${colors.red}${failed.length}${colors.reset}`);
}
console.log(`\n Run 'node tools/audit-doc-links.js' to verify remaining issues.\n`);
} else {
console.log(` Would fix: ${colors.yellow}${report.autoFixable.length}${colors.reset} link(s)`);
console.log(`\n To apply these fixes, run:`);
console.log(` node tools/fix-doc-links.js --apply\n`);
}
process.exit(failed.length > 0 ? 1 : 0);
walk(dir);
return files;
}
main().catch((error) => {
console.error('Error:', error.message);
process.exit(1);
});
/**
* Convert a markdown link href to site-relative path
*
* @param {string} href - The original href (e.g., "./file.md", "../other/file.md#anchor")
* @param {string} currentFilePath - Absolute path to the file containing this link
* @returns {string} - Site-relative path (e.g., "/path/to/file/", "/path/to/file/#anchor")
*/
function convertToSiteRelative(href, currentFilePath) {
// Skip external links
if (href.includes('://')) {
return href;
}
// Extract anchor and query string if present
let anchor = '';
let query = '';
let pathPortion = href;
const hashIndex = href.indexOf('#');
const queryIndex = href.indexOf('?');
if (hashIndex !== -1 || queryIndex !== -1) {
const firstDelimiter = Math.min(hashIndex === -1 ? Infinity : hashIndex, queryIndex === -1 ? Infinity : queryIndex);
pathPortion = href.slice(0, Math.max(0, firstDelimiter));
const suffix = href.slice(Math.max(0, firstDelimiter));
const anchorInSuffix = suffix.indexOf('#');
if (suffix.startsWith('?')) {
if (anchorInSuffix === -1) {
query = suffix;
} else {
query = suffix.slice(0, Math.max(0, anchorInSuffix));
anchor = suffix.slice(Math.max(0, anchorInSuffix));
}
} else {
anchor = suffix;
}
}
let absolutePath;
if (pathPortion.startsWith('/')) {
// Already site-relative - resolve from docs root
absolutePath = path.join(DOCS_ROOT, pathPortion);
} else {
// Relative path (./, ../, or bare filename) - resolve from current file's directory
const currentDir = path.dirname(currentFilePath);
absolutePath = path.resolve(currentDir, pathPortion);
}
// Convert to site-relative path (relative to docs root)
let siteRelative = '/' + path.relative(DOCS_ROOT, absolutePath);
// Normalize path separators for Windows
siteRelative = siteRelative.split(path.sep).join('/');
// Transform .md to trailing slash
if (siteRelative.endsWith('/index.md')) {
siteRelative = siteRelative.replace(/\/index\.md$/, '/');
} else if (siteRelative.endsWith('.md')) {
siteRelative = siteRelative.replace(/\.md$/, '/');
}
return siteRelative + query + anchor;
}
/**
* Process a single markdown file, skipping links inside fenced code blocks
*
* @param {string} filePath - Absolute path to the file
* @returns {Object} - { changed: boolean, original: string, updated: string, changes: Array }
*/
function processFile(filePath) {
const original = fs.readFileSync(filePath, 'utf-8');
const changes = [];
// Extract fenced code blocks and replace with placeholders
const codeBlocks = [];
const CODE_PLACEHOLDER = '\u0000CODE_BLOCK_';
let contentWithPlaceholders = original.replaceAll(/```[\s\S]*?```/g, (match) => {
const index = codeBlocks.length;
codeBlocks.push(match);
return `${CODE_PLACEHOLDER}${index}\u0000`;
});
// Process links only in non-code-block content
contentWithPlaceholders = contentWithPlaceholders.replaceAll(MARKDOWN_LINK_REGEX, (match, linkText, href) => {
// Skip external links
if (href.includes('://')) {
return match;
}
const newHref = convertToSiteRelative(href, filePath);
// Only record as change if actually different
if (newHref !== href) {
changes.push({ from: href, to: newHref });
return `[${linkText}](${newHref})`;
}
return match;
});
// Restore code blocks
const updated = contentWithPlaceholders.replaceAll(
new RegExp(`${CODE_PLACEHOLDER}(\\d+)\u0000`, 'g'),
(match, index) => codeBlocks[parseInt(index, 10)],
);
return {
changed: changes.length > 0,
original,
updated,
changes,
};
}
/**
* Validate that a site-relative link points to an existing file
*/
function validateLink(siteRelativePath) {
// Strip trailing slash and anchor/query
const checkPath = siteRelativePath.split('#')[0].split('?')[0];
if (checkPath.endsWith('/')) {
// Could be directory/index.md or file.md that became directory/
const asIndex = path.join(DOCS_ROOT, checkPath, 'index.md');
const asFile = path.join(DOCS_ROOT, checkPath.slice(0, -1) + '.md');
return fs.existsSync(asIndex) || fs.existsSync(asFile);
}
return fs.existsSync(path.join(DOCS_ROOT, checkPath));
}
// Main execution
console.log(`\nScanning docs in: ${DOCS_ROOT}`);
console.log(`Mode: ${DRY_RUN ? 'DRY RUN (use --write to apply changes)' : 'WRITE MODE'}\n`);
const files = getMarkdownFiles(DOCS_ROOT);
console.log(`Found ${files.length} markdown files (excluding _* paths)\n`);
let totalChanges = 0;
let filesChanged = 0;
const brokenLinks = [];
for (const filePath of files) {
const relativePath = path.relative(DOCS_ROOT, filePath);
const result = processFile(filePath);
if (result.changed) {
filesChanged++;
totalChanges += result.changes.length;
console.log(`\n${relativePath}`);
for (const change of result.changes) {
const isValid = validateLink(change.to);
const status = isValid ? ' ' : '! ';
console.log(`${status} ${change.from}`);
console.log(` -> ${change.to}`);
if (!isValid) {
brokenLinks.push({
file: relativePath,
link: change.to,
original: change.from,
});
}
}
if (!DRY_RUN) {
fs.writeFileSync(filePath, result.updated, 'utf-8');
}
}
}
console.log(`\n${'─'.repeat(60)}`);
console.log(`\nSummary:`);
console.log(` Files scanned: ${files.length}`);
console.log(` Files with changes: ${filesChanged}`);
console.log(` Total link updates: ${totalChanges}`);
if (brokenLinks.length > 0) {
console.log(`\n! Potential broken links (${brokenLinks.length}):`);
for (const bl of brokenLinks) {
console.log(` ${bl.file}: ${bl.link}`);
}
}
if (DRY_RUN && totalChanges > 0) {
console.log(`\nRun with --write to apply these changes`);
}
console.log('');

357
tools/validate-doc-links.js Normal file
View File

@ -0,0 +1,357 @@
/**
* Documentation Link Validator
*
* Validates site-relative links in markdown files and attempts to fix broken ones.
*
* What it checks:
* - All site-relative links (starting with /) point to existing .md files
* - Anchor links (#section) point to valid headings
*
* What it fixes:
* - Broken links where the target file can be found elsewhere in /docs
*
* Usage:
* node tools/validate-doc-links.js # Dry run (validate and show issues)
* node tools/validate-doc-links.js --write # Fix auto-fixable issues
*/
const fs = require('node:fs');
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;
// File extensions that are static assets, not markdown docs
const STATIC_ASSET_EXTENSIONS = ['.zip', '.txt', '.pdf', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.ico'];
// Regex to extract headings for anchor validation
const HEADING_PATTERN = /^#{1,6}\s+(.+)$/gm;
/**
* Get all markdown files in docs directory, excluding _* directories/files
*/
function getMarkdownFiles(dir) {
const files = [];
function walk(currentDir) {
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(currentDir, entry.name);
if (entry.name.startsWith('_')) {
continue;
}
if (entry.isDirectory()) {
walk(fullPath);
} else if (entry.isFile() && entry.name.endsWith('.md')) {
files.push(fullPath);
}
}
}
walk(dir);
return files;
}
/**
* Strip fenced code blocks from content
*/
function stripCodeBlocks(content) {
return content.replaceAll(/```[\s\S]*?```/g, '');
}
/**
* Convert a heading to its anchor slug
*/
function headingToAnchor(heading) {
return heading
.toLowerCase()
.replaceAll(/[\u{1F300}-\u{1F9FF}]/gu, '') // Remove emojis
.replaceAll(/[^\w\s-]/g, '') // Remove special chars
.replaceAll(/\s+/g, '-') // Spaces to hyphens
.replaceAll(/-+/g, '-') // Collapse hyphens
.replaceAll(/^-+|-+$/g, ''); // Trim hyphens
}
/**
* Extract anchor slugs from a markdown file
*/
function extractAnchors(content) {
const anchors = new Set();
let match;
HEADING_PATTERN.lastIndex = 0;
while ((match = HEADING_PATTERN.exec(content)) !== null) {
const headingText = match[1]
.trim()
.replaceAll(/`[^`]+`/g, '')
.replaceAll(/\*\*([^*]+)\*\*/g, '$1')
.replaceAll(/\*([^*]+)\*/g, '$1')
.replaceAll(/\[([^\]]+)\]\([^)]+\)/g, '$1')
.trim();
anchors.add(headingToAnchor(headingText));
}
return anchors;
}
/**
* Resolve a site-relative link to a file path
* /how-to/installation/install-bmad/ -> docs/how-to/installation/install-bmad.md or .../index.md
*/
function resolveLink(siteRelativePath) {
// Strip anchor and query
const checkPath = siteRelativePath.split('#')[0].split('?')[0];
if (checkPath.endsWith('/')) {
// Could be file.md or directory/index.md
const asFile = path.join(DOCS_ROOT, checkPath.slice(0, -1) + '.md');
const asIndex = path.join(DOCS_ROOT, checkPath, 'index.md');
if (fs.existsSync(asFile)) return asFile;
if (fs.existsSync(asIndex)) return asIndex;
return null;
}
// Direct path
const direct = path.join(DOCS_ROOT, checkPath);
if (fs.existsSync(direct)) return direct;
// Try with .md
const withMd = direct + '.md';
if (fs.existsSync(withMd)) return withMd;
return null;
}
/**
* Search for a file with directory context
*/
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 parts = cleanPath.split('/');
const fileName = parts.at(-1) + '.md';
const parentDir = parts.length > 1 ? parts.at(-2) : null;
const allFiles = getMarkdownFiles(DOCS_ROOT);
const matches = [];
for (const file of allFiles) {
const fileBaseName = path.basename(file);
const fileParentDir = path.basename(path.dirname(file));
// Exact filename match with parent directory context
if (fileBaseName === fileName) {
if (parentDir && fileParentDir === parentDir) {
// Strong match: both filename and parent dir match
return [file];
}
matches.push(file);
}
// Also check for index.md in a matching directory
if (fileBaseName === 'index.md' && fileParentDir === fileName.replace('.md', '')) {
matches.push(file);
}
}
return matches;
}
/**
* Convert absolute file path to site-relative URL
*/
function fileToSiteRelative(filePath) {
let relative = '/' + path.relative(DOCS_ROOT, filePath);
relative = relative.split(path.sep).join('/');
if (relative.endsWith('/index.md')) {
return relative.replace(/\/index\.md$/, '/');
}
return relative.replace(/\.md$/, '/');
}
/**
* Process a single file and find issues
*/
function processFile(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const strippedContent = stripCodeBlocks(content);
const issues = [];
let match;
LINK_REGEX.lastIndex = 0;
while ((match = LINK_REGEX.exec(strippedContent)) !== null) {
const linkText = match[1];
const href = match[2];
// Extract path and anchor
const hashIndex = href.indexOf('#');
const linkPath = hashIndex === -1 ? href : href.slice(0, hashIndex);
const anchor = hashIndex === -1 ? null : href.slice(hashIndex + 1);
// Skip static asset links (zip, txt, images, etc.)
const linkLower = linkPath.toLowerCase();
if (STATIC_ASSET_EXTENSIONS.some((ext) => linkLower.endsWith(ext))) {
continue;
}
// Validate the link target exists
const targetFile = resolveLink(linkPath);
if (!targetFile) {
// Link is broken - try to find the file
const candidates = findFileWithContext(linkPath);
const issue = {
type: 'broken-link',
linkText,
href,
linkPath,
fullMatch: match[0],
};
if (candidates.length === 1) {
issue.status = 'auto-fixable';
issue.suggestedFix = fileToSiteRelative(candidates[0]) + (anchor ? '#' + anchor : '');
issue.foundAt = path.relative(DOCS_ROOT, candidates[0]);
} else if (candidates.length > 1) {
issue.status = 'needs-review';
issue.candidates = candidates.map((c) => path.relative(DOCS_ROOT, c));
} else {
issue.status = 'manual-check';
}
issues.push(issue);
continue;
}
// Validate anchor if present
if (anchor) {
const targetContent = fs.readFileSync(targetFile, 'utf-8');
const anchors = extractAnchors(targetContent);
if (!anchors.has(anchor)) {
issues.push({
type: 'broken-anchor',
linkText,
href,
anchor,
status: 'manual-check',
message: `Anchor "#${anchor}" not found`,
});
}
}
}
return { content, issues };
}
/**
* Apply fixes to file content
*/
function applyFixes(content, issues) {
let updated = content;
for (const issue of issues) {
if (issue.status === 'auto-fixable' && issue.suggestedFix) {
const oldLink = `[${issue.linkText}](${issue.href})`;
const newLink = `[${issue.linkText}](${issue.suggestedFix})`;
updated = updated.replace(oldLink, newLink);
}
}
return updated;
}
// Main execution
console.log(`\nValidating docs in: ${DOCS_ROOT}`);
console.log(`Mode: ${DRY_RUN ? 'DRY RUN (use --write to fix)' : 'WRITE MODE'}\n`);
const files = getMarkdownFiles(DOCS_ROOT);
console.log(`Found ${files.length} markdown files\n`);
let totalIssues = 0;
let autoFixable = 0;
let needsReview = 0;
let manualCheck = 0;
let filesWithIssues = 0;
const allIssues = [];
for (const filePath of files) {
const relativePath = path.relative(DOCS_ROOT, filePath);
const { content, issues } = processFile(filePath);
if (issues.length > 0) {
filesWithIssues++;
totalIssues += issues.length;
console.log(`\n${relativePath}`);
for (const issue of issues) {
if (issue.status === 'auto-fixable') {
autoFixable++;
console.log(` [FIX] ${issue.href}`);
console.log(` -> ${issue.suggestedFix}`);
} else if (issue.status === 'needs-review') {
needsReview++;
console.log(` [REVIEW] ${issue.href}`);
console.log(` Multiple matches found:`);
for (const candidate of issue.candidates) {
console.log(` - ${candidate}`);
}
} else if (issue.type === 'broken-anchor') {
manualCheck++;
console.log(` [MANUAL] ${issue.href}`);
console.log(` ${issue.message}`);
} else {
manualCheck++;
console.log(` [MANUAL] ${issue.href}`);
console.log(` File not found anywhere - may need to remove link`);
}
allIssues.push({ file: relativePath, ...issue });
}
// Apply fixes if not dry run
if (!DRY_RUN) {
const fixableIssues = issues.filter((i) => i.status === 'auto-fixable');
if (fixableIssues.length > 0) {
const updated = applyFixes(content, fixableIssues);
fs.writeFileSync(filePath, updated, 'utf-8');
}
}
}
}
console.log(`\n${'─'.repeat(60)}`);
console.log(`\nSummary:`);
console.log(` Files scanned: ${files.length}`);
console.log(` Files with issues: ${filesWithIssues}`);
console.log(` Total issues: ${totalIssues}`);
if (totalIssues > 0) {
console.log(`\n Breakdown:`);
console.log(` Auto-fixable: ${autoFixable}`);
console.log(` Needs review: ${needsReview}`);
console.log(` Manual check: ${manualCheck}`);
}
if (totalIssues === 0) {
console.log(`\n All links valid!`);
} else if (DRY_RUN && autoFixable > 0) {
console.log(`\nRun with --write to auto-fix ${autoFixable} issue(s)`);
}
console.log('');
process.exit(totalIssues > 0 ? 1 : 0);

View File

@ -1,21 +1,22 @@
/**
* Rehype plugin to transform relative markdown file links (.md) to page routes
* Rehype plugin to transform markdown file links (.md) to page routes
*
* Transforms:
* ./path/to/file.md ./path/to/file/
* ./path/index.md ./path/ (index.md becomes directory root)
* ../path/file.md#anchor ../path/file/#anchor
* ./file.md?query=param ./file/?query=param
* /absolute/path/file.md /absolute/path/file/
*
* Only affects relative links (./, ../) - absolute and external links are unchanged
* Affects relative links (./, ../) and absolute paths (/) - external links are unchanged
*/
import { visit } from 'unist-util-visit';
/**
* Convert relative Markdown file links (./ or ../) into equivalent page route-style links.
* Convert Markdown file links (.md) into equivalent page route-style links.
*
* The returned transformer walks the HTML tree and rewrites anchor `href` values that are relative paths pointing to `.md` files. It preserves query strings and hash anchors, rewrites `.../index.md` to the directory root path (`.../`), and rewrites other `.md` file paths by removing the `.md` extension and ensuring a trailing slash. Absolute, external, non-relative, non-string, or links without `.md` are left unchanged.
* The returned transformer walks the HTML tree and rewrites anchor `href` values that are relative paths (./, ../) or absolute paths (/) pointing to `.md` files. It preserves query strings and hash anchors, rewrites `.../index.md` to the directory root path (`.../`), and rewrites other `.md` file paths by removing the `.md` extension and ensuring a trailing slash. External links (http://, https://) and non-.md links are left unchanged.
*
* @returns {function} A HAST tree transformer that mutates `a` element `href` properties as described.
*/
@ -34,8 +35,13 @@ export default function rehypeMarkdownLinks() {
return;
}
// Only transform relative paths starting with ./ or ../
if (!href.startsWith('./') && !href.startsWith('../')) {
// Skip external links (http://, https://, mailto:, etc.)
if (href.includes('://') || href.startsWith('mailto:') || href.startsWith('tel:')) {
return;
}
// Only transform paths starting with ./, ../, or / (absolute)
if (!href.startsWith('./') && !href.startsWith('../') && !href.startsWith('/')) {
return;
}