Problem or Motivation
Every comparable desktop app ships a command palette — a single keyboard-driven
overlay (⌘K / Ctrl+K in Linear/Vercel/Raycast, ⌘⇧P in VS Code / Codex desktop, ⌘K
in Claude's desktop app) that lets you search for and run any command without
hunting through menus. It is the fastest way to discover and trigger app actions.
OpenWork already has all the ingredients but no palette that ties them together:
- A centralized action registry (
apps/electron/src/renderer/actions/) with 26
actions carrying label, category, defaultHotkey, and — crucially — an
execute(actionId) method that runs the first enabled handler.
- The cmdk command primitives (
components/ui/command.tsx) — currently only
consumed by the in-input slash-command menu.
- Translated action labels (
shortcuts.action.*) and category headings
(shortcuts.category.*) already in every locale.
Today the action registry is surfaced only in read-only reference views (the
Keyboard Shortcuts dialog and the Settings → Shortcuts page). There is no way to
run an action by searching for it. Discovering an action means opening Settings
and scrolling, or memorizing a hotkey.
Proposed Solution
Add a global command palette opened with ⌘K / Ctrl+K (and from the App
menu). It:
- Lists every registry action, grouped by category, with its hotkey shown on the
right.
- Filters as you type (cmdk's built-in fuzzy match over the translated label).
- Shows a "No results found" empty state when nothing matches.
- On select, closes and calls the registry's
execute(actionId) — so "Settings",
"Toggle Theme", "New Chat", etc. run exactly as if their hotkey were pressed.
- Closes on
Esc / selection (integrated with the existing modal stack).
This is a frontend-only change:
- It reuses the existing action registry (
useActionRegistry().execute), the cmdk
primitives, and the existing hotkey/label infrastructure — no backend, no
qwen-code change.
- It introduces no new i18n keys: the input placeholder reuses
commands.searchCommands, the empty state reuses common.noResultsFound, labels
reuse shortcuts.action.*, and group headings reuse shortcuts.category.*.
Alternatives Considered
- Keyboard Shortcuts dialog / Settings → Shortcuts page already exist, but they
are reference surfaces — you can read a shortcut, not run the action. A palette
is the run surface every comparable app pairs with the reference.
- Slash-command menu (
/) exists inside the chat input, but it is scoped to
chat commands and the message composer, not global app actions.
Additional Context
Feasibility: frontend-only / doable. Verified against apps/electron — the
registry already exposes execute(), actions carry all needed display metadata,
and cmdk is already a dependency.
Acceptance criteria (CDP e2e assertion)
A new e2e/assertions/command-palette.assert.ts drives the real built app over CDP
and asserts the full path:
- Pressing
⌘K / Ctrl+K opens the palette; it renders and lists more than
one action row.
- Typing a query (
theme) narrows the list — every visible row contains the
query and the row count shrinks — and the known Toggle Theme action is
present.
- A no-match query (
zzqqxxnomatchzzqqxx) shows the empty state and hides every
row.
- Clearing the query restores the full list.
- Selecting Toggle Theme closes the palette and flips the app theme
(documentElement dark⇄light class), proving the palette actually executes
the action rather than merely displaying it.
Part of the autonomous desktop-feature loop (loop-bot).
Problem or Motivation
Every comparable desktop app ships a command palette — a single keyboard-driven
overlay (⌘K / Ctrl+K in Linear/Vercel/Raycast, ⌘⇧P in VS Code / Codex desktop, ⌘K
in Claude's desktop app) that lets you search for and run any command without
hunting through menus. It is the fastest way to discover and trigger app actions.
OpenWork already has all the ingredients but no palette that ties them together:
apps/electron/src/renderer/actions/) with 26actions carrying
label,category,defaultHotkey, and — crucially — anexecute(actionId)method that runs the first enabled handler.components/ui/command.tsx) — currently onlyconsumed by the in-input slash-command menu.
shortcuts.action.*) and category headings(
shortcuts.category.*) already in every locale.Today the action registry is surfaced only in read-only reference views (the
Keyboard Shortcuts dialog and the Settings → Shortcuts page). There is no way to
run an action by searching for it. Discovering an action means opening Settings
and scrolling, or memorizing a hotkey.
Proposed Solution
Add a global command palette opened with
⌘K/Ctrl+K(and from the Appmenu). It:
right.
execute(actionId)— so "Settings","Toggle Theme", "New Chat", etc. run exactly as if their hotkey were pressed.
Esc/ selection (integrated with the existing modal stack).This is a frontend-only change:
useActionRegistry().execute), the cmdkprimitives, and the existing hotkey/label infrastructure — no backend, no
qwen-code change.
commands.searchCommands, the empty state reusescommon.noResultsFound, labelsreuse
shortcuts.action.*, and group headings reuseshortcuts.category.*.Alternatives Considered
are reference surfaces — you can read a shortcut, not run the action. A palette
is the run surface every comparable app pairs with the reference.
/) exists inside the chat input, but it is scoped tochat commands and the message composer, not global app actions.
Additional Context
Feasibility: frontend-only / doable. Verified against
apps/electron— theregistry already exposes
execute(), actions carry all needed display metadata,and cmdk is already a dependency.
Acceptance criteria (CDP e2e assertion)
A new
e2e/assertions/command-palette.assert.tsdrives the real built app over CDPand asserts the full path:
⌘K/Ctrl+Kopens the palette; it renders and lists more thanone action row.
theme) narrows the list — every visible row contains thequery and the row count shrinks — and the known Toggle Theme action is
present.
zzqqxxnomatchzzqqxx) shows the empty state and hides everyrow.
(
documentElementdark⇄lightclass), proving the palette actually executesthe action rather than merely displaying it.
Part of the autonomous desktop-feature loop (
loop-bot).