Repository navigation
mux: TUI docs section #7328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+703
−137
Merged
mux: TUI docs section #7328
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
1e0c4b1
mux: docs section (getting started, concepts, keyboard, mouse, config…
lawrencecchen 1b74eab
mux docs: bring current with protocol v6, Alt layer, drag reorder, di…
lawrencecchen 56da7c4
chore: retrigger Vercel preview deploy (stuck pending check)
lawrencecchen b3f1ed5
Merge remote-tracking branch 'origin/main' into HEAD
lawrencecchen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| # cmux-mux docs | ||
|
|
||
| `cmux-mux` is a tmux-style multiplexer that speaks Ghostty's VT engine on both ends: PTY output is parsed into Ghostty terminal state, and attach clients receive Ghostty VT replay plus live output so another frontend can reconstruct the same surface. | ||
|
|
||
| ## Contents | ||
|
|
||
| - [Getting started](getting-started.md): build prerequisites, local and headless runs, sockets, detach and attach. | ||
| - [Concepts](concepts.md): session tree, focus, collapse behavior, tab naming, smart split, PTY and browser surfaces. | ||
| - [Keyboard](keyboard.md): prefix model, modeless Alt layer, default bindings, and `mux.json` key remapping. | ||
| - [Mouse](mouse.md): clickable UI, drag reorder, resize, scrollbars, menus, selection, pointer shape, and dialogs. | ||
| - [Configuration](configuration.md): full `mux.json` reference with defaults and a worked example. | ||
| - [Control socket protocol](protocol.md): JSON-lines framing, protocol v6 attach streams, events, and compatibility rules. | ||
| - [Browser panes](browser-panes.md): CDP-backed browser tabs, rendering, input, profiles, and current limitations. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| # Browser Panes | ||
|
|
||
| Browser panes are local Chrome/Chromium targets controlled with the Chrome DevTools Protocol. They live in the same pane and tab tree as PTY tabs, but their rendering and input path are CDP-based instead of VT-based. | ||
|
|
||
| ## Requirements | ||
|
|
||
| Browser panes need a local CDP endpoint or a launchable Chrome/Chromium-family binary. The TUI can reuse an external endpoint, discover one on configured local ports, or launch Chrome itself in `--headless=new` mode. | ||
|
|
||
| Endpoint selection order: | ||
|
|
||
| 1. `CMUX_MUX_CDP_URL` | ||
| 2. `browser.cdp_url` in `mux.json` | ||
| 3. Discovery on `browser.discover_ports` when `browser.discover` is true | ||
| 4. A launched Chrome using `browser.chrome_binary` or binary discovery in `mux-cdp` | ||
|
|
||
| Binary discovery checks configured paths, known macOS and Linux Chrome-family paths, then `PATH` names such as `google-chrome`, `chromium`, `brave-browser`, and `microsoft-edge`. | ||
|
|
||
| Set `CMUX_MUX_CDP_DEBUG` to print browser runtime debug messages to stderr. | ||
|
|
||
| ## Creating Panes | ||
|
|
||
| Use prefix `B`, or right-click a pane and choose `New browser tab`. The prompt starts with `https://`. | ||
|
|
||
| Bare domains get `https://` prepended. Inputs containing `://`, or starting with `about:`, `file:`, `data:`, `chrome:`, or `devtools:`, pass through unchanged. | ||
|
|
||
| Browser tabs are created inside an existing pane when one is active. If the session has no workspaces, creating a browser tab creates a workspace, screen, and pane around it. | ||
|
|
||
| ## Rendering | ||
|
|
||
| The browser runtime creates a target, attaches with CDP, enables the page domain, sets device metrics from the pane's cell size and detected cell pixels, and starts `Page.screencastFrame`. | ||
|
|
||
| The TUI draws the latest PNG frame with the kitty graphics protocol after each Ratatui frame. If a context menu or prompt overlaps the pane, the graphics placement is omitted for that frame so the terminal UI stays readable. | ||
|
|
||
| If the host terminal does not support kitty graphics, the pane displays `terminal has no kitty graphics support`. If the browser frame has not arrived yet, it displays a loading message. | ||
|
|
||
| ## Input | ||
|
|
||
| Printable character keys and paste use CDP insert-text. Enter, Backspace, Tab, Esc, arrows, Home, End, PageUp, PageDown, and Delete use CDP key events with modifier bits for Alt, Control, Super, and Shift. | ||
|
|
||
| Left click, drag, release, and wheel events inside browser content are forwarded as CDP mouse input. Wheel deltas are scaled by the detected cell height. | ||
|
|
||
| ## Profiles and Lifecycle | ||
|
|
||
| Browser panes share one browser runtime per mux session. Closing a browser tab closes only its target. Mux shutdown kills Chrome only when cmux launched it. | ||
|
|
||
| Launched Chrome uses a persistent cmux profile unless `browser.ephemeral` is true. `browser.user_data_dir` overrides the persistent profile path. When ephemeral mode is true, Chrome uses a temporary profile that is deleted on shutdown and ignores `browser.user_data_dir`. | ||
|
|
||
| The default launched profile is `~/Library/Application Support/cmux-mux/chrome-profile` on macOS. On non-macOS targets it is `$XDG_DATA_HOME/cmux-mux/chrome-profile` when `XDG_DATA_HOME` is set, then `~/.local/share/cmux-mux/chrome-profile`. | ||
|
|
||
| ## Limitations | ||
|
|
||
| Browser panes are local-only as of protocol v6. `attach-surface` returns an error for browser surfaces, attach clients do not receive browser frame streams, and a remote TUI shows a placeholder for browser panes. | ||
|
|
||
| Headful external Chrome can throttle screencast frames when the window or tab is hidden or occluded. Chrome 136 and newer do not allow `--remote-debugging-port` with the default user data directory, so reusable everyday Chrome profiles may not expose CDP. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # Concepts | ||
|
|
||
| ## Tree | ||
|
|
||
| The mux tree is: | ||
|
|
||
| ```text | ||
| session -> workspaces -> screens -> split-tree panes -> tabs | ||
| ``` | ||
|
|
||
| A session is one mux backend and one control socket. A workspace owns one or more screens. A screen is the layout selected in the status bar. A screen layout is a binary split tree whose leaves are panes. A pane owns an ordered tab list, and each tab is a surface. | ||
|
|
||
| The UI uses tmux-style verbs for screens. Prefix `c` creates a screen, prefix `n` and `p` switch screens, prefix `&` closes a screen, and prefix `,` renames a screen. PTY tabs use prefix `t`, tab chips, and tab context menus. | ||
|
|
||
| ## Active and Focus State | ||
|
|
||
| The session tracks the active workspace. Each workspace tracks its active screen. Each screen tracks its active pane. Each pane tracks its active tab. | ||
|
|
||
| Focusing a pane makes that pane's screen and workspace active. Selecting a workspace or screen changes that level's active item. Selecting a tab changes the active tab in one pane. | ||
|
|
||
| Pane focus tracks recent activity. When closing the active pane or the last tab in it, mux chooses the most recently active remaining pane on that screen instead of always choosing a neighbor. | ||
|
|
||
| ## Tabs and Names | ||
|
|
||
| Tabs are surfaces. A PTY tab wraps a child process connected to a pseudo-terminal. A browser tab wraps a local Chrome/Chromium target. | ||
|
|
||
| `rename-tab` sets the surface name. Empty tab names clear the custom name and fall back to the generated tab label. The old config key `rename-pane` is still accepted as an alias for the `rename-tab` key binding, but the UI rename action targets the tab surface, not the pane object. | ||
|
|
||
| Pane names still exist in the control socket through `rename-pane`. They are separate from the tab labels shown in the TUI. | ||
|
|
||
| ## Smart Split | ||
|
|
||
| The modeless `Alt-n` binding creates a new pane with smart split direction. The TUI first tries the focused pane. If that pane cannot split in the chosen direction, it tries the largest pane that can. | ||
|
|
||
| Direction follows a zellij-style rule using the terminal cell ratio. Tall enough panes split down. Wide enough panes split right. Panes below the configured size thresholds do not split. | ||
|
|
||
| ## Collapse Behavior | ||
|
|
||
| Closing a tab removes one surface. If the pane still has tabs, the active tab index moves to a remaining tab. | ||
|
|
||
| If a pane loses its last tab, that pane is removed from the split tree and its parent split collapses to the remaining child. If that empties the screen, the screen is removed. If that empties the workspace, the workspace is removed. If every workspace is gone, mux emits an `empty` event. | ||
|
|
||
| Closing a pane closes all tabs in that pane. Closing a screen closes every pane and tab in that screen. Closing a workspace closes every screen, pane, and tab in that workspace. | ||
|
|
||
| ## PTY and Browser Surfaces | ||
|
|
||
| A PTY surface parses child-process output with libghostty-vt. Frontends render snapshots of that terminal state. Attach clients receive a VT replay first, then a base64 stream of subsequent PTY bytes, plus ordered resize frames when the surface geometry changes. | ||
|
|
||
| A browser surface is a local Chrome/Chromium target controlled through the Chrome DevTools Protocol. The local TUI draws browser frames with kitty graphics and forwards keyboard, mouse, and wheel input over CDP. Browser surfaces are listed in the tree, but `attach-surface` does not stream browser pixels as of protocol v6. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| # Configuration | ||
|
|
||
| `cmux-mux` reads `~/.config/cmux/mux.json`, or `$XDG_CONFIG_HOME/cmux/mux.json` when `XDG_CONFIG_HOME` is set. Set `CMUX_MUX_CONFIG` to use another file; it takes precedence over both. Every documented key is optional. Unknown keys in the typed sections make the raw config invalid, so the TUI logs an error and falls back to defaults. | ||
|
|
||
| Colors accept `#rrggbb`, `#rgb`, an xterm-256 number, or a numeric string. | ||
|
|
||
| ## Theme | ||
|
|
||
| Selection colors are resolved in this order: explicit `mux.json`, Ghostty config keys `selection-background` and `selection-foreground`, then built-in defaults. Ghostty configs are read from `$XDG_CONFIG_HOME/ghostty/config` (when set), `~/.config/ghostty/config`, and on macOS `~/Library/Application Support/com.mitchellh.ghostty/config`; later entries in the file win. | ||
|
|
||
| | Key | Type | Default | Effect | | ||
| | --- | --- | --- | --- | | ||
| | `theme.selection_background` | color | `#3a3a3a`, seeded from Ghostty when present | Selection background in PTY panes | | ||
| | `theme.selection_foreground` | color or null | `null`, seeded from Ghostty when present | Selection foreground; `null` keeps each cell's foreground | | ||
| | `theme.sidebar_rail` | color | `110` | Rail color for the active workspace rows | | ||
| | `theme.sidebar_active_bg` | color | `236` | Background for the active workspace rows | | ||
| | `theme.tab_rail` | color | `110` | Rail color inside the active tab chip | | ||
| | `theme.tab_bg` | color | `236` | Background for inactive solid tab chips | | ||
| | `theme.tab_active_bg` | color or null | `null` | Overrides the focused and unfocused active-tab chip backgrounds | | ||
| | `theme.border_active` | color | `110` | Focused pane border | | ||
| | `theme.border_inactive` | color | `238` | Unfocused pane border | | ||
|
|
||
| ## Tabs | ||
|
|
||
| | Key | Type | Default | Effect | | ||
| | --- | --- | --- | --- | | ||
| | `tabs.min_width` | integer | `7` | Minimum tab label width, clamped to 3 through 40 | | ||
| | `tabs.solid_background` | boolean | `true` | Renders tab chips with solid backgrounds | | ||
| | `tabs.show_titles` | boolean | `false` | Shows full process titles after tab numbers | | ||
| | `tabs.agents` | string array | `["claude","codex","opencode","pi"]` | Agent names surfaced in tab labels when `show_titles` is false | | ||
|
|
||
| Tabs are numbered by default. A recognized agent program can appear after the number. A user-assigned tab name replaces the generated label. | ||
|
|
||
| ## Sidebar | ||
|
|
||
| | Key | Type | Default | Effect | | ||
| | --- | --- | --- | --- | | ||
| | `sidebar.width` | integer | `22` | Sidebar width, clamped to 10 through 60 on load | | ||
| | `sidebar.max_width` | integer | `0` | Maximum live drag width; `0` means no configured maximum | | ||
|
|
||
| Live sidebar dragging also leaves at least 40 columns for pane content. | ||
|
|
||
| ## Browser | ||
|
|
||
| | Key | Type | Default | Effect | | ||
| | --- | --- | --- | --- | | ||
| | `browser.chrome_binary` | string | `null` | Chrome/Chromium binary to launch when no external CDP endpoint is used | | ||
| | `browser.cdp_url` | string | `null` | External CDP endpoint, accepted as `http://host:port` or `ws://...` | | ||
| | `browser.discover` | boolean | `true` | Probe discovery ports before launching Chrome | | ||
| | `browser.discover_ports` | integer array | `[9222]` | Local ports to probe for `/json/version` | | ||
| | `browser.user_data_dir` | string | `null` | Persistent profile directory for launched Chrome | | ||
| | `browser.ephemeral` | boolean | `false` | Use a temporary launched Chrome profile and delete it on shutdown | | ||
|
|
||
| When `browser.ephemeral` is true, it takes precedence over `browser.user_data_dir`: launched Chrome uses a fresh temporary profile, and the configured directory is not deleted. | ||
|
|
||
| The default launched profile is `~/Library/Application Support/cmux-mux/chrome-profile` on macOS. On non-macOS targets it is `$XDG_DATA_HOME/cmux-mux/chrome-profile` when `XDG_DATA_HOME` is set, then `~/.local/share/cmux-mux/chrome-profile`. | ||
|
|
||
| ## Scrollbar | ||
|
|
||
| | Key | Type | Default | Effect | | ||
| | --- | --- | --- | --- | | ||
| | `scrollbar.position` | `"column"` or `"border"` | `"column"` | Dedicated scrollbar column or right-border overlay | | ||
|
|
||
| ## Keys | ||
|
|
||
| | Key | Type | Default | Effect | | ||
| | --- | --- | --- | --- | | ||
| | `keys.prefix` | chord string | `"ctrl+b"` | Prefix chord | | ||
| | `keys.alt_shortcuts` | boolean | `true` | Enables default modeless Alt bindings when true | | ||
| | `keys.new-tab` | chord string or array or `"none"` | `["t","alt+t"]` | New PTY tab | | ||
| | `keys.new_browser_tab` | chord string or array or `"none"` | `"B"` | Browser URL prompt | | ||
| | `keys.new-pane-smart` | chord string or array or `"none"` | `"alt+n"` | New pane using smart split direction | | ||
| | `keys.next-tab` | chord string or array or `"none"` | `"tab"` | Next tab | | ||
| | `keys.prev-tab` | chord string or array or `"none"` | `"backtab"` | Previous tab | | ||
| | `keys.split-right` | chord string or array or `"none"` | `"%"` | Split right | | ||
| | `keys.split-down` | chord string or array or `"none"` | `"\""` | Split down | | ||
| | `keys.close-tab` | chord string or array or `"none"` | `"x"` | Close active tab | | ||
| | `keys.close-pane` | chord string or array or `"none"` | `"X"` | Close active pane | | ||
| | `keys.rename-tab` | chord string or array or `"none"` | unbound | Rename active tab | | ||
| | `keys.rename-pane` | chord string or array or `"none"` | alias | Alias for `rename-tab` | | ||
| | `keys.rename-screen` | chord string or array or `"none"` | `","` | Rename active screen | | ||
| | `keys.rename-workspace` | chord string or array or `"none"` | `"$"` | Rename active workspace | | ||
| | `keys.close-screen` | chord string or array or `"none"` | `"&"` | Close active screen | | ||
| | `keys.prev-screen` | chord string or array or `"none"` | `["p","alt+["]` | Previous screen | | ||
| | `keys.next-screen` | chord string or array or `"none"` | `["n","alt+]"]` | Next screen | | ||
| | `keys.new-screen` | chord string or array or `"none"` | `"c"` | New screen | | ||
| | `keys.next-workspace` | chord string or array or `"none"` | `"w"` | Next workspace | | ||
| | `keys.new-workspace` | chord string or array or `"none"` | `"W"` | New workspace | | ||
| | `keys.toggle-sidebar` | chord string or array or `"none"` | `"s"` | Toggle sidebar | | ||
| | `keys.focus-left` | chord string or array or `"none"` | `["h","left","alt+h","alt+left"]` | Focus left | | ||
| | `keys.focus-right` | chord string or array or `"none"` | `["l","right","alt+l","alt+right"]` | Focus right | | ||
| | `keys.focus-up` | chord string or array or `"none"` | `["k","up","alt+k","alt+up"]` | Focus up | | ||
| | `keys.focus-down` | chord string or array or `"none"` | `["j","down","alt+j","alt+down"]` | Focus down | | ||
| | `keys.resize-grow` | chord string or array or `"none"` | `"alt+="` | Grow the focused split | | ||
| | `keys.resize-shrink` | chord string or array or `"none"` | `"alt+-"` | Shrink the focused split | | ||
| | `keys.scroll-up` | chord string or array or `"none"` | `"pageup"` | Scroll active PTY up 10 rows | | ||
| | `keys.scroll-down` | chord string or array or `"none"` | `"pagedown"` | Scroll active PTY down 10 rows | | ||
| | `keys.detach` | chord string or array or `"none"` | `"d"` | Quit local TUI or detach attached TUI | | ||
|
|
||
| Each action override replaces all default chords for that action. Values may be a string, an array of strings, or `"none"`. Non-string array entries are ignored. Set `keys.alt_shortcuts` to `false` to remove default Alt chords before applying user overrides; explicitly configured Alt chords still work. Prefix `1` through `9` stay fixed to tab selection. | ||
|
|
||
| Chord strings can be single characters or a key name with optional `ctrl`, `control`, `alt`, `option`, or `shift` modifiers. Examples: `"c"`, `"%"`, `"ctrl+b"`, `"alt+enter"`, `"tab"`, `"backtab"`, `"shift+tab"`, `"pageup"`, `"pagedown"`, `"esc"`, `"space"`, `"left"`, `"right"`, `"up"`, `"down"`, `"home"`, and `"end"`. | ||
|
|
||
| ## Example | ||
|
|
||
| ```json | ||
| { | ||
| "theme": { | ||
| "selection_background": "#355c7d", | ||
| "selection_foreground": null, | ||
| "sidebar_rail": "#87afd7", | ||
| "sidebar_active_bg": 236, | ||
| "tab_rail": "#87afd7", | ||
| "tab_bg": 236, | ||
| "tab_active_bg": null, | ||
| "border_active": "#87afd7", | ||
| "border_inactive": "#444444" | ||
| }, | ||
| "tabs": { | ||
| "min_width": 9, | ||
| "solid_background": true, | ||
| "show_titles": false, | ||
| "agents": ["claude", "codex", "opencode", "pi"] | ||
| }, | ||
| "sidebar": { | ||
| "width": 24, | ||
| "max_width": 40 | ||
| }, | ||
| "browser": { | ||
| "chrome_binary": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", | ||
| "cdp_url": "http://127.0.0.1:9222", | ||
| "discover": true, | ||
| "discover_ports": [9222, 9223], | ||
| "user_data_dir": "/Users/me/Library/Application Support/cmux-mux/chrome-profile", | ||
| "ephemeral": false | ||
| }, | ||
| "scrollbar": { | ||
| "position": "column" | ||
| }, | ||
| "keys": { | ||
| "prefix": "ctrl+a", | ||
| "alt_shortcuts": false, | ||
| "new-tab": ["t", "alt+t"], | ||
| "new_browser_tab": "B", | ||
| "new-pane-smart": "alt+n", | ||
| "next-tab": "tab", | ||
| "prev-tab": "backtab", | ||
| "next-screen": ["n", "alt+]"], | ||
| "prev-screen": ["p", "alt+["], | ||
| "rename-tab": "r", | ||
| "rename-screen": ",", | ||
| "focus-left": ["h", "left", "alt+h", "alt+left"], | ||
| "focus-right": ["l", "right", "alt+l", "alt+right"], | ||
| "close-pane": "none", | ||
| "detach": "d" | ||
| } | ||
| } | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| # Getting started | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Builds need zig 0.15.2, a Rust toolchain, and the `ghostty` submodule. `ghostty-vt-sys` compiles `libghostty-vt.a` from that submodule, so an uninitialized submodule fails before the TUI starts. | ||
|
|
||
| ```bash | ||
| cd mux | ||
| cargo build -p mux-tui | ||
| ``` | ||
|
|
||
| ## Local session | ||
|
|
||
| A normal run starts an in-process mux, opens the TUI, and serves the control socket. | ||
|
|
||
| ```bash | ||
| cd mux | ||
| cargo run -p mux-tui | ||
| cargo run -p mux-tui -- --session agents | ||
| ``` | ||
|
|
||
| The default session is `main`. Quitting a local TUI shuts down that in-process session and removes its socket. | ||
|
|
||
| Use `--term <value>` to set `TERM` for child PTYs. Without it, children get `xterm-256color`; the surface layer also honors `CMUX_MUX_TERM` when no CLI value is supplied. | ||
|
|
||
| ## Headless server and attach | ||
|
|
||
| Headless mode starts only the mux backend and control socket. | ||
|
|
||
| ```bash | ||
| cd mux | ||
| cargo run -p mux-tui -- --headless --session agents | ||
| ``` | ||
|
|
||
| Attach a TUI to that session from another terminal. | ||
|
|
||
| ```bash | ||
| cd mux | ||
| cargo run -p mux-tui -- attach --session agents | ||
| ``` | ||
|
|
||
| Detach from an attached TUI with prefix `d`. With default keys, that is `Ctrl-b d`. The server keeps running, and another `attach` reconnects to the same tree. PTY tabs attach with a Ghostty VT-state replay followed by a live output stream. | ||
|
|
||
| ## Sessions and sockets | ||
|
|
||
| The default socket path is: | ||
|
|
||
| ```text | ||
| $TMPDIR/cmux-mux-<uid>/<session>.sock | ||
| ``` | ||
|
|
||
| The usual default is `$XDG_RUNTIME_DIR/cmux-mux-<uid>/main.sock` when `XDG_RUNTIME_DIR` is set, then `$TMPDIR/cmux-mux-<uid>/main.sock`, then `/tmp/cmux-mux-<uid>/main.sock`. `--session <name>` changes the final file name. `--socket <path>` bypasses the session-derived path. Server-started child processes receive `CMUX_MUX_SOCKET` with the socket path. | ||
|
|
||
| ## Platforms and XDG | ||
|
|
||
| cmux-mux supports macOS and Linux; Windows support via ConPTY is planned for phase 2. The TUI config path resolves `CMUX_MUX_CONFIG`, then `$XDG_CONFIG_HOME/cmux/mux.json`, then `~/.config/cmux/mux.json`. | ||
|
|
||
| Launched Chrome profile paths are platform-specific. On macOS the default is `~/Library/Application Support/cmux-mux/chrome-profile`. On Linux and other non-macOS targets, `XDG_DATA_HOME` is used when set, then `~/.local/share/cmux-mux/chrome-profile`. | ||
|
|
||
| ## Development flow | ||
|
|
||
| Run tests from `mux/`. | ||
|
|
||
| ```bash | ||
| cargo test | ||
| ``` | ||
|
|
||
| Run the smoke scripts against a built binary. Set `CMUX_MUX_BIN` to test a non-default binary. | ||
|
|
||
| ```bash | ||
| cargo build -p mux-tui | ||
| python3 scripts/smoke-tui.py | ||
| python3 scripts/smoke-attach.py | ||
| ``` | ||
|
|
||
| This checkout does not contain `scripts/mux-dev.sh`; use the cargo and smoke commands above for the TUI flow. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fix the socket example so it matches the fallback chain.
The block at Lines 46-50 shows only
$TMPDIR/..., but the rest of this section andmux/scripts/smoke-attach.pyfall back throughXDG_RUNTIME_DIR,TMPDIR, and/tmp. Please update or remove the example so it doesn't contradict the actual lookup order.🤖 Prompt for AI Agents