From f5388731dd261fe9948a7935dd3de23c915a421b Mon Sep 17 00:00:00 2001 From: Julius Olsson Date: Sun, 26 Jul 2026 23:22:13 +0200 Subject: [PATCH 1/7] docs: plan uniform command activation semantics Six classification agents swept all 99 catalog commands and the surface wiring after a user report that Alt+P does nothing. The rule this establishes: invoking a command that shows a surface makes it visible; invoking it again dismisses it -- from EVERY invocation source, not just from inside the palette. Three independent layers break that today, and no single-layer fix is sufficient. A toggle written in a command body is unreachable if the router refuses the second keypress; a router fix is pointless if the command has no way to ask whether it is already open. Co-Authored-By: Claude Opus 5 (1M context) --- ...2026-07-26-command-activation-semantics.md | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-26-command-activation-semantics.md diff --git a/docs/superpowers/plans/2026-07-26-command-activation-semantics.md b/docs/superpowers/plans/2026-07-26-command-activation-semantics.md new file mode 100644 index 00000000..7bfb4eb7 --- /dev/null +++ b/docs/superpowers/plans/2026-07-26-command-activation-semantics.md @@ -0,0 +1,217 @@ +# Command activation semantics + +**Status:** planned, 2026-07-26 +**Origin:** user reported that ⌥P (Prompt Template…) does nothing. Six classification +agents then swept all 99 catalog commands and the surface/store wiring. + +--- + +## The one-sentence rule this establishes + +> Invoking a command that shows a surface makes that surface visible; invoking it +> again dismisses it. That must be true from **every** invocation source, not just +> from inside the palette. + +Nothing in the app enforces this today. Three independent layers break it, and no +single-layer fix is sufficient — a toggle written in a command body is unreachable +if the router refuses the second keypress, and a router fix is pointless if the +command has no way to ask "am I already open?". + +--- + +## Layer 1 — the interaction-ownership gate makes dialogs un-dismissable by chord + +`useKeybinds.ts:333` returns out of the entire key handler when +`hasAppInteractionOwner()` is true. That marker is stamped by **every** Radix +`DialogContent` (`components/ui/dialog.tsx:57`). The binding router lives at +`useKeybinds.ts:579`, well after the bail. + +Consequence: **any surface built as a Dialog makes its own chord unreachable while +it is open.** The command's `run` is never called. This is not an admission +refusal — nothing in `when`, `resolveCommandAvailability` or the gateway is +involved, and no change confined to a `commands/*.ts` file can fix it. + +This is why the user's chords split the way they do: + +| Round-trips today | Dead second press | +|---|---| +| ⌥R Reader, ⌥S Spotlight (`MainSurface` inline) | ⌘⇧U Usage (Dialog) | +| Agent Status (plain `