cmux-debugging
Debug logging, Debug menu, runtime pitfalls, typing-latency-sensitive paths, SwiftUI list snapshot boundaries, OS-version repros, and local visual iteration for cmux. Use when adding debug probes, diagnosing UI/runtime issues, touching terminal rendering, tab/sidebar list views, drag/drop UTTypes, or using the Debug menu.
Security Assessment
About cmux-debugging
The cmux-debugging skill supports debugging the cmux macOS application, covering debug logging, the Debug menu, runtime pitfalls, typing-latency-sensitive paths, SwiftUI list snapshot boundaries, OS-version repros, and local visual iteration. It is used when adding debug probes, diagnosing UI or runtime issues, touching terminal rendering, tab or sidebar list views, drag/drop UTTypes, or using the Debug menu. Its purpose is to instrument and diagnose cmux safely without introducing performance regressions in latency-critical code.
For debug logging, events such as keys, mouse, focus, splits, and tabs go into a unified DEBUG build log that can be followed with tail -f against the path in /tmp/cmux-last-debug-log-path (falling back to /tmp/cmux-debug.log). Untagged Debug apps log to /tmp/cmux-debug.log while tagged apps launched via ./scripts/reload.sh --tag <tag> log to /tmp/cmux-debug-<tag>.log; reload.sh also writes the current CLI path and updates /tmp/cmux-cli and $HOME/.local/bin/cmux-dev. The logging is implemented in DebugEventLog.swift with an app shim in Sources/App/DebugLogging.swift, exposes the free function cmuxDebugLog("message"), and uses a 500-entry ring buffer whose full contents can be dumped via CMUXDebugLog.DebugEventLog.shared.dump(). Both the package implementation and shim are guarded by #if DEBUG, so all call sites must be wrapped in #if DEBUG / #endif. The Debug menu appears in the macOS menu bar only in DEBUG builds and, under Debug > Debug Windows, holds alphabetically ordered panels for tuning layout, colors, and behavior; adding a toggle means creating an NSWindowController subclass with a shared singleton, registering it in Sources/cmuxApp.swift, and adding a SwiftUI view with @AppStorage bindings.
The skill targets contributors working on the cmux codebase, especially in performance-sensitive areas. It documents runtime pitfalls: custom drag-and-drop UTTypes must be declared in Resources/Info.plist under UTExportedTypeDeclarations; do not add an app-level display link or manual ghostty_surface_draw loop; WindowTerminalHostView.hitTest() and TabItemView equality are typing-latency-sensitive and must not gain extra work or reads; TerminalSurface.forceRefresh() runs on every keystroke and must avoid allocations, file I/O, or formatting; SurfaceSearchOverlay must be mounted from GhosttySurfaceScrollView; list subtrees using LazyVStack/LazyHStack/List/ForEach must pass immutable row snapshots plus closures and never observable stores; functions called from SwiftUI body must not mutate state; and because Foundation, SwiftUI, AttributeGraph, and WebKit semantics change between macOS versions, repros should be tested on the reporter's macOS. Detailed references include references/debug-event-log.md and references/runtime-pitfalls.md.
FAQ
Where does cmux write its debug event log?
Untagged Debug apps log to /tmp/cmux-debug.log, and tagged apps launched with ./scripts/reload.sh --tag <tag> log to /tmp/cmux-debug-<tag>.log. You can follow the current one with tail -f against /tmp/cmux-last-debug-log-path, which reload.sh keeps updated.
How do I add a debug log entry from cmux code?
Call the free function cmuxDebugLog("message"), which logs with a timestamp and appends to the file in real time. Because the implementation is #if DEBUG, all call sites must be wrapped in #if DEBUG / #endif. The log uses a 500-entry ring buffer, and CMUXDebugLog.DebugEventLog.shared.dump() writes the full buffer to file.
What is the Debug menu and when is it available?
It is a Debug menu in the macOS menu bar available only in DEBUG builds, used for visual iteration. Debug > Debug Windows holds alphabetically ordered panels for tuning layout, colors, and behavior. When a user says 'debug menu' or 'debug window' they mean this menu, not defaults write.
How do I add a new debug toggle or visual option?
Create an NSWindowController subclass with a shared singleton, add it to the Debug Windows menu in Sources/cmuxApp.swift, and add a SwiftUI view with @AppStorage bindings for live changes.
What runtime pitfalls affect typing latency?
WindowTerminalHostView.hitTest() is latency-sensitive with routing gated to pointer events; TabItemView uses Equatable plus .equatable() to skip body re-evaluation; and TerminalSurface.forceRefresh() runs on every keystroke, so avoid adding allocations, file I/O, or formatting there. Also avoid an app-level display link or manual ghostty_surface_draw loop.
Install cmux-debugging
Quick Setup:
- Copy the skill folder to
.claude/skills/ - Claude will automatically detect and use the skill
Repository
manaflow-ai/cmux