# cmux agent notes ## Initial setup Run the setup script to initialize submodules and build GhosttyKit: ```bash ./scripts/setup.sh ``` ## Local dev After making code changes, always run the reload script with a tag to launch the Debug app: ```bash ./scripts/reload.sh --tag fix-zsh-autosuggestions ``` After making code changes, always run the build: ```bash xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug -destination 'platform=macOS' build ``` When rebuilding GhosttyKit.xcframework, always use Release optimizations: ```bash cd ghostty && zig build -Demit-xcframework=true -Doptimize=ReleaseFast ``` When rebuilding cmuxd for release/bundling, always use ReleaseFast: ```bash cd cmuxd && zig build -Doptimize=ReleaseFast ``` `reload` = kill and launch the Debug app only (tag required): ```bash ./scripts/reload.sh --tag ``` `reloadp` = kill and launch the Release app: ```bash ./scripts/reloadp.sh ``` `reloads` = kill and launch the Release app as "cmux STAGING" (isolated from production cmux): ```bash ./scripts/reloads.sh ``` `reload2` = reload both Debug and Release (tag required for Debug reload): ```bash ./scripts/reload2.sh --tag ``` For parallel/isolated builds (e.g., testing a feature alongside the main app), use `--tag` with a short descriptive name: ```bash ./scripts/reload.sh --tag fix-blur-effect ``` This creates an isolated app with its own name, bundle ID, socket, and derived data path so it runs side-by-side with the main app. Important: use a non-`/tmp` derived data path if you need xcframework resolution (the script handles this automatically). Before launching a new tagged run, clean up any older tags you started in this session (quit old tagged app + remove its `/tmp` socket/derived data). ## Debug event log All debug events (keys, mouse, focus, splits, tabs) go to a single unified log in DEBUG builds: ```bash tail -f /tmp/cmux-debug.log ``` - Implementation: `vendor/bonsplit/Sources/Bonsplit/Public/DebugEventLog.swift` - Free function `dlog("message")` — logs with timestamp and appends to file in real time - Entire file is `#if DEBUG`; all call sites must be wrapped in `#if DEBUG` / `#endif` - 500-entry ring buffer; `DebugEventLog.shared.dump()` writes full buffer to file - Key events logged in `AppDelegate.swift` (monitor, performKeyEquivalent) - Mouse/UI events logged inline in views (ContentView, BrowserPanelView, etc.) - Focus events: `focus.panel`, `focus.bonsplit`, `focus.firstResponder`, `focus.moveFocus` - Bonsplit events: `tab.select`, `tab.close`, `tab.dragStart`, `tab.drop`, `pane.focus`, `pane.drop`, `divider.dragStart` ## Pitfalls - Do not add an app-level display link or manual `ghostty_surface_draw` loop; rely on Ghostty wakeups/renderer to avoid typing lag. ## E2E mac UI tests Run UI tests on the UTM macOS VM (never on the host machine). Always run e2e UI tests via `ssh cmux-vm`: ```bash ssh cmux-vm 'cd /Users/cmux/GhosttyTabs && xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug -destination "platform=macOS" -only-testing:GhosttyTabsUITests/UpdatePillUITests test' ``` ## Basic tests Run basic automated tests on the UTM macOS VM (never on the host machine): ```bash ssh cmux-vm 'cd /Users/cmux/GhosttyTabs && xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug -destination "platform=macOS" build && pkill -x "cmux DEV" || true && APP=$(find /Users/cmux/Library/Developer/Xcode/DerivedData -path "*/Build/Products/Debug/cmux DEV.app" -print -quit) && open "$APP" && for i in {1..20}; do [ -S /tmp/cmux.sock ] && break; sleep 0.5; done && python3 tests/test_update_timing.py && python3 tests/test_signals_auto.py && python3 tests/test_ctrl_socket.py && python3 tests/test_notifications.py' ``` ## Ghostty submodule workflow Ghostty changes must be committed in the `ghostty` submodule and pushed to the `manaflow-ai/ghostty` fork. Keep `docs/ghostty-fork.md` up to date with any fork changes and conflict notes. ```bash cd ghostty git remote -v # origin = upstream, manaflow = fork git checkout -b git add git commit -m "..." git push manaflow ``` To keep the fork up to date with upstream: ```bash cd ghostty git fetch origin git checkout main git merge origin/main git push manaflow main ``` Then update the parent repo with the new submodule SHA: ```bash cd .. git add ghostty git commit -m "Update ghostty submodule" ``` ## Release Use the `/release` command to prepare a new release. This will: 1. Determine the new version (bumps minor by default) 2. Gather commits since the last tag and update the changelog 3. Update `CHANGELOG.md` and `docs-site/content/docs/changelog.mdx` 4. Run `./scripts/bump-version.sh` to update both versions 5. Commit, tag, and push Version bumping: ```bash ./scripts/bump-version.sh # bump minor (0.15.0 → 0.16.0) ./scripts/bump-version.sh patch # bump patch (0.15.0 → 0.15.1) ./scripts/bump-version.sh major # bump major (0.15.0 → 1.0.0) ./scripts/bump-version.sh 1.0.0 # set specific version ``` This updates both `MARKETING_VERSION` and `CURRENT_PROJECT_VERSION` (build number). The build number is auto-incremented and is required for Sparkle auto-update to work. Manual release steps (if not using the command): ```bash git tag vX.Y.Z git push origin vX.Y.Z gh run watch --repo manaflow-ai/cmux ``` Notes: - Requires GitHub secrets: `APPLE_CERTIFICATE_BASE64`, `APPLE_CERTIFICATE_PASSWORD`, `APPLE_SIGNING_IDENTITY`, `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, `APPLE_TEAM_ID`. - The release asset is `cmux-macos.dmg` attached to the tag. - README download button points to `releases/latest/download/cmux-macos.dmg`. - Versioning: bump the minor version for updates unless explicitly asked otherwise. - Changelog: always update both `CHANGELOG.md` and the docs-site version.