You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ addresses, and machine-specific workflow details.
20
20
-`TranscriptionPipeline`: shared transcribe -> polish -> paste -> persist control flow for stop paths; the ViewModel implements `TranscriptionPipelineHost`.
21
21
- Strict concurrency is `complete` on app and test targets. Keep new code warning-free instead of widening unsafe isolation.
22
22
- Engines: MLX Whisper local (default; vendored `LocalPackages/MLXWhisper`), Deepgram Nova-3 batch, Deepgram Flux Live, ElevenLabs Scribe batch/realtime, and Local AI Server batch STT through OpenAI-style endpoints. WhisperKit was removed deliberately (2026-07-06; MLX runs the same weights ~6x faster) — do not reintroduce it, and keep `EnginePortfolioMigration` mapping stored `whisper` selections to `mlx_whisper` and purging the CoreML caches.
23
-
-`LocalPackages/MLXWhisper` is vendored from mlx-audio-swift (MIT, pinned commit in its Package.swift header) trimmed to the Whisper model. Local additions: initial-prompt (`<|startofprev|>`) vocabulary support, real auto language detection, and a downloader with progress; sync upstream fixes manually and keep the pin comment current. Its sources are exempt from repo swift-format lint. Building anything that links mlx-swift needs the Xcode Metal Toolchain component (`xcodebuild -downloadComponent MetalToolchain`) and `-skipPackagePluginValidation` on headless xcodebuild (already in the Makefile); plain `swift build` produces a binary without Metal shaders that dies at MLX init — bench with the package's `mlxwhisper-cli` built via xcodebuild instead (XCTest-host numbers are not representative for the GPU path).
23
+
- `LocalPackages/MLXWhisper` is vendored from mlx-audio-swift (MIT, pinned commit in its Package.swift header) trimmed to the Whisper model. Local additions: initial-prompt (`<|startofprev|>`) vocabulary support, real auto language detection, a downloader with progress, quantized-checkpoint loading (4-bit), a Task-cancellation hook in the decode loop, and HF snapshots pinned to commit shas (bump revisions in `MLXWhisperModel.revision` + `WhisperModelDownloader.tokenizerRepo`); sync upstream fixes manually and keep the pin comment current. Its sources are exempt from repo swift-format lint. Building anything that links mlx-swift needs the Xcode Metal Toolchain component (`xcodebuild -downloadComponent MetalToolchain`) and `-skipPackagePluginValidation` on headless xcodebuild (already in the Makefile); plain `swift build` produces a binary without Metal shaders that dies at MLX init — bench with the package's `mlxwhisper-cli` built via xcodebuild instead (XCTest-host numbers are not representative for the GPU path).
24
24
- Audio capture: one class, `AudioCaptureEngine`, serves every engine. `.batch` records a WAV at `AudioUploadQuality`, except whisper-family targets (MLX Whisper, Local AI Server) on the STT-oriented qualities (ultra-fast, medium), which capture 16 kHz directly — whisper decodes at 16 kHz and a higher-rate capture only adds a second resample. `.streaming` keeps fixed 16 kHz mono int16 for WebSocket compatibility and emits PCM chunks (batch is streaming with a nil chunk handler). Do not reintroduce per-path capture classes.
25
25
- Streaming engines (Flux, ElevenLabs realtime) are driven through `StreamingDictationSession` plus one shared start/stop/pause/abort/binding path in the ViewModel (`StreamingEngineContext`). Do not add per-engine copies of that flow.
26
26
- Observation: `MLXWhisperTranscriber` and the vocabulary/AI-memory/prompt-context managers are `@Observable` — views read them directly; do not reintroduce `@Published` mirrors in the ViewModel. High-frequency tickers (recording duration) stay OFF ObservableObject state: publish through a subject and subscribe locally in the one view that renders them.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+33Lines changed: 33 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,6 +6,39 @@ This project follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
7
7
## [Unreleased]
8
8
9
+
## [2.9.0] - 2026-07-09
10
+
11
+
### Added
12
+
13
+
-**Large V3 Turbo (4-bit) local model** — a new quantized tier of the recommended turbo model: 464 MB download instead of 1.5 GB and roughly a third of the RAM while transcribing (~0.5 GB vs ~1.6 GB) at comparable quality. The vendored MLX engine now reads quantized checkpoints natively (packed 4-bit weights, quantized tied embeddings), so more tiers can follow.
14
+
-**Liquid Glass overlay on macOS 26** — the recording pill and the dock chip render in real glass, and they visually fuse when the droplet detaches from or absorbs into the chip. Older systems keep the exact material look they have today.
15
+
-**VoiceOver support across the app** — every icon-only button now has a spoken label (overlay controls, History actions, model rows, vocabulary tools), the overlay announces dictation phases (recording started, transcribing, text pasted, failed), the audio player's scrubber is adjustable with VoiceOver and arrow keys (±5 s), and hover-only affordances like vocabulary chip deletion also reveal on keyboard focus.
16
+
-**Export notice** — the History save panels for audio and text exports now remind that the file will contain dictated content before it leaves the app.
17
+
18
+
### Changed
19
+
20
+
-**Retrying and re-transcribing now run through the same pipeline as live dictations** — retry results update the original History row (no duplicate rows), stale results from an abandoned retry can no longer overwrite a newer dictation, and the audio behind a failed dictation is never cleaned up while it can still be retried.
21
+
-**Consistent motion and color language** — animations across Settings, History, and Welcome now use the shared motion tokens (including new transition and shake timings), Welcome steps and pill content swap with a blur-replace transition (Reduce Motion keeps plain crossfades), and green-as-text uses an adaptive darker shade that passes WCAG contrast on light backgrounds. The app also ships a real AccentColor, so selection tint matches the brand in every window.
22
+
-**Cloud batch engines pre-warm their connection** when the recording starts, shaving the DNS/TLS handshake (~100–400 ms) off the stop-to-paste wait on cold starts.
23
+
- The vendored MLX decode loop honors task cancellation between decode steps — groundwork for cancellable re-transcriptions of long recordings.
24
+
25
+
### Fixed
26
+
27
+
-**Two latent crash windows in audio setup** — the onboarding microphone probe and the capture-setup cleanup path called AVFAudio APIs outside the engine guard; a device route change at the wrong moment could kill the app with the same uncatchable exception class that caused historic crashes. All engine calls now go through the guard.
28
+
-**Settings window no longer clips its content** — the window was created at 800×560 while the content laid out at 860×620 (diverged in v2.2.0); both now share one constant, and the History window minimum matches its real layout.
29
+
-**Cmd+, opens the real Settings window** — previously a phantom empty settings window could appear while an app window was focused.
30
+
-**History survives database corruption** — a corrupt history database is detected on open (integrity check), sidelined with a timestamped name, and recreated fresh; History keeps working instead of silently doing nothing until reinstall.
31
+
- A race between unloading and loading local models could leave a freshly loaded model unloaded (or two resident at once); model loads are now generation-checked.
32
+
- "now" and the m/h/d suffixes in History timestamps were hardcoded English in the Spanish UI; they are localized.
33
+
- White text on the amber processing color in the menu bar failed contrast badly (≈1.6:1); processing states now use dark text on amber.
34
+
35
+
### Security
36
+
37
+
-**Pasted text is sanitized before it reaches the clipboard** — control characters, ANSI escape sequences, bidirectional-override characters, and zero-width characters are stripped from polish output and raw fallbacks alike, so a misbehaving or hostile polish endpoint cannot smuggle terminal escapes or spoofed text into what Cmd+V types.
38
+
-**Clipboard writes are marked concealed** (`org.nspasteboard.ConcealedType`), so clipboard managers and Universal Clipboard treat dictated text as sensitive instead of syncing and indexing it.
39
+
- History storage (database and audio) is created user-only (`0o700`).
40
+
- Supply chain hardening: Hugging Face model downloads are pinned to exact commit revisions, GitHub Actions are pinned by commit SHA, an unused Downloads entitlement was removed, and SECURITY.md documents supported versions and the reporting channel.
0 commit comments