refactor(adapters): let tmux _run carry output encoding and per-call env#41
Conversation
BaseTmuxBackend._run gains a class-level _ENCODING (default None) and an optional keyword-only env kwarg, both threaded into subprocess.run with defaults byte-identical to today's POSIX behavior. A native-Windows leaf can then force UTF-8 decoding and spawn with a scrubbed env without re-implementing the spawn primitive. The POSIX TmuxMultiplexer is unchanged at runtime (no encoding, no env passed); existing tmux tests pass unmodified, plus regression tests for the default path, a subclass setting _ENCODING, and a non-leaking custom env. Closes bmad-code-org#40
|
Warning Review limit reached
Next review available in: 51 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughBaseTmuxBackend._run now accepts per-call env and a configurable encoding class attribute, and the tmux docs and tests were updated to match the new subprocess contract. Changestmux _run seam extension
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
🤖 Augment PR SummarySummary: Refactors the tmux spawn seam to support backend-controlled output decoding and per-call environment injection, primarily to reduce override surface for a future native-Windows backend. Changes:
Technical Notes: Defaults ( 🤖 Was this summary useful? React with 👍 or 👎 |
| argv: list[str], | ||
| *, | ||
| check: bool = True, | ||
| env: dict[str, str] | None = None, |
There was a problem hiding this comment.
BaseTmuxBackend._run now accepts kw-only env, so any subclass override should accept env as well (even if unused) to avoid a future TypeError if callers start passing it; other locations where this applies: tests/test_multiplexer.py:263.
Severity: medium
Other Locations
tests/test_multiplexer.py:263
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Addressed in e5aa06a — the PsmuxStyle test double now accepts env=None. (No production caller passes env yet, so this was latent, but worth closing now.)
…d _run seam Review fixups for bmad-code-org#41: - porting doc: decoding is the _ENCODING class attr and env a _run param; overriding _run itself is now only for binary/timeout - PsmuxStyle test double accepts the new env kwarg so it stays signature-compatible when a contract method starts forwarding env= - _run docstring: scrubbed envs must be built by removing vars from a copy of the parent env (Windows children need SystemRoot etc.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pbean
left a comment
There was a problem hiding this comment.
Validated against main: the defaults are byte-identical on POSIX (encoding=None ≡ bare text=True, env=None ≡ inherit), no in-tree caller or override breaks (the only _run override is a test double), and the seam matches where the adapter work was already headed — a psmux leaf now sets _ENCODING/passes env= instead of re-implementing the spawn primitive. Full CI matrix (linux+windows, py3.11–3.14) green.
I pushed one review-fixup commit (e5aa06a) to the branch rather than blocking on nits:
docs/porting-to-a-new-os.mdstill described decoding as an_run()override — synced to the new seam- widened the
PsmuxStyletest double to acceptenv=(also flagged by Augment) so it stays signature-compatible once a contract method forwards it - one docstring caveat: scrubbed envs should be built by removing vars from a copy of the parent env (Windows children need
SystemRootetc.)
Thanks for the clean, well-tested contribution — the issue #40 write-up made this easy to verify.
|
@CodeRabbit review |
|
✅ Action performedReview finished.
|
| an eventual native-Windows "psmux" — can subclass :class:`BaseTmuxBackend` and | ||
| override only the single spawn primitive :meth:`BaseTmuxBackend._run` (to tweak | ||
| the binary / decoding / timeout) plus the few divergent methods (e.g. the | ||
| the binary or timeout — output decoding and per-call ``env`` are ``_run`` |
There was a problem hiding this comment.
src/automator/adapters/tmux_base.py:8-9: The docstring says output decoding is an _run parameter, but decoding is configured via the _ENCODING class attribute (there is no _run(..., encoding=...) kwarg). Consider rewording so readers don’t assume they can pass encoding directly to _run.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Valid catch — the module docstring did claim decoding was a _run parameter. Fixed in 350589f: it now names _ENCODING as the class attribute and keeps env as the only per-call parameter.
| monkeypatch.setattr(tmux_base.subprocess, "run", rec) | ||
| before = dict(os.environ) | ||
|
|
||
| scrubbed = {"PATH": os.environ.get("PATH", "")} # e.g. nesting-guard vars dropped |
There was a problem hiding this comment.
tests/test_multiplexer.py:322: The test’s scrubbed env example builds an env from scratch with only PATH, which conflicts with the nearby _run docstring guidance to copy the parent env and remove vars (important on Windows for SystemRoot, etc.). It might be worth aligning this example with that guidance so it doesn’t get copied as a safe template.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
There was a problem hiding this comment.
Agreed — the example contradicted the docstring guidance it sits next to. Fixed in 350589f: the test now sets a nesting-guard TMUX var and builds scrubbed by copying the parent env and deleting it, so the template models the safe pattern (and the forwarding assertion is no longer trivially parent-shaped).
…e env scrub Review fixups (round 2) for bmad-code-org#41: - module docstring: decoding is the _ENCODING class attribute, not a _run parameter — only env is; reword so nobody tries _run(..., encoding=...) - env-forwarding test: build the scrubbed env by copying the parent and removing the nesting-guard var, matching the _run docstring guidance, instead of rebuilding from scratch (unsafe template on Windows) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
augment review |
What
Widens
BaseTmuxBackend._run(src/automator/adapters/tmux_base.py) to expose the two knobs its docstring already advertised — output decoding and a per-callenv— so a future native-Windows (psmux) leaf overrides zero lines of spawn plumbing._ENCODING: str | None = Noneclass attribute → threaded assubprocess.run(..., encoding=self._ENCODING)envkwarg → threaded assubprocess.run(..., env=env)Both default to today's behavior byte-for-byte.
Guarantees (POSIX/tmux unchanged)
_ENCODINGdefaults toNone→subprocess.run(..., text=True, encoding=None)is identical to the current baretext=True(locale decoding). No POSIX read path changes.envdefaults toNone→ inherits the parent environment, exactly as today._tmuxand every current caller are untouched.Tests
tests/test_multiplexer.py— existing tmux tests pass unmodified (the file is additive-only), plus three regression tests:encoding=Noneandenv=None(byte-identity)_ENCODING="utf-8"reachessubprocess.runenvis forwarded to the child without leaking into the parent processruffandblackclean; fulltest_multiplexer+test_generic_tmuxsuites green.Notes
Non-behavioral enablement — it shrinks a future native-Windows backend's override surface to near zero and is independently useful to anyone driving
tmuxfrom a non-UTF-8 locale, where the current locale-default decode can corrupt-Foutput.Closes #40
Summary by CodeRabbit
Bug Fixes
checkbehavior while ensuring the parent process environment remains unchanged.Tests
envand encoding propagation behavior.Documentation
_run(..., env=...)contract and encoding handling expectations.