Skip to content

fix: pin UTF-8 stdout in resolvers so Windows cp1252 doesn't crash - #2578

Open
aranellaeth wants to merge 1 commit into
bmad-code-org:mainfrom
aranellaeth:fix/windows-cp1252-utf8-resolvers
Open

fix: pin UTF-8 stdout in resolvers so Windows cp1252 doesn't crash#2578
aranellaeth wants to merge 1 commit into
bmad-code-org:mainfrom
aranellaeth:fix/windows-cp1252-utf8-resolvers

Conversation

@aranellaeth

Copy link
Copy Markdown

What

Pin UTF-8 on stdout / subprocess output in resolve_config, resolve_party, resolve_personas, and brain so emoji agent icons and em-dashes stop crashing on Windows cp1252.

Why

On Windows, Python's default stdout encoding is cp1252. These scripts emit ensure_ascii=False JSON with emoji agent icons (or read a child's UTF-8 stdout as cp1252), so party-mode, forge-idea, and brainstorming crash with UnicodeEncodeError. resolve_customization.py already guards this with write_json_stdout; these siblings were missed.

Repro (Windows, Python 3.11+): PYTHONIOENCODING=cp1252 python _bmad/scripts/resolve_config.py --project-root . --key agentsUnicodeEncodeError on \U0001f4ca (📊).

How

  • resolve_config.py: add write_json_stdout() that reconfigures stdout to UTF-8 (the same helper resolve_customization.py already uses)
  • resolve_party.py / resolve_personas.py: decode subprocess output as UTF-8 (errors="replace") in _run_json
  • brain.py: reconfigure stdout/stderr to UTF-8 at main() entry

Testing

Existing pytest suites pass (59). Reproduced the crash with PYTHONIOENCODING=cp1252 and confirmed exit 0 with emoji preserved after the fix.

Windows defaults stdout to cp1252, so resolve_config, resolve_party,
resolve_personas, and brain crash (UnicodeEncodeError) or corrupt output
on emoji agent icons and em-dashes. resolve_customization.py already
guards this; apply the same UTF-8 pinning to its siblings.

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

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changes make CLI and resolver output handling explicitly UTF-8-aware. Console streams are reconfigured when supported, JSON output preserves non-ASCII characters, and subprocess stdout decoding uses UTF-8 with replacement errors.

Changes

UTF-8 Output Handling

Layer / File(s) Summary
Console output encoding
src/core-skills/bmad-brainstorming/scripts/brain.py, src/scripts/resolve_config.py
CLI streams are configured for UTF-8 when supported, and merged JSON is emitted with non-ASCII characters preserved.
Resolver subprocess decoding
src/core-skills/bmad-forge-idea/scripts/resolve_personas.py, src/core-skills/bmad-party-mode/scripts/resolve_party.py
Captured subprocess output is decoded as UTF-8 with replacement handling before existing validation and JSON parsing.og

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the UTF-8 stdout/subprocess encoding fix for the resolver scripts, especially on Windows cp1252.
Description check ✅ Passed The description matches the change set and explains the Windows cp1252 UTF-8 handling fix across the affected scripts.
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 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)
src/core-skills/bmad-forge-idea/scripts/resolve_personas.py (1)

49-65: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the duplicated _run_json helper.

_run_json is byte-for-byte identical in resolve_personas.py (lines 48-67) and resolve_party.py (lines 46-65). If these scripts share a common package or utility module, extracting this function would prevent the implementations from diverging over time. If they're intentionally standalone per-skill scripts, the duplication is acceptable.

The UTF-8 encoding change itself is correct — encoding="utf-8", errors="replace" with text=True properly decodes child process output, and the 60s timeout and failure checks are preserved.

🤖 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 `@src/core-skills/bmad-forge-idea/scripts/resolve_personas.py` around lines 49
- 65, Extract the identical _run_json helper shared by resolve_personas.py and
resolve_party.py into their common utility or package module, then update both
scripts to import and reuse it. Preserve the existing UTF-8 decoding, timeout,
failure handling, and JSON parsing behavior; if no shared module is appropriate,
leave the standalone implementations unchanged.
🤖 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 `@src/core-skills/bmad-forge-idea/scripts/resolve_personas.py`:
- Around line 49-65: Extract the identical _run_json helper shared by
resolve_personas.py and resolve_party.py into their common utility or package
module, then update both scripts to import and reuse it. Preserve the existing
UTF-8 decoding, timeout, failure handling, and JSON parsing behavior; if no
shared module is appropriate, leave the standalone implementations unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a7664864-bac5-4a60-949b-9915a6acacfa

📥 Commits

Reviewing files that changed from the base of the PR and between 49069b8 and 5f9ef65.

📒 Files selected for processing (4)
  • src/core-skills/bmad-brainstorming/scripts/brain.py
  • src/core-skills/bmad-forge-idea/scripts/resolve_personas.py
  • src/core-skills/bmad-party-mode/scripts/resolve_party.py
  • src/scripts/resolve_config.py

@aranellaeth

Copy link
Copy Markdown
Author

Thanks!

_run_json is intentionally duplicated—these are standalone, stdlib-only per-skill scripts with no shared package to import from, and the duplication predates this PR (I only applied the encoding fix to the existing copies). Extracting a shared module would be a larger packaging change, out of scope for this targeted fix.

Happy to follow up separately if a shared script utility is ever introduced.

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

Checked the UTF-8 stream changes against the existing resolver pattern. The focused suite passes with 59 tests, and a cp1252 reproduction now exits cleanly with the emoji preserved. The base branch fails with UnicodeEncodeError. The diff is focused and looks correct.

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.

2 participants