Skip to content

models: cache weights outside ~/Documents so the LaunchAgent can load them - #11

Open
bdeol2 wants to merge 1 commit into
digimata:masterfrom
bdeol2:fix/model-cache-outside-documents
Open

models: cache weights outside ~/Documents so the LaunchAgent can load them#11
bdeol2 wants to merge 1 commit into
digimata:masterfrom
bdeol2:fix/model-cache-outside-documents

Conversation

@bdeol2

@bdeol2 bdeol2 commented Jul 30, 2026

Copy link
Copy Markdown

parrot install --launch-at-login cannot start on a clean machine. The agent
loads the model, fails, exits 1, and — because the generated plist sets
KeepAlive.SuccessfulExit=false — launchd restarts it in a loop.

Cause

WhisperKit delegates downloads to HubApi, whose downloadBase defaults to
~/Documents/huggingface. ~/Documents is TCC-protected on macOS:

  • Run from a terminal, parrot inherits the terminal's Documents access, so
    model loading works. This is why it isn't visible in normal foreground use.
  • Run by launchd, parrot has no Documents access of its own, so warmUp()
    fails.

The error also misreports what happened:

warmup failed: modelsUnavailable("Model not found. Please check the model
or repo name and try again.\nError: invalidMetadataError("Could not remove
corrupted metadata file: “model.mil.metadata” couldn’t be removed because
you don’t have permission to access it.")")

Nothing is corrupt. The directory is unreadable, and HubApi surfaces that as a
metadata error while trying to clean up.

Fix

Pass an explicit downloadBase of ~/Library/Application Support/parrot,
which is outside TCC. I chose this over granting parrot access to Documents or
Full Disk Access because it needs fewer privileges, not more — the daemon
already holds Accessibility and Microphone, and adding a third broad grant to
reach a cache directory seemed like the wrong direction.

Existing users

Weights are kept by moving the cache once, rather than re-downloading:

mkdir -p ~/Library/Application\ Support/parrot
mv ~/Documents/huggingface/models ~/Library/Application\ Support/parrot/models

Worth a README note; happy to add one here if you'd like it in the same PR.

Verified

  • Before the change, under launchd: the invalidMetadataError above, runs
    incrementing on a loop.
  • After, under launchd: ✓ whisper-base.en ready, then listening on fn hold,
    runs = 1, no restarts. Dictation into a native text field works end to end,
    with the migrated cache and no re-download.
  • Foreground use is unaffected: parrot models download whisper-base.en
    resolves from the new location.
  • swift build -c release clean on this commit alone.

Not verified: only tested with whisper-base.en on macOS 15 / Apple Silicon,
and only with a migrated cache — I did not test a first-run download into the
new location from scratch.

Relationship to #9

Complementary, no overlap. #9 hardens where the daemon writes its logs; this
fixes the daemon being unable to start at all. Different files, so no conflict
#9 touches Install.swift/Parrot.swift, this only touches
WhisperKitTranscriber.swift.

… them

WhisperKit delegates downloads to HubApi, whose downloadBase defaults to
~/Documents/huggingface. ~/Documents is TCC-protected on macOS, so:

  - launched from a terminal, parrot inherits the terminal's Documents
    access and model loading works, which is why this isn't visible
    during normal foreground use;
  - launched by launchd, parrot has no Documents access of its own and
    warmUp() fails, so `parrot install --launch-at-login` cannot start
    on a clean machine.

The failure is also misreported. HubApi surfaces it as a corrupted-file
error rather than a permission one:

  warmup failed: modelsUnavailable("Model not found. Please check the
  model or repo name and try again.\nError: invalidMetadataError(\"Could
  not remove corrupted metadata file: “model.mil.metadata”
  couldn’t be removed because you don’t have permission to
  access it.\")")

Nothing is corrupt; the directory is unreadable. Combined with
KeepAlive.SuccessfulExit=false the agent then restart-loops.

Pass an explicit downloadBase of ~/Library/Application Support/parrot,
which is outside TCC. This needs fewer privileges than the alternatives
of granting parrot access to Documents or Full Disk Access.

Existing users keep their weights by moving the cache once:

  mkdir -p ~/Library/Application\ Support/parrot
  mv ~/Documents/huggingface/models \
     ~/Library/Application\ Support/parrot/models

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant