Document engine APIs, settings, update checking, and embedding constraints - #135
Conversation
BLURTENGINE.md was accurate but incomplete: a set of public API added since its last revision had never been documented at all. Nothing in the guide contradicted the source — it just stopped short of it. Adds coverage for: - Record cues: RecordingCueGate's edge detection, SoundPack/SoundPackStore and the generated catalog, and the fact that the cue audio lives in the app bundle rather than the package. - RecentDictations and OverlayOriginStore, alongside the overlay geometry they sit next to. - Settings and persistence: the store roster with each key and what unset means, why DefaultsKey + PersistedSettings.resetAll are one edit rather than two, and the trimmedNonEmpty / prefix(maxUTF8Bytes:) rules. - Update checking: UpdateChecker, SemanticVersion, AutomaticUpdateCheck's launch gate, and UpdateAlertContent. - SigningIdentity / SigningIdentityMigration, next to SetupReadiness, plus why its defaults key stays outside the reset roster. - A new "Embedding outside Blurt" section naming the constants that hard-code Blurt's identity (Keychain service, log subsystem and paths, defaults prefixes, update feed) and which of them a host can actually override. Docs only; no source changes. scripts/check.sh --portable passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012cpCgfMDhNBQYFQS2zgDGy
Quick start only said "from a checkout or as a local path dependency", which undersold it — Package.swift is at the repo root with a semver tag history, so the engine is consumable today. Shows the actual .package(url:from:) snippet, and flags that the tags are Blurt's app releases from the DMG pipeline rather than independent engine releases, so a patch bump says nothing about whether the engine changed. Expands "Embedding outside Blurt" into the three things that are actually in the way of a third-party host, each with what closing it would take: - Blurt's identity baked into engine defaults (Keychain service, os_log subsystem, log paths, defaults prefix, update feed, product name) — only the update URL has a real seam from outside, and the rest need a host-supplied identity value. - Update/ being Blurt's self-updater inside a dictation library, why it lives in the engine at all (the shell has no unit-test target), and why a target split has to keep the DefaultsKey reset roster intact. - SoundPack shipping 192 voices whose cue stems resolve to nothing, because all 384 .m4a files are app-side. Also corrects the catalog size in Record cues to the exact 192. Docs only; no source changes. scripts/check.sh --portable passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012cpCgfMDhNBQYFQS2zgDGy
Dev buildDownload Blurt.app — built from Installing itcd ~/Downloads
unzip -o blurt-dev-build-pr-135.zip # GitHub wraps every artifact in a zip
unzip -o Blurt-dev-3603621.zip
find Blurt.app -exec xattr -c {} + # clear quarantine: xattr lost -r in macOS 12.3
rm -rf /Applications/Blurt.app && cp -R Blurt.app /Applications/
open -a BlurtIt is ad-hoc signed and not notarized: Gatekeeper refuses to open it until Expect that re-grant once per dev build, including a second build of this tccutil reset Accessibility dev.alex.blurt |
main moved to d8491e2 (#132 conversation_context/word_boost, #135 engine docs), which made the PR un-mergeable. Only BLURTENGINE.md conflicted; the Swift auto-merged and both of this branch's DictationSession changes (setPhase(.connecting), mic.cancelCapture()) survived intact. Three doc conflicts, all resolved by taking main's rewritten prose and re-applying this branch's additions on top: - The "cleanup happens server-side" bullet is main's verbatim — it now describes conversation_context/word_boost, and the version here still described the deleted TranscriptionPrompt. - The projections bullet takes main's text with `.connecting` re-inserted into the OverlayUIState list and the menu-bar clause. - The settled-decisions rows combine both edits: CoreAudio joins the allowed-imports line, and transcription steering points at ConversationContext rather than the now-deleted TranscriptionPrompt. Also corrected a sentence main added while this branch was open: its new "Record cues" section described the chime as firing on the idle→recording edge, which stopped being the whole story once `.connecting` landed in front of `.recording`. It now names the connecting→recording edge and why the chime must not fire at the press. main did not touch RecordingCueGate, PipelinePhase, OverlayUIState or MenuBarStatus, so there was no semantic overlap in the projections. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JU1Ln2MKMsF9PJf1FLMQRX
What & why
This expands
BLURTENGINE.mdwith comprehensive documentation of the engine's public APIs and design constraints that were previously undocumented or scattered across source comments.New sections:
Quick start: Clarified package consumption (both remote and local paths) and added a note about version tags being app releases, not engine releases, with a forward reference to embedding constraints.
Record cues: Documented
RecordingCueGate(the edge detector that prevents chime retriggering),SoundPack(the sound catalog and its generation pipeline), and the fact that audio files live in the app bundle, not the package.Settings and persistence: Added a table of all
UserDefaults-backed stores (TriggerKeyStore,SoundPackStore,KeyTermsStore, etc.), their keys, and defaults. Explained the decode-with-default pattern, the singleDefaultsKeyenum that powersresetAll(), and the string helpers (trimmedNonEmpty(),prefix(maxUTF8Bytes:)) that enforce the "usable text" rule.Update checking: Documented
UpdateChecker,SemanticVersion,AutomaticUpdateCheck, andUpdateAlertContent— the decision half of self-update that lives in the engine because the AppKit shell has no test target.Embedding outside Blurt: A new section flagging three things that are Blurt-specific and have no opt-out today:
Update/types aren't part of a dictation engine and live here only for test coverage reasons.SoundPackships metadata without audio files, which live in the app bundle.Each subsection explains the constraint, why it exists, and what a second host would need to do to work around it or fix it properly.
SigningIdentityMigrationandSigningIdentity, explaining the macOS designated-requirement wrinkle and why the migration key lives outside the settings roster.How it was tested
scripts/check.shpasses (or CI will, if I'm not on a Mac)No code changes; documentation only. Existing tests and CI coverage remain unchanged.
https://claude.ai/code/session_012cpCgfMDhNBQYFQS2zgDGy