Skip to content

fix(setup): never delete live core BMAD config/manifest (#64)#73

Open
pbean wants to merge 2 commits into
mainfrom
fix/64-setup-preserve-core-config
Open

fix(setup): never delete live core BMAD config/manifest (#64)#73
pbean wants to merge 2 commits into
mainfrom
fix/64-setup-preserve-core-config

Conversation

@pbean

@pbean pbean commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #64. Running /bmad-loop-setup in a multi-module BMAD v6 project deleted live, manifest-tracked BMAD infrastructure — _bmad/core/config.yaml, per-module config, and the entire _bmad/_config/ manifest directory — breaking future npx bmad-method install upgrades and violating the README's "your standard BMAD install is never modified" guarantee.

Four destructive paths were confirmed in source (the reporter named three; validation found the fourth):

Path What it destroyed
cleanup-legacy.pydirs_to_remove = [module_code, "core"] + also_remove shutil.rmtree of _bmad/core/ (and _config/ via --also-remove)
SKILL.md cleanup command passed --also-remove _config → manifest dir
merge-config.pycleanup_legacy_configs() unlinked _bmad/core/config.yaml
merge-help-csv.pycleanup_legacy_csvs() unlinked _bmad/core/module-help.csv

The --skills-dir "safety check" only guarded dirs containing a SKILL.md; config-only dirs bypassed it and were removed while the JSON still reported skills_verified: true.

Root cause

The scripts are a fork of the bmad-code-org/bmad-builder setup-skill-template, which assumes the installer stages redundant skill payloads + config under _bmad/<module>/ and core/. On BMAD v6 that's false: per-module config.yaml is live, skills live at .claude/skills/, and _bmad/_config/ is the live installer manifest. Same root cause as upstream bmad-code-org/bmad-builder#96 (whose maintainer plans to remove the scaffolder — which won't fix bmad-loop's already-shipped fork, so this fixes it here).

Fix

Adopt #96's version-agnostic verified-redundant-payload guard. A directory is removed only when:

  • it contains ≥1 SKILL.md, and
  • it carries no live config/manifest files (config.yaml, module-help.csv, installer manifests, or the _config/ dir), and
  • with --skills-dir, every skill in it is verified installed.

Live config dirs (core/, per-module, _config/) are protected and reported in a new directories_protected field. The merge scripts still read legacy config as fallback defaults but no longer delete it. No version check needed — the decision is driven entirely by directory contents, so it safely no-ops on v6 while still cleaning genuine pre-v6 payload dirs.

SKILL.md drops --also-remove _config and its prose is updated accordingly.

Behavior note

On a bmad-auto→bmad-loop rename, a stale _bmad/bauto/config.yaml (if it holds only config) is now preserved rather than deleted — harmless residue, documented in SKILL.md as a manual-cleanup option. This is the correct trade-off given the "never delete live config" invariant.

Tests

New tests/test_setup_cleanup_scripts.py runs the real scripts end-to-end and asserts:

  • the documented invocation is a no-op on a v6 tree; core//_config//per-module config survive
  • explicit --module-code core --also-remove _config still leaves them intact
  • a genuine redundant skill-payload dir is removed
  • a payload dir whose skill is missing from --skills-dir errors (exit 1) instead of deleting
  • the merge scripts preserve core/config.yaml and core/module-help.csv

Full suite: 1425 passed, 1 skipped. trunk check clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed setup cleanup to preserve live BMAD core configuration and installer metadata during upgrades.
    • Prevented accidental deletion of legacy configuration files and help CSVs during config/help merges.
    • Cleanup now removes only genuinely redundant leftover payload directories (verified via SKILL.md) while skipping protected live/manifest-related directories.
    • Added regression coverage to ensure safe behavior (including when explicitly targeting legacy cleanup options) and correct reporting when expected skills are missing.

bmad-loop-setup's cleanup scripts hardcoded `core` in their delete lists
(and the SKILL passed `--also-remove _config`), so running /bmad-loop-setup
in a multi-module BMAD v6 project deleted _bmad/core/config.yaml, per-module
config, and the entire _bmad/_config/ manifest — breaking future
`npx bmad-method install` upgrades and violating the "standard BMAD install
is never modified" guarantee.

Cleanup now removes a directory only when it is a verified-redundant skill
payload: it contains a SKILL.md, carries no live config/manifest files, and
(with --skills-dir) its skills are verified installed. Live config dirs
(core/, per-module, _config/) are protected and reported under a new
`directories_protected` field. The merge scripts still read legacy config as
fallback defaults but no longer delete it (on v6 those files are live and
manifest-tracked). Version-agnostic — driven by directory contents, no
version check.

Adds tests/test_setup_cleanup_scripts.py exercising the real scripts.
Same root cause as upstream bmad-code-org/bmad-builder#96.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64ba23b7-7241-4c47-93f3-75eefa608d70

📥 Commits

Reviewing files that changed from the base of the PR and between 5bfca83 and bb0ff97.

📒 Files selected for processing (2)
  • src/bmad_loop/data/skills/bmad-loop-setup/scripts/cleanup-legacy.py
  • tests/test_setup_cleanup_scripts.py

Walkthrough

The bmad-loop-setup cleanup and merge scripts now preserve live BMAD v6 config and installer-manifest state. Cleanup only removes verified redundant skill payloads, merge scripts keep legacy config and CSV files, and the setup docs, changelog, and regression tests were updated to match.

Changes

Cleanup and merge preservation fix

Layer / File(s) Summary
Cleanup script classification logic
src/bmad_loop/data/skills/bmad-loop-setup/scripts/cleanup-legacy.py
Replaces verify_skills_installed() with config/manifest-aware classification, removes hardcoded core from candidate selection, and adds directories_protected to the JSON result.
Merge scripts preserve legacy config and CSV
src/bmad_loop/data/skills/bmad-loop-setup/scripts/merge-config.py, src/bmad_loop/data/skills/bmad-loop-setup/scripts/merge-help-csv.py
Both scripts now treat legacy files as preserved inputs, return empty deletion lists, and update their documentation/help text to reflect read-only legacy handling.
SKILL.md and CHANGELOG documentation updates
src/bmad_loop/data/skills/bmad-loop-setup/SKILL.md, CHANGELOG.md
Setup instructions and reporting are revised to describe preservation of live config, removal only of verified-redundant payloads, and the new changelog entry for the fix.
Regression test suite for cleanup and merge scripts
tests/test_setup_cleanup_scripts.py
Adds subprocess-based regression tests covering v6-like cleanup behavior, protected config/manifest preservation, verified payload deletion, missing-skill failures, and merge-script preservation of legacy files.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Poem

A rabbit hopped through _bmad core,
"No more deleting what you shouldn't, no more!"
Configs stay safe, manifests gleam,
Redundant payloads drift like a dream.
Tests gave a hop, and docs gave a nod —
🐰 v6 stays tidy, as snug as a pod.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main fix: preventing deletion of live BMAD core config and manifest files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/64-setup-preserve-core-config

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@augmentcode

augmentcode Bot commented Jul 6, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: Prevents bmad-loop-setup from deleting live, manifest-tracked BMAD v6 infrastructure under _bmad/ (core config, per-module config, and the installer manifest).

Changes:

  • Reworks cleanup-legacy.py to remove only verified redundant skill-payload directories (requires SKILL.md, no config/manifest markers, and optional installed-skill verification).
  • Adds explicit reporting for protected directories via directories_protected, and improves directories_not_found reporting for TOCTOU/nested removals.
  • Disables legacy file deletion in merge-config.py and merge-help-csv.py while retaining legacy reads as fallback defaults.
  • Updates SKILL.md guidance to reflect the new safety model and removes the documented --also-remove _config invocation.
  • Adds end-to-end regression tests covering v6 no-op behavior, protected core/_config, payload removal, and missing-skill error handling.

Technical Notes: The cleanup decision is content-based (no version checks) and aims to preserve shared BMAD state while still cleaning genuine pre-v6 staged payloads.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/bmad_loop/data/skills/bmad-loop-setup/scripts/cleanup-legacy.py Outdated
cleanup-legacy.py discarded cleanup_directories()'s not_found return, so a
removable dir that vanished between classify_dirs() and removal (TOCTOU, or a
nested --also-remove target removed with its parent earlier in the loop) fell
out of every JSON list — directories_removed, directories_protected, and
directories_not_found — while safety_checks.skills_verified still printed true,
misreporting what happened.

Merge cleanup_directories()'s not_found into the classify-time not_found before
building the result. The two are disjoint (cleanup only processes `removable`,
which excludes classify's not_found), so plain concatenation is a strict
superset that cannot change existing behavior.

Adds a deterministic regression test that removes a nested --also-remove target
whose parent is deleted first, asserting the child surfaces in
directories_not_found. Addresses augmentcode[bot] review on PR #73.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pbean

pbean commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

augment review

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Everything else is left untouched. On a modern BMAD v6 install the per-module and
core directories hold only live config (no staged SKILL.md), and _bmad/_config/ is
the live installer manifest — so this script is a safe no-op there and never deletes
shared BMAD state. 'core' and '_config' are never removed. The removal decision is

@augmentcode augmentcode Bot Jul 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module docstring states that 'core' is never removed, but the implementation only hard-codes protection for _config by name (and otherwise relies on marker files). If core/ ever lacks those markers but contains SKILL.md payload, it looks eligible for removal, so the wording may be stronger than the actual guarantee.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

missing = []
if path.name == "_config":
return True
for marker in _CONFIG_MARKERS:

@augmentcode augmentcode Bot Jul 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_config_bearing() only checks for marker files directly under the candidate directory, while find_skill_dirs() scans recursively; if config/manifest markers can exist deeper in the tree, a directory could be misclassified as removable. Consider whether this guard should also be recursive (or otherwise more conservative) to avoid any chance of deleting live state.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bmad-loop-setup deletes core BMAD config/manifest (_bmad/core/config.yaml, _bmad/_config/) in multi-module projects

1 participant