fix(pulse): VoiceServer reads the DA voice from LIFEOS_CONFIG.toml - #2107
Open
pai-scaffolde wants to merge 1 commit into
Open
fix(pulse): VoiceServer reads the DA voice from LIFEOS_CONFIG.toml#2107pai-scaffolde wants to merge 1 commit into
pai-scaffolde wants to merge 1 commit into
Conversation
voice.ts resolved the main voice from settings.json daidentity.voices.main only. That block is a runtime mirror of LIFEOS_CONFIG.toml [da.voices.main] (the canonical source per SystemUserBoundary.md, written by the Interview), and nothing in the shipped tree writes the mirror, so every fresh install kept speaking the template default (Rachel) whatever voice the principal chose. hooks/lib/identity.ts already reads the config first (PR danielmiessler#1781); VoiceServer was the last reader on the mirror. Read [da.voices.main] through LifeosConfig.ts (Bun-native TOML, no new dependency) at startup and on the /notify/personality live read; fall back to the settings.json mirror only when no config loads. Verified with a temp HOME: config voice_id wins when the toml exists, the mirror's id is used when it does not; before the change the mirror's id won in both cases. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reproduced on a fresh LifeOS 7.40.4 install (macOS, Claude Code in the Claude desktop app); the fix was applied to that install and run there before filing. Precedent: PR #1781 made
hooks/lib/identity.tsread the config first;voice.tswas left on the mirror.Observed
After
/interviewwrote a customvoice_idintoUSER/CONFIG/LIFEOS_CONFIG.toml [da.voices.main], Pulse kept speaking with the template default voice (Rachel,21m00Tcm4TlvDq8ikWAM).settings.jsonhad nodaidentity.voices.main.voiceIdof its own; nothing in the shipped tree writes that block.Root cause
LIFEOS/PULSE/VoiceServer/voice.tsresolves the main voice fromsettings.json daidentity.voicesonly (loadVoiceConfigFromSettings()at startup and a live read on/notify/personality). PerSystemUserBoundary.mdandsettings.enhancements.json("LIFEOS_CONFIG.toml is the canonical config source; settings.json carries a runtime mirror of daidentity for hooks") the toml is canonical and the Interview writes only the toml. No shipped tool projects the mirror, so the VoiceServer never sees the chosen voice.Fix
Read
[da.voices.main]throughLIFEOS/TOOLS/LifeosConfig.ts(Bun-native TOML, no new dependency) — the same loader identity.ts uses:configMainVoice()mapsLifeosVoiceSettingsto the module'sVoiceEntry(same defaults the settings.json mapper applies) and returnsnullwhen no config loads (LifeosConfig throws on a missing file, empty[da].name, or missingvoice_id— that catch is the fallback path).loadVoiceConfig()= settings.json mirror, then the config's main voice overridingvoices.main/voicesByVoiceId/defaultVoiceIdwhen present.startVoice()calls it./notify/personalitylive read tries the config first, then the mirror as before.Why not have the installer write the mirror instead: that keeps two writers for one value and leaves this reader inconsistent with the ones that already went to the config (#1781); the doctrine is that system code reads identity through
loadLifeosConfig().How tested
Probe (
startVoice({enabled:true})thenvoiceHealth().default_voice_id), temp HOME whosesettings.jsonmirror carries Rachel,LIFEOS_CONFIG_PATHpointing at a temp toml with a distinct id:21m00Tcm4TlvDq8ikWAM(mirror)21m00Tcm4TlvDq8ikWAMAAAAAAAAAAAAAAAAAAAA(config)21m00Tcm4TlvDq8ikWAM(mirror fallback)Transpiles (
bun build --target=bun --no-bundle). On the live install,curl localhost:31337/voice/health | jq .default_voice_idreturns the toml's voice after a Pulse restart.🤖 Generated with Claude Code