# D40. The author's ElevenLabs key lives in one place; the keychain is used only after the author's gesture (14 Oct 2026)

Amends D29. On 14 Oct 2026 an installed build of the app (ad hoc signed, no Developer ID yet) asked for the keychain at its very first launch: the app decrypted the key with `safeStorage` at startup and at every module's opening, and the keychain item had been made by the development build, another ad hoc identity to macOS. Every unsigned build would have asked again, and a prompt that comes before any gesture reads as an app reaching for a secret nobody asked it to use. Decided:
- **One place, as the author chose.** When their AI may use the key (the default), it is only in the 0600 file the command line and agents read (`<local data>/credentials/elevenlabs-api-key`, `keyFile`), which the engine reads too (`resolveKey` falls back on it): no keychain at all, and `elabora voice key set` writes that same place. When their AI may not, the key is only in the system's secure storage (the app's `safeStorage`: Keychain, DPAPI, libsecret), and there is no file. Changing the choice moves the key, written in its new place before it leaves the old one, so that a failure loses nothing; keeping a key clears the other place; removing it clears both, without the keychain. Two copies were two secrets to keep in step, and for this key the file is as safe as the keychain (D29: an agent runs as the author and could read either).
- **The keychain is used only after the author's gesture**: keeping a key, moving it, and the first time a launch calls ElevenLabs (a voice searched, heard or set by its id, an estimate before « Générer », the quota asked for). The app's engine host asks the main process for the key before such a request; the main process reads it once and keeps it in memory for the launch. Never at startup, nor when a module or the settings open: what the app shows (a key or none, masked, where it is) is read without the secret, the masked form being kept beside the choice. With the key in the keychain, the quota is read at that gesture rather than when a module opens (« Afficher le quota » in Elabora settings and in the module's voices). A key the keychain cannot decrypt, or that the author refused to give, reads as no key for the launch, said once in the log; the app's log names every use of the keychain.
- **No keychain question on macOS or Windows**, where the Keychain and DPAPI are always there; on Linux, whether a keyring exists is asked only when a key must go into it, so a computer without one keeps the key for the author's AI.
- **No migration** (the product is not published, D39): when both places hold a key, the choice says which is read, and the other goes with the next key kept.
- Rejected: reading the key at startup to hand it to the engine ahead of time (the prompt before any gesture); the keychain as a second copy beside the file (two places to keep in step, and the file is what agents need); signing the builds as the only answer (a Developer ID keeps one identity across updates, so fewer prompts, but the development and installed builds still differ, and a read at startup stays a read nobody asked for).
*Revisit if:* signed builds still surprise authors with a prompt at a gesture they did not expect, or a platform lets agents use a keychain item without prompts.
