Skip to content

Latest commit

 

History

History
204 lines (155 loc) · 12.4 KB

storage-paths.md

File metadata and controls

204 lines (155 loc) · 12.4 KB

Storage Paths

Current App Layout On main

The current Transcripted app defaults to a Transcripted-named Application Support root:

  • app support root: ~/Library/Application Support/Transcripted/
  • default capture library: ~/Library/Application Support/Transcripted/captures/

Users can point the capture library at a different folder in Settings via the transcriptSaveLocation preference. When the current library still has saved meetings, dictations, or writing, Settings offers to move or copy those captures to the new folder before switching. Both skip destination name collisions instead of overwriting. Copy never deletes originals. Move copies first, switches the library, then sends each copied original to the Trash only if its copy exists and the original hasn't changed since it was copied; anything else stays in the old folder. App-owned state, cache, logs, and temp files always stay under ~/Library/Application Support/Transcripted/.

Dictation

Dictation artifacts live under:

  • root: <capture-library>/dictations/
  • current runtime output: daily markdown files like Dictations_2026-04-11.md

DictationStoragePaths.transcriptsFolder points directly at the dictations folder. There is no extra transcripts/ subdirectory in the current app layout.

Kept dictation audio lives in <capture-library>/dictations/audio/, one file per take named from its session UUID: <uuid>.m4a, or <uuid>.wav until background compression finishes (or if it failed). Files are 0600 in a 0700 folder. The day file's Audio: line stores the path relative to the dictations folder (audio/<uuid>.m4a), so it survives a library move; Move and Copy carry dictations/audio/*.m4a|*.wav like the day files (audio named by a day file that stays behind on a name collision stays behind with it). Deleting a dictation in Home deletes its kept audio once the undo window closes. DictationAudioArchive (Sources/Dictation/DictationAudioArchive.swift) owns keep, resolve, compress, and prune. How long audio stays is Settings → Storage → Keep dictation audio (dictation-audio-keep in AudioStoragePreferences: Don't keep, 7 days, 30 days (default), Forever); pruning runs at launch and when the setting changes, and only touches regular files with those names, never symlinks.

Until the transcript saves, a take's audio stays in the private recovery folder ~/Library/Application Support/Transcripted/state/dictation-audio-recovery/ (app state, not the library). After a successful save it moves into dictations/audio/ when audio is kept, or is deleted when it isn't. A failed save leaves it in recovery.

Writing

Saved writing lives under:

  • root: <capture-library>/writing/
  • runtime output: one Markdown file per local day, like Writing_2026-09-25.md. The format is in docs/capture-format.md ("Writing day files").

