Skip to content

cmux TUI distribution: npx cmux / uvx cmux via prebuilt binaries - #7651

Merged
lawrencecchen merged 6 commits into
mainfrom
feat-cmux-tui-dist
Jul 8, 2026
Merged

lawrencecchen merged 6 commits into
mainfrom
feat-cmux-tui-dist

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

Makes the cmux-mux TUI installable as npx cmux and uvx cmux.

  • Cross-platform release binaries (darwin arm64/x64, linux x64/arm64 green; windows experimental) via cargo-zigbuild + a zig cross-target map in ghostty-vt-sys build.rs, plus a fix for the windows bindgen failure that has been red on main since 2026-07-06 (canonicalize returns \?\ verbatim paths clang can't resolve nested includes from).
  • npm: cmux launcher (esbuild-style) + 4 platform packages via optionalDependencies; publishing at 0.9.0 with no --tag deliberately takes over latest from the 0.8.3 cloud-VM CLI (confirm_tui_cmux dispatch gate).
  • PyPI: per-platform wheels with a cmux console entry point exec'ing the bundled binary; 0.9.0 outranks the 0.1.x SDK so uvx resolves the TUI.
  • Nightly channel: tui-nightly.yml publishes prerelease versions to npm nightly dist-tag and PEP 440 .dev wheels; default resolution never sees them.
  • Release cuts: tui-release-cut.yml computes the next version from cmux-tui-v* tags, tags, and explicitly dispatches build + PyPI publish (GITHUB_TOKEN tag pushes don't trigger workflows). npm publish stays a manual confirm-gated dispatch.
  • All publish workflows are inert until dispatched/tagged; OIDC trusted publishing + provenance; SHA-pinned actions; fable-judged over two rounds (real npm pack/install and pip install/run verified).

Verified in CI: full build+package pipeline green on tag cmux-tui-v0.0.2 (real binaries, linux binary executed, wheel pip-installed and cmux --help run). SDK relocation to cmux-sdk is a separate follow-up.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Note

Medium Risk
Publishing workflows can change npm latest and PyPI cmux resolution for all users once dispatched; gates and dist-tags mitigate mistakes but registry impact is real.

Overview
Adds end-to-end distribution for the cmux-mux TUI as npx cmux and uvx cmux, with GitHub Actions to build per-platform binaries, wrap them for npm/PyPI, and publish stable, nightly, and tag-driven releases.

A reusable tui-build-package.yml matrix-builds cmux-mux for macOS (arm64/x64) and Linux (x64/arm64) via native/cross cargo-zigbuild, optionally an experimental Windows GNU binary, then runs package_npm.py / package_pypi.py to produce a launcher plus four platform npm packages and per-platform wheels, with CI smoke checks. mux-tui-release.yml, tui-nightly.yml, tui-publish-npm.yml, tui-publish-pypi.yml, and tui-release-cut.yml wire version derivation, OIDC publishing (npm nightly vs un-tagged stable latest with confirm_tui_cmux), PyPI attestations, and explicit workflow dispatches after token-pushed tags.

Packaging adds an npm cmux.js shim that execs optional cmux-tui-* binaries, plus mux/dist/RELEASING-TUI.md. ghostty-vt-sys/build.rs strips Windows \\?\ paths for bindgen and extends zig cross-target mappings for release builds.

Reviewed by Cursor Bugbot for commit 8aa8c8f. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Ship the cmux TUI as prebuilt binaries so it runs with npx cmux and uvx cmux. Adds cross‑platform builds, packaging, nightly channel, and release workflows.

  • New Features

    • Cross‑platform binaries (macOS arm64/x64, Linux x64/arm64; Windows experimental) via cargo-zigbuild + zig target map in ghostty-vt-sys.
    • npm: cmux launcher that execs a per‑platform optional dependency (cmux-tui-darwin-*, cmux-tui-linux-*). Use npx cmux.
    • PyPI: per‑platform cmux wheels with a cmux console entry point. Use uvx cmux.
    • Workflows: reusable tui-build-package.yml; release builder mux-tui-release.yml; nightly tui-nightly.yml (npm nightly tag and PEP 440 .dev wheels); tui-publish-npm.yml (manual, confirm‑gated); tui-publish-pypi.yml; tui-release-cut.yml to tag cmux-tui-vX.Y.Z and dispatch builds. Docs in mux/dist/RELEASING-TUI.md.
  • Bug Fixes

    • Windows bindgen: strip \\?\ verbatim prefixes so clang can resolve nested includes (fixes build failure); adds zig cross‑target mappings for release builds.

Written for commit 8aa8c8f. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added release and publishing workflows for TUI binaries and packages, including manual, tagged, nightly, npm, and PyPI release paths.
    • Added support for packaging multiple platforms, with Windows builds included where needed.
    • Added a release-cut flow that creates version tags and triggers downstream publishing automatically.
  • Bug Fixes

    • Improved Windows path handling during builds.
    • Expanded cross-compilation target support for release artifacts.

Adds mux-tui-release.yml building the cmux-mux TUI for the five distribution
targets (darwin arm64/x64, linux x64/arm64, windows x64-gnu) via cargo-zigbuild,
and extends ghostty-vt-sys build.rs to map those targets to zig cross-targets.
Foundation for npx cmux / uvx cmux (wrapper packaging follows once binaries build).
Main `cmux` package: bin shim resolves cmux-tui-<platform> optional dep and
execs the prebuilt cmux-mux binary. Platform packages are generated in CI from
the release binaries. Versions are placeholder (0.0.0-managed), synced at publish.
…platforms

Windows bindgen fails on the nested ghostty vt headers under mingw clang;
mark the matrix leg continue-on-error and drop win32-x64 from the launcher's
platform map until fixed. darwin arm64/x64 + linux x64/arm64 all build.
package_npm.py generates the 4 platform packages + versioned launcher;
package_pypi.py builds per-platform wheels (cmux console entry point exec'ing
the bundled cmux-mux, RECORD/external_attr correct — judge-verified via real
npm pack->install and pip install->run). mux-tui-release.yml gains a package
job with binary + wheel smoke tests. tui-publish-npm.yml (dispatch-only,
confirm_tui_cmux gate, latest takeover, github-hosted provenance, npm>=11.5.1)
and tui-publish-pypi.yml (tag+dispatch, env pypi-tui). Dispatch inputs routed
through env per judge review (injection surface). RELEASING-TUI.md documents
registry setup.
tui-build-package.yml (reusable workflow_call) shared by release/publish/
nightly callers. tui-nightly.yml publishes 0.X.Y-nightly.YYYYMMDD.N to npm
--tag nightly and PEP 440 .dev wheels to PyPI (default resolution ignores
both; npx cmux@nightly opts in), pinned to one resolved sha across the
matrix. tui-release-cut.yml computes the next version from cmux-tui-v* tags,
creates the tag, and explicitly dispatches build + PyPI publish (GITHUB_TOKEN
tag pushes never fire other workflows). tui-publish-npm.yml gains a strict
stable-version gate so a nightly can never land on npm latest. Judge-approved
(fable round 2 + re-verify).
std::fs::canonicalize returns extended-length paths on Windows; clang accepts
the root header via \\?\ but cannot resolve its nested relative includes
(ghostty/vt.h -> ghostty/vt/types.h file-not-found), which has failed the
windows-experimental leg on main since at least 2026-07-06. Strip the
verbatim prefix before handing paths to bindgen.
@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Building Building Preview, Comment Jul 8, 2026 9:01pm
cmux-staging Building Building Preview, Comment Jul 8, 2026 9:01pm

@coderabbitai

coderabbitai Bot commented Jul 8, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

An error occurred during the review process. Please try again later.

📝 Walkthrough

Walkthrough

Adds seven new GitHub Actions workflows implementing a full cmux-tui release pipeline: version derivation, a reusable build/package workflow (npm, PyPI, optional Windows), and publish flows for releases, nightly builds, manual npm/PyPI publishing, and release cutting. Also updates ghostty-vt-sys build.rs for Windows path normalization and expanded Zig target mappings.

Changes

TUI release build and publish workflows

Layer / File(s) Summary
Reusable build-and-package workflow
.github/workflows/tui-build-package.yml
Defines workflow_call inputs, builds cmux-mux across a Linux/macOS target matrix, optionally builds an experimental Windows binary, then packages/verifies npm and PyPI artifacts.
Tag/dispatch release workflow
.github/workflows/mux-tui-release.yml
Derives version from tag push or manual dispatch input and calls the reusable build-package workflow with npm, PyPI, and Windows builds enabled.
Nightly build and publish
.github/workflows/tui-nightly.yml
Computes timestamped nightly versions from the latest release tag, builds via the reusable workflow pinned to head_sha, and publishes npm (nightly dist-tag) and PyPI packages with OIDC provenance/attestations.
Manual npm and PyPI publish
.github/workflows/tui-publish-npm.yml, .github/workflows/tui-publish-pypi.yml
Validates a strict X.Y.Z version, builds via the reusable workflow, then publishes platform packages and launcher package to npm (confirmation-gated, with Trusted Publisher fallback instructions) or wheels to PyPI via Trusted Publisher OIDC.
Release-cut tagging and dispatch
.github/workflows/tui-release-cut.yml
Computes the next semver version from existing cmux-tui-v* tags, creates and pushes a new tag, and dispatches the release and PyPI-publish workflows against it.

Estimated code review effort: 4 (Complex) | ~60 minutes

Windows build path and target mapping fix

Layer / File(s) Summary
Path normalization and target mapping
mux/crates/ghostty-vt-sys/build.rs
Adds strip_windows_verbatim to normalize \\?\-prefixed canonicalized paths on Windows, and extends zig_target_for_rust_target with additional Darwin/Linux GNU cross-compilation mappings.

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

Sequence Diagram(s)

sequenceDiagram
  participant Trigger as Tag Push / Dispatch
  participant VersionJob as version job
  participant BuildPackage as tui-build-package.yml
  participant PublishNpm as npm registry
  participant PublishPyPI as PyPI

  Trigger->>VersionJob: derive and validate version
  VersionJob->>BuildPackage: call workflow_call(version, flags)
  BuildPackage->>BuildPackage: build binaries per target matrix
  BuildPackage->>BuildPackage: package npm / pypi artifacts
  BuildPackage-->>VersionJob: upload artifacts
  VersionJob->>PublishNpm: publish platform + launcher packages
  VersionJob->>PublishPyPI: publish wheels with attestations
Loading

Possibly related PRs

  • manaflow-ai/cmux#7180: Both PRs modify the same mux/crates/ghostty-vt-sys/build.rs—this PR adds Windows path normalization and target mapping extensions, the other introduced the original build script.
  • manaflow-ai/cmux#7346: Both PRs extend zig_target_for_rust_target in the same build script.
  • manaflow-ai/cmux#7378: Both PRs touch the same build.rs used for compiling Ghostty VT for cross-target builds.

Suggested reviewers: austinywang

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-cmux-tui-dist

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.

@greptile-apps

greptile-apps Bot commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds end-to-end distribution for the cmux-mux TUI binary as npx cmux and uvx cmux, wiring cross-platform Rust builds, npm/PyPI packaging, nightly publishing, and a release-cut workflow. A ghostty-vt-sys/build.rs fix strips Windows \\?\ verbatim path prefixes so bindgen/clang can resolve nested includes, and new zig cross-target mappings are added (guarded by target != host so they only fire for cross-compilation).

  • tui-build-package.yml matrix-builds cmux-mux for macOS arm64/x64 and Linux x64/arm64 via native/zigbuild cross, then runs package_npm.py / package_pypi.py to produce an esbuild-style npm launcher + 4 platform packages and per-platform wheels with smoke tests.
  • tui-nightly.yml builds once and publishes to npm nightly dist-tag + PyPI .dev versions daily; tui-release-cut.yml creates an annotated cmux-tui-vX.Y.Z tag and explicitly dispatches build + PyPI workflows; npm publish is a separate manual confirm-gated dispatch.
  • The confirm_tui_cmux gate in tui-publish-npm.yml runs after the ~60-minute build (its default is false), wasting compute when the flag is omitted; tui-publish-pypi.yml has both a push.tags trigger and is explicitly dispatched by tui-release-cut.yml, creating a sequential double-publish path if the same tag is pushed again after a release cut.

Confidence Score: 4/5

Safe to merge; the two workflow design issues are operational annoyances rather than correctness failures, and the packaging and build.rs changes are well-structured.

The confirm_tui_cmux gate defaulting to false while sitting after a 60-minute build will surprise the first operator who forgets the flag. The tui-publish-pypi.yml dual-trigger means a direct tag re-push after a tui-release-cut.yml run causes a noisy but harmless PyPI rejection. Neither causes silent data corruption or broken end-user installs.

.github/workflows/tui-publish-npm.yml (confirmation gate placement) and .github/workflows/tui-publish-pypi.yml (dual-trigger path).

Important Files Changed

Filename Overview
.github/workflows/tui-build-package.yml Reusable workflow for matrix-building cmux-mux across 4 platforms (+ optional Windows) and packaging npm/PyPI artifacts; smoke-tests run the Linux x64 binary before upload.
.github/workflows/mux-tui-release.yml Thin wrapper over tui-build-package.yml triggered by tag push or workflow_dispatch; produces build+package artifacts for inspection but no publish step. Artifacts are not reused by publish workflows.
.github/workflows/tui-publish-npm.yml Manual-dispatch npm publish with confirm_tui_cmux gate; gate runs in the publish job (after the ~60-minute build) rather than in validate-version, wasting a full build when the flag is missing (its default is false).
.github/workflows/tui-publish-pypi.yml OIDC-attested PyPI publish triggered by both push.tags and workflow_dispatch (from tui-release-cut.yml); dual-trigger path means a direct tag push after a release-cut dispatch causes a second publish attempt that PyPI will reject.
.github/workflows/tui-nightly.yml Daily scheduled nightly: derives next-stable + date + run-number versions, builds once, publishes to npm nightly dist-tag and PyPI .dev; single build shared by both publish jobs.
.github/workflows/tui-release-cut.yml Creates annotated cmux-tui-vX.Y.Z tag on main and explicitly dispatches mux-tui-release.yml + tui-publish-pypi.yml (required since GITHUB_TOKEN pushes suppress tag triggers); the dispatched mux-tui-release.yml artifacts are never consumed by publish workflows.
mux/crates/ghostty-vt-sys/build.rs Adds strip_windows_verbatim to fix bindgen's \?\ path failure on Windows hosts; adds macOS/Linux zig target mappings guarded by target != host so they only activate for cross-compilation, not native builds.
mux/dist/npm/cmux/bin/cmux.js Standard esbuild-style launcher: resolves per-platform optional dependency, execs the binary with spawnSync + stdio:inherit, re-signals on signal, exits with status code.
mux/dist/scripts/package_npm.py Generates per-platform npm packages and the cmux launcher package from prebuilt binaries; validates version format, sets executable bits, stamps optionalDependencies.
mux/dist/scripts/package_pypi.py Hand-builds platform-specific wheels with embedded binary, correct RECORD hashes, entry_points.txt, and deterministic ZIP timestamps; uses os.execv for process replacement in the console entry point.
mux/dist/npm/cmux/package.json Template package.json with placeholder 0.0.0-managed version and optionalDependencies; version and deps are overwritten by package_npm.py at build time.
mux/dist/RELEASING-TUI.md Runbook for one-time registry setup, nightly channel, and stable release cut; accurately describes the GITHUB_TOKEN suppression workaround and the manual npm confirm gate.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Dev as Developer
    participant RC as tui-release-cut.yml
    participant MR as mux-tui-release.yml
    participant PP as tui-publish-pypi.yml
    participant PN as tui-publish-npm.yml
    participant BPkg as tui-build-package.yml
    participant PyPI
    participant npm

    Dev->>RC: dispatch (bump/version)
    RC->>RC: compute next version, create annotated tag
    RC->>RC: git push tag (GITHUB_TOKEN suppressed)
    RC->>MR: gh workflow run (inspection build)
    RC->>PP: gh workflow run
    MR->>BPkg: build+package (npm+pypi artifacts)
    Note over MR,BPkg: Artifacts uploaded but not consumed by publish
    PP->>BPkg: build+package (pypi only)
    BPkg-->>PP: pypi-wheels artifact
    PP->>PyPI: pypa/gh-action-pypi-publish (OIDC)

    Dev->>PN: "dispatch (version + confirm_tui_cmux=true)"
    PN->>PN: validate-version
    PN->>BPkg: build+package (npm only)
    BPkg-->>PN: npm-packages artifact
    PN->>npm: npm publish --provenance (no --tag, becomes latest)

    Note over Dev,npm: Nightly path (daily schedule)
    BPkg-->>BPkg: single build
    BPkg-->>npm: publish --tag nightly
    BPkg-->>PyPI: publish .dev version
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Dev as Developer
    participant RC as tui-release-cut.yml
    participant MR as mux-tui-release.yml
    participant PP as tui-publish-pypi.yml
    participant PN as tui-publish-npm.yml
    participant BPkg as tui-build-package.yml
    participant PyPI
    participant npm

    Dev->>RC: dispatch (bump/version)
    RC->>RC: compute next version, create annotated tag
    RC->>RC: git push tag (GITHUB_TOKEN suppressed)
    RC->>MR: gh workflow run (inspection build)
    RC->>PP: gh workflow run
    MR->>BPkg: build+package (npm+pypi artifacts)
    Note over MR,BPkg: Artifacts uploaded but not consumed by publish
    PP->>BPkg: build+package (pypi only)
    BPkg-->>PP: pypi-wheels artifact
    PP->>PyPI: pypa/gh-action-pypi-publish (OIDC)

    Dev->>PN: "dispatch (version + confirm_tui_cmux=true)"
    PN->>PN: validate-version
    PN->>BPkg: build+package (npm only)
    BPkg-->>PN: npm-packages artifact
    PN->>npm: npm publish --provenance (no --tag, becomes latest)

    Note over Dev,npm: Nightly path (daily schedule)
    BPkg-->>BPkg: single build
    BPkg-->>npm: publish --tag nightly
    BPkg-->>PyPI: publish .dev version
Loading

Comments Outside Diff (3)

  1. .github/workflows/tui-publish-npm.yml, line 613-617 (link)

    P2 confirm_tui_cmux gate runs after 60-minute build

    The confirm_tui_cmux confirmation check sits in the publish job, which only starts after the entire build-package matrix (~60 minutes) completes. The input defaults to false, so a dispatcher who forgets to set it will burn a full build run before hitting the refusal. Moving the confirmation check into validate-version (which runs first) would fail fast before any compute is spent.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  2. .github/workflows/tui-publish-pypi.yml, line 683-686 (link)

    P2 Dual-trigger path creates double-publish risk

    tui-publish-pypi.yml fires on push: tags: cmux-tui-v*. tui-release-cut.yml pushes the tag via GITHUB_TOKEN (which GitHub suppresses), so the tag trigger is silent for that path — only the explicit gh workflow run dispatch fires. However, if a developer later runs git push origin refs/tags/cmux-tui-vX.Y.Z to verify or recreate the tag, the tag push trigger fires again and tui-publish-pypi.yml attempts to re-publish an already-published version. PyPI rejects this loudly (File already exists), but the failure can appear confusing in an incident. The concurrency group with cancel-in-progress: false does not block sequential runs from the same tag. Consider removing the push.tags trigger and relying solely on explicit dispatch from tui-release-cut.yml, or adding a PyPI check-before-publish guard.

  3. .github/workflows/tui-release-cut.yml, line 927-943 (link)

    P2 mux-tui-release.yml artifacts are never consumed by publish workflows

    tui-release-cut.yml dispatches both mux-tui-release.yml (build + package, npm + PyPI artifacts) and tui-publish-pypi.yml. But tui-publish-pypi.yml calls tui-build-package.yml independently — it does not download or reuse the artifacts produced by mux-tui-release.yml. Similarly, the manually dispatched tui-publish-npm.yml runs its own full build. This means a release cut triggers 3 independent full matrix builds (mux-tui-release, tui-publish-pypi, tui-publish-npm) instead of one. If mux-tui-release.yml is intentionally an inspection-only build, a comment or doc note would prevent operator confusion about which artifacts actually land on registries.

Reviews (1): Last reviewed commit: "mux: fix windows bindgen by stripping th..." | Re-trigger Greptile

@lawrencecchen
lawrencecchen merged commit be35353 into main Jul 8, 2026
59 of 65 checks passed

This branch was successfully deployed

1 active and 1 inactive deployments
Preview – cmux — 8aa8c8f6 Deployed Jul 9, 2026 by vercel[bot]
pypi-tui — 8aa8c8f6 Deployed Jul 8, 2026 by lawrencecchen via publish #3
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.

1 participant