github/spec-kit · error · BundlerError
No README.md found in '{bundle_dir}'. Every bundle must ship
Error message
No README.md found in '{bundle_dir}'. Every bundle must ship a README.md describing it. What it means
The bundle artifact contract requires a human-facing README.md next to bundle.yml; build_bundle() refuses to publish a bundle with no description. This is a deliberate quality gate, not an incidental file check — it fires even when bundle.yml itself is valid.
Source
Thrown at src/specify_cli/bundler/services/packager.py:46
@dataclass
class BuildResult:
artifact_path: Path
file_count: int
def build_bundle(
bundle_dir: Path,
output_dir: Path | None = None,
) -> BuildResult:
bundle_dir = Path(bundle_dir).resolve()
manifest_path = bundle_dir / "bundle.yml"
if not manifest_path.exists():
raise BundlerError(f"No bundle.yml found in '{bundle_dir}'.")
# The artifact contract requires a human-facing README.md alongside the
# manifest; refuse early rather than publish a bundle with no description.
if not (bundle_dir / "README.md").exists():
raise BundlerError(
f"No README.md found in '{bundle_dir}'. Every bundle must ship a "
"README.md describing it."
)
manifest = BundleManifest.from_file(manifest_path)
report = validate_manifest(manifest)
if not report.ok:
raise BundlerError(
"Refusing to build an invalid manifest. Run 'specify bundle validate' "
"and fix:\n - " + "\n - ".join(report.errors)
)
out_dir = Path(output_dir).resolve() if output_dir else bundle_dir
out_dir.mkdir(parents=True, exist_ok=True)
artifact_name = f"{manifest.bundle.id}-{manifest.bundle.version}.zip"
artifact_path = out_dir / artifact_name
# Defense in depth: even though validate_manifest() rejects unsafe ids, make
# sure a crafted id cannot push the artifact outside the output directory.View on GitHub (pinned to bf88c9f9a8)
Solutions
- Create <bundle_dir>/README.md describing what the bundle installs and why (exact name, top level of the bundle dir).
- Check for case or extension mismatches: readme.md/README.rst will not satisfy the check.
- Re-run `specify bundle build` after adding the file.
Example fix
echo '# My Bundle\nInstalls the X preset and Y extension.' > <bundle_dir>/README.md
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path assert (bundle_dir / "README.md").is_file(), "bundle needs a top-level README.md" build_bundle(bundle_dir)
Try / catch
from specify_cli.bundler.core import BundlerError
try:
build_bundle(bundle_dir)
except BundlerError as exc:
if "README.md" in str(exc):
(bundle_dir / "README.md").write_text("# Bundle\nTODO: describe.")
raise Prevention
- Treat README.md as part of the bundle manifest contract — create it the moment you create bundle.yml.
- Use the exact name README.md at the bundle root; case and extension matter.
- Add a repo lint/check that every bundle directory ships both files.
When it happens
Trigger: Calling build_bundle() on a directory that has bundle.yml but no README.md — typically an author who wrote the manifest and components but never documented the bundle.
Common situations: New bundle authors; README saved as readme.md or README.rst (case/extension mismatch); README placed in a subdirectory instead of the bundle root.
Related errors
- No bundle.yml found in '{bundle_dir}'.
- Refusing to build an invalid manifest. Run 'specify bundle v
- Malformed catalog config at {path}: expected a mapping at th
- Unsupported catalog config schema version '{str(schema_versi
- Malformed catalog config at {path}: 'catalogs' must be a lis
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/53c5f03920472a1a.
Report an issue: GitHub.