The main app writes these day files, never the keyboard. The folder is created 0700 and each file 0600. FileManager.writingSupportDir resolves the folder (FileManager.writingDirectory(in:) for a library other than the current one), and mcp-directories.json lists it as writingDirectory. That key is optional: manifests written before Writing lack it and get rewritten once with it, and tools that predate it ignore it. Choosing a new capture library prepares writing/ next to meetings/ and dictations/, and Move and Copy carry writing/*.md with the same collision and changed-since-copy rules as dictation day files.

App-owned Writing state stays under Application Support when the capture library moves:

  • state root: ~/Library/Application Support/Transcripted/writing/, holding the keyboard socket ghost.sock, runtime.lock, the text-free Outcome Ledger/ and Word Diary/ (Tilde's plaintext word diary isn't ported; accepted text is saved only by Save my writing), and the encrypted Personal History/. Outcome Ledger/events.jsonl is cut back to its newest 12 MiB once it passes 24 MiB, which still covers the seven-day window
  • models: ~/Library/Application Support/Transcripted/models/writing/<id>/model.gguf, excluded from backup. The Writing tab's Delete model empties this folder (never Delete all writing); it refuses the folder if it's a symlink
  • diagnostics log: ~/Library/Application Support/Transcripted/logs/writing-diagnostics.log, rolled to writing-diagnostics.log.1 at 4 MB (one old generation kept)

Closed, secret-scrubbed writing waiting for its day-file save is owned by ~/Library/Application Support/Transcripted/writing/Pending Entries/pending-writing.json. This private 0600 journal in a 0700 folder stays local when the capture library moves or goes offline. Publication is replayed by Entry ID so a restart cannot append the same entry twice. Up to 256 closed entries / 8 MiB may wait; a full or unavailable recovery store refuses new closed-entry admission rather than dropping old entries. Save errors stay visible until every pending entry is resolved. Consent changes, scope narrowing, opt-out and Delete all discard pending writing intentionally. Raw open entries and scrubber context are never journaled; a crash/force quit can still lose unfinished writing. When the final open entry can't be closed into durable ownership, graceful Quit asks first (Keep Open / Quit Anyway); logout, restart and shutdown go ahead and lose that entry.

Meetings

Meeting captures live under:

  • root: <capture-library>/meetings/

The meetings capture folder contains user-facing artifacts:

  • markdown transcripts: <capture-library>/meetings/*.md
  • retained recording audio: <capture-library>/meetings/audio/*_audio/

After a successful transcript save, app-managed retained .wav audio is converted to .m4a and the original .wav is removed only after conversion succeeds. The Storage settings page controls whether retained audio is deleted after 7 days, 30 days, or never. Markdown transcripts are not removed by audio retention cleanup.

On launch, Transcripted also performs best-effort compression for existing retained audio folders that already have matching Markdown transcripts. Failed audio that is still referenced by the failed-meeting retry queue can also be compressed in place, with the queue updated to point at the new .m4a files before the original .wav files are removed. Orphaned audio without a saved transcript or failed-queue entry is left alone instead of guessing ownership.

App-owned meeting state is stored separately under:

  • speaker DB: ~/Library/Application Support/Transcripted/state/speakers.sqlite (WeSpeaker voiceprints); the default ReDimNet2 voiceprint model keeps its own state/speakers_redimnet2-b4.sqlite, since voiceprints from different models can't be compared
  • stats DB: ~/Library/Application Support/Transcripted/state/stats.sqlite
  • failed queue: ~/Library/Application Support/Transcripted/state/failed_transcriptions.json
  • queued import journals: ~/Library/Application Support/Transcripted/state/imported_transcription_queue/
  • runtime diagnostics marker: ~/Library/Application Support/Transcripted/state/runtime-diagnostics.json
  • stopped dictation audio: ~/Library/Application Support/Transcripted/state/dictation-audio-recovery/ (a private WAV plus .json written when a dictation stops, deleted once its text is saved; a short failed take's WAV is usually dropped with the error, while a take of 30 s or more keeps it behind a Transcribe It button. At the next launch a leftover under 30 s is deleted; one of 30 s or more, or one whose length can't be read, stays here quietly with nothing asking about it)
  • dictionary-fix backups: ~/Library/Application Support/Transcripted/state/dictionary-fix-backups/ (one folder per "Fix them" from the Corrections list: the original text of each meeting it changed plus a receipt.json; kept 3 days so Undo survives a relaunch, pruned at launch, and dropped when the meeting is deleted from Home). Backups follow the meeting's file name, so renaming a fixed meeting drops its Undo at the next launch; the prune is skipped while the meetings folder is missing (for example on an unmounted drive)

Claude Desktop integration installs the bundled read-only MCP helper under:

  • MCP helper: ~/Library/Application Support/Transcripted/mcp/transcripted-mcp
  • MCP directory manifest: ~/Library/Application Support/Transcripted/mcp-directories.json

The opt-in live meeting helper (Tools/TranscriptedLive) writes outside the app's folder, under ~/Library/Application Support/TranscriptedLive/ (or TRANSCRIPTED_LIVE_DIR):

  • session.json: the helper's state and current ghost lines
  • meetings/<id>.jsonl: the rough transcript of each meeting it heard; the helper deletes ones older than 24 h when it starts. Deleting a meeting in the app, moving the capture library and the app's cleanup never touch this folder

Script-installed experimental models (never downloaded by the app) live under:

  • Parakeet Ultra: ~/Library/Application Support/Transcripted/models/parakeet-ultra/parakeet-tdt-0.6b-v3/, installed by scripts/models/parakeet-ultra/install.sh and only used when its transcripted-model.json marker is present

The ReDimNet2 voiceprint model ships inside the app (Transcripted.app/Contents/Resources/redimnet2-voiceprint/Model.mlmodelc). The build copies it from the shared FluidAudio model cache, where the app also looks when the bundle has none: ~/Library/Application Support/FluidAudio/Models/redimnet2-b4-slim/Model.mlmodelc, put there by scripts/models/redimnet2/install.sh. The app never downloads it.

Temporary audio scratch paths live under:

  • raw recordings: ~/Library/Application Support/Transcripted/tmp/recordings/
  • speaker clips: ~/Library/Application Support/Transcripted/tmp/recordings/speaker_clips/

Successful live and imported meeting recordings are copied from scratch into the meeting capture library before scratch cleanup. Failed live meeting transcriptions also copy their available recording audio there while keeping the scratch files available for retry. Explicitly discarded recordings still delete their scratch audio.

These paths are defined on the app side in Sources/Meeting/MeetingStoragePaths.swift and then injected into TranscriptedCore through CoreStoragePaths.

Logs And Events

App-side observability output currently lives under:

  • debug log: ~/Library/Application Support/Transcripted/logs/debug.log
  • events: ~/Library/Application Support/Transcripted/logs/events.jsonl
  • Writing diagnostics: ~/Library/Application Support/Transcripted/logs/writing-diagnostics.log

The embedded TranscriptedCore logger also writes JSONL under the same logs directory:

  • core pipeline log: ~/Library/Application Support/Transcripted/logs/app.jsonl

TranscriptedCore Defaults

CoreStoragePaths.default now uses the same Transcripted-named Application Support layout:

  • meeting captures: ~/Library/Application Support/Transcripted/captures/meetings/
  • databases + failed queue: ~/Library/Application Support/Transcripted/state/
  • raw audio scratch: ~/Library/Application Support/Transcripted/tmp/recordings/
  • logs: ~/Library/Application Support/Transcripted/logs/

The app still injects its own CoreStoragePaths so the meeting capture folder can follow the user-selected capture library.

Standalone Tool Fallbacks

The standalone tools do not all resolve paths the same way:

  • TranscriptedCLI first follows the app-selected capture library from mcp-directories.json or the app's transcriptSaveLocation preference, then falls back to the current Transcripted capture folders, then legacy Draft .../transcripts/, then ~/Documents/Transcripted/; explicit --data-dir, --meetings-dir, --dictations-dir, or matching env vars still override this
  • TranscriptedMCP first follows the app-selected capture library from mcp-directories.json or the app's transcriptSaveLocation preference, then falls back to the current-plus-legacy read order. It keeps its SQLite index under ~/Library/Application Support/Transcripted/cache/ by default; if TRANSCRIPTED_DATA_DIR is set, it instead keeps the index in that shared root unless TRANSCRIPTED_INDEX_DIR is also set
  • TranscriptedQA follows the app-selected capture library from mcp-directories.json or the transcriptSaveLocation preference, scans the current and existing legacy fallback capture directories, keeps state/log validation under the app-owned ~/Library/Application Support/Transcripted/ root, and accepts explicit --path, --dictations-path, --state-dir, and --log-path overrides for nonstandard setups