# Lifecycle & Socket Control

> Contrasts tmux's client-server fork, lock, imsg, and Unix socket lifecycle with cmux's in-app socket listener, access modes, CLI client behavior, and local automation guardrails.

- 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:server.c`
- `tmux-tmux:client.c`
- `tmux-tmux:proc.c`
- `tmux-tmux:control.c`
- `manaflow-ai-cmux:Sources/TerminalController.swift`
- `manaflow-ai-cmux:Sources/SocketControlSettings.swift`
- `manaflow-ai-cmux:CLI/cmux.swift`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [tmux-tmux:server.c](tmux-tmux/server.c)
- [tmux-tmux:client.c](tmux-tmux/client.c)
- [tmux-tmux:proc.c](tmux-tmux/proc.c)
- [tmux-tmux:control.c](tmux-tmux/control.c)
- [tmux-tmux:server-acl.c](tmux-tmux/server-acl.c)
- [manaflow-ai-cmux:Sources/TerminalController.swift](manaflow-ai-cmux/Sources/TerminalController.swift)
- [manaflow-ai-cmux:Sources/SocketControlSettings.swift](manaflow-ai-cmux/Sources/SocketControlSettings.swift)
- [manaflow-ai-cmux:Sources/SocketControlSettings+SocketPathMarkers.swift](manaflow-ai-cmux/Sources/SocketControlSettings+SocketPathMarkers.swift)
- [manaflow-ai-cmux:Sources/cmuxApp.swift](manaflow-ai-cmux/Sources/cmuxApp.swift)
- [manaflow-ai-cmux:Sources/AppDelegate.swift](manaflow-ai-cmux/Sources/AppDelegate.swift)
- [manaflow-ai-cmux:CLI/cmux.swift](manaflow-ai-cmux/CLI/cmux.swift)
- [manaflow-ai-cmux:CLI/CLISocketPathResolver.swift](manaflow-ai-cmux/CLI/CLISocketPathResolver.swift)
</details>

# Lifecycle & Socket Control

This page compares two local-control models. tmux treats the Unix socket as the entrance to a long-lived, forked server process. cmux treats the socket as an in-app listener owned by the macOS app, with explicit modes for local automation, password access, and open access.

The difference matters because both systems solve the same product problem, "let a local CLI control a terminal workspace," but they assign trust and lifecycle ownership differently. tmux optimizes for a durable multiplexer daemon; cmux optimizes for app-mediated control, UI-aware automation, and guardrails around local agents.

## Runtime Ownership Model

tmux starts from a client process that either connects to an existing Unix-domain socket or starts the server. On connect failure, the client uses a `.lock` file with `flock`, retries to avoid racing another starter, unlinks a stale socket, and calls `server_start`. The server path can fork and daemonize through `proc_fork_and_daemon`, then initializes the server process, socket, clients, sessions, and accept loop.

cmux starts socket control from app state. The app computes the effective socket mode, chooses an active path, and calls `TerminalController.shared.start(...)`; if the mode is off, it stops the listener. AppDelegate has a similar startup/restart path, including reservation of an initial socket path before the listener starts.

Sources: [tmux-tmux:client.c:73-180](), [tmux-tmux:server.c:176-235](), [tmux-tmux:proc.c:359-380](), [manaflow-ai-cmux:Sources/cmuxApp.swift:851-865](), [manaflow-ai-cmux:Sources/AppDelegate.swift:3464-3507]()

```mermaid
sequenceDiagram
    participant TmuxCLI as tmux client
    participant TmuxServer as tmux server process
    participant CmuxApp as cmux app
    participant CmuxCLI as cmux CLI

    TmuxCLI->>TmuxServer: connect AF_UNIX socket
    alt socket missing or refused and start allowed
        TmuxCLI->>TmuxCLI: lock socket.lock, retry, unlink stale path
        TmuxCLI->>TmuxServer: fork/daemonize server_start
    end
    TmuxServer->>TmuxCLI: imsg protocol replies

    CmuxApp->>CmuxApp: compute effective SocketControlMode
    CmuxApp->>CmuxApp: bind/listen DispatchSource socket listener
    CmuxCLI->>CmuxApp: newline-delimited command or JSON
    CmuxApp->>CmuxCLI: text or JSON response
