Skip to content

Rebrand cmux → Programa (core rename + runtime contracts, phased)#48

Merged
arzafran merged 23 commits into
mainfrom
feat/rebrand-cmux-to-programa
Jul 2, 2026
Merged

Rebrand cmux → Programa (core rename + runtime contracts, phased)#48
arzafran merged 23 commits into
mainfrom
feat/rebrand-cmux-to-programa

Conversation

@arzafran

@arzafran arzafran commented Jul 1, 2026

Copy link
Copy Markdown
Member

What this does

Renames the product from cmux to Programa throughout the codebase, done as a series of build-verified phases instead of one big sweep (a prior blanket attempt was reverted for producing an inconsistent diff). Every commit here builds green on its own.

Crucially, the two places where a rename could lose user data — the config files and stored preferences — ship with migrations, so existing users keep working after they update:

  • ~/.config/cmux/ and project-root cmux.json are still read if the new ~/.config/programa/ / programa.json don't exist yet.
  • Every cmux-prefixed UserDefaults value is copied forward to its programa key once, on first launch.

Summary

Twelve commits, each build-gated (-scheme programa … build, or build-for-testing for the test phase):

  • Docs — cmux→Programa, manaflow-ai/cmuxdarkroomengineering/programa, README promo cleanup.
  • Symbols / files / test targetsCmux*Programa*; 6 source files + both test targets renamed with pbxproj/scheme updates.
  • Schemes / CLI target / scripts / CI — schemes → programa*, cmux-cliprograma-cli, bridging header, reload*.sh/CI -scheme + test-target refs. (PRODUCT_NAME was already programa.)
  • Config paths — dual-read legacy fallback (see above).
  • DockTileCmuxDockTilePluginProgramaDockTilePlugin (class + target + product + app Info.plist NSDockTilePlugIn, in lockstep).
  • AppleScript@objc(CmuxScript*)ProgramaScript*.sdef cocoa-class refs + user-facing dictionary text; AppleEvent code= values preserved.
  • Browser JS bridge__cmux* globals + cmuxIMEState/cmuxAddressBarFocusState/cmuxReactGrab handlers renamed in lockstep across 7 files.
  • CMUXCommit Info.plist key → ProgramaCommit (build writer + all readers).
  • UserDefaults — one-time copy-forward migration (never deletes legacy keys) + renamed standalone keys.

Deliberately not in this PR (tracked in plans/rebrand-progress.md), because they can only be verified by CI/manual runtime tests, not the local compile gate:

  • Shell-integration lockstep ($cmux_* protocol tokens ↔ Swift, ~100+ shell functions).
  • CLI command name + SSH ~/.cmux~/.programa bootstrap (386 refs, needs per-occurrence categorization).
  • User-facing Localizable.xcstrings brand strings (EN+JA).
  • Release artifacts (cmux.entitlements, DMG names, homebrew).

Analytics cmuxterm is intentionally kept for historical continuity.

Test Plan

  • Compiles: xcodebuild -scheme programa … build green after every phase
  • Test bundles compile: build-for-testing -scheme programa-ci
  • Unit tests on CI (programa-unit)
  • E2E / SSH / socket tests on CI (verify no runtime contract broke)
  • Manual: dock icon switching, AppleScript dispatch, browser IME/find, config + prefs migration on an existing install

arzafran added 23 commits July 1, 2026 11:12
Rename cmux → Programa in prose, manaflow-ai/cmux → darkroomengineering/programa,
cmux-macos.dmg → programa-macos.dmg. Remove prior-owner promo content from README
(manaflow star history, Founder's Edition Stripe link, personal contacts).
Mechanical s/Cmux/Programa/g across Sources/**, CLI/**, cmuxTests/**,
excluding AppleScriptSupport.swift (@objc .sdef contract) and
AppIconDockTilePlugin.swift (principal-class target) — both self-contained.
Filenames, pbxproj, and scheme unchanged; builds green with the cmux scheme.
git mv the 6 Cmux/cmux-named sources (cmuxApp, CmuxConfig, CmuxConfigExecutor,
CmuxDirectoryTrust, Panels/CmuxWebView, CLI/cmux) → Programa*/programa and update
every project.pbxproj ref (build file, file reference path, group, sources phase).
Builds green with the cmux scheme.
…rogramaUITests (Phase 3)

git mv both test dirs + CmuxConfigTests.swift → ProgramaConfigTests.swift; update
project.pbxproj (targets, products, group paths, config-list names) and the three
schemes' test-target labels. App product label (cmux.app) and scheme filenames
remain for Phase 4. build-for-testing (cmux-ci) green; tests not run locally per policy.
- Schemes cmux{,-unit,-ci}.xcscheme → programa*; app label cmux.app → programa.app
- CLI target cmux-cli → programa-cli, PRODUCT_MODULE_NAME cmux_cli → programa_cli,
  stale product refs cmux/cmux.app → programa/programa.app (PRODUCT_NAME already
  Programa/programa — unchanged)
- Bridging header cmux-Bridging-Header.h → programa-Bridging-Header.h
- scripts: -scheme cmux → programa, DerivedData/cmux- tag prefix → programa-
- CI: -scheme + -only-testing/-skip-testing test-target refs → programa*

Deferred (Phase 6): the Copy-Resources build phase (CMUXCommit plist key +
shell-integration copy — byte-verified untouched), the cmux CLI command name,
release-artifact/entitlements naming. Builds green with the new programa scheme.
…e 5)

Global config, settings.json, and project-root config now prefer the new
programa paths (~/.config/programa/, programa.json) and transparently fall back
to the legacy cmux paths when only those exist, so existing users keep working:
- ProgramaConfigStore.globalConfigPath: effective(new, legacy)
- ProgramaSettingsFileStore.defaultPrimaryPath: effective(new, legacy)
- findProgramaConfig: accepts programa.json then cmux.json; new configs default
  to programa.json
- display/help strings + command.cmuxConfig.subtitle → programa.json

UserDefaults key cmux.settingsFile.backups.v1 intentionally left (renaming would
orphan stored backups — deferred to Phase 6 key migration). Builds green.
…ePlugin (Phase 6a)

Class + target + product (CmuxDockTilePlugin.plugin → ProgramaDockTilePlugin.plugin)
+ app Info.plist NSDockTilePlugIn value, in lockstep. Notification value was already
com.darkroom.programa.*. Compiles; dock-icon switching to be manually verified.
…sdef text (Phase 6b)

@objc(CmuxScript{Window,Tab,Terminal,InputTextCommand}) → Programa* in lockstep with
the .sdef cocoa class refs; sdef dictionary/suite/description text cmux → Programa.
AppleEvent codes (code="Cmux…") preserved (internal dispatch, invisible to users).
Compiles; AppleScript dispatch to be manually verified.
…a*/programa* (Phase 6c)

Lockstep rename across all 7 files that inject or handle the tokens: __cmux* page
globals → __programa*, and the JS↔Swift message handlers cmuxIMEState,
cmuxAddressBarFocusState, cmuxReactGrab → programa*. Internal app-owned bridge (both
sides ship together). Compiles; browser IME/address-bar/ReactGrab to be runtime-verified.
…hase 6e)

Build-phase writer (Copy Resources PlistBuddy) + all reader sites (ProgramaApp,
ContentView, CLI) in lockstep. Regenerated every build (no cross-version
persistence), so no migration shim needed. Builds green.
…hase 6, UserDefaults)

Add a version-gated startup migration that copies every cmux-prefixed default to its
programa-prefixed key (never deletes the legacy key), so no user preference is lost by
the rebrand. Rename the standalone persisted keys (welcomeShown, surfacePoolEnabled,
devMutate…, debugBG, focusDebug, keyLatencyProbe, shortcutMonitorTrace, typingTimingLogs,
settingsFile.backups). Port keys (cmuxPortBase/Range) and socket-mode value (cmuxonly)
deferred to their own contracts (shell-integration / socket-mode). Builds green.
…ow-up)

