Problem
FreeFlow currently has no awareness of the text surrounding the cursor when pasting dictated text. The spacing logic in writeTranscriptToPasteboard blindly appends a space after sentence-ending punctuation (.!?), and the LLM is not given any surrounding text context. This causes several issues:
1. Trailing whitespace artifact
Every dictation that ends with punctuation appends a trailing space, even when the cursor is at the end of a text field (no text follows). The user sees a visible trailing space after every sentence they dictate.
Current behavior: "Hello world." (with trailing space)
Expected behavior: "Hello world." (no trailing space; consecutive dictations should add leading space instead)
2. Incorrect capitalization when inserting mid-sentence
The LLM always capitalizes the first word of the transcript because it has no knowledge of what comes before the cursor. When inserting text mid-sentence, this produces incorrect output.
Example: Cursor is after "I think " → dictates "we should go" → gets "We should go" (uppercase W)
Expected: "we should go" (lowercase, since we're mid-sentence)
3. Capitalization fails for list items
After a Markdown/plaintext list marker like "- ", "* ", or "1. ", the first letter should be capitalized, but the system doesn't detect list boundaries.
4. Duplicate/conflicting punctuation when inserting mid-text
The LLM adds terminal punctuation assuming the transcript ends the sentence. When the text following the cursor already has punctuation, this creates duplicates like ".." or conflicts like ".?".
5. No surrounding context sent to LLM
The post-processing LLM receives only CONTEXT (app activity summary) and RAW_TRANSCRIPTION, but never the text before and after the cursor. This means the LLM cannot make informed grammatical or spelling decisions based on the actual insertion point.
Proposed Solution
- Read surrounding text via Accessibility API — Use
kAXValueAttribute + kAXSelectedTextRangeAttribute to read precedingText and followingText from the focused text field.
- Apply deterministic formatting rules — Capitalize at sentence boundaries, newlines, and list markers; lowercase mid-sentence; remove conflicting punctuation; clean all Unicode whitespace variants.
- Smart spacing — Leading space only when
precedingText ends with a word character; trailing space only when followingText starts with a word character; no trailing space at end of field.
- Feed context to LLM — Include
PRECEDING_TEXT and FOLLOWING_TEXT in the user prompt so the model can make better cleanup decisions.
- Electron/Web hack — For Chromium-based apps where the AX tree doesn't auto-sync, perform a zero-net-movement keypress (→←) to force refresh.
- Skip screenshot when text context is available — Saves ~200ms per dictation when the Accessibility API can read the text field directly.
Problem
FreeFlow currently has no awareness of the text surrounding the cursor when pasting dictated text. The spacing logic in
writeTranscriptToPasteboardblindly appends a space after sentence-ending punctuation (.!?), and the LLM is not given any surrounding text context. This causes several issues:1. Trailing whitespace artifact
Every dictation that ends with punctuation appends a trailing space, even when the cursor is at the end of a text field (no text follows). The user sees a visible trailing space after every sentence they dictate.
Current behavior:
"Hello world."(with trailing space)Expected behavior:
"Hello world."(no trailing space; consecutive dictations should add leading space instead)2. Incorrect capitalization when inserting mid-sentence
The LLM always capitalizes the first word of the transcript because it has no knowledge of what comes before the cursor. When inserting text mid-sentence, this produces incorrect output.
Example: Cursor is after
"I think "→ dictates "we should go" → gets"We should go"(uppercase W)Expected:
"we should go"(lowercase, since we're mid-sentence)3. Capitalization fails for list items
After a Markdown/plaintext list marker like
"- ","* ", or"1. ", the first letter should be capitalized, but the system doesn't detect list boundaries.4. Duplicate/conflicting punctuation when inserting mid-text
The LLM adds terminal punctuation assuming the transcript ends the sentence. When the text following the cursor already has punctuation, this creates duplicates like
".."or conflicts like".?".5. No surrounding context sent to LLM
The post-processing LLM receives only
CONTEXT(app activity summary) andRAW_TRANSCRIPTION, but never the text before and after the cursor. This means the LLM cannot make informed grammatical or spelling decisions based on the actual insertion point.Proposed Solution
kAXValueAttribute+kAXSelectedTextRangeAttributeto readprecedingTextandfollowingTextfrom the focused text field.precedingTextends with a word character; trailing space only whenfollowingTextstarts with a word character; no trailing space at end of field.PRECEDING_TEXTandFOLLOWING_TEXTin the user prompt so the model can make better cleanup decisions.