- Rewrite transcriptions on each step. Do some custom modifications that Freestyle as is cannot do.
- Tweak the post-processing feed-up step whatever way that you like.
- Reroute the output. Send transcriptions to any external service of your own.
An overview of Freestyle’s Stack
- The server owns transcription, cleanup, settings, and the plugin database. Most hooks run here.
- The app (the Electron client) owns audio capture, the UI, and delivering text to your window. A couple of hooks run here.
The pipeline
api argument: api.control cancels or consumes the run (consume() skips the rest of the pipeline and delivers nothing — how a voice command “eats” an utterance), and api.llm exposes the host’s configured LLM to server hooks. See the SDK reference.
Building a plugin allows you to modify what happens at each step of Freestyle’s dictation pipeline. The SDK offers hooks like afterTranscribe and beforeOutput that lets you control the inputs and the outputs at each step of the pipeline. In those hooks you can write functions that can do anything as long as it runs properly in a node environment.
Where plugins live
Installed plugins sit in the user-data directory underplugins/<slug>/. Two settings control loading:
plugins: a JSON array of specifiers, or[specifier, options]tuples.disabled_plugins: specifiers to skip.
Sandboxing
- Each plugin’s settings live under
plugin:<name>:<key>, isolated from other plugins. - A throwing hook is caught and reported. It won’t break the pipeline.
- UI pages are served by the local server at
/api/plugins/<slug>/ui/*and confined by the host to their own/api/plugins/<slug>/…namespace (plus/api/health) — no filesystem access, and no reach into settings, keys, or history. They call the server throughwindow.freestyle.
Plugin pages in the app
A plugin that ships a UI page (viacontributes.pages in its manifest) appears automatically as an item in the app’s sidebar, under the built-in sections. Enabling or disabling the plugin adds or removes its nav entry.
Next: build your first plugin.