Skip to content

fix(installer): stop copying __pycache__ into IDE skill trees - #2695

Open
tjoignant wants to merge 1 commit into
bmad-code-org:mainfrom
tjoignant:fix/manifest-excludes-pycache
Open

fix(installer): stop copying __pycache__ into IDE skill trees#2695
tjoignant wants to merge 1 commit into
bmad-code-org:mainfrom
tjoignant:fix/manifest-excludes-pycache

Conversation

@tjoignant

Copy link
Copy Markdown

What

The IDE skill copy now filters __pycache__ directories and .pyc/.pyo files, so Python bytecode shipped in the npm tarball no longer lands in users' skill trees.

Why

Fixes #2694.

Installing today writes the maintainer's build artifacts into every project:

$ find .claude/skills -name "*.pyc" -path "*bmad*" | wc -l
5

They are genuinely shipped rather than locally generated — the sha256 is identical from the published package through files-manifest.csv to the installed file, and the bytecode is cpython-311 even when the local interpreter is 3.14.

The installer already declares this must not happen. Installer._installSharedScripts filters the same artifacts for _bmad/scripts under the comment "Ship only the runtime scripts — dev-only tests and Python caches must not land in user projects" — which is why _bmad/scripts/ is clean while .claude/skills/**/scripts/ is not. This applies one rule in both places.

How

  • Hoisted the skill-copy filter out of installSkillsFromManifest into a module-level shouldSkipSkillArtifact(name) in tools/installer/ide/_config-driven.js, exported so it is unit-testable.
  • Added __pycache__ to the skipped names and .pyc / .pyo to the skipped suffixes. Existing behaviour is unchanged: OS artifacts, dotfiles (with the .gitkeep exemption), and editor backups filter exactly as before.
  • Left tests/ directories alone. _installSharedScripts drops them for _bmad/scripts, but they are tracked in the skill manifest today, so removing them is a separate call for maintainers rather than something to slip into this fix.

Testing

node test/test-installation-components.js — 465 passed, 0 failed (was 455).

New Test Suite 53 covers the predicate directly and adds an end-to-end case: it plants scripts/__pycache__/helper.cpython-311.pyc alongside scripts/helper.py in the source fixture, runs a real claude-code install, and asserts the .py arrives while __pycache__ does not.

I verified the test is not vacuous by reverting only the two filter entries on the fixed branch — the end-to-end assertion fails, and passes again once restored.

npx prettier --check and npx eslint --max-warnings=0 are clean on both changed files.

