PluginBench
Skill
Pass
Audit score 90

cmux-debugging

manaflow-ai/cmux

Debug logging, menu, and runtime pitfalls for cmux terminal development.

What is cmux-debugging?

Provides debug event logging, a Debug menu for visual iteration, and documents critical runtime pitfalls when modifying cmux's terminal rendering, UI hit-testing, and list virtualization. Use when adding instrumentation, diagnosing UI/performance issues, or touching latency-sensitive code paths.

  • Unified debug event log for keys, mouse, focus, splits, and tabs with real-time file output
  • Debug menu in macOS menu bar for live tuning of layout, colors, and behavior
  • Ring-buffer event logging with 500-entry capacity and dump-to-file functionality
  • Guidance on typing-latency-sensitive code paths (hit-testing, TerminalSurface.forceRefresh, TabItemView equality)
  • Documentation of SwiftUI list snapshot boundaries and immutable row snapshot patterns
  • OS-version-specific testing notes for Foundation, SwiftUI, and WebKit semantics

How to install cmux-debugging

npx skills add null --skill cmux-debugging
Prerequisites
  • cmux development environment set up
  • macOS with DEBUG build of cmux
  • Familiarity with Swift and SwiftUI
Claude Code
Cursor
Windsurf
Cline

How to use cmux-debugging

  1. 1.Run `tail -f "$(cat /tmp/cmux-last-debug-log-path 2>/dev/null || echo /tmp/cmux-debug.log)"` to stream debug events
  2. 2.Wrap debug log calls in `#if DEBUG` / `#endif` blocks using `cmuxDebugLog("message")`
  3. 3.Access the Debug menu from the macOS menu bar in DEBUG builds to toggle visual options
  4. 4.Create new debug toggles by subclassing `NSWindowController` with `@AppStorage` bindings
  5. 5.Consult references/debug-event-log.md and references/runtime-pitfalls.md before modifying latency-sensitive code

Use cases

Good for
  • Adding debug probes to diagnose UI rendering or event-handling issues during development
  • Iterating on layout and colors using the Debug menu without recompilation
  • Troubleshooting typing lag by identifying allocations or I/O in latency-critical paths
  • Testing drag-and-drop UTType declarations and list virtualization behavior
  • Reproducing OS-version-specific bugs by testing on the reporter's macOS version
Who it's for
  • cmux developers adding instrumentation or fixing UI/runtime bugs
  • Engineers optimizing terminal rendering performance and keystroke latency
  • Developers working on tab/sidebar list views, drag-and-drop, or search overlays

cmux-debugging FAQ

Where do debug logs go?

Untagged Debug app writes to `/tmp/cmux-debug.log`; tagged builds write to `/tmp/cmux-debug-<tag>.log`. The `reload.sh` script updates `/tmp/cmux-last-debug-log-path` with the current path.

How do I add a new debug toggle?

Create an `NSWindowController` subclass with a `shared` singleton, add it to the Debug Windows menu in `Sources/cmuxApp.swift`, and use `@AppStorage` bindings in the SwiftUI view for live changes.

Why is my code causing typing lag?

Check if you are adding allocations, file I/O, or formatting in `TerminalSurface.forceRefresh()`, or adding work outside the `isPointerEvent` guard in `WindowTerminalHostView.hitTest()`. These are called on every keystroke.

What are list snapshot boundaries?

List subtrees using `LazyVStack`, `LazyHStack`, `List`, or `ForEach` must pass immutable row snapshots and closures below the boundary, not observable stores. This prevents unnecessary re-evaluation during typing.

How do I test OS-version-specific bugs?

Test on the reporter's macOS version before declaring a repro disproven, as Foundation, SwiftUI, AttributeGraph, and WebKit semantics can change between major versions.

Full instructions (SKILL.md)

Source of truth, from manaflow-ai/cmux.


name: cmux-debugging description: "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."

cmux Debugging

Debug event log

When adding debug event instrumentation, put events (keys, mouse, focus, splits, tabs) in the unified DEBUG build log. This is not a blanket requirement to add logs to every new code path. Most temporary probes should be added only during the dogfood debug loop and removed before merge.

tail -f "$(cat /tmp/cmux-last-debug-log-path 2>/dev/null || echo /tmp/cmux-debug.log)"
  • Untagged Debug app: /tmp/cmux-debug.log
  • Tagged Debug app (./scripts/reload.sh --tag <tag>): /tmp/cmux-debug-<tag>.log
  • reload.sh writes the current path to /tmp/cmux-last-debug-log-path
  • reload.sh writes the selected dev CLI path to /tmp/cmux-last-cli-path
  • reload.sh updates /tmp/cmux-cli and $HOME/.local/bin/cmux-dev to that CLI
  • Implementation: Packages/macOS/CMUXDebugLog/Sources/CMUXDebugLog/DebugEventLog.swift
  • App shim: Sources/App/DebugLogging.swift
  • Free function cmuxDebugLog("message") logs with timestamp and appends to file in real time from cmux code
  • The package implementation and app shim are #if DEBUG; all call sites must be wrapped in #if DEBUG / #endif
  • 500-entry ring buffer; CMUXDebugLog.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

Debug menu

The app has a Debug menu in the macOS menu bar only in DEBUG builds. Use it for visual iteration.

  • Debug > Debug Windows contains panels for tuning layout, colors, and behavior. Entries are alphabetical with no dividers.
  • To add a 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.
  • When the user says "debug menu" or "debug window", they mean this menu, not defaults write.

Runtime pitfalls

  • Custom UTTypes for drag-and-drop must be declared in Resources/Info.plist under UTExportedTypeDeclarations.
  • Do not add an app-level display link or manual ghostty_surface_draw loop; rely on Ghostty wakeups/renderer to avoid typing lag.
  • WindowTerminalHostView.hitTest() is typing-latency-sensitive. All divider/sidebar/drag routing is gated to pointer events only. Do not add work outside the isPointerEvent guard.
  • TabItemView uses Equatable conformance plus .equatable() to skip body re-evaluation during typing. Do not add environment/store/binding reads without updating equality and the call site.
  • TerminalSurface.forceRefresh() is called on every keystroke. Do not add allocations, file I/O, or formatting there.
  • SurfaceSearchOverlay must be mounted from GhosttySurfaceScrollView in Sources/GhosttyTerminalView.swift, not from SwiftUI panel containers.
  • List subtrees with LazyVStack, LazyHStack, List, or ForEach must pass immutable row snapshots plus closures below the boundary. Do not pass observable stores into row views.
  • Functions called from SwiftUI body must not mutate state or schedule store writes.
  • Foundation, SwiftUI, AttributeGraph, and WebKit semantics can change between macOS major versions. Test on the reporter's macOS before declaring a user repro disproven.

Detailed references

  • Read references/debug-event-log.md when adding or interpreting debug log probes.
  • Read references/runtime-pitfalls.md before touching terminal rendering, hit testing, tab rows, list virtualization, search overlay layering, or OS-version-sensitive code.