<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Clavio App</title>
    <description>The latest articles on DEV Community by Clavio App (@clavioapp).</description>
    <link>https://dev.to/clavioapp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4117115%2F9468732e-102b-42e7-bafb-8ae1abb48d58.png</url>
      <title>DEV Community: Clavio App</title>
      <link>https://dev.to/clavioapp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/clavioapp"/>
    <language>en</language>
    <item>
      <title>Building per-app dictation on macOS: focus, profiles, and optional send</title>
      <dc:creator>Clavio App</dc:creator>
      <pubDate>Sat, 12 Sep 2026 09:31:41 +0000</pubDate>
      <link>https://dev.to/clavioapp/building-per-app-dictation-on-macos-focus-profiles-and-optional-send-2ge4</link>
      <guid>https://dev.to/clavioapp/building-per-app-dictation-on-macos-focus-profiles-and-optional-send-2ge4</guid>
      <description>&lt;p&gt;Dictating a coding prompt and dictating an email can involve the same microphone and speech recognizer. They should not necessarily involve the same writing style—or the same action after the text appears.&lt;/p&gt;

&lt;p&gt;We build &lt;strong&gt;Clavio, hands-free dictation for Mac&lt;/strong&gt;, at Just Tools LTD. This is a developer's explanation of one part of the app: how we separate application identity, writing preferences, listening mode, and delivery. The implementation details below are based on our Mac code; the short pseudocode is illustrative, not a drop-in library.&lt;/p&gt;

&lt;p&gt;The video above is our existing walkthrough, including wake-word setup and a separate profile for Claude.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. “The active app” is more than one value
&lt;/h2&gt;

&lt;p&gt;On macOS, &lt;code&gt;NSWorkspace&lt;/code&gt; exposes the frontmost application and an application-activation notification. That gives a useful starting point: identify an app by its bundle identifier, not its display name.&lt;/p&gt;

&lt;p&gt;But reading the frontmost app only when transcription finishes is too late. Someone can start dictating in an editor, click the dictation panel, and finish speaking while that panel has focus. The panel should not become the writing-style target merely because it is visible.&lt;/p&gt;

&lt;p&gt;We distinguish three values:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;What it represents&lt;/th&gt;
&lt;th&gt;Why keep it?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Live frontmost app&lt;/td&gt;
&lt;td&gt;The latest activated app, including Clavio&lt;/td&gt;
&lt;td&gt;Current UI and focus decisions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Last external app&lt;/td&gt;
&lt;td&gt;The latest activated app other than Clavio&lt;/td&gt;
&lt;td&gt;Preserve useful context when our own UI appears&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session target&lt;/td&gt;
&lt;td&gt;The target selected when a recording session starts&lt;/td&gt;
&lt;td&gt;Keep processing associated with that session&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Clavio seeds the focus cache on launch and updates it from activation notifications. Published UI state is updated on the main queue. This also avoids repeatedly requesting application information in UI hot paths.&lt;/p&gt;

&lt;p&gt;There is an important edge case: starting dictation &lt;strong&gt;inside Clavio&lt;/strong&gt; must not blindly reactivate an older external app. A remembered target is context, not permission to send text anywhere.&lt;/p&gt;

&lt;p&gt;Apple documents the underlying &lt;a href="https://developer.apple.com/documentation/appkit/nsworkspace/didactivateapplicationnotification" rel="noopener noreferrer"&gt;application-activation notification&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Model the profile as independent choices
&lt;/h2&gt;

&lt;p&gt;A profile is not just a long prompt. Clavio stores user preferences keyed by the application's bundle ID, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Polish intensity and tone overrides.&lt;/li&gt;
&lt;li&gt;Listening mode and pause timing overrides.&lt;/li&gt;
&lt;li&gt;Optional custom wake phrases.&lt;/li&gt;
&lt;li&gt;The action, if any, after text insertion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These choices answer different questions. “Professional tone” describes the output. “Wake word” describes when capture begins. “Press Return” describes a later interaction with the destination app. Combining them into one setting makes surprising behavior harder to explain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1psjws92tjgt97qm4cdy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1psjws92tjgt97qm4cdy.png" alt="Clavio app profile with Global, Always, Wake and Key listening choices, wake phrases and pause settings" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The app profile exposes listening choices separately from writing preferences.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For example, someone might choose a keyboard-triggered mode and a professional tone for email, then wake-word activation and a direct tone for a coding assistant. Automatic sending remains a separate decision in each app.&lt;/p&gt;

