# Command & Config Surfaces

> Shows how tmux exposes a grammar, command queue, options, key bindings, and config loading, while cmux layers JSONC project config, command execution, Ghostty config compatibility, and CLI configuration commands.

- Repository: tmux/tmux-with-manaflow-ai-cmux
- GitHub: https://github.com/tmux/tmux
- Human wiki: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc
- Complete Markdown: https://grok-wiki.com/public/wiki/tmux-tmux-with-manaflow-ai-cmux-62db34dfaddc/llms-full.txt

## Source Files

- `tmux-tmux:cmd-parse.y`
- `tmux-tmux:cmd-queue.c`
- `tmux-tmux:cfg.c`
- `tmux-tmux:options.c`
- `tmux-tmux:key-bindings.c`
- `manaflow-ai-cmux:Sources/CmuxConfig.swift`
- `manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift`
- `manaflow-ai-cmux:Sources/GhosttyConfig.swift`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:cmd-parse.y](tmux-tmux/cmd-parse.y)
- [tmux-tmux:cmd-queue.c](tmux-tmux/cmd-queue.c)
- [tmux-tmux:cfg.c](tmux-tmux/cfg.c)
- [tmux-tmux:options.c](tmux-tmux/options.c)
- [tmux-tmux:key-bindings.c](tmux-tmux/key-bindings.c)
- [tmux-tmux:cmd-bind-key.c](tmux-tmux/cmd-bind-key.c)
- [tmux-tmux:cmd-set-option.c](tmux-tmux/cmd-set-option.c)
- [manaflow-ai-cmux:Sources/CmuxConfig.swift](manaflow-ai-cmux/Sources/CmuxConfig.swift)
- [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift)
- [manaflow-ai-cmux:Sources/GhosttyConfig.swift](manaflow-ai-cmux/Sources/GhosttyConfig.swift)
- [manaflow-ai-cmux:Sources/CmuxWorkspaceDefinition.swift](manaflow-ai-cmux/Sources/CmuxWorkspaceDefinition.swift)
- [manaflow-ai-cmux:Sources/JSONCParser.swift](manaflow-ai-cmux/Sources/JSONCParser.swift)
- [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift)
- [manaflow-ai-cmux:cmuxTests/CmuxConfigTests.swift](manaflow-ai-cmux/cmuxTests/CmuxConfigTests.swift)
</details>

# Command & Config Surfaces

tmux and cmux both expose user-programmable command surfaces, but they choose different center points. tmux treats configuration, key bindings, hooks, and command prompts as one command language: parse text into command lists, enqueue command items, and execute them through a shared queue. cmux uses JSONC as the product-facing config shape, resolves actions and commands into UI or workspace behavior, then uses shell input, workspace creation, Ghostty-compatible parsing, and CLI helpers as execution/configuration surfaces.

This matters because both projects need extensibility without hard-wiring one automation vendor or hosted service. tmux stays portable by making the terminal multiplexer itself the grammar and runtime. cmux stays BYOC/BYOK-friendly by making config files, shell commands, local paths, and app-owned trust decisions the boundaries rather than assuming a particular model provider.

## Surface Map

| Area | tmux | cmux |
| --- | --- | --- |
| Primary config language | tmux command grammar in `cmd-parse.y` | JSONC decoded into `CmuxConfigFile` and related Codable structs |
| Execution unit | `struct cmdq_item` containing command/callback state | `CmuxResolvedConfigAction` or `CmuxCommandDefinition` executed by `CmuxConfigExecutor` |
| Config load | Config files parse into command lists and append to the global command queue | Global and local `cmux.json` files are parsed, merged, cached, and watched |
| Options | Runtime option tree with parent lookup, type parsing, arrays, and command-valued options | Structured fields for UI, actions, notifications, vault, commands, and workspace definitions |
| Key/action binding | Key tables store key-to-`cmd_list` bindings | Surface tab buttons, palette actions, shortcuts, workspace commands, and terminal commands |
| Compatibility layer | Native tmux command syntax | Ghostty config load order and key-value parser for terminal appearance/behavior |

