# Project Commands, Surface Buttons & Trust Gates

> The configuration mechanics behind project-specific commands, surface tab bar buttons, notification hooks, workspace commands, and confirmation gates for local automation.

- Repository: manaflow-ai/cmux
- GitHub: https://github.com/manaflow-ai/cmux
- Human wiki: https://grok-wiki.com/public/wiki/manaflow-ai-cmux-5a511656cb1a
- Complete Markdown: https://grok-wiki.com/public/wiki/manaflow-ai-cmux-5a511656cb1a/llms-full.txt

## Source Files

- `Sources/CmuxConfig.swift`
- `Sources/CmuxConfigExecutor.swift`
- `Sources/CmuxSurfaceTabBarBuiltInAction.swift`
- `Sources/WorkspaceActionDispatcher.swift`
- `Sources/Settings/ConfigSettingsView.swift`
- `cmuxTests/CmuxConfigTests.swift`
- `cmuxTests/CmuxConfigContextMenuTests.swift`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [Sources/CmuxConfig.swift](Sources/CmuxConfig.swift)
- [Sources/CmuxConfigExecutor.swift](Sources/CmuxConfigExecutor.swift)
- [Sources/CmuxSurfaceTabBarBuiltInAction.swift](Sources/CmuxSurfaceTabBarBuiltInAction.swift)
- [Sources/WorkspaceActionDispatcher.swift](Sources/WorkspaceActionDispatcher.swift)
- [Sources/Settings/ConfigSettingsView.swift](Sources/Settings/ConfigSettingsView.swift)
- [Sources/CmuxActionTrust.swift](Sources/CmuxActionTrust.swift)
- [Sources/TerminalNotificationPolicy.swift](Sources/TerminalNotificationPolicy.swift)
- [Sources/Workspace.swift](Sources/Workspace.swift)
- [Sources/ContentView.swift](Sources/ContentView.swift)
- [Sources/AppDelegate.swift](Sources/AppDelegate.swift)
- [cmuxTests/CmuxConfigTests.swift](cmuxTests/CmuxConfigTests.swift)
- [cmuxTests/CmuxConfigContextMenuTests.swift](cmuxTests/CmuxConfigContextMenuTests.swift)
</details>

# Project Commands, Surface Buttons & Trust Gates

cmux lets a global or project-local `cmux.json` turn repository knowledge into runnable UI: command-palette actions, surface tab bar buttons, notification policy hooks, and workspace creation flows. The important design point is that these are local automation hooks, not a provider-specific integration layer. The config model can start known agents such as Codex or Claude Code, but it can also run arbitrary shell commands and workspace definitions, which keeps the architecture BYOC/BYOK-friendly.

This page used repository code as source of truth. No `STRATEGY.md` or `docs/solutions/**` files were present in the prepared checkout; the Compound Engineering guidance was available only as bundled prompt context for page shape, not as an installed local repo skill.

Sources: [Sources/CmuxConfig.swift:10-18](), [Sources/CmuxConfig.swift:783-908](), [Sources/CmuxConfig.swift:1030-1095]()

## Mental Model

```text
cmux.json
  actions + commands + ui + notifications
        |
        v
CmuxConfigStore
  merges global/local config, resolves action ids, records source paths
        |
        +--> Command palette / shortcuts
        +--> New workspace button and context menu
        +--> Bonsplit surface tab bar buttons
        +--> Terminal notification policy hooks
        |
        v
CmuxConfigExecutor + CmuxActionTrust
  run once, trust and run, or cancel project-local automation
```

`CmuxConfigStore` is the coordinator. It publishes resolved commands, actions, surface buttons, notification hooks, configuration issues, and source-path metadata. Those source paths matter because the trust gate distinguishes global config from project-local config and fingerprints the exact automation being approved.

Sources: [Sources/CmuxConfig.swift:1831-1853](), [Sources/CmuxConfig.swift:2089-2269](), [Sources/CmuxConfigExecutor.swift:188-241]()

## Configuration Shape

The root config supports these project-automation fields:

