Repository navigation
feat(voice): hold one key to talk, with a tone at each end - #87
Merged
Merged
Conversation
ANT1OFF
force-pushed
the
feat/voice-one-key
branch
from
November 2, 2026 07:36
8be43ad to
db504ba
Compare
Dictation can be bound to one modifier held alone (Right ⌥ by default on macOS; the chord stays elsewhere, where Right Alt is AltGr). Held alone it works anywhere in the window and dictates into the composer in use: it starts at the press, a tap under 300 ms or a press with another key discards silently, and a double tap keeps listening until the next press. Start and stop tones are synthesised with Web Audio: the start tone once capture is live and the press is a hold, the stop tone on release, nothing for a discard. Settings → Voice input gets Sounds with a volume.
ANT1OFF
force-pushed
the
feat/voice-one-key
branch
from
November 2, 2026 08:35
f42269d to
74ee5db
Compare
ANT1OFF
added a commit
that referenced
this pull request
Nov 2, 2026
Desktop release metadata proposal only. Merging this PR does not publish or tag Gram; follow docs/RELEASING.md to release. --- ## [1.4.0](v1.3.1...v1.4.0) (2026-11-02) ### Features * **agents:** identify Gram's Claude processes as the gram entrypoint ([#91](#91)) ([f7dd703](f7dd703)) * **desktop:** run on Linux ([#82](#82)) ([1d37deb](1d37deb)) * **desktop:** turn voice input off on Linux with one check ([#79](#79)) ([470ff8b](470ff8b)) * **orchestration:** a person's PR comment wakes the worker that owns it ([#86](#86)) ([19bdc1c](19bdc1c)) * **orchestration:** a wrap-up turn when a worker stops without reporting ([#88](#88)) ([36a07fb](36a07fb)) * **orchestration:** workers say what they ruled out and check before repeating ([#90](#90)) ([8bdce01](8bdce01)) * **release:** publish and update Linux AppImage and .deb ([#95](#95)) ([c33c464](c33c464)) * **voice:** an accurate mode with a Parakeet pass on each pause ([#83](#83)) ([2b04a52](2b04a52)) * **voice:** hold one key to talk, with a tone at each end ([#87](#87)) ([1a9b3ef](1a9b3ef)) * **voice:** start capture at the press, and an opt-in ready microphone ([#81](#81)) ([505d240](505d240)) * **web:** a Done section that keeps the last 7 days ([#65](#65)) ([8c7bd49](8c7bd49)) * **web:** Done lists every finished chat ([#67](#67)) ([c91d9ac](c91d9ac)) * **web:** one attention count, quieter rows, a sidebar and board that agree ([#92](#92)) ([f193da4](f193da4)) * **web:** orchestrator → workers in the sidebar, a board that matches ([#80](#80)) ([686e737](686e737)) ### Bug Fixes * **desktop:** harden the Linux key vault and autostart entry ([#85](#85)) ([4b35eac](4b35eac)) * **e2e:** hold the t-flaky turn while the smoke test reads its opening line ([#93](#93)) ([2edc4ac](2edc4ac)) * **e2e:** release the dictation tap as soon as a word is heard ([#94](#94)) ([7781194](7781194)) * prepare only approved local-check sources ([#32](#32)) ([af3fab7](af3fab7)) * repair main after [#32](#32) ([#68](#68)) ([ce352e6](ce352e6)) * **voice:** keep the last word after release ([#78](#78)) ([cc40a47](cc40a47)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: gram-release-please[bot] <351321620+gram-release-please[bot]@users.noreply.github.com> Co-authored-by: Johan <32440065+ANT1OFF@users.noreply.github.com>
ANT1OFF
added a commit
that referenced
this pull request
Nov 2, 2026
Voice input stops being an experiment: it is a Settings page of its own, **Voice**, with the switch at the top and a push-to-talk key you can change from there. ### What changes - **Voice is a nav group** between Notifications and Advanced (Mic icon). It is listed and found by search on every platform, whether voice is on or off. The `experimental` tag on the page is gone, and so is the redirect to Diagnostics. Diagnostics' Experimental group and Advanced's "Experimental" row went too, since nothing else was in them. The old word "experimental" still finds the page in search, the same way Workspaces kept it after 0.7. - **Off by default, consent unchanged.** Turning it on still shows the model's size and licence before any download. Turning it off still deletes the models. On Linux the page shows the switch disabled with `VOICE_UNSUPPORTED_NOTE`. - **Existing users keep their state.** The switch is still stored as `experimental.voiceInput` (contracts: "the key keeps its name after a feature graduates"). Nothing is migrated, so anyone who had it on still has it on. There's a test for this in `packages/contracts/src/settings.test.ts`. - **Push-to-talk key row** (shown while voice is on): the current binding with platform labels, a **Change…** button that opens the same `KeyCaptureDialog` Settings → Keyboard uses, and the ↺ reset beside the label (Hint: "Reset to default"). The behaviour help changes with the binding: for a modifier held alone it is "hold anywhere / double-tap to keep listening", for a chord it is "tap to start and stop / hold while you talk". Clashes with other bindings are flagged. Saving goes through one new hook, `useSaveBindings`, which Keyboard now uses too. Both write `keybindings.json`, so there is one binding and no second setting. - **The recorder already captured lone modifiers** (#87). The audit found it handles Right ⌥/⌘/⌃/⇧ on key-up. Added: - `fn` as a lone modifier. Whether Electron reports it depends on the keyboard, so this is not verified on hardware. - Caveats: off macOS, choosing Right Alt warns that it is AltGr on many layouts. On macOS, choosing Fn points to "Press 🌐 key to → Do Nothing". - **Dictate shortcut in Keyboard and in the ? overlay**: the catalog's `experimental: "voiceInput"` is replaced by `listed: voiceInputOn`. The shortcut is listed while voice is on and hidden while it's off, because then it does nothing (and on Linux it never can). The Voice page offers the key once voice is on. - Docs: `AGENTS_AND_FEATURES.md` now names Settings → Voice, the stored key, and both places to rebind. - No dictation or speech-process behaviour changed. ### What's New `whats-new/` only accepts fragments for the current package version (1.4.0), which is already tagged (`assemble.test.ts` enforces both rules). So the card belongs in the 1.5.0 release PR. Suggested copy: *"Voice is a setting of its own — Voice input is no longer experimental: turn it on in Settings under Voice, and pick your push-to-talk key there, one modifier held alone or a chord. It isn't on Linux yet."* ### Verification - `bunx vitest run src/settings src/keyboard src/dictation src/composer/composer-dictation.test.tsx src/palette` (apps/web): 66 files, 514 tests pass. New: `dictate-key-row.test.tsx` (lone modifier, chord, clash, reset, AltGr warning) and caveat/Fn cases in `key-capture-dialog.test.tsx`. Updated: listing in `search.test.tsx`, nav in `settings-nav.test.tsx`, `listedShortcuts` in `catalog.test.ts`. - `bunx vitest run src/settings.test.ts` (contracts): 46 pass, including the existing-user case. - `bun run --filter @gram/web e2e e2e/dictation.spec.ts e2e/settings.spec.ts --workers=1`: 28/28 pass. This includes the rewritten Settings test (page listed while off, consent before download) and a new key-picker test: Right Ctrl held alone, the same binding shown in Keyboard, a ⌘L clash replaced, Esc cancels, reset. - `bun run fmt:check`, `bun run lint`, `bun run check:scaffold`: pass. - `bun run typecheck`: this machine reports 262 errors on untouched `main` (021df5d) as well as on this branch, and none are in files this PR touches. That looks environmental (local toolchain); CI is the authority. ### Known limits - Fn as a push-to-talk key has not been tried on real hardware. - The Linux AltGr warning only appears where the recorder can be reached. On Linux, voice can't be on, so in practice it shows on Windows. ### Screenshots **Settings → Voice, with voice input on** (dark) | Before | After | | --- | --- | |  |  | **Settings → Voice, with voice input on** (light) | Before | After | | --- | --- | |  |  | **Settings → Voice, off: listed as a page of its own, with only the switch** (dark) | Before | After | | --- | --- | |  |  | **The dictation key's recorder, Right ⌘ held alone just recorded** (dark) | Before | After | | --- | --- | |  |  |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Hold one key to dictate, as Hex does, with an audible start and stop.
KeyboardEvent.codelowercased (altright), which the keybindings file pattern already accepts. Labels follow the platform throughformatKeys: "Right ⌥" on macOS, "Right Alt" on Linux and Windows.{. I asked the orchestrator to confirm this default; it's one line (DICTATE_KEYSinkeyboard/catalog.ts) if it should change.Verification
dictation.spec.ts, 17 passed. Each test now pins its binding, so the same presses work on macOS and Linux runners. New:[659, 880].key-capture.spec.tsandkeyboard-nav.spec.tspass.catalog-coverageseesAltRightpressed.vitest(dictation, keyboard, settings, palette, contracts settings),typecheck,lint,fmt:check,check:scaffold,check:docs, the three e2e specs.Known limits
globalShortcut: the key only works while a Gram window has the focus.Screenshots
Settings → Advanced → Voice input, with voice input on (dark)