The skill copy filtered OS and editor artifacts but not Python bytecode
caches, so the five __pycache__/*.pyc files carried in the published
tarball landed in every user's skill tree. Their sha256 is identical from
package to disk, and they are cpython-311 regardless of the local
interpreter, so they are the maintainer's build output rather than
anything generated locally.

_installSharedScripts already states the intended rule for _bmad/scripts
("dev-only tests and Python caches must not land in user projects") and
filters on it. This applies the same rule to the skill copy.

Hoists the predicate to a testable shouldSkipSkillArtifact() and adds
Test Suite 53, which asserts end to end that a cache planted in the
source tree does not reach the installed skill while helper.py does.

Refs bmad-code-org#2694
@greptile-apps

greptile-apps Bot commented Aug 7, 2026

Copy link
Copy Markdown

Greptile Summary

The PR prevents Python bytecode caches from being copied into IDE skill trees while preserving the existing OS, editor-artifact, and dotfile filtering behavior.

  • Extracts and exports a testable skill-artifact predicate.
  • Excludes pycache, .pyc, and .pyo entries during recursive skill copying.
  • Adds predicate-level and end-to-end installer coverage.

Confidence Score: 4/5

The installer change appears safe to merge; the only identified issue is non-blocking test-fixture cleanup on exceptional paths.

The artifact predicate preserves the previous filtering behavior and correctly blocks Python cache entries, while the new test can leave temporary directories behind if setup or filesystem operations throw.

Files Needing Attention: test/test-installation-components.js

Important Files Changed

Filename Overview
tools/installer/ide/_config-driven.js Correctly centralizes the existing artifact filter and extends it to exclude Python bytecode caches without changing root-copy semantics.
test/test-installation-components.js Adds meaningful direct and end-to-end coverage, but exceptional paths can leak both newly allocated temporary directory trees.
Prompt To Fix All With AI
### Issue 1
test/test-installation-components.js:4078-4079
**Cleanup skips exceptional paths**

The new test removes its two temporary directory trees only at the end of the `try` block. When an awaited filesystem or installer operation throws, control jumps directly to `catch`, leaving the temporary fixtures on disk to accumulate across repeated local or CI runs.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(installer): stop copying __pycache__..." | Re-trigger Greptile

Comment on lines +4078 to +4079
await fs.remove(tempProjectDir53);
await fs.remove(path.dirname(installedBmadDir53));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Cleanup skips exceptional paths

The new test removes its two temporary directory trees only at the end of the try block. When an awaited filesystem or installer operation throws, control jumps directly to catch, leaving the temporary fixtures on disk to accumulate across repeated local or CI runs.

Prompt To Fix With AI
This is a comment left during a code review.
Path: test/test-installation-components.js
Line: 4078-4079

Comment:
**Cleanup skips exceptional paths**

The new test removes its two temporary directory trees only at the end of the `try` block. When an awaited filesystem or installer operation throws, control jumps directly to `catch`, leaving the temporary fixtures on disk to accumulate across repeated local or CI runs.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Skill artifact filtering

Layer / File(s) Summary
Shared artifact filter
tools/installer/ide/_config-driven.js
Adds and exports shouldSkipSkillArtifact for OS, editor, hidden, temporary, backup, and Python cache artifacts.
Skill copy integration and validation
tools/installer/ide/_config-driven.js, test/test-installation-components.js
Uses the shared predicate during skill copying. Tests confirm that Python sources and SKILL.md remain while __pycache__ and .DS_Store files are excluded.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: alexeyv, bmadcode, bdsoha

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary fix: preventing the installer from copying pycache into IDE skill trees.
Description check ✅ Passed The description explains the filtering change, its cause, implementation, testing, and connection to issue #2694.
Linked Issues check ✅ Passed The PR satisfies issue #2694 by excluding pycache directories and Python bytecode files from IDE skill installations.
Out of Scope Changes check ✅ Passed The changes remain within scope by updating the skill filter, adding focused tests, and exporting the predicate for unit testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
test/test-installation-components.js (1)

4048-4053: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover .pyo and suffix-filter integration cases.

The predicate includes .pyo, but the unit assertions cover only .pyc. The end-to-end fixture places the .pyc only inside __pycache__, so it does not verify suffix filtering during fs.copy. Add root-level .pyc and .pyo fixtures, then assert both are excluded while helper.py remains installed.

Proposed test additions
     assert(shouldSkipSkillArtifact('sprint_plan.cpython-311.pyc') === true, '.pyc files are treated as artifacts');
+    assert(shouldSkipSkillArtifact('sprint_plan.pyo') === true, '.pyo files are treated as artifacts');
...
     await fs.writeFile(path.join(sourceScripts53, 'helper.py'), 'print("hello")\n');
+    await fs.writeFile(path.join(sourceScripts53, 'helper.pyc'), 'bytecode');
+    await fs.writeFile(path.join(sourceScripts53, 'helper.pyo'), 'bytecode');
...
     assert(await fs.pathExists(path.join(installedSkill53, 'scripts', 'helper.py')), 'Python sources are installed');
+    assert(!(await fs.pathExists(path.join(installedSkill53, 'scripts', 'helper.pyc'))), '.pyc files are excluded');
+    assert(!(await fs.pathExists(path.join(installedSkill53, 'scripts', 'helper.pyo'))), '.pyo files are excluded');

Also applies to: 4055-4076

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/test-installation-components.js` around lines 4048 - 4053, Extend the
installation fixture and assertions around shouldSkipSkillArtifact to cover
root-level .pyc and .pyo files, verifying both are excluded during fs.copy. Keep
the existing __pycache__ coverage and assert helper.py remains installed to
confirm ordinary Python sources are preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/test-installation-components.js`:
- Around line 4048-4053: Extend the installation fixture and assertions around
shouldSkipSkillArtifact to cover root-level .pyc and .pyo files, verifying both
are excluded during fs.copy. Keep the existing __pycache__ coverage and assert
helper.py remains installed to confirm ordinary Python sources are preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fd2687b7-77a6-4262-acdc-4baedcf86d07

📥 Commits

Reviewing files that changed from the base of the PR and between cbb69e6 and 101ed50.

📒 Files selected for processing (2)
  • test/test-installation-components.js
  • tools/installer/ide/_config-driven.js

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.

Installer ships upstream __pycache__/*.pyc into the IDE skill tree, contradicting its own "no Python caches in user projects" policy

1 participant