From be7c2a1a5a8f53049dc1ef3b961a3d46586b82b6 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Tue, 22 Sep 2026 22:58:31 -0700 Subject: [PATCH] Make the shortcut reference list every action the schema accepts skills/cmux-keyboard-shortcuts/SKILL.md tells agents "Do not invent action IDs. Validate against the schema or shortcut-actions.md." The reference listed 119 of the schema's 154 ids, so an agent binding openDiffViewer, openTeamPicker, newCloudMachine, markWorkspaceDone, sendCtrlFToTerminal, any of the 11 diffViewer* ids, or any of the four resize-pane-* ids was told it had invented a valid action. The file claimed to be auto-generated and was not. The 36 missing ids are added under their existing groups, plus one new "Markdown and diff viewer" group, and tests/test_cmux_settings_supported_paths.py now asserts the file and the schema enum agree in both directions. cmux-skill-contract.yml already triggers on web/data/cmux.schema.json, so the guard fires on the change that introduces drift rather than at the next audit. all-keys.md carried the same false "Auto-generated" header and also lags the schema. Its header now says what is true. Generating it properly needs type, default, and description extraction and is left as follow-up. Two unrelated fixes in the same surface: - skills/cmux-workspace/SKILL.md hand-set CMUX_SOCKET_PATH and invoked the ambient cmux binary, the exact path CLAUDE.md routes around because it "can target the user's main app socket". It now uses the scrubbed helper. - skills/cmux-review/SKILL.md referred to a vocabulary "already exercised by Cultist". That word appeared exactly once in the repository, so no reader could resolve it. Verified: the new assertion fails when an id is removed from the reference and passes when restored; the full file is 7/7 green; sync-test-wiring --check is ok across 1038 test files. Co-Authored-By: Claude Opus 5 --- skills/cmux-review/SKILL.md | 2 +- skills/cmux-settings/references/all-keys.md | 4 +- .../references/shortcut-actions.md | 173 +++++++++++------- skills/cmux-workspace/SKILL.md | 2 +- tests/test_cmux_settings_supported_paths.py | 38 ++++ 5 files changed, 150 insertions(+), 69 deletions(-) diff --git a/skills/cmux-review/SKILL.md b/skills/cmux-review/SKILL.md index 0d226b736afb..e4cedc026beb 100644 --- a/skills/cmux-review/SKILL.md +++ b/skills/cmux-review/SKILL.md @@ -125,7 +125,7 @@ A vague concern is a hypothesis, not a finding. ### Preserve epistemic provenance -Use the repository-evidence vocabulary already exercised by Cultist: +Use the repository-evidence vocabulary: - `PROVEN` — exact machine fact or guarantee established by direct evidence; - `DERIVED` — deterministic conclusion from explicit facts; diff --git a/skills/cmux-settings/references/all-keys.md b/skills/cmux-settings/references/all-keys.md index 68c3b1c24e28..ad47b533cd68 100644 --- a/skills/cmux-settings/references/all-keys.md +++ b/skills/cmux-settings/references/all-keys.md @@ -1,6 +1,8 @@ # All settings keys -Auto-generated from `web/data/cmux.schema.json`. For the rendered docs, see `https://cmux.com/docs/configuration`. +Hand-maintained from `web/data/cmux.schema.json` and known to lag it. The schema is +authoritative; `cmux-settings list-supported` enumerates what the helper accepts. For the +rendered docs, see `https://cmux.com/docs/configuration`. ## app diff --git a/skills/cmux-settings/references/shortcut-actions.md b/skills/cmux-settings/references/shortcut-actions.md index ef1fb90e97cd..e78d597e7e45 100644 --- a/skills/cmux-settings/references/shortcut-actions.md +++ b/skills/cmux-settings/references/shortcut-actions.md @@ -1,6 +1,8 @@ # Keyboard shortcut action ids -Auto-generated from `web/data/cmux.schema.json` (`shortcuts.bindings.propertyNames.enum`). +Every action id in `web/data/cmux.schema.json` +(`shortcuts.bindings.propertyNames.enum`). `tests/test_cmux_settings_supported_paths.py` +fails if this list and the schema disagree, so an id missing here is a bug in this file. Values for `shortcuts.bindings.`: @@ -10,93 +12,107 @@ Values for `shortcuts.bindings.`: ## App -- `shortcuts.bindings.openSettings` -- `shortcuts.bindings.reloadConfiguration` -- `shortcuts.bindings.showHideAllWindows` +- `shortcuts.bindings.closeWindow` - `shortcuts.bindings.globalSearch` - `shortcuts.bindings.newWindow` -- `shortcuts.bindings.closeWindow` -- `shortcuts.bindings.toggleFullScreen` -- `shortcuts.bindings.quit` - `shortcuts.bindings.openFolder` +- `shortcuts.bindings.openSettings` +- `shortcuts.bindings.openTeamPicker` +- `shortcuts.bindings.quit` +- `shortcuts.bindings.reloadConfiguration` - `shortcuts.bindings.sendFeedback` +- `shortcuts.bindings.showHideAllWindows` +- `shortcuts.bindings.toggleFullScreen` ## Tabs -- `shortcuts.bindings.newTab` +- `shortcuts.bindings.closeOtherTabsInPane` +- `shortcuts.bindings.closeTab` - `shortcuts.bindings.newBrowserWorkspace` -- `shortcuts.bindings.reopenPreviousSession` +- `shortcuts.bindings.newTab` - `shortcuts.bindings.renameTab` -- `shortcuts.bindings.closeTab` -- `shortcuts.bindings.closeOtherTabsInPane` +- `shortcuts.bindings.reopenPreviousSession` ## Workspace -- `shortcuts.bindings.goToWorkspace` -- `shortcuts.bindings.selectWorkspaceByNumber` -- `shortcuts.bindings.renameWorkspace` -- `shortcuts.bindings.editWorkspaceDescription` - `shortcuts.bindings.closeWorkspace` -- `shortcuts.bindings.newWorkspaceGroup` +- `shortcuts.bindings.cycleWorkspaceStatus` +- `shortcuts.bindings.editWorkspaceDescription` +- `shortcuts.bindings.goToWorkspace` - `shortcuts.bindings.groupSelectedWorkspaces` -- `shortcuts.bindings.toggleFocusedWorkspaceGroupCollapsed` -- `shortcuts.bindings.reopenClosedWorkspace` -- `shortcuts.bindings.reopenClosedBrowserPanel` (legacy ID for **Reopen Last Closed**) -- `shortcuts.bindings.moveWorkspaceUp` +- `shortcuts.bindings.markWorkspaceDone` - `shortcuts.bindings.moveWorkspaceDown` +- `shortcuts.bindings.moveWorkspaceUp` +- `shortcuts.bindings.newCloudMachine` +- `shortcuts.bindings.newCloudWorkspace` +- `shortcuts.bindings.newWorkspaceGroup` +- `shortcuts.bindings.renameWorkspace` +- `shortcuts.bindings.reopenClosedBrowserPanel` +- `shortcuts.bindings.reopenClosedWorkspace` +- `shortcuts.bindings.selectWorkspaceByNumber` +- `shortcuts.bindings.toggleFocusedWorkspaceGroupCollapsed` ## Panes and surfaces -- `shortcuts.bindings.nextSurface` -- `shortcuts.bindings.prevSurface` +- `shortcuts.bindings.attachTextBoxFile` +- `shortcuts.bindings.clearScreenKeepScrollback` +- `shortcuts.bindings.cycleTextBoxSubmitAction` +- `shortcuts.bindings.decreaseWorkspaceTerminalFontSize` +- `shortcuts.bindings.equalizeSplits` +- `shortcuts.bindings.focusDown` +- `shortcuts.bindings.focusHistoryBack` +- `shortcuts.bindings.focusHistoryForward` +- `shortcuts.bindings.focusLeft` +- `shortcuts.bindings.focusNextPane` +- `shortcuts.bindings.focusPreviousPane` +- `shortcuts.bindings.focusRight` +- `shortcuts.bindings.focusTextBoxInput` +- `shortcuts.bindings.focusUp` +- `shortcuts.bindings.increaseWorkspaceTerminalFontSize` - `shortcuts.bindings.moveSurfaceLeft` - `shortcuts.bindings.moveSurfaceRight` -- `shortcuts.bindings.moveSurfaceToPreviousPane` - `shortcuts.bindings.moveSurfaceToNextPane` +- `shortcuts.bindings.moveSurfaceToPaneDown` - `shortcuts.bindings.moveSurfaceToPaneLeft` - `shortcuts.bindings.moveSurfaceToPaneRight` - `shortcuts.bindings.moveSurfaceToPaneUp` -- `shortcuts.bindings.moveSurfaceToPaneDown` -- `shortcuts.bindings.selectSurfaceByNumber` +- `shortcuts.bindings.moveSurfaceToPreviousPane` - `shortcuts.bindings.newSurface` -- `shortcuts.bindings.toggleTerminalCopyMode` -- `shortcuts.bindings.clearScreenKeepScrollback` +- `shortcuts.bindings.nextSurface` +- `shortcuts.bindings.prevSurface` +- `shortcuts.bindings.resetWorkspaceTerminalFontSize` +- `shortcuts.bindings.resize-pane-down` +- `shortcuts.bindings.resize-pane-left` +- `shortcuts.bindings.resize-pane-right` +- `shortcuts.bindings.resize-pane-up` +- `shortcuts.bindings.selectSurfaceByNumber` - `shortcuts.bindings.simulatorHome` - `shortcuts.bindings.simulatorRotateLeft` - `shortcuts.bindings.simulatorRotateRight` - `shortcuts.bindings.simulatorToggleAppearance` - `shortcuts.bindings.simulatorToggleSoftwareKeyboard` -- `shortcuts.bindings.focusLeft` -- `shortcuts.bindings.focusRight` -- `shortcuts.bindings.focusUp` -- `shortcuts.bindings.focusDown` -- `shortcuts.bindings.focusPreviousPane` -- `shortcuts.bindings.focusNextPane` -- `shortcuts.bindings.splitRight` - `shortcuts.bindings.splitDown` +- `shortcuts.bindings.splitRight` - `shortcuts.bindings.toggleSplitZoom` -- `shortcuts.bindings.increaseWorkspaceTerminalFontSize` -- `shortcuts.bindings.decreaseWorkspaceTerminalFontSize` -- `shortcuts.bindings.resetWorkspaceTerminalFontSize` -- `shortcuts.bindings.equalizeSplits` +- `shortcuts.bindings.toggleTerminalCopyMode` ## Canvas -- `shortcuts.bindings.toggleCanvasLayout` -- `shortcuts.bindings.canvasRevealFocusedPane` -- `shortcuts.bindings.canvasOverview` -- `shortcuts.bindings.canvasZoomIn` -- `shortcuts.bindings.canvasZoomOut` -- `shortcuts.bindings.canvasZoomReset` -- `shortcuts.bindings.canvasTidy` +- `shortcuts.bindings.canvasAlignBottom` - `shortcuts.bindings.canvasAlignLeft` - `shortcuts.bindings.canvasAlignRight` - `shortcuts.bindings.canvasAlignTop` -- `shortcuts.bindings.canvasAlignBottom` -- `shortcuts.bindings.canvasEqualizeWidths` -- `shortcuts.bindings.canvasEqualizeHeights` - `shortcuts.bindings.canvasDistributeHorizontally` - `shortcuts.bindings.canvasDistributeVertically` +- `shortcuts.bindings.canvasEqualizeHeights` +- `shortcuts.bindings.canvasEqualizeWidths` +- `shortcuts.bindings.canvasOverview` +- `shortcuts.bindings.canvasRevealFocusedPane` +- `shortcuts.bindings.canvasTidy` +- `shortcuts.bindings.canvasZoomIn` +- `shortcuts.bindings.canvasZoomOut` +- `shortcuts.bindings.canvasZoomReset` +- `shortcuts.bindings.toggleCanvasLayout` ## Command palette @@ -106,43 +122,46 @@ Values for `shortcuts.bindings.`: ## Notifications -- `shortcuts.bindings.showNotifications` +- `shortcuts.bindings.clearAllNotifications` - `shortcuts.bindings.jumpToUnread` -- `shortcuts.bindings.toggleUnread` -- `shortcuts.bindings.markOldestUnreadAndJumpNext` - `shortcuts.bindings.markAllNotificationsRead` -- `shortcuts.bindings.clearAllNotifications` +- `shortcuts.bindings.markOldestUnreadAndJumpNext` +- `shortcuts.bindings.showNotifications` +- `shortcuts.bindings.toggleUnread` - `shortcuts.bindings.triggerFlash` ## Right sidebar -- `shortcuts.bindings.toggleSidebar` - `shortcuts.bindings.focusRightSidebar` -- `shortcuts.bindings.switchRightSidebarToFiles` -- `shortcuts.bindings.switchRightSidebarToFind` -- `shortcuts.bindings.switchRightSidebarToSessions` -- `shortcuts.bindings.switchRightSidebarToFeed` -- `shortcuts.bindings.switchRightSidebarToDock` -- `shortcuts.bindings.switchRightSidebarToMachines` - `shortcuts.bindings.nextSidebarTab` -- `shortcuts.bindings.prevSidebarTab` - `shortcuts.bindings.nextSidebarTabInGroup` +- `shortcuts.bindings.prevSidebarTab` - `shortcuts.bindings.prevSidebarTabInGroup` +- `shortcuts.bindings.switchRightSidebarToDock` +- `shortcuts.bindings.switchRightSidebarToFeed` +- `shortcuts.bindings.switchRightSidebarToFiles` +- `shortcuts.bindings.switchRightSidebarToFind` +- `shortcuts.bindings.switchRightSidebarToMachines` +- `shortcuts.bindings.switchRightSidebarToSessions` +- `shortcuts.bindings.toggleSidebar` ## Browser -- `shortcuts.bindings.splitBrowserRight` -- `shortcuts.bindings.splitBrowserDown` -- `shortcuts.bindings.openBrowser` -- `shortcuts.bindings.focusBrowserAddressBar` - `shortcuts.bindings.browserBack` - `shortcuts.bindings.browserForward` +- `shortcuts.bindings.browserHardReload` - `shortcuts.bindings.browserReload` - `shortcuts.bindings.browserZoomIn` - `shortcuts.bindings.browserZoomOut` - `shortcuts.bindings.browserZoomReset` -- `shortcuts.bindings.toggleBrowserDeveloperTools` +- `shortcuts.bindings.focusBrowserAddressBar` +- `shortcuts.bindings.openBrowser` - `shortcuts.bindings.showBrowserJavaScriptConsole` +- `shortcuts.bindings.splitBrowserDown` +- `shortcuts.bindings.splitBrowserRight` +- `shortcuts.bindings.toggleBrowserDesignMode` +- `shortcuts.bindings.toggleBrowserDeveloperTools` +- `shortcuts.bindings.toggleBrowserFocusMode` ## Find @@ -151,10 +170,32 @@ Values for `shortcuts.bindings.`: - `shortcuts.bindings.findNext` - `shortcuts.bindings.findPrevious` - `shortcuts.bindings.hideFind` +- `shortcuts.bindings.sendCtrlFToTerminal` - `shortcuts.bindings.useSelectionForFind` ## Files and React Grab -- `shortcuts.bindings.toggleFileExplorer` +- `shortcuts.bindings.fileExplorerOpenSelection` +- `shortcuts.bindings.fileExplorerOpenSelectionFinderAlias` - `shortcuts.bindings.saveFilePreview` +- `shortcuts.bindings.toggleFileExplorer` - `shortcuts.bindings.toggleReactGrab` + +## Markdown and diff viewer + +- `shortcuts.bindings.diffViewerNextFile` +- `shortcuts.bindings.diffViewerOpenFileSearch` +- `shortcuts.bindings.diffViewerPreviousFile` +- `shortcuts.bindings.diffViewerScrollDown` +- `shortcuts.bindings.diffViewerScrollDownEmacs` +- `shortcuts.bindings.diffViewerScrollHalfPageDown` +- `shortcuts.bindings.diffViewerScrollHalfPageUp` +- `shortcuts.bindings.diffViewerScrollToBottom` +- `shortcuts.bindings.diffViewerScrollToTop` +- `shortcuts.bindings.diffViewerScrollUp` +- `shortcuts.bindings.diffViewerScrollUpEmacs` +- `shortcuts.bindings.markdownZoomIn` +- `shortcuts.bindings.markdownZoomOut` +- `shortcuts.bindings.markdownZoomReset` +- `shortcuts.bindings.openDiffViewer` +- `shortcuts.bindings.toggleChecklistItemComplete` diff --git a/skills/cmux-workspace/SKILL.md b/skills/cmux-workspace/SKILL.md index 82baa06d0efe..102eaa9cc5f8 100644 --- a/skills/cmux-workspace/SKILL.md +++ b/skills/cmux-workspace/SKILL.md @@ -94,7 +94,7 @@ For cmux app/runtime changes in a cmux source checkout, use a tagged reload from ```bash ./scripts/reload.sh --tag -CMUX_SOCKET_PATH=/tmp/cmux-debug-.sock cmux identify --json +CMUX_TAG= scripts/cmux-debug-cli.sh identify --json ``` ## Socket access diff --git a/tests/test_cmux_settings_supported_paths.py b/tests/test_cmux_settings_supported_paths.py index 8b15447106a0..ffc170283e8f 100644 --- a/tests/test_cmux_settings_supported_paths.py +++ b/tests/test_cmux_settings_supported_paths.py @@ -7,6 +7,7 @@ import json from pathlib import Path +import re import shutil import subprocess import sys @@ -121,5 +122,42 @@ def test_lists_paths_previously_only_in_checkout_source(self): self.assertEqual(result.stderr, "") +class ShortcutActionReferenceTests(unittest.TestCase): + """The shortcut reference must list exactly the schema's action ids. + + skills/cmux-keyboard-shortcuts/SKILL.md tells agents to validate action ids + against this reference, so an id the schema accepts but the file omits reads + as invented. Drift here silently blocks a real binding. + """ + + def test_reference_lists_every_schema_action(self): + schema = json.loads( + (REPO_ROOT / "web" / "data" / "cmux.schema.json").read_text() + ) + enum = schema["properties"]["shortcuts"]["properties"]["bindings"][ + "propertyNames" + ]["enum"] + reference = ( + REPO_ROOT + / "skills" + / "cmux-settings" + / "references" + / "shortcut-actions.md" + ).read_text() + listed = set( + re.findall(r"^-\s+`shortcuts\.bindings\.([A-Za-z0-9-]+)`", reference, re.M) + ) + self.assertEqual( + sorted(set(enum) - listed), + [], + "shortcut-actions.md is missing action ids the schema accepts", + ) + self.assertEqual( + sorted(listed - set(enum)), + [], + "shortcut-actions.md lists action ids the schema rejects", + ) + + if __name__ == "__main__": unittest.main()