| Field | Purpose |
| --- | --- |
| `actions` | Named reusable actions for palette entries, shortcuts, buttons, and new-workspace menus. |
| `commands` | Named commands. Each entry is either a shell command or a workspace definition, never both. |
| `newWorkspaceCommand` | Legacy/direct way to bind the new-workspace action to a workspace command name. |
| `ui.newWorkspace.action` | Action-based replacement for `newWorkspaceCommand`. |
| `ui.newWorkspace.contextMenu` | Ordered new-workspace menu entries, including separators. |
| `ui.surfaceTabBar.buttons` | Current surface tab bar button list. |
| `surfaceTabBarButtons` | Legacy root-level button list. |
| `notifications.hooks` | Local command hooks that can rewrite or suppress notification envelopes. |
| `notifications.hooksMode` | `append` or `replace` behavior for inherited notification hooks. |

The decoder trims and validates sensitive fields. `newWorkspaceCommand` cannot be blank, surface tab bar button ids cannot duplicate, notification hooks require nonblank `id` and `command`, and hook timeouts must be positive. `ui.surfaceTabBar.buttons` takes precedence over the legacy root `surfaceTabBarButtons` field when both are present.

Sources: [Sources/CmuxConfig.swift:10-85](), [Sources/CmuxConfig.swift:127-167](), [Sources/CmuxConfig.swift:188-217]()

## Global, Local, And Hierarchical Resolution

The default global config path is `~/.config/cmux/cmux.json`. A local config is discovered from the selected workspace directory by walking upward and checking `.cmux/cmux.json` and `cmux.json`; if nothing exists, cmux still has a default local target at `.cmux/cmux.json`. For notification hooks, cmux can collect the full config hierarchy from root to leaf rather than only the nearest file.

Local config takes precedence for new-workspace action, context menu, `newWorkspaceCommand`, surface tab buttons, and commands. Global config fills in missing values. Command names are de-duplicated by first-seen name, so a local command with the same name shadows the global one.

Sources: [Sources/CmuxConfig.swift:1859-1862](), [Sources/CmuxConfig.swift:1975-2003](), [Sources/CmuxConfig.swift:2040-2087](), [Sources/CmuxConfig.swift:2125-2186]()

## Actions, Commands, And Provider Neutrality

`actions` are reusable UI actions. An action can be:

| Action type | Runtime meaning |
| --- | --- |
| `builtin` | One of cmux's built-in UI actions. |
| `command` | Shell input sent to a terminal or started in a new tab depending on target. |
| `agent` | Convenience wrapper for known agent commands. |
| `workspaceCommand` | Reference to a named workspace command. |
| no runnable action | Ignored unless overriding metadata on an existing built-in. |

The built-in agent enum currently maps `codex` to `codex` and `claude`/`claudeCode`/`claude-code` to `claude`. That is a convenience, not the architectural boundary: plain `command` actions can run any CLI, including BYOC/BYOK wrappers, locally managed model gateways, or provider-neutral scripts.

`commands` are separate named entries. A command must define either `command` or `workspace`, and the decoder rejects entries that define both or neither. Shell commands can appear in the command palette and run in the current terminal. Workspace commands create configured workspaces with optional cwd, color, restart policy, and layout tree.

Sources: [Sources/CmuxConfig.swift:308-360](), [Sources/CmuxConfig.swift:783-908](), [Sources/CmuxConfig.swift:1030-1095](), [Sources/CmuxConfig.swift:1563-1638]()

## Surface Tab Bar Buttons

Surface tab bar buttons can be legacy strings or objects. Object buttons accept `id`, `title`, `icon`, `tooltip`, exactly one runnable form (`action`, `builtin`, `command`, `agent`, or `type: "workspaceCommand"`), optional `confirm`, and optional terminal `target`. Default buttons are new terminal, new browser, split right, and split down.

Built-in ids are canonicalized. For example, `newTerminal` becomes `cmux.newTerminal`, and several Cloud VM aliases collapse to `cmux.cloudvm`. This lets users write shorter config while the resolver still avoids duplicate alias definitions.

Button actions resolve through the action registry first, then through built-ins. Resolved buttons inherit title, tooltip, icon, confirm, terminal target, and source paths from the referenced action unless the button overrides them. Workspace-command buttons are hidden if their referenced command is missing or is not actually a workspace command.

Sources: [Sources/CmuxSurfaceTabBarBuiltInAction.swift:4-68](), [Sources/CmuxConfig.swift:1125-1210](), [Sources/CmuxConfig.swift:1234-1379](), [Sources/CmuxConfig.swift:2438-2560](), [cmuxTests/CmuxConfigTests.swift:1281-1326]()

