Skip to content

Add a Compose From Instructions key: speak what to write, get it pasted - #307

Merged
alexkroman merged 1 commit into
mainfrom
compose-from-instructions
Nov 6, 2026
Merged

alexkroman merged 1 commit into
mainfrom
compose-from-instructions

Conversation

@alexkroman

Copy link
Copy Markdown
Collaborator

What

A new trigger-key action, Compose From Instructions, next to Rewrite Selection. You don't dictate the words. You say what you want written, and Blurt writes it and pastes it at the cursor:

start blurting → "ok I'm writing a Slack response, make it this and that way: hey Dan, we should have a feature to just speak instructions…" → a Slack-formatted message

You set it on Settings › Keys like any other action. No key does it by default.

How

  • Routing (SelectionSpeechRouting): compose takes Control Your Mac's no-selection path. The press doesn't read the Accessibility selection, but it still has to prove itself by a tap or hold before the mic opens. It then records with pressHandingBack, and on .handedBack the transcript becomes the router's job.
  • MessageComposer (Sources/BlurtEngine/Rewrite/): one Gemma chat completion through GatewayConnection.send, the same path the rewrite key uses. The gateway URL stays in ReadAloudLLM.swift, so check-invariants.sh needs no new carve-out.
  • App awareness: the composer gets the name of the app the press pinned as its paste target (DictationSession.pinnedAppName). The writing fits where it lands: a chat message for Slack, an email for Mail. That's the pinned app, not whatever is in front later, so switching apps while it transcribes can't put an email into Slack. Only the app name is sent, never the window title or any field's text.
  • Paste: the same as a rewrite (replaceSelection): no separator, over a selection if there is one, otherwise at the cursor. Rewrite and compose now share one paste job (paste(as:named:_:)), so cancelling and the Pasted/Copied/error notices behave the same for both.
  • Pill: new OverlayUIState.composing ("Writing…").

Settled decisions

This adds a second gateway client whose output is pasted. Your request (2026-11-06) is recorded as the owner's direction in the AGENTS.md row, the project-guardrails skill and the invariant gate's advice text. It's not a door back to a cleanup pass: the transcript is instructions to write from, and those words are never pasted.

Tests

  • MessageComposerTests: the wire request (system prompt, <app> + <spoken_instructions> user turn, model, cap) and that a truncated reply is never pasted.
  • SelectionSpeechRoutingComposeTests: no selection read, tap/hold proof, hand-back → .compose, "Writing" state, a press abandons the job, nothing said.
  • SelectionSpeechRouterComposeTests: end to end through the session. The writing is aimed at the pinned app and pasted with no separator; also covers Copied, the error notice, and a press abandoning it.
  • UI: testComposeKeyPastesTheComposition, and the Keys tab lists the new action.

Local scripts/check.sh is green (engine coverage 92.43%). The UI suite and leak scan are left to CI.

🤖 Generated with Claude Code

A new trigger-key action beside Rewrite Selection. Instead of dictating the
words themselves, the user speaks instructions ("ok, a Slack reply to Dan: we
should have a feature to just speak instructions, keep it casual") and the text
they describe is written and pasted at the cursor.

- Routing: compose takes Control Your Mac's no-selection path (.selected from
  the key-down, still proving itself by tap or hold), records with
  pressHandingBack, and hands the transcript to the router's job.
- MessageComposer (Rewrite/): one Gemma chat completion through
  GatewayConnection.send, so no new invariant carve-out. It gets the name of the
  app the press pinned as its paste target (DictationSession.pinnedAppName), so
  the writing fits Slack vs Mail even if the user switches apps meanwhile.
- Pasted like a rewrite (replaceSelection); rewrite and compose share one
  paste job. New pill state .composing ("Writing…").
- Keys/Sounds/ready-screen rows, UI-test double and harness button, engine
  and UI tests; AGENTS.md, guardrails skill and invariant advice updated for
  the second pasted gateway client (owner-directed 2026-11-06).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alexkroman
alexkroman enabled auto-merge (squash) November 6, 2026 17:48
@alexkroman
alexkroman merged commit 999cefd into main Nov 6, 2026
13 checks passed
@alexkroman
alexkroman deleted the compose-from-instructions branch November 6, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants