
Cmux Debugging
- 2.5k installs
- 25.6k repo stars
- Updated August 5, 2026
- manaflow-ai/cmux
cmux-debugging is an agent skill that diagnoses stuck panes, broken agent sessions, IPC failures, and race conditions for developers who run cmux terminal workflows locally or in CI.
About
cmux-debugging is a task-scoped agent skill in the manaflow-ai/cmux repository for diagnosing runtime issues in cmux, a Ghostty-based macOS terminal with vertical tabs built for AI coding agents. The skill documents DEBUG event log destinations and ring-buffer behavior guarded by #if DEBUG, Debug menu extension patterns, and runtime pitfalls including UTTypes registration, terminal rendering latency, hit-testing guards, SwiftUI list snapshot boundaries, and body-time mutation prohibitions. Two reference files—debug-event-log.md and runtime-pitfalls.md—provide deep troubleshooting context alongside agents/openai.yaml metadata. Developers reach for cmux-debugging when cmux panes freeze, agent sessions break, IPC socket communication fails, or CI agent workflows show race conditions. Install via npx skills add manaflow-ai/cmux --skill cmux-debugging.
- Traces pane spawn and teardown failure modes
- Isolates agent IPC and stdin/stdout routing bugs
- Provides reproducible minimal failing session steps
- Covers log locations and diagnostic commands
- Documents recovery paths for corrupted session state
Cmux Debugging by the numbers
- 2,536 all-time installs (skills.sh)
- +301 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #34 of 596 Debugging skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/manaflow-ai/cmux --skill cmux-debuggingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.5k |
|---|---|
| repo stars | ★ 25.6k |
| Last updated | August 5, 2026 |
| Repository | manaflow-ai/cmux ↗ |
How do you debug cmux stuck panes and agent sessions?
Diagnose stuck panes, broken agent sessions, IPC failures, and race conditions when cmux misbehaves in local or CI agent workflows.
Who is it for?
Developers running cmux locally or in CI who hit stuck panes, broken agent sessions, IPC socket failures, or SwiftUI terminal rendering bugs.
Skip if: Developers not using cmux or those needing general application debugging unrelated to cmux terminal panes and agent IPC.
When should I use this skill?
cmux panes freeze, agent sessions disconnect, IPC or socket errors appear, or terminal rendering and hit-testing bugs occur in cmux workflows.
What you get
Debug event log interpretation, runtime pitfall fixes, IPC diagnosis notes, and validated cmux session recovery steps
- Debug diagnosis report
- Runtime pitfall fix steps
- Event log interpretation
By the numbers
- Includes 2 reference files: debug-event-log.md and runtime-pitfalls.md
- SKILL.md spans 54 lines with agents/openai.yaml metadata
Files
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.shwrites the current path to/tmp/cmux-last-debug-log-pathreload.shwrites the selected dev CLI path to/tmp/cmux-last-cli-pathreload.shupdates/tmp/cmux-cliand$HOME/.local/bin/cmux-devto 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
NSWindowControllersubclass with asharedsingleton, add it to the "Debug Windows" menu inSources/cmuxApp.swift, and add a SwiftUI view with@AppStoragebindings 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.plistunderUTExportedTypeDeclarations. - Do not add an app-level display link or manual
ghostty_surface_drawloop; 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 theisPointerEventguard.TabItemViewusesEquatableconformance 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.SurfaceSearchOverlaymust be mounted fromGhosttySurfaceScrollViewinSources/GhosttyTerminalView.swift, not from SwiftUI panel containers.- List subtrees with
LazyVStack,LazyHStack,List, orForEachmust pass immutable row snapshots plus closures below the boundary. Do not pass observable stores into row views. - Functions called from SwiftUI
bodymust 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.
interface:
display_name: "cmux Debugging"
short_description: "Use cmux debug logs, Debug menu, and runtime pitfall rules safely."
default_prompt: "Use this skill when adding debug probes, diagnosing cmux UI/runtime issues, touching typing-sensitive terminal paths, SwiftUI list rows, drag/drop UTTypes, search overlay layering, or Debug menu windows."
Debug Event Log
The debug event log is the preferred shared destination for temporary and durable DEBUG-only probes.
Destination
Tagged builds write tag-specific logs:
- untagged Debug app:
/tmp/cmux-debug.log - tagged Debug app:
/tmp/cmux-debug-<tag>.log
reload.sh writes the current path to /tmp/cmux-last-debug-log-path, so the most robust tail command is:
tail -f "$(cat /tmp/cmux-last-debug-log-path 2>/dev/null || echo /tmp/cmux-debug.log)"Use this instead of guessing whether the current run is tagged.
Shape
The package implementation lives in Packages/macOS/CMUXDebugLog/Sources/CMUXDebugLog/DebugEventLog.swift, and the app shim lives in Sources/App/DebugLogging.swift.
Call sites use:
#if DEBUG
cmuxDebugLog("focus.panel ...")
#endifEvery call site must be guarded by #if DEBUG / #endif. The implementation and shim are DEBUG-only, so unguarded call sites break non-Debug builds.
When to add probes
Add probes during a dogfood debug loop when they help answer a concrete question:
- Which event path fired?
- Which panel or pane had focus?
- Which split/tab/drop transition occurred?
- Did a stale view or responder receive an event?
- Did a path fire on every keypress?
Do not add broad instrumentation just because a file is nearby. Remove temporary probes before merge unless they are low-volume and clearly useful for future debugging.
Naming
Prefer stable event prefixes:
focus.panelfocus.bonsplitfocus.firstResponderfocus.moveFocustab.selecttab.closetab.dragStarttab.droppane.focuspane.dropdivider.dragStart
Put dynamic details after the prefix. This makes rg, tail, and log filtering practical.
Ring buffer
The debug logger has a 500-entry ring buffer. CMUXDebugLog.DebugEventLog.shared.dump() writes the full buffer to file. Use this when the interesting event occurred before you started tailing.
Runtime Pitfalls
This reference expands the high-risk cmux runtime rules.
Drag-and-drop UTTypes
Custom UTTypes must be declared in Resources/Info.plist under UTExportedTypeDeclarations. Examples include:
com.splittabbar.tabtransfercom.cmux.sidebar-tab-reorder
If drag/drop works only inside a narrow local test but fails across process or extension boundaries, check Info.plist before rewriting the drag model.
Terminal rendering and typing latency
Do not add an app-level display link or manual ghostty_surface_draw loop. cmux relies on Ghostty wakeups and renderer scheduling. A second draw loop can make typing lag worse and hide the real invalidation source.
TerminalSurface.forceRefresh() in Sources/GhosttyTerminalView.swift is called on every keystroke. Do not add:
- allocation-heavy formatting
- file I/O
- logging to disk
- string interpolation in hot loops
- layout work
If you need to observe this path, use the smallest possible DEBUG-only probe and remove it before merge unless it is intentionally durable.
Hit testing
WindowTerminalHostView.hitTest() in TerminalWindowPortal.swift is called on every event, including keyboard events. Divider/sidebar/drag routing is intentionally gated to pointer events.
Do not add work outside the isPointerEvent guard. Even "small" checks compound on typing paths.
Tab rows
TabItemView in ContentView.swift uses Equatable conformance plus .equatable() to skip body re-evaluation during typing.
Before adding any of these to the view:
@EnvironmentObject@ObservedObject@Binding- a plain store read in
body - a new parameter derived from mutable global state
Update the == function and verify the ForEach call site still uses .equatable(). Prefer passing precomputed immutable values.
Terminal find layering
SurfaceSearchOverlay must be mounted from GhosttySurfaceScrollView in Sources/GhosttyTerminalView.swift, the AppKit portal layer. Do not mount it from SwiftUI panel containers such as Sources/Panels/TerminalPanelView.swift.
Portal-hosted terminal views can sit above SwiftUI during split/workspace churn. Mounting the search UI at the wrong layer creates intermittently hidden or detached search controls.
Snapshot boundary for list subtrees
In any SwiftUI panel whose body contains a LazyVStack, LazyHStack, List, or ForEach of rows, no view below that boundary may hold a reference to an ObservableObject or @Observable store. That includes:
@ObservedObject@EnvironmentObject@StateObject@Bindable- a plain
let store: SomeStore
Rows and drop gaps receive immutable value snapshots plus closure action bundles only.
This avoids the class of bugs where an orthogonal published change invalidates every row and thrashes LazyLayoutViewCache, causing a main-thread spin loop. Reference patterns include IndexSectionActions, SectionGapActions, and SessionSearchFn in Sources/SessionIndexView.swift.
No body-time mutation
A function called from SwiftUI body, directly or through a helper, must not:
- write observable state
- schedule
Task { @MainActor in store.x = ... } - call
DispatchQueue.main.asyncto write store state
State-changing work triggered by "new data appeared" belongs in a reload completion, a didSet, or a property observer. It does not belong in the projection that feeds ForEach.
OS-version repros
Foundation, SwiftUI, AttributeGraph, and WebKit behavior can change silently between macOS versions. A function that seems deterministic on macOS 26 may behave differently on macOS 14 or 15.
Concrete example: URL(fileURLWithPath: "/").deletingLastPathComponent().path returned "/.." on macOS 14 and 15 but "/" on macOS 26.
When a user reports a repro on an older macOS, test on that macOS before declaring the repro disproven. AWS M4 Pro builders such as cmux-aws-mac, cmux-aws-m4pro, and aws-m4pro-1..6 are pre-provisioned on macOS 15.7.4 and are the preferred empirical repro path.
Related skills
How it compares
Pick cmux-debugging over cmux-diagnostics when the issue is runtime rendering or IPC bugs rather than CLI health checks and settings validation.
FAQ
What runtime issues does cmux-debugging cover?
cmux-debugging covers stuck panes, broken agent sessions, IPC failures, and race conditions in cmux. Reference docs detail UTTypes registration, terminal rendering latency, hit-testing guards, SwiftUI list boundaries, and body-time mutation errors.
How do you install cmux-debugging?
Install cmux-debugging with npx skills add manaflow-ai/cmux --skill cmux-debugging. The skill lives in skills/cmux-debugging/ with reference docs for debug event logs and runtime pitfalls in the cmux repository.