Releases: DRYCodeWorks/tacet
Release list
tacet v0.1.3
tacet v0.1.3
Corrects the message you see when an installed bundle never starts. It
blamed /Applications and called ~/Applications known-good; both were
disproved isolating #25. The cause is com.apple.quarantine, a quarantined
bundle hangs in ~/Applications too, and the first blocked launch wedges
the path so removing the attribute does not recover it. The message now
says all three, and gives a recovery that works.
Also the first release cut by CI rather than by hand: signed, notarized
and stapled on a runner, with the cask bump opened by a GitHub App
scoped to the tap alone.
tacet v0.1.2
Since v0.1.1 the Homebrew cask served a build six commits behind main. The Quit menu item did nothing, and once it did work there was no way to reopen the app short of knowing the launchctl kickstart incantation. This release fixes both, and fixes the cask hang that made the whole thing hard to see.
Fixed
- The cask no longer hangs on install. Casks quarantine by default, and tacet is only ever exec'd directly — launchd starts it, and
install-server.shexecs it to verify. Exec'ing a quarantined bundle blocks in_dyld_startwaiting on a consent decision that has no UI to answer it, so the app deadlocked before running a line of its own code. Notarization did not help: the gate is consent, not assessment. The cask now strips quarantine inpostflight, before anything can exec the binary. (#25, tap#6) - Quit works. The menu item had no target, so it did nothing.
- You can reopen the app. Launching with no arguments now runs the agent, which is what double-clicking a
.appdoes. Previously it printed usage and exited 2 — invisible from Finder, which made Quit a one-way door. --helpexits 0 on stdout; an unknown role exits 2 on stderr. Scripts can tell those apart.- A wedged install fails diagnosably.
install-server.shparses its arguments properly and bounds the binary check instead of blocking indefinitely. - Developer ID rebuilds no longer reset TCC grants, so Accessibility and Microphone survive an upgrade.
- Installers use a Homebrew-installed bundle rather than building over it, so you do not end up with two copies and a notarized app does not get re-signed.
Install
brew install --cask drycodeworks/tap/tacet
Then run ./install-server.sh (the machine that transcribes) or ./install-client.sh (the machine you dictate from) from a clone.
If you installed v0.1.1 from the cask and it wedged, brew uninstall --cask tacet and reinstall. The first blocked launch wedges the path, so if it still hangs, remove /Applications/Tacet.app before reinstalling.
Verification
Developer ID signed, notarized (submission 1dc6120e), stapled. spctl -a reports accepted / source=Notarized Developer ID. 53 Swift + 111 Python tests pass.
tacet v0.1.1
Fixed
Transcription quality regression — vocabulary biasing was silently off.
When the shell installer replaced the launchd plist templates, three
whisper-server flags stopped being passed: --prompt, --no-timestamps, and
--suppress-nst. whisper.prompt was still read from config.toml and still
documented, but nothing consumed it, so every technical term decoded unbiased
while the service started, answered, and logged nothing unusual. If your jargon
has been coming back mangled since the Swift server landed, this is why.
Losing --suppress-nst also meant Whisper's non-speech tokens ([BLANK_AUDIO]
and friends) could be pasted at your cursor verbatim — sanitization only
collapses whitespace and control characters.
Installers no longer sign ad-hoc by accident. With TACET_SIGN_IDENTITY
unset, build-app.sh used to fall back to an ad-hoc signature and report
success. That bundle installs fine and fails later, somewhere else: TCC grants
key on the designated requirement, and an ad-hoc DR is a bare cdhash, so
Accessibility and Microphone consent dies on the next rebuild — while
notarization rejects the same bundle only after upload.
build-app.sh now resolves a Developer ID from the keychain when the variable
is unset, and exits rather than downgrading. Ad-hoc is available deliberately
with TACET_ALLOW_ADHOC=1. Both --doctor implementations now report the
signature type; they had been passing ad-hoc bundles, because
codesign --verify --strict is satisfied by one.
Known issues
--promptbiases tokens, not phrases, so compounds whose parts are ordinary
words still split —ReplacingMergeTreetranscribes as "replacing MergeTree"
even with the term in your prompt (#23).- A fresh install ships no vocabulary at all;
whisper.promptis empty by
default and is the single cheapest accuracy win available (#24).
Upgrading
Re-run ./install-server.sh to pick up the corrected plist. If you only want
the flags without reinstalling the app bundle, re-render the plists and reload
the whisper agent alone.
Your ~/.config/tacet/config.toml is untouched by the upgrade — and is not
backed up by anything. Worth a copy somewhere.
tacet v0.1.0 — alpha
Push-to-talk dictation for macOS. Hold Ctrl+Alt+Space, speak, release — the transcript is pasted at the cursor, including into a terminal reached over SSH or mosh.
Transcription is local (whisper.cpp, model held resident). Audio never leaves your hardware: no cloud ASR, no account.
This is an alpha. It works, and it has been used daily — but by one person, on two Macs, with one microphone.
Install
git clone https://github.com/DRYCodeWorks/tacet && cd tacet
./install-server.sh # transcription side
./install-client.sh # hotkey, mic, pasteOn one Mac, run both. On two, run install-server.sh on the machine holding the model and install-client.sh on the one you type at.
Tacet.zip below is the same app bundle the installers build, prebuilt and signed with Developer ID (Team Q6G8B5282N), notarized by Apple and stapled — so it launches without a Gatekeeper prompt. The installers still handle launchd, the model download, and config rendering, so the clone is the supported path; the zip is for inspecting or hand-placing the bundle.
Two permissions no installer can grant for you — Microphone and Accessibility — have to be approved in System Settings. The README covers what to click and how to tell which one is missing.
Known rough edges
- Silence threshold is calibrated against synthetic audio, not a real microphone. A different mic in a different room may need a different number. Every request logs its measured RMS so you can calibrate from evidence.
- First-word clipping. ~670 ms of device-open latency will swallow a fast first word if you speak the instant you press the key. Pre-warming would fix it at the cost of holding the mic open continuously — a privacy trade that should be deliberate, so it is not built.
- End-to-end latency is not rigorously measured. If it feels consistently above ~2 s, the lever is a faster model, not this pipeline.
License
MIT.