```

## Socket Creation, Binding, and Cleanup

tmux creates an `AF_UNIX` stream socket at `socket_path`, unlinks any previous path first, binds with a restrictive `umask`, listens with backlog 128, and makes the server socket nonblocking. The server also updates socket execute bits based on whether any session is attached. On `SIGUSR1`, it recreates the socket and re-adds the accept event.

cmux also creates an `AF_UNIX` stream socket and listens with backlog 128, but it does this inside `TerminalController`. The start path acquires or consumes a socket-path lock, binds the listener, falls back after bind failures when configured to do so, applies permissions from the selected access mode, configures the socket nonblocking, records the last socket path, and posts a listener-start notification. Stop cancels the read source and monitor, shuts down and closes the socket, conditionally unlinks only if the current path identity matches the listener's bound identity, and releases the path lock.

Sources: [tmux-tmux:server.c:105-150](), [tmux-tmux:server.c:331-365](), [tmux-tmux:server.c:431-454](), [manaflow-ai-cmux:Sources/TerminalController.swift:1539-1782](), [manaflow-ai-cmux:Sources/TerminalController.swift:2030-2121](), [manaflow-ai-cmux:Sources/SocketControlSettings+SocketPathMarkers.swift:4-39]()

| Concern | tmux | cmux |
|---|---|---|
| Owner | Forked server process | macOS app singleton controller |
| Socket path cleanup | `unlink` before bind | identity-aware unlink on failed start or stop |
| Backlog | 128 | 128 |
| Permission model | `umask` at bind plus execute-bit updates | explicit mode-derived `chmod` |
| Restart | signal-driven socket recreation | app setting/startup/restart paths |

## Accept Loop and Message Protocol

tmux accepts clients in the server event loop, creates a server-side client object, and checks ACL admission. Once a peer exists, `proc.c` owns the imsg event machinery: it reads messages, checks protocol version, dispatches callbacks, writes queued messages, supports fd passing, and stores peer UID from `getpeereid`. Client startup sends identify messages including flags, terminal name, cwd, stdin/stdout fds, pid, and environment, then sends the initial command over imsg.

cmux uses a `DispatchSourceRead` on the listener socket. Accept drains pending clients in a loop, treats transient accept errors separately from rearm/backoff failures, then hands each client to a socket handler. The protocol is line-oriented: the handler reads newline-delimited UTF-8, supports event-stream requests, dispatches V1 text commands or V2 JSON commands, and writes one response per line.

Sources: [tmux-tmux:server.c:367-408](), [tmux-tmux:proc.c:70-176](), [tmux-tmux:proc.c:301-336](), [tmux-tmux:client.c:343-401](), [tmux-tmux:client.c:448-494](), [manaflow-ai-cmux:Sources/TerminalController.swift:2399-2468](), [manaflow-ai-cmux:Sources/TerminalController.swift:2680-2758](), [manaflow-ai-cmux:Sources/TerminalController.swift:2877-2918]()

## Control Mode Versus cmux CLI Commands

tmux control mode is a protocol mode for clients. It creates per-client control state, bufferevents, pane output queues, and subscriptions. Input lines are parsed as tmux commands, while output ordering is carefully preserved so `%output` blocks can hold later notifications until the pane output has been written.

cmux exposes a much wider CLI surface over its app socket: workspace, pane, browser, feed, auth, notification, and tmux-compatibility commands. The CLI resolves a socket path, connects, authenticates if a socket password is available, and sends newline-terminated text or JSON. It also has special no-socket paths for help, docs, and some settings/config commands, so users can inspect or configure without a running socket.

Sources: [tmux-tmux:control.c:30-44](), [tmux-tmux:control.c:553-583](), [tmux-tmux:control.c:769-817](), [tmux-tmux:control.c:831-854](), [manaflow-ai-cmux:CLI/cmux.swift:2690-3060](), [manaflow-ai-cmux:CLI/cmux.swift:29454-29644]()

## Access Modes and Local Trust

tmux access is UID-based once a peer connects. Server ACL initialization allows root, when the server owner is not root, and the server owner's UID. New clients are admitted only if their peer UID is present; read-only state is copied to the client when the ACL user is marked read-only. The accept callback rejects disallowed clients with `access not allowed`.

cmux exposes access as product modes. `off` disables the listener. `cmuxOnly` allows only processes started inside cmux terminals. `automation` allows external local automation clients from the same macOS user without the ancestry check. `password` requires socket authentication. `allowAll` sets the socket file to `0666` and is explicitly described as unsafe. All non-open modes use `0600` socket permissions.

Sources: [tmux-tmux:server.c:396-400](), [tmux-tmux:server-acl.c:52-63](), [tmux-tmux:server-acl.c:96-119](), [tmux-tmux:server-acl.c:122-179](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:8-62](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:760-776]()

## cmux Automation Guardrails

cmux's default mode is `cmuxOnly`. In that mode, the socket handler verifies the peer PID with `LOCAL_PEERPID` and walks the process tree to confirm the caller descends from the cmux process. If the PID cannot be read, it falls back to `LOCAL_PEERCRED` and requires the same UID. Password mode gates both V1 `auth <password>` and V2 `auth.login` before dispatching commands. The password can come from `CMUX_SOCKET_PASSWORD`, a local Application Support file, or a legacy keychain fallback.

The CLI mirrors those guardrails from the client side. Before connecting to a local socket, it verifies the path exists, is a Unix socket, and is owned by the current user to avoid fake-socket attacks. The CLI also resolves passwords from explicit `--password`, environment, local file, or keychain, then sends `auth <password>` before normal commands.

Sources: [manaflow-ai-cmux:Sources/TerminalController.swift:818-856](), [manaflow-ai-cmux:Sources/TerminalController.swift:2153-2234](), [manaflow-ai-cmux:Sources/TerminalController.swift:2680-2758](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:64-132](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:164-212](), [manaflow-ai-cmux:CLI/cmux.swift:1328-1450](), [manaflow-ai-cmux:CLI/cmux.swift:1710-1764](), [manaflow-ai-cmux:CLI/cmux.swift:4833-4848]()

## Socket Path Discovery

tmux clients target the configured `socket_path` and rely on lock/retry/start behavior when the path is missing or refused. cmux has more path-discovery logic because app variants, debug tags, and stable releases can coexist. `SocketControlSettings.socketPath` honors `CMUX_SOCKET_PATH` only under controlled conditions, reserves stable release paths, and falls back to user-scoped stable paths when another user owns the stable socket. The CLI resolver prefers connectable candidates, then existing socket files, then discovered tagged debug sockets.

Sources: [tmux-tmux:client.c:103-180](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:293-355](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:421-492](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:601-640](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:644-670](), [manaflow-ai-cmux:CLI/CLISocketPathResolver.swift:82-160](), [manaflow-ai-cmux:CLI/CLISocketPathResolver.swift:216-321](), [manaflow-ai-cmux:CLI/CLISocketPathResolver.swift:433-449]()

## Portable Design Lessons

tmux's strongest portable idea is making server startup race-safe: connect, lock, retry, clean stale paths, then start one owner. cmux's strongest portable idea is turning socket exposure into a user-visible access mode, with stricter defaults and client-side fake-socket checks. These ideas are provider-neutral: neither requires a particular AI model, hosted service, or proprietary connector. They can be applied to BYOC/BYOK systems as local process, file, repository, or catalog-level policies around a Unix socket protocol.

A Grok-Wiki or local-agent integration should preserve that neutrality by treating socket control as a local capability boundary: discover a socket path, verify ownership, select an access mode, authenticate only when required, and send explicit commands. Do not couple socket access to a model provider; couple it to local identity, process ancestry, file permissions, and user-approved automation scope.

Sources: [tmux-tmux:client.c:121-165](), [tmux-tmux:server.c:105-144](), [manaflow-ai-cmux:Sources/SocketControlSettings.swift:8-62](), [manaflow-ai-cmux:CLI/cmux.swift:1716-1726]()

## Summary

tmux makes the socket a daemon gateway: the client may bootstrap the server, the server owns accept and imsg dispatch, and ACLs are UID-based. cmux makes the socket an app-controlled automation surface: app settings decide whether the listener runs, access modes shape permissions and authentication, and the CLI adds path discovery plus ownership checks before sending newline-delimited commands. The shared pattern is local Unix socket control; the main architectural difference is whether lifecycle belongs to a detached server or the foreground application runtime. Sources: [tmux-tmux:server.c:176-235](), [manaflow-ai-cmux:Sources/TerminalController.swift:1539-1782]()