Sources: [tmux-tmux:cmd-parse.y:42-90](tmux-tmux/cmd-parse.y#L42-L90), [tmux-tmux:cmd-queue.c:35-94](tmux-tmux/cmd-queue.c#L35-L94), [manaflow-ai-cmux:Sources/CmuxConfig.swift:10-85](manaflow-ai-cmux/Sources/CmuxConfig.swift#L10-L85), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:8-65](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L8-L65), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:183-240](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L183-L240)

## tmux: Grammar First, Queue Second

tmux’s command parser builds an intermediate parse tree with command arguments that can be strings, nested commands, or already-parsed command lists. The yacc grammar handles statements, conditions, expanded formats, and command arguments before `cmd_parse_build_command` converts the parsed arguments into `args_value` entries and calls `cmd_parse`. Alias expansion is also part of the parser path, so aliases are resolved before the final command list is built.

```text
tmux config/key/prompt text
        |
        v
cmd-parse.y grammar + aliases
        |
        v
struct cmd_list
        |
        v
cmdq_get_command -> cmdq_append / cmdq_insert_after
        |
        v
cmdq_next -> cmdq_fire_command -> entry->exec
```

The command queue is the runtime boundary. A `cmdq_item` holds the command or callback, shared queue state, source/target find states, client references, grouping, and waiting/fired flags. `cmdq_get_command` expands a `cmd_list` into linked queue items, and `cmdq_next` fires command or callback items until the queue is empty or a command returns wait. Errors remove later commands in the same group.

Sources: [tmux-tmux:cmd-parse.y:120-215](tmux-tmux/cmd-parse.y#L120-L215), [tmux-tmux:cmd-parse.y:438-470](tmux-tmux/cmd-parse.y#L438-L470), [tmux-tmux:cmd-parse.y:768-865](tmux-tmux/cmd-parse.y#L768-L865), [tmux-tmux:cmd-queue.c:493-537](tmux-tmux/cmd-queue.c#L493-L537), [tmux-tmux:cmd-queue.c:730-800](tmux-tmux/cmd-queue.c#L730-L800)

### Config Files Are Command Sources

tmux does not give config files a separate object model. `start_cfg` loads configured files without a client and appends a completion callback to the global queue. `load_cfg` opens the file, sets parse metadata such as file, line, client, and current item, parses via `cmd_parse_from_file`, and turns the resulting command list into queue items. Buffer-backed config loading follows the same pattern via `cmd_parse_from_buffer`.

The key design consequence: config loading, command strings, key bindings, hooks, and source-file behavior all share the same command grammar and queue semantics.

Sources: [tmux-tmux:cfg.c:64-92](tmux-tmux/cfg.c#L64-L92), [tmux-tmux:cfg.c:95-150](tmux-tmux/cfg.c#L95-L150), [tmux-tmux:cfg.c:155-202](tmux-tmux/cfg.c#L155-L202), [tmux-tmux:cmd-parse.y:938-1032](tmux-tmux/cmd-parse.y#L938-L1032)

### Options and Hooks Reuse the Parser

tmux options are stored in red-black trees with parent lookup. Option names support direct lookup, mapped names, array indexes like `name[3]`, prefix matching, and user options beginning with `@`. Command-valued options are parsed through `cmd_parse_from_string`, both for defaults and for `options_from_string`.

`set-option`, `set-window-option`, and `set-hook` all share `cmd_set_option_exec`. That command expands the option name, resolves the option scope, validates indexes and `-o` behavior, parses typed values, updates arrays or scalar options, and pushes option changes.

Sources: [tmux-tmux:options.c:50-68](tmux-tmux/options.c#L50-L68), [tmux-tmux:options.c:216-240](tmux-tmux/options.c#L216-L240), [tmux-tmux:options.c:257-296](tmux-tmux/options.c#L257-L296), [tmux-tmux:options.c:624-727](tmux-tmux/options.c#L624-L727), [tmux-tmux:options.c:1098-1176](tmux-tmux/options.c#L1098-L1176), [tmux-tmux:cmd-set-option.c:83-205](tmux-tmux/cmd-set-option.c#L83-L205), [tmux-tmux:cmd-set-option.c:203-260](tmux-tmux/cmd-set-option.c#L203-L260)

### Key Bindings Store Command Lists

`bind-key` accepts either parsed command arguments or a string that is parsed into a command list. `key_bindings_add` stores the resulting `cmd_list` in a key table. Defaults are themselves strings parsed through `cmd_parse_from_string` and appended to the global queue during key binding initialization. Dispatching a key builds a new command queue state from the current key event and target state, then appends or inserts the bound command list.

Sources: [tmux-tmux:cmd-bind-key.c:35-106](tmux-tmux/cmd-bind-key.c#L35-L106), [tmux-tmux:key-bindings.c:106-124](tmux-tmux/key-bindings.c#L106-L124), [tmux-tmux:key-bindings.c:191-226](tmux-tmux/key-bindings.c#L191-L226), [tmux-tmux:key-bindings.c:650-679](tmux-tmux/key-bindings.c#L650-L679), [tmux-tmux:key-bindings.c:690-719](tmux-tmux/key-bindings.c#L690-L719)

## cmux: JSONC Model, Resolved Actions, Explicit Trust

cmux starts with structured config. `CmuxConfigFile` contains actions, UI, notifications, `newWorkspaceCommand`, surface tab bar buttons, commands, and vault configuration. Commands are stricter than tmux command strings: a `CmuxCommandDefinition` must have a non-blank name and exactly one runnable form, either `workspace` or `command`. A workspace command can carry name, cwd, color, and layout through `CmuxWorkspaceDefinition`.

```swift
// manaflow-ai-cmux:Sources/CmuxConfig.swift
struct CmuxCommandDefinition: Codable, Sendable, Identifiable {
    var name: String
    var workspace: CmuxWorkspaceDefinition?
    var command: String?
    var confirm: Bool?
}
```

Sources: [manaflow-ai-cmux:Sources/CmuxConfig.swift:10-85](manaflow-ai-cmux/Sources/CmuxConfig.swift#L10-L85), [manaflow-ai-cmux:Sources/CmuxConfig.swift:1563-1638](manaflow-ai-cmux/Sources/CmuxConfig.swift#L1563-L1638), [manaflow-ai-cmux:Sources/CmuxWorkspaceDefinition.swift:3-36](manaflow-ai-cmux/Sources/CmuxWorkspaceDefinition.swift#L3-L36), [manaflow-ai-cmux:cmuxTests/CmuxConfigTests.swift:36-100](manaflow-ai-cmux/cmuxTests/CmuxConfigTests.swift#L36-L100)

### Global and Local Config Resolution

cmux has a layered config model rather than one global command queue. The default global path is `~/.config/cmux/cmux.json`. Local project config is discovered by walking upward and checking `.cmux/cmux.json` and `cmux.json`, with hierarchy results reversed so parent configs can be considered before deeper configs. During `loadAll`, local config takes precedence for workspace action, context menu, new workspace command, surface buttons, and command names; global config fills missing pieces.

Actions are then resolved into a registry seeded with built-ins. Global actions are applied first, local actions second, and commands become custom resolved actions when no action with the same command id exists.

Sources: [manaflow-ai-cmux:Sources/CmuxConfig.swift:1854-1862](manaflow-ai-cmux/Sources/CmuxConfig.swift#L1854-L1862), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2021-2088](manaflow-ai-cmux/Sources/CmuxConfig.swift#L2021-L2088), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2120-2250](manaflow-ai-cmux/Sources/CmuxConfig.swift#L2120-L2250), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2375-2430](manaflow-ai-cmux/Sources/CmuxConfig.swift#L2375-L2430), [manaflow-ai-cmux:cmuxTests/CmuxConfigTests.swift:337-380](manaflow-ai-cmux/cmuxTests/CmuxConfigTests.swift#L337-L380)

### JSONC Parsing Is a Compatibility Layer, Not a Runtime

cmux accepts JSONC by preprocessing files before `JSONDecoder` sees them. The parser detects common JSON encodings, strips a BOM, removes line and block comments outside strings, removes legal trailing commas, and reports malformed trailing commas or unterminated block comments. `parseConfig` caches by file size, modification date, and workspace color palette fingerprint, then stores either decoded config or a schema issue.

This keeps the product surface friendly for hand-edited config files while preserving a typed Swift runtime model.

Sources: [manaflow-ai-cmux:Sources/JSONCParser.swift:3-10](manaflow-ai-cmux/Sources/JSONCParser.swift#L3-L10), [manaflow-ai-cmux:Sources/JSONCParser.swift:12-78](manaflow-ai-cmux/Sources/JSONCParser.swift#L12-L78), [manaflow-ai-cmux:Sources/JSONCParser.swift:80-146](manaflow-ai-cmux/Sources/JSONCParser.swift#L80-L146), [manaflow-ai-cmux:Sources/JSONCParser.swift:148-220](manaflow-ai-cmux/Sources/JSONCParser.swift#L148-L220), [manaflow-ai-cmux:Sources/CmuxConfig.swift:2829-2897](manaflow-ai-cmux/Sources/CmuxConfig.swift#L2829-L2897)

## cmux Execution Surfaces

`CmuxConfigExecutor` separates two runnable forms. Workspace commands create or select workspaces, resolve cwd relative to a base cwd, set custom title/color, and apply layout. Terminal commands are sanitized, authorized, suffixed with a newline, and sent either to the current terminal or a new tab in the current pane.

Project-local config is treated as a trust boundary. If the action comes from the global config path, it runs directly. If it comes from a project path, cmux checks a trust descriptor and optional confirmation before executing. This is the main difference from tmux: tmux trusts its command stream once parsed, while cmux distinguishes global/user-owned config from project-local automation.

Sources: [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:8-65](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L8-L65), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:68-118](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L68-L118), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:125-160](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L125-L160), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:188-241](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L188-L241), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:454-515](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L454-L515)

## Ghostty Compatibility as Config Input

cmux also reads Ghostty config for terminal behavior and appearance. The loader matches Ghostty’s macOS load order, including XDG paths, Application Support paths, conditional legacy config inclusion, and cmux app-support config paths. The parser handles simple `key=value` directives for font, font size, theme, working directory, scrollback, background/foreground/cursor colors, opacity, and blur.

Recursive `config-file` directives are collected after each file is parsed. Included paths are expanded for `~`, resolved relative to the parent directory when needed, and read with a loaded-path set for recursive includes. This makes Ghostty compatibility an adapter layer around local files rather than a separate remote dependency.

Sources: [manaflow-ai-cmux:Sources/GhosttyConfig.swift:82-130](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L82-L130), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:183-240](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L183-L240), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:370-455](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L370-L455), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:510-646](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L510-L646), [manaflow-ai-cmux:Sources/GhosttyConfig.swift:962-968](manaflow-ai-cmux/Sources/GhosttyConfig.swift#L962-L968)

## CLI Configuration Commands

cmux exposes config operations through `cmux config`. The CLI supports path/docs output, `doctor|check|validate`, and `reload`. `reload` connects to a socket-backed app command path and sends `reload_config`; the non-socket subcommands can run without a running app. `config doctor` validates JSONC syntax by preprocessing, requiring a top-level JSON object, and reporting keys, bytes, status, and errors.

This is a more explicit support surface than tmux’s config parser: tmux reports config parse/runtime causes through command queue output and control mode, while cmux gives users a separate inspection and validation command for config files before reload.

Sources: [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:3-67](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L3-L67), [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:69-136](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L69-L136), [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:198-210](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L198-L210), [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:300-325](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L300-L325), [manaflow-ai-cmux:CLI/CMUXCLI+Config.swift:327-423](manaflow-ai-cmux/CLI/CMUXCLI+Config.swift#L327-L423), [tmux-tmux:cfg.c:222-258](tmux-tmux/cfg.c#L222-L258)

## Portable Design Lessons

| Lesson | tmux evidence | cmux evidence | Portable idea |
| --- | --- | --- | --- |
| Keep one runtime command representation | Parsed text becomes `cmd_list`, then `cmdq_item` | JSONC becomes resolved actions/commands before execution | Normalize inputs before executing them |
| Treat config as code only when the language is the product | `.tmux.conf` is tmux command syntax | `cmux.json` is typed config, not a shell script | Choose grammar when scripting is the feature; choose schema when UX and validation matter |
| Preserve local-first control | Config files are local and queued in-process | JSONC, Ghostty config, shell commands, and paths are local surfaces | BYOC/BYOK-friendly systems should accept file and process boundaries without requiring hosted providers |
| Make unsafe/project-local automation visible | tmux has no project-local trust layer in these files | cmux checks trust descriptors for non-global config before action execution | Project config should be considered a different trust surface from user global config |

Sources: [tmux-tmux:cmd-parse.y:983-1032](tmux-tmux/cmd-parse.y#L983-L1032), [tmux-tmux:cmd-queue.c:597-684](tmux-tmux/cmd-queue.c#L597-L684), [manaflow-ai-cmux:Sources/CmuxConfig.swift:1563-1638](manaflow-ai-cmux/Sources/CmuxConfig.swift#L1563-L1638), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:188-241](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L188-L241)

## Summary

tmux is strongest when every user-facing surface can be expressed as tmux commands: config files, hooks, options, and key bindings all converge on `cmd_parse` and `cmdq`. cmux is strongest when product configuration must be inspectable, mergeable, project-aware, and safer for local automation: JSONC is decoded into typed definitions, resolved into app actions, guarded at project boundaries, and supported by CLI validation plus Ghostty config compatibility. Both designs are provider-neutral because their extension points are local grammar, files, commands, paths, and process execution rather than a required cloud or model provider. Sources: [tmux-tmux:key-bindings.c:690-719](tmux-tmux/key-bindings.c#L690-L719), [manaflow-ai-cmux:Sources/CmuxConfigExecutor.swift:125-160](manaflow-ai-cmux/Sources/CmuxConfigExecutor.swift#L125-L160)
