Mac Apps
freeflow-james
What It Does
Section titled “What It Does”A Mac menu bar dictation app — free, open-source alternative to Wispr Flow, Superwhisper, and Monologue. Hold Fn to talk, or tap Command-Fn to toggle, and whatever you say gets pasted into the active text field with AI cleanup.
This repo (freeflow-james) is James’s daily-driver fork. It tracks zachlatta/freeflow as upstream and carries personal customizations (UI tweaks, behavior changes, experiments) that may or may not flow back upstream as PRs.
When To Use
Section titled “When To Use”- All day, every day. This is the dictation engine that powers James’s voice-first input — most of what hits Wispr Flow’s old slot now hits FreeFlow.
- For Edit Mode work — highlight existing text, speak an instruction like “make this shorter” or “turn this into bullets,” and FreeFlow rewrites it in place.
- When you want context-aware cleanup — FreeFlow can read the surrounding app context so names, jargon, and project terms come back spelled correctly.
How It Works
Section titled “How It Works”- App lives in the menu bar. Hotkeys are configurable in Settings.
- Hold the talk key, speak. Audio routes to the configured transcription provider (Groq by default, OpenAI-compatible API).
- Cleanup pass — a Claude-style LLM call that uses surrounding app context plus your custom vocabulary to fix names, terms, and phrasing.
- Text gets pasted into the focused field. No FreeFlow server in the middle, so audio + cleanup go provider → your Mac, nothing stored upstream.
Where It Lives
Section titled “Where It Lives”- Daily-driver repo:
~/apps/freeflow-james/(this one — what James actually runs) - PR-staging fork:
~/apps/freeflow/(ojhurst/freeflowon GitHub — clean branches off upstream, used to send improvements back tozachlatta/freeflow) - Bundle path on disk:
/Applications/FreeFlow James.app - Bundle ID:
com.zachlatta.freeflow.dev— unchanged from upstream so TCC permission grants survive merges.
Two-Repo Setup
Section titled “Two-Repo Setup”freeflow-james is for everything James runs every day, including changes that may never go upstream.
freeflow is for sending PRs back. Branch off upstream/main, apply ONLY the change you want to propose, PR that branch to zachlatta/freeflow. Keeps personal-only customizations out of upstream.
Code Signing — Required, Not Optional
Section titled “Code Signing — Required, Not Optional”The Makefile defaults to CODESIGN_IDENTITY ?= FreeFlow Dev which expects a self-signed cert that does not exist on James’s machines. Always build with the Apple Development cert:
CODESIGN_IDENTITY="Apple Development: ojhurst@gmail.com (FKLXWDKTW3)" makeWhy this matters: ad-hoc signed builds get a different cert hash on every rebuild, which breaks TCC permission grants (Accessibility, Screen Recording, Microphone). Apple-signed builds keep a stable hash so grants persist.
One-Time Keychain ACL Fix Per Machine
Section titled “One-Time Keychain ACL Fix Per Machine”The Apple cert’s private key ships with an interactive ACL. codesign works from a Terminal James is physically logged into, but fails with errSecInternalComponent from SSH sessions, Claude Code’s Bash tool, or anything else without an attached UI. Run this once per machine in a local interactive Terminal:
bash ~/apps/cc/bin/unlock-keychain-acl.shIdempotent. After it succeeds, codesign with the Apple Development cert works from any caller, including Claude’s Bash and SSH sessions. Repeat on every machine that holds the cert (Studio + MBP).
When Claude Is SSH’d From A Different Machine
Section titled “When Claude Is SSH’d From A Different Machine”If Claude is on Studio but James is at MBP, do NOT try to build + sign on Studio — Claude’s Bash there has no UI keychain auth and codesign will fail with errSecInternalComponent. Instead, push the source from Studio and route the entire build through an interactive Terminal on MBP via:
bash ~/apps/cc/bin/run-terminal-over-ssh.sh mbp /tmp/freeflow-build-deploy.shThat Terminal has UI keychain auth, codesign succeeds, and the deployed .app lands on the machine James actually uses.
Pulling Updates From Upstream
Section titled “Pulling Updates From Upstream”git fetch upstreamgit merge upstream/mainResolve conflicts carefully — James’s local customizations may overlap with upstream changes.
Known Gaps / Quirks
Section titled “Known Gaps / Quirks”- App name on disk is
FreeFlow James.app, distinct from the upstreamFreeFlow Dev.app. Bundle ID stays upstream’s so TCC carries over. - Privacy: there is no FreeFlow server. Audio and prompts go to the configured transcription + LLM provider (Groq by default), nothing else.
- Edit Mode is opt-in in settings — when off, FreeFlow only inserts new text, never rewrites existing selections.