test_ci_scheme_testaction_debug.sh referenced the old cmux.xcscheme path and
test_bundled_ghostty_theme_picker_helper.sh used -scheme cmux; both broke after the
Phase 4 scheme rename. Points them at programa.xcscheme / -scheme programa.
Rename cmux.entitlements → programa.entitlements (git mv + the 3 signing refs in
build-sign-upload.sh, release.yml, nightly.yml — pbxproj CODE_SIGN_ENTITLEMENTS is
empty, so the Xcode build is unaffected). Rename nightly DMG/artifact names
cmux-nightly-* → programa-nightly-* and the release dry-run artifact. Homebrew cask
refs left as-is (external repo, deprecated per board cleanup).
The macos-26 runner is ~2x slower than macos-15 (same suite: 23m on macos-15 vs
>45m on macos-26). The rebrand changed project.pbxproj, which is part of the
DerivedData cache key, so every run on this branch rebuilds from a cold cache and
macos-26 consistently hit the 45m cap. Not a code issue — macos-15 passes the same
tests. Give macos-26 headroom.
Localizable.xcstrings (50 EN strings; JA had none) + matching Swift defaultValue/Text
fallbacks. Brand nouns → "Programa" (Quit/About/CLI/settings/dialogs/updates);
command/binary references → lowercase "programa" (Install 'programa' in PATH,
Usage: programa claude-teams/omo, and the sendText("programa welcome") terminal
command). Localization KEYS with lowercase cmux (cmuxOnly, cmuxConfig) preserved via
value-only edits + a (?![A-Z]) guard. Builds green.
…functional)

The CLI product is PRODUCT_NAME=programa and is bundled at Contents/Resources/bin/programa,
but the app still looked for bin/cmux and installed /usr/local/bin/cmux — a pre-existing
mismatch (main is mid-rebrand) that left the 'Install CLI' + CLI resolution broken. Point
them at bin/programa and /usr/local/bin/programa. Also fix the remaining 'programa welcome'
terminal command send, the menu-bar title/tooltip, and brand fallbacks (window title, app
name for notifications) cmux → Programa. Socket contract already agrees (shared last-socket-path
hint). Builds green.
…hase 6d)

Rename the two integration scripts (cmux-{bash,zsh}-integration → programa-*) and every
cmux_ shell-protocol token in lockstep across the scripts, the embedded-shell Swift string
literals (Workspace, AppDelegate, BrowserPopupWindowController), and CLI/programa.swift
(SSH bootstrap + loaders). The cross-boundary env vars were already PROGRAMA_*. PostHog
analytics events (cmux_daily_active/hourly_active) intentionally preserved for continuity.
Compiles; shell integration behavior verified by E2E CI (port detection, PR sidebar).
…Phase 6f functional)

- ${..._BIN:-cmux} tmux-shim fallbacks → :-programa (were invoking the old binary name)
- manaflow-ai/cmux nightly/release workflow URLs → darkroomengineering/programa
- /tmp/cmux* socket + hint paths → /tmp/programa* (fixes latent mismatch with the app's
  SocketControlSettings + reload.sh, which already use /tmp/programa*)
- sentry tag + dispatch-queue labels cmux → programa

Left cmux-relay-auth (JSON handshake protocol shared with the Go remote daemon — needs a
coordinated both-sides change). Builds green.
…e 6, cosmetic)

~90 cmuxXxx Swift identifiers + ~60 dotted cmux.* Notification/queue/error-domain literals
across 30 Sources/CLI files → programa*. Verified with build-for-testing (app + programaTests
+ programaUITests compile). Deliberately preserved identifiers/strings hard-coded by the test
targets and tests_v2 (e.g. SocketControlMode.cmuxOnly rawValue "cmuxonly", cmux*ForTesting
helpers, "cmux.main"/"cmux.settings"/"cmux.about" test-asserted keys, cmux-ssh-startup-*
asserted in test_ssh_remote_cli_metadata) — those need a coordinated app+test rename (follow-up).
Also fixed the 'Bundled Programa CLI' error string. Analytics events + cmux-relay-auth untouched.
@arzafran arzafran merged commit 6ad5488 into main Jul 2, 2026
5 of 8 checks passed
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