&lt;p&gt;This is application-level identity. A browser bundle ID alone does not identify Gmail versus another website in a neighboring tab. Website-specific routing is a separate problem; it should not be implied by an app-level profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Resolve tone and intensity separately
&lt;/h2&gt;

&lt;p&gt;An unset override should mean “inherit,” not “erase the default.” Clavio's writing-settings resolver handles intensity and tone independently.&lt;/p&gt;

&lt;p&gt;For intensity, it checks the explicit app preference, then an app/catalog-derived default, then the user's global preference, and finally a built-in fallback. Tone has its own path: explicit app tone, catalog tone, user tone, or no specific tone.&lt;/p&gt;

&lt;p&gt;An illustrative version looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;intensity = firstAvailable(
    app.intensityOverride,
    catalogEntry.defaultIntensity,
    user.defaultIntensity,
    builtInIntensity
)

tone = firstAvailable(
    app.toneOverride,
    catalogEntry.defaultTone,
    user.preferredTone,
    noSpecificTone
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why two paths? A user may want a particular tone while leaving the amount of rewriting inherited. Treating the whole profile as either “custom” or “default” would lose that distinction.&lt;/p&gt;

&lt;p&gt;When both values have explicit app overrides, the resolver skips the catalog lookup. When a default cannot be obtained, it falls back instead of making dictation depend on a catalog response. That fallback does &lt;strong&gt;not&lt;/strong&gt; make speech transcription offline; it only keeps preference resolution from being an unnecessary blocker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4hbk1h30nmv613bw2umf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4hbk1h30nmv613bw2umf.png" alt="Clavio Polish panel showing tone presets and Fast, Clean, Tidy and Rewrite intensity choices" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tone and editing intensity describe different dimensions of the result.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Listening mode is a runtime policy
&lt;/h2&gt;

&lt;p&gt;The listening-mode resolver checks an explicit per-app override and otherwise inherits the global mode. The recording coordinator consumes that result when application activation changes.&lt;/p&gt;

&lt;p&gt;The distinction between Wake Word and Always On must remain meaningful. If a wake detector cannot operate, silently treating ordinary speech as an Always On session would change what the user agreed to. The resolver preserves the selected mode; runtime components can suspend capture without relabeling it as another mode.&lt;/p&gt;

&lt;p&gt;Custom app wake phrases also need a destination check. In Clavio, the detector can listen for a combined set of custom phrases, but the trigger is checked against the current app. The shared brand wake phrases remain separate from those app-specific additions.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Inserting text and sending it are separate operations
&lt;/h2&gt;

&lt;p&gt;The overall flow is easier to reason about when its stages stay explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application activation → update focus context
Recording starts       → choose session target
Recording finishes     → transcribe and resolve writing settings
Text is ready          → check delivery destination and insert
Post-paste action      → perform only the configured action, if any
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Posting a paste shortcut is not the same as proving that an app accepted the text. Electron apps, native fields, focus changes, and timing can all affect delivery. Clavio keeps delivery diagnostics separate from the act of posting the event, and its insertion paths include checks for security-sensitive destinations such as password fields.&lt;/p&gt;

&lt;p&gt;The same distinction matters for Return: depending on the destination, it can send a message or simply insert a new line. Automatic sending is useful for some prompting workflows, but users should be able to leave it disabled wherever they want to review text first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cases worth testing in any per-app implementation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Start in an editor, then click the dictation panel before processing completes.&lt;/li&gt;
&lt;li&gt;Start in the dictation app itself after previously using another app.&lt;/li&gt;
&lt;li&gt;Override only tone, leaving intensity inherited.&lt;/li&gt;
&lt;li&gt;Switch between an app with an explicit listening mode and one using the global mode.&lt;/li&gt;
&lt;li&gt;Change focus before insertion, including to a password prompt.&lt;/li&gt;
&lt;li&gt;Keep post-paste actions disabled and verify that text remains available for review.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are useful engineering tests even if the recognizer itself is already accurate. A perfect transcript in the wrong app, with an unexpected Return key, is still a poor result.&lt;/p&gt;

&lt;p&gt;If you want to try the implementation rather than build it, &lt;a href="https://clavioapp.com/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=per_app_architecture" rel="noopener noreferrer"&gt;Clavio is available for Apple Silicon Macs running macOS 14.2 or later&lt;/a&gt;. Dictation transcription and text polishing use online processing; wake-word and voice-profile functions run on the Mac. The &lt;a href="https://clavioapp.com/#plans" rel="noopener noreferrer"&gt;current plans&lt;/a&gt; explain the Free allowance and Pro features, including the advanced controls shown in the walkthrough.&lt;/p&gt;

&lt;p&gt;For this kind of Mac utility, the design work extends beyond converting speech into text: the app must keep track of which settings apply, which destination belongs to a session, and which actions the user actually selected.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Clavio for Mac: six spoken briefs for coding assistants</title>
      <dc:creator>Clavio App</dc:creator>
      <pubDate>Wed, 09 Sep 2026 10:51:23 +0000</pubDate>
      <link>https://dev.to/clavioapp/clavio-for-mac-six-spoken-briefs-for-coding-assistants-b6d</link>
      <guid>https://dev.to/clavioapp/clavio-for-mac-six-spoken-briefs-for-coding-assistants-b6d</guid>
      <description>&lt;p&gt;“Make the form work better” is easy to say. It is much harder to implement: better validation, a different layout and clearer loading feedback are three different tasks.&lt;/p&gt;

&lt;p&gt;A useful spoken brief gives the assistant something it can inspect and something you can verify. Start with four landmarks: &lt;strong&gt;goal, context, constraints and done when&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm Stas, director of Just Tools LTD, the company behind Clavio, an AI dictation app for Mac. Below are six structures you can use with Clavio, another dictation tool, or a keyboard. The examples are illustrative tasks, not customer results.&lt;/p&gt;

&lt;h2&gt;
  
  
  See voice input in action
&lt;/h2&gt;

&lt;p&gt;This short Claude demo shows dictation and optional automatic sending. For the coding tasks below, keep the brief visible, review it and send it when you are ready.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/wwdMe_vp8VI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Report a reproducible bug
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structure:&lt;/strong&gt; When I… I expect… Instead… Reproduce it by… Keep… Fixed means…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When I submit an empty comment, I expect a validation message. Instead, the submit button stays in its loading state. Open a post, leave the comment empty and press Send. Keep the existing API response format. Fixed means the message appears and the button can be used again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Give the assistant a trigger and an observable failure. Paste the exact error message afterwards if you have one. Saying “there is a network error” loses information that a status code or stack trace might contain.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Request a small feature
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structure:&lt;/strong&gt; The user needs… Put it in… It should… Preserve… Ready means…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The user needs to copy a support reference from the error panel. Put a copy button beside the reference. Show a short confirmation after copying. Preserve normal text selection. Ready means the button works with a keyboard, the copied value matches the reference, and a failed copy does not show success.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Keep the request centred on one user action. The last condition matters: a visual confirmation should reflect what happened, rather than appear whenever a button was pressed.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Ask for a focused review
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structure:&lt;/strong&gt; Review… Focus on… For each finding, explain… For now…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Review the changes to comment submission. Focus on duplicate requests and failed retries. For each finding, explain the trigger, the user-visible result and the relevant code. For now, report findings before changing files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That final sentence defines the output you want. If the task is diagnosis, say so. Otherwise a review can quietly turn into a larger implementation task.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Describe a bounded refactor
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structure:&lt;/strong&gt; The repeated logic is… Simplify… Preserve… Avoid… Check…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The loading-state logic is repeated in three settings panels. Extract shared state handling where it improves readability. Preserve each panel's error messages and public interface. Avoid a new dependency. Check saving, retrying and closing a panel while a request is in progress.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A refactor needs a behaviour boundary. Name what must stay true, and let the assistant inspect the code before deciding what can reasonably be shared.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Request a test for a failure mode
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structure:&lt;/strong&gt; Protect against… Start with… Trigger… Assert… Also cover…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Protect against losing a draft after a failed save. Start with an edited draft, make the save request fail, and assert that the text remains available for another attempt. Also cover a successful retry. Use the project's existing test tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This describes the failure the test should catch. It gives more direction than “add tests” without prescribing the test's internal implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Prepare a PR description
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structure:&lt;/strong&gt; The problem was… The change now… Scope is… Checks completed were… Still uncertain is…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The problem was that the save button stayed disabled after a network failure. The change restores the button and keeps the draft. The scope is the editor's retry state. The completed check was a manual failed-save and successful-retry sequence. Automated checks have not been run yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Only include validation that happened. If you cannot remember whether a check passed, verify it before putting it in the description.&lt;/p&gt;

&lt;h2&gt;
  
  
  The review pass matters as much as the template
&lt;/h2&gt;

&lt;p&gt;Read the resulting brief once before sending it. Check four details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Names:&lt;/strong&gt; Are file, function and service names correct?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Numbers:&lt;/strong&gt; Did a timeout, version or limit survive accurately?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Negations:&lt;/strong&gt; Did “do not change the API” keep the “not”?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stopping point:&lt;/strong&gt; Is it clear whether the assistant should investigate, edit or report?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Type or paste exact identifiers and symbols when that is easier. Speaking the explanation and typing a function name is a useful combination.&lt;/p&gt;

&lt;p&gt;Here is a simple check for your next task: could someone read the final instruction and tell whether the result satisfies it? If “done” still means “make it nicer,” add one observable condition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the briefs with Clavio on Mac
&lt;/h2&gt;

&lt;p&gt;For a first coding brief, focus the assistant's message field and start with &lt;strong&gt;Hold key&lt;/strong&gt;. Use &lt;strong&gt;Clean&lt;/strong&gt; if you want punctuation and filler cleanup while keeping the wording close. Leave &lt;strong&gt;After paste&lt;/strong&gt; set to &lt;strong&gt;None&lt;/strong&gt; so the result stays visible for review.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy5a0yhss1soffkfdyq6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy5a0yhss1soffkfdyq6g.png" alt="Clavio's general Polish panel with tone presets and the Fast, Clean, Tidy and Rewrite intensity choices" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Clavio's general Polish settings. This screenshot shows the available controls; Tidy is selected here. For the first coding brief above, choose Clean.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An app profile lets you keep a technical writing style for Claude and a more conversational tone for email. Listening modes can differ too: for example, a wake phrase in Claude and Hold key in your email app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe0rv5aewfyya4719zw5z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe0rv5aewfyya4719zw5z.png" alt="Clavio app profile showing Global, Always, Wake and Key listening choices, wake phrases and pause settings" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Listening and pause controls inside an app profile. This example inherits the global listening mode; the same panel offers app-specific choices.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Clavio also offers wake-word and Always On modes, with app-specific settings. Its per-app style, tone and pause controls are listed under Pro. The free allowance of 3,000 polished words per month does not make every advanced control free. Clavio requires Apple Silicon and macOS 14.2 or later; ordinary transcription and polishing use online processing.&lt;/p&gt;

&lt;p&gt;You can check the current features and plans on the &lt;a href="https://clavioapp.com/?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=spoken_briefs_202609&amp;amp;utm_content=six_templates" rel="noopener noreferrer"&gt;Clavio website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Which detail do you most often have to add to a coding task after the first attempt: context, constraints or the definition of done?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI disclosure: This article was drafted with AI using my product notes. The task examples are illustrative.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
