Native macOS on-device transcription — hold a hotkey, speak, release, text at the cursor
Full context is in CLAUDE.md. This file is the short operational loop.
- Swift 6, strict concurrency, macOS 26.0
- XcodeGen project (
project.yml) —Utt.xcodeprojis generated - The Composable Architecture 1.26.1
- FluidAudio (Parakeet TDT v3) + WhisperKit
UttCoreis a plain SwiftPM package: pure logic, all the tests
just check— the gate: just-fmt-check + loc-check + dir-check + lint + build + testjust lint-fix—swiftlint --fix, then relintjust build/just build-releasejust test—swift testinUttCorejust run— build, kill the running copy, launchjust dr— print the designated requirement (TCC stability)just generate— regenerate the Xcode project fromproject.yml
Run just check after every change. On failure, work in this order:
just lint-fixjust buildjust test
Don't block on just check while a feature is still in progress — hand it to the
verify-runner subagent and keep building. It applies safe auto-fixes itself and writes
anything it can't safely resolve to .claude/tickets/ instead of stopping you. Read
.claude/tickets/ before treating a feature as done, and delete a ticket once you've
confirmed its issue is fixed.
- Reducer
switchcases stay one line and delegate to aprivate extensionmethod. - Child → parent is pattern-matching on the child action, not a delegate action.
- Views read
@Shared(.uttSettings)directly;AppFeature.Actionis notBindableAction, so a child binding is routed by hand:store.send(.history(.binding(.set(\.searchText, $0)))). - New pure logic goes in
UttCorewith a test. Anything needing a screen or a microphone does not. - Comments explain why, especially where the platform misbehaves. There are a lot of those; they are the most valuable text in the repo.
- Swift Testing (
@Test,@Suite,#expect), not XCTest. - Files:
UttCore/Tests/UttCoreTests/ - One test:
cd UttCore && swift test --filter HotKeyProcessorTests
view.windowis nil inmakeNSViewand one runloop turn later. SubclassNSViewand overrideviewDidMoveToWindow..fullSizeContentViewdoes not shrink the window frame; only removing.titleddoes.import IOKit.pwr_mgt— notIOKit.pm, not bareIOKit.log streammisbehaves under the rtk wrapper; use/usr/bin/log show --last 30s --style compact --info --debug --predicate 'subsystem == "dev.jurrejan.utt"'.xcodebuildneeds-skipMacroValidation -skipPackagePluginValidation, or it demands an interactive trust click whenever a macro fingerprint moves.
- Do not run
just xcode— never open Xcode. - Do not archive, notarize, push, or touch the signing identity without asking.
- Do not modify the deployment target without asking.
- Anything needing a live hotkey press needs the user physically present. Ask first; do not assume they are ready.