Menu

D37. A local voices' model can be removed, never under a generation; the lines made stay (13 Oct 2026)

Asked on 13 October: the local voices in Elabora settings, by language, installed or not, each with its size and a way to install, remove or reinstall it: a French model takes 354 MB and an author who narrates in English only, or with ElevenLabs, may want the room back.

  • What is removed is the model of a language’s local voices on this computer (<local app data>/voices/pocket-tts/<bundle>/), nothing else. Narration made with it is in the modules (assets/narration/, D24) and its takes in the project’s local data (voice-takes/): both stay, and a line keeps its audio and its credit. The next generation in that language downloads the model again, as on first use (the app offers it first).
  • Never under a generation. Whoever says lines with a model holds it (models/download.ts holdFiles): a file per hold in <bundle>/.in-use/, named by its process, from the first line of a generation to its last (generateNarration, through the provider’s hold), and around each line said otherwise. Removing it is refused (E_VOICE_IN_USE, « a generation is saying lines with it ») while a live process holds it, here or in another (the app, a command, an MCP server), and while it is being downloaded; it does not wait, as a generation can take minutes and the author is better told. Holds of a process that is gone are ignored.
  • No race. A hold and a removal both take the folder’s lock (now <bundle>.lock, beside the folder, holding the process, what it does, download, hold or remove, and a token: made whole at once by linking a file of its own to that name, released only by its owner): a hold that comes first refuses the removal, one that comes after finds the folder gone and downloads it again. A lock or a hold of a process that is gone, or written before the computer last started (its process id may be another’s now), counts for nothing; a dead lock is taken over by renaming it away and checking it is still the one found dead, so that two processes cannot both take it over. The folder is renamed away first (at once, and refused whole where a system keeps open files, Windows), then deleted; what a removal stopped midway left is deleted the next time. The model this process keeps in memory between lines is freed before.
  • Reinstall is a removal then a download (elabora voice install <language> --force), under the same rule: a damaged or doubtful model is downloaded again without a separate command.
  • Interface. VoiceProvider gains model, uninstall and hold, and status says the size on disk, the download’s size, a download under way in any process (its bytes read from the disk, so another process’s shows too) and whether it is in use; localVoices(language?) lists the local voices by language with their model (LocalVoicesView), uninstallVoices(language) removes every local provider’s model of a language. CLI elabora voice models, elabora voice uninstall, elabora voice install --force; MCP elabora_voice_models, elabora_voice_uninstall (destructive: only when the author asks), elabora_voice_install { force }. ELABORA_VOICE_MODELS_MANIFEST gives a bundle made-up files, for tests only (the app’s checks install a model of the real sizes from a local server).
  • The word aligners (D27: French 355 MB, English 95 MB), downloaded the same way into <local app data>/aligners/, were left out of the first list; D38 lists them with the voices, and every optional download after them. Revisit if: authors want a model kept on an external disk, models move to a shared folder of several users, or a removal must wait for the generation to end rather than be refused. Extended to every optional download, the word aligners first, by D38.