# cmux Debugging Tools: Complete Guide to Development and Testing

> Master cmux debugging tools with this guide. Explore tagged Unix sockets, ring-buffer logging, and JSON-RPC simulation for efficient development and testing of the terminal multiplexer.

- Repository: [manaflow-ai/cmux](https://github.com/manaflow-ai/cmux)
- Tags: how-to-guide
- Published: 2026-03-29

---

**cmux ships with a full-stack debugging ecosystem that uses tagged Unix domain sockets, a high-performance ring-buffer logger, and JSON-RPC simulation commands to enable automated testing and deep inspection of the terminal multiplexer.**

The manaflow-ai/cmux repository provides a comprehensive debugging infrastructure designed specifically for terminal emulator development. These tools allow developers to trace UI events, simulate keyboard input programmatically, and inspect internal state without manual interaction, all centered around a **tagged debug socket** architecture.

## The Debug Socket Architecture

At the heart of cmux debugging is a **Unix domain socket** created at `/tmp/cmux-debug-<tag>.sock` that accepts JSON-RPC commands. This socket serves as the command bridge between the CLI, UI tests, and the running application instance.

### Socket Creation and Auto-Discovery

The debug socket is created automatically when launching a debug build. In [`Sources/cmuxApp.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/cmuxApp.swift) at line 651, the application initializes the socket listener, while the corresponding client logic in [`CLI/cmux.swift`](https://github.com/manaflow-ai/cmux/blob/main/CLI/cmux.swift) at line 12935 handles auto-discovery. The CLI resolves the active socket through three methods:

- The `CMUX_SOCKET` environment variable
- The `CMUX_TAG` environment variable  
- Scanning `/tmp/cmux-debug-*.sock` for the most recent socket

This design allows multiple tagged instances to run side-by-side without conflicts.

### Tagged Build Isolation

Use the provided build script to generate isolated debug instances:

```bash
./scripts/reload.sh --tag my-feature --launch

```

The [`scripts/reload.sh`](https://github.com/manaflow-ai/cmux/blob/main/scripts/reload.sh) script builds a Debug app with a unique bundle ID and derived data path, then prints the socket location. Each tagged build writes to its own socket path and log file, enabling parallel development on multiple features.

## Logging with dlog and DebugEventLog

cmux implements a lightweight, thread-safe logging system through the `dlog` helper macro, which feeds into a 500-entry ring buffer managed by `DebugEventLog`.

### The Ring Buffer Implementation

Every `dlog()` call expands to `DebugEventLog.shared.log(message)`, storing timestamped events in memory. The implementation resides in the Bonsplit submodule at [`vendor/bonsplit/Sources/Bonsplit/Public/DebugEventLog.swift`](https://github.com/manaflow-ai/cmux/blob/main/vendor/bonsplit/Sources/Bonsplit/Public/DebugEventLog.swift) (referenced in [`CLAUDE.md`](https://github.com/manaflow-ai/cmux/blob/main/CLAUDE.md) at line 126). This ring buffer captures the last 500 events regardless of log levels, ensuring critical context is available during crashes.

### Writing and Dumping Debug Logs

Insert debug statements anywhere in the Swift codebase:

```swift
// In Sources/Workspace.swift or any DEBUG-guarded section
dlog("🪲 Workspace layout refreshed after split")

```

Messages appear in both the in-memory buffer and `/tmp/cmux-debug-<tag>.log`. To persist the full buffer to disk programmatically:

```bash

# From within a running process (debugger or temporary UI button)

DebugEventLog.shared.dump()

```

This writes `~/Library/Application Support/cmux/debug-log-<timestamp>.txt` containing the complete event history since launch.

## Simulation Commands and JSON-RPC Interface

The debug socket exposes a JSON-RPC interface for driving the UI without human interaction, enabling automated integration testing and precise reproduction of bug scenarios.

### Available Simulation Commands

The [`Sources/TerminalController.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/TerminalController.swift) file implements command parsing (see the help text near line 11146). Key commands include:

- **`simulate_type`** – Injects text into the focused terminal pane
- **`simulate_shortcut`** – Triggers keyboard shortcuts (e.g., `cmd+w`)
- **`layout_debug`** – Dumps current terminal layout state

These commands mirror user interactions exactly, making them ideal for regression testing complex window management behaviors.

### Sending Commands via Netcat

Interact with a running instance directly through the socket:

```bash

# Type "hello world" into the active terminal

printf '{"method":"simulate_type","params":["hello world"]}\n' | \
  nc -U /tmp/cmux-debug-my-feature.sock

```

For CLI convenience, the `cmux` binary handles socket discovery automatically:

```bash

# Auto-discovers socket and sends shortcut

cmux simulate_shortcut cmd+w

# Or specify explicitly

cmux --socket /tmp/cmux-debug-my-feature.sock simulate_shortcut cmd+w

```

## Debug-Only UI Helpers

The codebase includes a family of `debug*` methods exposed only in Debug builds, guarded by `#if DEBUG` preprocessor directives. These methods, such as `debugRenderStats()` and `debugHasSearchOverlay()`, expose internal view state for validation in unit tests.

In [`cmuxTests/TerminalAndGhosttyTests.swift`](https://github.com/manaflow-ai/cmux/blob/main/cmuxTests/TerminalAndGhosttyTests.swift) at line 1899, you can see examples of these helpers validating rendering pipelines and overlay states. They provide programmatic access to visual properties that are otherwise opaque to the testing framework.

## Summary

- **Tagged debug sockets** at `/tmp/cmux-debug-<tag>.sock` provide isolated JSON-RPC command channels for each build instance, created in [`Sources/cmuxApp.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/cmuxApp.swift) and discovered via [`CLI/cmux.swift`](https://github.com/manaflow-ai/cmux/blob/main/CLI/cmux.swift).
- **The `dlog` system** writes to a 500-entry ring buffer in `DebugEventLog`, with automatic log files at `/tmp/cmux-debug-<tag>.log`.
- **Simulation commands** like `simulate_type` and `simulate_shortcut` enable scriptable UI automation through [`Sources/TerminalController.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/TerminalController.swift).
- **`scripts/reload.sh --tag <name>`** generates isolated debug builds that won't conflict with production instances.
- **Debug-only view helpers** expose internal state for unit testing when compiled with `DEBUG` flags.

## Frequently Asked Questions

### How do I connect to a running cmux debug instance?

The `cmux` CLI automatically discovers the correct socket by checking `CMUX_SOCKET`, `CMUX_TAG`, or scanning `/tmp/cmux-debug-*.sock` as implemented in [`CLI/cmux.swift`](https://github.com/manaflow-ai/cmux/blob/main/CLI/cmux.swift) at line 12935. Simply run `cmux status` to verify which socket path the CLI will use, then issue commands like `cmux simulate_type "text"`.

### What is the difference between `dlog` and standard logging?

`dlog` is a specialized, high-performance logger that writes to a fixed 500-entry ring buffer in `DebugEventLog`, making it ideal for capturing recent history during crashes without flooding the console. Unlike standard `print` statements, `dlog` entries are both memory-buffered and written to `/tmp/cmux-debug-<tag>.log`, and can be dumped to persistent storage via `DebugEventLog.shared.dump()`.

### How do I run multiple debug builds simultaneously?

Use the `./scripts/reload.sh --tag <unique-name>` command for each instance. This script generates builds with unique bundle IDs and derived data paths, ensuring each instance creates its own socket at `/tmp/cmux-debug-<tag>.sock` and log file. You can then target specific instances using `CMUX_TAG=<tag>` or the `--socket` CLI flag.

### Where are debug logs stored?

Debug logs exist in two locations: a transient human-readable file at `/tmp/cmux-debug-<tag>.log` that updates in real-time, and a persistent dump at `~/Library/Application Support/cmux/debug-log-<timestamp>.txt` created when calling `DebugEventLog.shared.dump()`. You can monitor live activity with `tail -f /tmp/cmux-debug-<tag>.log` during development sessions.