Plugin API Reference
This is the complete API reference for the Freeway Plugin SDK. All functions are available via import freeway.
Control Flow
Section titled “Control Flow”freeway.cancel()
Section titled “freeway.cancel()”Cancel the current operation and stop the plugin chain.
freeway.cancel()Effects:
- In
before_paste: Prevents text from being pasted, stops subsequent plugins - In
before_recordingorbefore_transcribe: Cancels the recording/transcription, stops subsequent plugins
Use case: Voice commands that should trigger an action but not paste text.
def before_paste(): text = freeway.get_text() if "cancel that" in text.lower(): freeway.cancel() freeway.log("Operation cancelled by user")freeway.skip_paste()
Section titled “freeway.skip_paste()”Skip the paste operation but continue executing subsequent plugins.
freeway.skip_paste()Effects:
- Only effective in
before_pastehook - Text will not be pasted
after_pasteandon_stop_recordinghooks will still run
Use case: Plugins that handle output themselves (e.g., saving to file).
def before_paste(): text = freeway.get_text()
# Save to file instead of pasting with open("/tmp/transcription.txt", "w") as f: f.write(text)
freeway.skip_paste() freeway.log("Saved to file instead of pasting")freeway.stop_chain()
Section titled “freeway.stop_chain()”Stop executing subsequent plugins but continue with the operation.
freeway.stop_chain()Effects:
- For
before_paste: Text will still be pasted, but remaining plugins won’t run
Use case: When your plugin has fully processed the text and other plugins shouldn’t modify it.
def before_paste(): text = freeway.get_text()
# Apply final formatting freeway.set_text(text.strip())
# Don't let other plugins modify this freeway.stop_chain()Text Access/Modification
Section titled “Text Access/Modification”freeway.get_text()
Section titled “freeway.get_text()”Get the current transcribed text.
text = freeway.get_text()Returns: str | None — The transcribed and normalized text, or None if not available.
Availability: Only in hooks that have access to text (before_paste, after_paste).
def before_paste(): text = freeway.get_text()
if text and "hello" in text.lower(): freeway.log("User said hello!")freeway.set_text(text)
Section titled “freeway.set_text(text)”Replace the transcribed text with a new value.
freeway.set_text("new text")Parameters:
text(str): The new text to use for pasting
Effects:
- Only effective in
before_pastehook - Subsequent plugins will receive the modified text
def before_paste(): text = freeway.get_text()
# Convert to title case freeway.set_text(text.title())Settings Access
Section titled “Settings Access”freeway.get_setting(key)
Section titled “freeway.get_setting(key)”Get a user setting value by key.
value = freeway.get_setting("api_key")Parameters:
key(str): The setting name frommeta.json
Returns: The setting value, or None if not found.
def before_paste(): api_key = freeway.get_setting("api_key") model = freeway.get_setting("model_name")
if not api_key: freeway.log("API key not configured") returnfreeway.get_settings()
Section titled “freeway.get_settings()”Get all user settings as a dictionary.
settings = freeway.get_settings()Returns: dict — Dictionary of all setting name-value pairs.
def before_paste(): settings = freeway.get_settings()
if settings.get("enabled"): process(settings.get("api_key"))Context Paths
Section titled “Context Paths”freeway.get_wav_path()
Section titled “freeway.get_wav_path()”Get the path to the recorded audio file.
wav_path = freeway.get_wav_path()Returns: str | None — Full path to voice.wav in the temp session folder.
Availability: Not available in before_recording hook.
def before_paste(): wav_path = freeway.get_wav_path()
if wav_path: # Process the audio file audio_duration = get_audio_duration(wav_path) freeway.log(f"Audio duration: {audio_duration}s")freeway.get_meta_path()
Section titled “freeway.get_meta_path()”Get the path to the recording metadata file.
meta_path = freeway.get_meta_path()Returns: str | None — Full path to meta.json in the temp session folder.
The metadata file contains:
id: Session UUIDapp_version: Freeway versionrecorded_at: ISO timestampaudio_duration: Duration in secondssample_rate: Audio sample ratemicrophone_id: Device IDmicrophone_name: Device nametext: Transcribed textword_count: Number of words
import json
def before_paste(): meta_path = freeway.get_meta_path()
with open(meta_path) as f: meta = json.load(f)
freeway.log(f"Recording ID: {meta['id']}") freeway.log(f"Duration: {meta['audio_duration']}s")freeway.get_temp_dir()
Section titled “freeway.get_temp_dir()”Get the path to the temp session directory.
temp_dir = freeway.get_temp_dir()Returns: str | None — Full path to the Temp/<UUID>/ directory for this session.
Use case: Store temporary files during processing.
import os
def before_paste(): temp_dir = freeway.get_temp_dir() output_path = os.path.join(temp_dir, "processed.txt")
with open(output_path, "w") as f: f.write(processed_text)UI Feedback
Section titled “UI Feedback”freeway.set_status_text(text)
Section titled “freeway.set_status_text(text)”Display status text in the Freeway visualizer panel.
freeway.set_status_text("Processing...")Parameters:
text(str): Status message to display
Effects:
- Shows a puzzle piece icon with the text in the visualizer footer
- Automatically cleared when the hook completes
Use case: Show progress during long operations.
def before_paste(): freeway.set_status_text("Processing with AI...")
result = call_ai_api(text)
freeway.set_status_text("Done!")freeway.set_indicator_color(color)
Section titled “freeway.set_indicator_color(color)”Change the menu bar indicator color.
freeway.set_indicator_color("#ff9500")Parameters:
color(str): HEX color string (e.g.,"#ff9500","#00ff00")
Effects:
- Changes the recording indicator in the menu bar icon
- Automatically reset when the hook completes
def before_paste(): # Red for error freeway.set_indicator_color("#ff0000")
# Green for success freeway.set_indicator_color("#00ff00")
# Blue for processing freeway.set_indicator_color("#0000ff")System Info
Section titled “System Info”freeway.get_appearance_theme()
Section titled “freeway.get_appearance_theme()”Get the current system appearance theme.
theme = freeway.get_appearance_theme()Returns: str — "light" or "dark" based on macOS system appearance.
Use case: Adapt visual feedback to the current theme.
def before_paste(): theme = freeway.get_appearance_theme()
if theme == "dark": freeway.set_indicator_color("#ffffff") else: freeway.set_indicator_color("#000000")Keyboard Control
Section titled “Keyboard Control”freeway.press_keys(keys)
Section titled “freeway.press_keys(keys)”Press a keyboard shortcut.
freeway.press_keys(["Command", "V"])Parameters:
keys(list[str]): List of key names
Key names (macOS conventions):
- Modifiers:
"Command","Control","Option","Shift" - Letters:
"A","B","C", etc. - Special:
"Return","Tab","Space","Escape" - Arrows:
"UpArrow","DownArrow","LeftArrow","RightArrow"
def before_paste(): # Paste shortcut freeway.press_keys(["Command", "V"])
# Show hidden files in Finder freeway.press_keys(["Command", "Shift", "."])freeway.release_keys(keys)
Section titled “freeway.release_keys(keys)”Release previously pressed keys.
freeway.release_keys(["Command", "V"])Parameters:
keys(list[str]): List of key names to release
import time
def before_paste(): # Hold Shift freeway.press_keys(["Shift"])
time.sleep(0.1)
# Release Shift freeway.release_keys(["Shift"])Trigger Info
Section titled “Trigger Info”freeway.get_trigger()
Section titled “freeway.get_trigger()”Get the trigger configuration for this plugin.
trigger = freeway.get_trigger()Returns: dict | None — Dictionary with trigger settings, or None if no trigger is configured.
Dictionary keys:
pattern(str | None): The trigger pattern from settingsmatch_type(str | None): The match type —"startsWith","endsWith","match","contains", or"regex"
Match types:
| Type | Description |
|---|---|
startsWith | Text must start with the pattern |
endsWith | Text must end with the pattern |
match | Text must exactly match the pattern (case-insensitive) |
contains | Text must contain the pattern anywhere (default) |
regex | Pattern is treated as a regular expression |
Regex patterns:
Regex uses ICU Regular Expressions syntax (NSRegularExpression). Matching is case-insensitive by default. Text is normalized before matching: punctuation is removed and whitespace is trimmed.
| Pattern | Matches |
|---|---|
^hey freeway | Text starting with “hey freeway” |
please$ | Text ending with “please” |
^(open|start) chat | ”open chat” or “start chat” at the beginning |
^(open|launch|start) | Text starting with “open”, “launch”, or “start” |
send (email|message) to | ”send email to…” or “send message to…” |
remind me in \d+ minutes | ”remind me in 5 minutes”, “remind me in 30 minutes” |
^translate .+ to (spanish|french|german)$ | ”translate hello to spanish” |
^(what|who|where|when|why|how)\b | Questions starting with interrogative words |
Regex examples in meta.json:
{ "trigger": { "pattern": "^(hey|ok|hi) freeway", "matchType": "regex" }}{ "trigger": { "pattern": "^search (for |on )?", "matchType": "regex" }}Note: Trigger matching is handled automatically by Freeway — your plugin only runs when the text matches. Use get_trigger() when you need to know the pattern (e.g., to strip trigger phrase from text).
def before_paste(): trigger = freeway.get_trigger() text = freeway.get_text()
if trigger and trigger.get("pattern"): pattern = trigger["pattern"] match_type = trigger.get("match_type", "contains")
freeway.log(f"Triggered by: {pattern} ({match_type})")
# Strip trigger phrase from start of text if match_type == "startsWith": text_lower = text.lower() pattern_lower = pattern.lower() if text_lower.startswith(pattern_lower): text = text[len(pattern):].strip() freeway.set_text(text)Logging
Section titled “Logging”freeway.log(message)
Section titled “freeway.log(message)”Log a message to the Freeway console.
freeway.log("Debug message")Parameters:
message(str): The message to log
Use case: Debugging and tracking plugin behavior.
def before_paste(): freeway.log("Processing started")
result = process_text(text)
freeway.log(f"Processed {len(result)} characters")View logs in Freeway’s debug console (accessible from the menu bar icon).