Split out of #10, which was originally an onboarding question ("after login… now what?"). Several people have since reported a different problem in that thread, so it gets its own issue.
Symptom
After a login that reports success, the dashboard's daemon badge stays on:
Daemon sees an anonymous session — run login to connect.
…and running login again doesn't clear it. Reported by @ITFinesse and @lcarbow in #10.
Why this is not simply a duplicate of #11
#11 (Windows ships a Linux keytar.node) is one route to this symptom, but it is Windows-only, and the reason codes don't line up:
So closing these as dupes of #11 risks dead-ending Linux users on a Windows packaging bug. Hence this umbrella.
The one thing we need from you
Please post your OS plus the verbatim reason field from:
~/.perplexity-mcp/profiles/<profile>/daemon-status.json
That single field forks the diagnosis cleanly:
reason |
vault.enc |
Most likely cause |
vault-locked |
present |
Windows → #11 (Linux ELF keytar.node). Linux → no libsecret, or the passphrase isn't in the daemon's env (0.8.49 class) — try Refresh state, install gnome-keyring, or set PERPLEXITY_VAULT_PASSPHRASE |
not-logged-in |
absent |
The vault seal never happened — login died before writing it |
not-logged-in |
present |
The vault unsealed fine but the live auth probe failed (expired cookie, CF block). "Run login" will not fix this — misleading message, see below |
The forking lines in daemon.log: [vault] getSavedCookies failed (vault-locked) · no vault.enc … run login first · No authenticated session (anonymous mode) · Auth check failed:.
Known contributing bugs
1. Stale status file — FIXED (unreleased). shutdown() wrote authenticated:false to daemon-status.json on its way out, and a crashed daemon just left its last write behind. The extension read that file with no liveness check, despite pid sitting right there in the payload. So a daemon that had merely stopped rendered "anonymous session" forever, and no amount of logging in could clear it. This is the best fit for "cant get it to change out of this status." getAccountSnapshot() now ignores a status whose writing process is gone.
2. not-logged-in is used as a catch-all — open. reason is computed as authenticated ? "ok" : wasLastVaultLocked() ? "vault-locked" : "not-logged-in". But authenticated is a live network probe, not "cookies exist" — any probe failure (expired session, CF block, nav timeout) lands on not-logged-in with a perfectly healthy vault, telling the user to run a login that cannot help. Needs a third reason (e.g. auth-check-failed) set when the vault did unseal but the probe still failed. Shared-contract change (DaemonAuthStatus.reason), so older daemons degrade to the existing else-branch.
3. Vault seal failure crashes the login runner — open. manual-login-runner.js, login-runner.js, and impit-login-runner.js all call vault.set(...) uncaught, so a seal failure kills the runner before it writes the models cache or emits {ok:true} — the user sees a generic crash instead of "your OS keychain is unavailable; set a vault passphrase." cli.js already does this preflight properly via checkVaultUnseal(); the extension-driven runners should reuse it.
4. Linux without libsecret — open (docs at minimum). MX Linux/XFCE and friends ship no keyring. The intended mitigation is the passphrase, but build-daemon-env.ts only peeks at an existing secret and resolves it at daemon spawn, so a daemon warm-started before the user's first login never gets one and stays anonymous until "Refresh state" fires a /daemon/reinit.
Fix 1 is in the tree; 2–4 are tracked here.
Split out of #10, which was originally an onboarding question ("after login… now what?"). Several people have since reported a different problem in that thread, so it gets its own issue.
Symptom
After a login that reports success, the dashboard's daemon badge stays on:
…and running login again doesn't clear it. Reported by @ITFinesse and @lcarbow in #10.
Why this is not simply a duplicate of #11
#11 (Windows ships a Linux
keytar.node) is one route to this symptom, but it is Windows-only, and the reason codes don't line up:daemon.logline ([vault] getSavedCookies failed … Vault locked) sets_lastVaultLocked = true, which yieldsreason: "vault-locked"and renders a different string: "Daemon can't unlock this profile's vault — click Refresh state to re-send your passphrase."not-logged-instring instead.So closing these as dupes of #11 risks dead-ending Linux users on a Windows packaging bug. Hence this umbrella.
The one thing we need from you
Please post your OS plus the verbatim
reasonfield from:That single field forks the diagnosis cleanly:
reasonvault-lockedkeytar.node). Linux → no libsecret, or the passphrase isn't in the daemon's env (0.8.49 class) — try Refresh state, installgnome-keyring, or setPERPLEXITY_VAULT_PASSPHRASEnot-logged-innot-logged-inThe forking lines in
daemon.log:[vault] getSavedCookies failed(vault-locked) ·no vault.enc … run login first·No authenticated session (anonymous mode)·Auth check failed:.Known contributing bugs
1. Stale status file — FIXED (unreleased).
shutdown()wroteauthenticated:falsetodaemon-status.jsonon its way out, and a crashed daemon just left its last write behind. The extension read that file with no liveness check, despitepidsitting right there in the payload. So a daemon that had merely stopped rendered "anonymous session" forever, and no amount of logging in could clear it. This is the best fit for "cant get it to change out of this status."getAccountSnapshot()now ignores a status whose writing process is gone.2.
not-logged-inis used as a catch-all — open.reasonis computed asauthenticated ? "ok" : wasLastVaultLocked() ? "vault-locked" : "not-logged-in". Butauthenticatedis a live network probe, not "cookies exist" — any probe failure (expired session, CF block, nav timeout) lands onnot-logged-inwith a perfectly healthy vault, telling the user to run a login that cannot help. Needs a third reason (e.g.auth-check-failed) set when the vault did unseal but the probe still failed. Shared-contract change (DaemonAuthStatus.reason), so older daemons degrade to the existing else-branch.3. Vault seal failure crashes the login runner — open.
manual-login-runner.js,login-runner.js, andimpit-login-runner.jsall callvault.set(...)uncaught, so a seal failure kills the runner before it writes the models cache or emits{ok:true}— the user sees a generic crash instead of "your OS keychain is unavailable; set a vault passphrase."cli.jsalready does this preflight properly viacheckVaultUnseal(); the extension-driven runners should reuse it.4. Linux without libsecret — open (docs at minimum). MX Linux/XFCE and friends ship no keyring. The intended mitigation is the passphrase, but
build-daemon-env.tsonly peeks at an existing secret and resolves it at daemon spawn, so a daemon warm-started before the user's first login never gets one and stays anonymous until "Refresh state" fires a/daemon/reinit.Fix 1 is in the tree; 2–4 are tracked here.