### Icons Are Part Of The Trust Surface

Button icons can be SF Symbols, emoji, or image paths. Project-local image paths are restricted: project config cannot use absolute paths, tilde expansion, HTTP(S), or files outside the project root. Images are capped at 1 MB, SVGs are parsed, and unsafe SVG constructs such as scripts, external references, `javascript:`, `data:`, `file:`, and remote URLs are rejected.

Untrusted project-local icons can render as a lock placeholder before trust is granted. This is why the surface button trust descriptor includes an icon fingerprint: changing the local icon can invalidate prior trust.

Sources: [Sources/CmuxConfig.swift:362-445](), [Sources/CmuxConfig.swift:512-579](), [Sources/CmuxConfig.swift:589-730](), [Sources/Workspace.swift:9898-9913](), [cmuxTests/CmuxConfigTests.swift:494-564]()

## Workspace Commands And New Workspace UI

Workspace commands are the high-leverage feature for project onboarding. A repository can define a named workspace, cwd, color, restart behavior, and layout. Layouts are trees of panes and splits, and surfaces can be terminal or browser entries. Tests cover plain workspace commands, restart behaviors, pane layouts, split layouts, and nested split/browser layouts.

When a workspace command runs, `CmuxConfigExecutor` resolves cwd relative to the base cwd, creates a workspace, sets custom title/color, optionally closes an old workspace according to restart behavior, and applies the custom layout. Restart behavior includes `new`, `ignore`, `recreate`, and `confirm`.

Sources: [Sources/CmuxConfig.swift:1641-1765](), [Sources/CmuxConfigExecutor.swift:454-515](), [cmuxTests/CmuxConfigTests.swift:1347-1465]()

### New Workspace Action And Context Menu

The new-workspace button can use `ui.newWorkspace.action` or the older `newWorkspaceCommand`. Action-based config is more flexible because the same action model can target built-ins, shell commands, or workspace commands. If an action points to a workspace command, cmux validates that the named command exists and has a `workspace` body.

The context menu defaults to New Workspace and Cloud VM. A configured empty context menu hides defaults. Context menu entries preserve order, allow separators, resolve built-ins and action overrides, filter invalid workspace command actions, and surface configuration issues for missing or non-workspace command references.

Sources: [Sources/CmuxConfig.swift:1831-1835](), [Sources/CmuxConfig.swift:2596-2674](), [Sources/CmuxConfig.swift:2676-2747](), [Sources/AppDelegate.swift:6692-6725](), [cmuxTests/CmuxConfigContextMenuTests.swift:39-99](), [cmuxTests/CmuxConfigContextMenuTests.swift:312-370]()

## Command Palette And Shortcuts

Resolved actions can enter the command palette when `palette` is enabled. Built-ins are not returned as custom palette actions, but command definitions are automatically converted into actions when no explicit action id exists for the command. Action shortcuts are supported as a single string such as `cmd+shift+c` or a one/two-stroke chord array.

Built-in palette commands also consult the config action registry before falling back to hardcoded behavior. For example, New Terminal, New Browser, Split Right, and Split Down first try `executeConfiguredAction` for their canonical built-in ids, then fall back to the app default.

Sources: [Sources/CmuxConfig.swift:2375-2436](), [Sources/CmuxConfig.swift:2571-2594](), [Sources/ContentView.swift:7308-7335](), [Sources/ContentView.swift:7468-7490](), [Sources/ContentView.swift:7858-7892](), [cmuxTests/CmuxConfigTests.swift:586-622]()

## Trust Gates For Project Automation

The trust gate is deliberately source-aware. Global config actions are authorized automatically. Project-local config actions prompt unless the exact trust descriptor is already trusted and the action does not explicitly request `confirm`. The dialog offers Run Once, Trust and Run, or Cancel. Trust and Run stores a fingerprint in Application Support under `cmux/trusted-actions.json`.

The fingerprint includes schema version, action id, kind, command or workspace command payload, target, config path, project root, and project-local icon fingerprint. That makes trust content-addressed to the automation definition rather than a blanket repository approval.

Sources: [Sources/CmuxConfigExecutor.swift:188-241](), [Sources/CmuxConfigExecutor.swift:275-326](), [Sources/CmuxConfigExecutor.swift:328-437](), [Sources/CmuxActionTrust.swift:4-25](), [Sources/CmuxActionTrust.swift:27-76]()

