Summary
With user accounts configured (the default once auth/users.yaml exists, and GENTLY_NO_AUTH unset), a user who opens the dashboard without signing in connects as Anonymous / view-only. Every chat, command, and cancel they send is silently dropped at the control gate, so plan mode and the agent appear completely unresponsive — you type, nothing happens, no error, no agent reply, no LLM call. There is no obvious in-context cue that you need to sign in and take control first.
This bit a real local-testing session: messages were sent into /plan, the agent never responded, and the only signal was a notification toast that was itself misleading (see Bug 2).
Context: the new view-only-login / control-lock paradigm landed in #43 (UX v2); this issue is about hardening its UX.
Repro
- Have
D:\Gently3\auth\users.yaml present (accounts configured) and don't set GENTLY_NO_AUTH.
python launch_gently.py (agent enabled).
- Open the dashboard without signing in → you connect as Anonymous.
- Open agent chat,
/plan, type a message.
- Expected: the agent engages plan mode, or you're clearly told you must sign in / take control.
Actual: message is dropped; you get a "Viewing only — control is held by another client" toast even though nobody holds control. No agent response.
Evidence (from a real session)
- Transcript: 21 frames, 0 agent replies; user
chat frames present; 4× "Viewing only — control is held by another client" notifications, each with you_have_control=False, holder=None.
- Interaction log never created → the message never reached the agent / LLM.
Root cause
gently/ui/web/routes/agent_ws.py:
- L340
can_control = role in CONTROL_ROLES — Anonymous role is not in CONTROL_ROLES.
- L658
if _control["holder"] is None and can_control: — control is only auto-granted to a control-capable client, so an Anonymous client never becomes holder.
- L831–832 the drive gate drops the message:
if msg_type in ("chat", "command", "cancel") and client_id != _control["holder"]:
holder_label = _client_labels.get(_control["holder"]) or "another client"
... # notify + continue (message dropped)
Bugs / gaps
1. Silent lockout with no actionable path. An anonymous user has no clear way to discover they must sign in. The bounce toast does not link to a sign-in action, and take_control (L806) just says "Your account can watch but not control" — a dead end without a sign-in affordance surfaced at that moment.
2. Misleading "another client" message. When holder is None (nobody holds control), L832 falls back to "another client", so the toast claims "control is held by another client" — false. It should distinguish:
- nobody holds control + you can't control → "Sign in to take control."
- nobody holds control + you can → auto-grant or "Click Take control."
- someone else holds it → name them.
3. (Related, minor) WebSocket reconnect race. gently/ui/web/routes/websocket.py:97 logs WebSocket error: Cannot call "send" once a close message has been sent. on fast disconnect/reconnect — the send isn't guarded by a connection-state check. Benign (auto-reconnects) but noisy.
Suggested improvements
- Surface control/identity state prominently: a persistent header chip — Viewing only · Sign in to control vs In control — instead of relying on transient toasts.
- When an anonymous/viewer user attempts to drive, return a notification that includes a sign-in action (and, post sign-in, auto-grant control if free).
- Fix the
holder is None labeling so the message reflects reality (Bug 2).
- Consider an explicit "request/take control" affordance that's discoverable before the first dropped message.
- Guard the viz-socket send against a closed connection (Bug 3).
Workaround
GENTLY_NO_AUTH=1 (env or project-root .env) disables accounts so localhost auto-holds control — fine for local/dev, but not a fix for the multi-user UX.
Environment
Summary
With user accounts configured (the default once
auth/users.yamlexists, andGENTLY_NO_AUTHunset), a user who opens the dashboard without signing in connects as Anonymous / view-only. Everychat,command, andcancelthey send is silently dropped at the control gate, so plan mode and the agent appear completely unresponsive — you type, nothing happens, no error, no agent reply, no LLM call. There is no obvious in-context cue that you need to sign in and take control first.This bit a real local-testing session: messages were sent into
/plan, the agent never responded, and the only signal was anotificationtoast that was itself misleading (see Bug 2).Context: the new view-only-login / control-lock paradigm landed in #43 (UX v2); this issue is about hardening its UX.
Repro
D:\Gently3\auth\users.yamlpresent (accounts configured) and don't setGENTLY_NO_AUTH.python launch_gently.py(agent enabled)./plan, type a message.Actual: message is dropped; you get a "Viewing only — control is held by another client" toast even though nobody holds control. No agent response.
Evidence (from a real session)
chatframes present; 4× "Viewing only — control is held by another client" notifications, each withyou_have_control=False, holder=None.Root cause
gently/ui/web/routes/agent_ws.py:can_control = role in CONTROL_ROLES— Anonymous role is not inCONTROL_ROLES.if _control["holder"] is None and can_control:— control is only auto-granted to a control-capable client, so an Anonymous client never becomes holder.Bugs / gaps
1. Silent lockout with no actionable path. An anonymous user has no clear way to discover they must sign in. The bounce toast does not link to a sign-in action, and
take_control(L806) just says "Your account can watch but not control" — a dead end without a sign-in affordance surfaced at that moment.2. Misleading "another client" message. When
holder is None(nobody holds control), L832 falls back to"another client", so the toast claims "control is held by another client" — false. It should distinguish:3. (Related, minor) WebSocket reconnect race.
gently/ui/web/routes/websocket.py:97logsWebSocket error: Cannot call "send" once a close message has been sent.on fast disconnect/reconnect — the send isn't guarded by a connection-state check. Benign (auto-reconnects) but noisy.Suggested improvements
holder is Nonelabeling so the message reflects reality (Bug 2).Workaround
GENTLY_NO_AUTH=1(env or project-root.env) disables accounts so localhost auto-holds control — fine for local/dev, but not a fix for the multi-user UX.Environment
feature/ux-v2@b8df6107(PR UX v2: agent-first entry paradigm, shared-visibility surface, and model migration #43).venv,python launch_gently.py(agent enabled, device connected)