Profiles
The same sentence should come out differently depending on where it lands. git status typed into a terminal must not become Git status., and a Slack message should not arrive uncapitalized.
OpenVoice knows which application has focus and applies the rules that application deserves. That mapping is a profile.
The three that ship
| Terminal | Editor | Prose | |
|---|---|---|---|
| Capitalization | forced lowercase | sentence case | sentence case |
| Closing period | no | no | yes |
| Fillers | light | light | aggressive |
| Voice commands | yes | yes | yes |
| Case transforms | yes | yes | no |
| Dictionaries | shell + code | code | code |
Terminal matches WindowsTerminal.exe, powershell.exe, pwsh.exe, cmd.exe, wt.exe and alacritty.exe. No capitalization and no trailing period, because both would corrupt a command. Case transforms stay on because flag and path names benefit from them.
Editor matches Code.exe, Cursor.exe, idea64.exe, devenv.exe, zed.exe and sublime_text.exe.
Prose matches slack.exe, Discord.exe, Notion.exe, chrome.exe, msedge.exe, firefox.exe and olk.exe. It closes sentences with a period and strips discourse markers, because chat and mail are the places where "um, so, you know" is worth removing and a missing full stop is worth adding.
Gmail resolves to the prose profile through chrome.exe, since it runs in a browser. Rules are per profile, not per application.
What that looks like
One sentence, three destinations:
heard: um so we need to call use effect here comma then return null
terminal: so we need to call useEffect here, then return null
editor: So we need to call useEffect here, then return null
prose: So we need to call useEffect here, then return null.
And the case that makes the point sharpest, because the shell dictionary is only enabled in one of them:
heard: cube control get pods
terminal: kubectl get pods
editor: Cube control get pods
No capital and no trailing period, so the terminal version runs. You can try all of this on the home page, which runs the real rules in your browser.
The pipeline
Seven rules, in a fixed order:
parse -> repeats -> fillers -> commands -> dictionary -> case -> capitalize -> profile
The order is load-bearing. Fillers run early so a stray "um" cannot break a multi-word command match. Commands run before the dictionary so spoken punctuation becomes literal tokens the dictionary will not try to interpret. Capitalization runs late, after identifiers have been resolved into tokens it is forbidden to touch, because capitalizing useEffect into UseEffect at the start of a sentence would turn working code into a compile error.
Choosing which one applies
Profiles are matched against the executable name, case-insensitively, and the first match wins. Your own profiles are consulted before the built-in ones, so you can override any of them without editing what ships.
An application that matches nothing gets the default profile: sentence case, no closing period, light fillers, voice commands and case transforms on, code dictionary only.
Seeing why
Every format records a stage-by-stage trace, so "the formatter did something weird" is a diagnosable report rather than an unfalsifiable one. The Debug panel shows it, and so does the CLI:
ov format "cube control get pods" --profile terminal --trace