### Execution Paths

Terminal commands are sanitized for display, approved, then sent with a trailing newline. Actions default to opening a new tab in the current pane, while command definitions default to the current terminal path. Workspace commands go through the same authorization boundary, then call the workspace creation path.

Surface tab bar executable buttons have three branches: non-Bonsplit built-ins such as New Workspace and Cloud VM, workspace commands, and terminal commands. Workspace buttons focus the pane first, derive a base cwd from the pane or workspace, then execute through `CmuxConfigExecutor`. Terminal buttons use the same shell-input authorization path and then send input to the current terminal or create a new tab depending on target.

Sources: [Sources/CmuxConfigExecutor.swift:7-65](), [Sources/CmuxConfigExecutor.swift:68-161](), [Sources/Workspace.swift:16766-16845](), [Sources/AppDelegate.swift:13847-13863]()

## Notification Hooks

Notification hooks are command-line policy filters. Global hooks run without project trust descriptors; local hooks get `notificationHook` trust descriptors and must be approved unless already trusted. Hooks are disabled when `enabled` is false, use a default timeout of 20 seconds, and run with cwd set to the project root for their config file.

Hook inheritance starts with global hooks, then applies local configs in hierarchy order. A local config with `hooksMode: "replace"` clears previously inherited hooks before appending its own. Tests verify append order, disabled hooks, cwd selection, explicit local configs outside the discovered hierarchy, and replacement behavior.

Sources: [Sources/CmuxConfig.swift:146-167](), [Sources/CmuxConfig.swift:2005-2019](), [Sources/CmuxConfig.swift:2271-2343](), [cmuxTests/CmuxConfigTests.swift:951-1131]()

At runtime, the notification policy engine passes an envelope through hooks in order. Each hook receives sorted JSON on stdin and environment variables such as `CMUX_NOTIFICATION_TITLE`, `CMUX_NOTIFICATION_SUBTITLE`, `CMUX_NOTIFICATION_BODY`, `CMUX_NOTIFICATION_WORKSPACE_ID`, `CMUX_NOTIFICATION_SURFACE_ID`, and `CMUX_NOTIFICATION_POLICY_JSON`. Hooks run via `/bin/sh -c`, with stdout capped and stderr separately buffered.

Sources: [Sources/TerminalNotificationPolicy.swift:231-312](), [Sources/TerminalNotificationPolicy.swift:314-371](), [Sources/TerminalNotificationPolicy.swift:419-561]()

## Settings And Feedback Loops

The Config Settings window gives users a direct editor for the cmux config and a read-only preview for the effective synced config. Save writes the cmux config and reloads configuration; Reload refreshes from disk and asks `GhosttyApp` to reload configuration. The view also exposes paths, open-in-editor, and reveal-in-Finder affordances.

Schema and resolution issues are not silent. `CmuxConfigStore` records `schemaError`, `newWorkspaceActionNotFound`, `newWorkspaceCommandNotFound`, and `newWorkspaceCommandRequiresWorkspace`; the command palette can surface those issues so users can jump to the source config.

Sources: [Sources/Settings/ConfigSettingsView.swift:43-150](), [Sources/Settings/ConfigSettingsView.swift:186-263](), [Sources/CmuxConfig.swift:1778-1828](), [Sources/CmuxConfig.swift:2860-2935](), [Sources/ContentView.swift:7308-7318](), [Sources/ContentView.swift:7922-7929]()

## Feature Scout Notes

The reusable idea worth copying is the combination of project-local automation and content-addressed approval. cmux does not hardcode a model provider into the trust system; it fingerprints the actual local command, workspace definition, target, config path, project root, and icon content. That pattern supports BYOC/BYOK because teams can plug in their own CLI, local broker, model gateway, or hosted agent wrapper while keeping one UI and one confirmation model.

A Grok-Wiki integration should keep the same boundary: treat skill packs and generated wiki recipes as portable file, repository, or catalog sources; resolve them into local commands or actions; and route execution through the same trust-descriptor mechanism rather than special-casing a proprietary connector.

Sources: [Sources/CmuxConfig.swift:2375-2436](), [Sources/CmuxConfigExecutor.swift:328-437](), [Sources/CmuxActionTrust.swift:4-25]()
