refactor: remove downloads page and bundle generation (#1577)

The downloads page offered bmad-sources.zip and bmad-prompts.zip, both
redundant: GitHub provides source archives for every tag natively, and
npx bmad-method install is the supported path for compiled prompts.

Remove the downloads page, all bundle generation code, the archiver
dependency, and nav links. The llms.txt and llms-full.txt files (the
genuinely useful artifacts) continue to be generated as before.
This commit is contained in:
Alex Verkhovsky 2026-02-06 22:26:39 -07:00 committed by GitHub
parent 97bfe0a485
commit a8cda7c6fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 7 additions and 215 deletions

View File

@ -1,74 +0,0 @@
---
title: Downloads
---
Download BMad Method resources for offline use, AI training, or integration.
## Source Bundles
Download these from the `downloads/` folder on the documentation site.
| File | Description |
| ------------------ | ------------------------------- |
| `bmad-sources.zip` | Complete BMad source files |
| `bmad-prompts.zip` | Agent and workflow prompts only |
## LLM-Optimized Files
These files are designed for AI consumption - perfect for loading into Claude, ChatGPT, or any LLM context window. See [API Access](#api-access) below for URLs.
| File | Description | Use Case |
| --------------- | ----------------------------------- | -------------------------- |
| `llms.txt` | Documentation index with summaries | Quick overview, navigation |
| `llms-full.txt` | Complete documentation concatenated | Full context loading |
### Using with LLMs
**Claude Projects:**
```
Upload llms-full.txt as project knowledge
```
**ChatGPT:**
```
Paste llms.txt for navigation, or sections from llms-full.txt as needed
```
**API Usage:**
```python
import requests
docs = requests.get("https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt").text
# Include in your system prompt or context
```
## Installation Options
```bash
npx bmad-method install
```
[More details](/docs/how-to/install-bmad.md)
## Version Information
- **Current Version:** See [CHANGELOG](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md)
- **Release Notes:** Available on [GitHub Releases](https://github.com/bmad-code-org/BMAD-METHOD/releases)
## API Access
For programmatic access to BMad documentation:
```bash
# Get documentation index
curl https://bmad-code-org.github.io/BMAD-METHOD/llms.txt
# Get full documentation
curl https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt
```
## Contributing
Want to improve BMad Method? Check out:
- [Contributing Guide](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CONTRIBUTING.md)
- [GitHub Repository](https://github.com/bmad-code-org/BMAD-METHOD)

View File

@ -42,8 +42,6 @@ Fetch `llms-full.txt` into your session:
https://bmad-code-org.github.io/BMAD-METHOD/llms-full.txt
```
See the [Downloads page](/docs/downloads.md) for other downloadable resources.
### 3. Ask Your Question
:::note[Example]

View File

@ -89,7 +89,6 @@
"@astrojs/sitemap": "^3.6.0",
"@astrojs/starlight": "^0.37.5",
"@eslint/js": "^9.33.0",
"archiver": "^7.0.1",
"astro": "^5.16.0",
"c8": "^10.1.3",
"eslint": "^9.33.0",

View File

@ -2,10 +2,10 @@
* BMAD Documentation Build Pipeline
*
* Consolidates docs from multiple sources, generates LLM-friendly files,
* creates downloadable bundles, and builds the Astro+Starlight site.
* and builds the Astro+Starlight site.
*
* Build outputs:
* build/artifacts/ - With llms.txt, llms-full.txt, ZIPs
* build/artifacts/ - With llms.txt, llms-full.txt
* build/site/ - Final Astro output (deployable)
*/
@ -13,7 +13,6 @@ import { execSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import archiver from 'archiver';
import { getSiteUrl } from '../website/src/lib/site-url.mjs';
// =============================================================================
@ -35,7 +34,6 @@ const LLM_EXCLUDE_PATTERNS = [
'changelog',
'ide-info/',
'v4-to-v6-upgrade',
'downloads/',
'faq',
'reference/glossary/',
'explanation/game-dev/',
@ -81,17 +79,16 @@ main().catch((error) => {
// =============================================================================
// Pipeline Stages
/**
* Generate LLM files and downloadable bundles for the documentation pipeline.
* Generate LLM files for the documentation pipeline.
*
* Creates the build/artifacts directory, writes `llms.txt` and `llms-full.txt` (sourced from the provided docs directory),
* and produces download ZIP bundles.
* Creates the build/artifacts directory and writes `llms.txt` and `llms-full.txt` (sourced from the provided docs directory).
*
* @param {string} docsDir - Path to the source docs directory containing Markdown files.
* @returns {string} Path to the created artifacts directory.
*/
async function generateArtifacts(docsDir) {
printHeader('Generating LLM files and download bundles');
printHeader('Generating LLM files');
const outputDir = path.join(BUILD_DIR, 'artifacts');
fs.mkdirSync(outputDir, { recursive: true });
@ -99,7 +96,6 @@ async function generateArtifacts(docsDir) {
// Generate LLM files reading from docs/, output to artifacts/
generateLlmsTxt(outputDir);
generateLlmsFullTxt(docsDir, outputDir);
await generateDownloadBundles(outputDir);
console.log();
console.log(` \u001B[32m✓\u001B[0m Artifact generation complete`);
@ -176,8 +172,6 @@ function generateLlmsTxt(outputDir) {
'## Quick Links',
'',
`- [Full Documentation (llms-full.txt)](${siteUrl}/llms-full.txt) - Complete docs for AI context`,
`- [Source Bundle](${siteUrl}/downloads/bmad-sources.zip) - Complete source code`,
`- [Prompts Bundle](${siteUrl}/downloads/bmad-prompts.zip) - Agent prompts and workflows`,
'',
].join('\n');
@ -249,7 +243,6 @@ function compareLlmDocs(a, b) {
function getLlmSortKey(filePath) {
if (filePath === 'index.md') return 0;
if (filePath === 'downloads.md') return 1;
if (filePath.startsWith(`tutorials${path.sep}`) || filePath.startsWith('tutorials/')) return 2;
if (filePath.startsWith(`how-to${path.sep}`) || filePath.startsWith('how-to/')) return 3;
if (filePath.startsWith(`explanation${path.sep}`) || filePath.startsWith('explanation/')) return 4;
@ -322,48 +315,6 @@ function validateLlmSize(content) {
}
}
// =============================================================================
// Download Bundle Generation
// =============================================================================
async function generateDownloadBundles(outputDir) {
console.log(' → Generating download bundles...');
const downloadsDir = path.join(outputDir, 'downloads');
fs.mkdirSync(downloadsDir, { recursive: true });
await generateSourcesBundle(downloadsDir);
await generatePromptsBundle(downloadsDir);
}
async function generateSourcesBundle(downloadsDir) {
const srcDir = path.join(PROJECT_ROOT, 'src');
if (!fs.existsSync(srcDir)) return;
const zipPath = path.join(downloadsDir, 'bmad-sources.zip');
await createZipArchive(srcDir, zipPath, ['__pycache__', '.pyc', '.DS_Store', 'node_modules']);
const size = (fs.statSync(zipPath).size / 1024 / 1024).toFixed(1);
console.log(` bmad-sources.zip (${size}M)`);
}
/**
* Create a zip archive of the project's prompts modules and place it in the downloads directory.
*
* Creates bmad-prompts.zip from src/modules, excluding common unwanted paths, writes it to the provided downloads directory, and logs the resulting file size. If the modules directory does not exist, the function returns without creating a bundle.
* @param {string} downloadsDir - Destination directory where bmad-prompts.zip will be written.
*/
async function generatePromptsBundle(downloadsDir) {
const modulesDir = path.join(PROJECT_ROOT, 'src', 'modules');
if (!fs.existsSync(modulesDir)) return;
const zipPath = path.join(downloadsDir, 'bmad-prompts.zip');
await createZipArchive(modulesDir, zipPath, ['docs', '.DS_Store', '__pycache__', 'node_modules']);
const size = Math.floor(fs.statSync(zipPath).size / 1024);
console.log(` bmad-prompts.zip (${size}K)`);
}
// =============================================================================
// Astro Build
/**
@ -384,7 +335,6 @@ function runAstroBuild() {
* Copy generated artifact files into the built site directory.
*
* Copies llms.txt and llms-full.txt from the artifacts directory into the site directory.
* If a downloads subdirectory exists under artifacts, copies it into siteDir/downloads.
*
* @param {string} artifactsDir - Path to the build artifacts directory containing generated files.
* @param {string} siteDir - Path to the target site directory where artifacts should be placed.
@ -394,11 +344,6 @@ function copyArtifactsToSite(artifactsDir, siteDir) {
fs.copyFileSync(path.join(artifactsDir, 'llms.txt'), path.join(siteDir, 'llms.txt'));
fs.copyFileSync(path.join(artifactsDir, 'llms-full.txt'), path.join(siteDir, 'llms-full.txt'));
const downloadsDir = path.join(artifactsDir, 'downloads');
if (fs.existsSync(downloadsDir)) {
copyDirectory(downloadsDir, path.join(siteDir, 'downloads'));
}
}
// =============================================================================
@ -407,7 +352,7 @@ function copyArtifactsToSite(artifactsDir, siteDir) {
* Prints a concise end-of-build summary and displays a sample listing of the final site directory.
*
* @param {string} docsDir - Path to the source documentation directory used for the build.
* @param {string} artifactsDir - Path to the directory containing generated artifacts (e.g., llms.txt, downloads).
* @param {string} artifactsDir - Path to the directory containing generated artifacts (e.g., llms.txt).
* @param {string} siteDir - Path to the final built site directory whose contents will be listed.
*/
@ -526,35 +471,6 @@ function copyDirectory(src, dest, exclude = []) {
return true;
}
/**
* Create a ZIP archive of a directory, optionally excluding entries that match given substrings.
* @param {string} sourceDir - Path to the source directory to archive.
* @param {string} outputPath - Path to write the resulting ZIP file.
* @param {string[]} [exclude=[]] - Array of substrings; any entry whose path includes one of these substrings will be omitted.
* @returns {Promise<void>} Resolves when the archive has been fully written and closed, rejects on error.
*/
function createZipArchive(sourceDir, outputPath, exclude = []) {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(outputPath);
const archive = archiver('zip', { zlib: { level: 9 } });
output.on('close', resolve);
archive.on('error', reject);
archive.pipe(output);
const baseName = path.basename(sourceDir);
archive.directory(sourceDir, baseName, (entry) => {
for (const pattern of exclude) {
if (entry.name.includes(pattern)) return false;
}
return entry;
});
archive.finalize();
});
}
// =============================================================================
// Console Output Formatting
// =============================================================================

View File

@ -73,4 +73,3 @@ Note: If copying, remember to keep the copy in sync with changes to `docs/`.
The build pipeline (`npm run docs:build`) produces:
- Static HTML site in `build/site/`
- LLM-friendly files: `llms.txt`, `llms-full.txt`
- Downloadable ZIP bundles in `downloads/`

View File

@ -26,9 +26,6 @@ const shouldRenderSearch =
{shouldRenderSearch && <Search {...Astro.props} />}
</div>
<div class="sl-hidden md:sl-flex print:hidden right-group">
<nav class="sl-flex nav-links">
<a href={`${import.meta.env.BASE_URL}downloads/`}>Downloads</a>
</nav>
<div class="sl-flex social-icons">
<SocialIcons {...Astro.props} />
</div>
@ -55,33 +52,11 @@ const shouldRenderSearch =
}
.right-group,
.social-icons,
.nav-links {
.social-icons {
gap: 1rem;
align-items: center;
}
.nav-links a {
color: var(--sl-color-white);
text-decoration: none;
font-size: 0.875rem;
font-weight: 500;
padding: 0.25rem 0.5rem;
border-radius: 4px;
transition: color 0.15s ease, background-color 0.15s ease;
}
.nav-links a:hover {
color: var(--sl-color-accent);
background-color: rgba(140, 140, 255, 0.1);
}
.nav-links::after {
content: '';
height: 2rem;
border-inline-end: 1px solid var(--sl-color-gray-5);
}
.social-icons::after {
content: '';
height: 2rem;

View File

@ -9,9 +9,6 @@ import type { Props } from '@astrojs/starlight/props';
<div class="sl-flex social-icons">
<SocialIcons {...Astro.props} />
</div>
<nav class="sl-flex nav-links">
<a href={`${import.meta.env.BASE_URL}downloads/`}>Downloads</a>
</nav>
<ThemeSelect {...Astro.props} />
<LanguageSelect {...Astro.props} />
</div>
@ -33,21 +30,4 @@ import type { Props } from '@astrojs/starlight/props';
padding: 0.5rem 0;
align-items: center;
}
.nav-links {
gap: 1rem;
align-items: center;
}
.nav-links a {
color: var(--sl-color-white);
text-decoration: none;
font-size: 0.875rem;
font-weight: 500;
padding: 0.5rem 0.75rem;
border-radius: 4px;
transition: color 0.15s ease, background-color 0.15s ease;
}
.nav-links a:hover {
color: var(--sl-color-accent);
background-color: rgba(140, 140, 255, 0.1);
}
</style>

View File

@ -3,7 +3,6 @@
*
* Transforms:
* /img/foo.png /BMAD-METHOD/img/foo.png (when base is /BMAD-METHOD/)
* /downloads/file.zip /BMAD-METHOD/downloads/file.zip
* /llms.txt /BMAD-METHOD/llms.txt
*
* Only affects absolute paths (/) - relative paths and external URLs are unchanged.