Skip to main content
Doug’s assistant panel, draft network calls, conversation management, and the assistant activity view are owned by the assistant remote and the organisation feature remote. The shell’s role is limited to the header toggle, the user-menu entry, the availability bridge that decides whether to show them, and toggle-state persistence.

What the shell owns

The shell retains three assistant-related modules in src/assistant/: Everything else — the SSE turn loop, draft accept/reject/edit network calls, conversation list, draft state machine, activity audit, and fatigue summary — is owned by the assistant remote (appframe-aside widget slot) and the organisation feature remote (Settings → Assistant activity).

Assistant panel and widget slot

The panel mounts as a RemoteWidgetSlot in the appframe-aside slot, outside AppFrame, so it persists across route changes. The shell loads it lazily:
  • Availability entry (assistant/availability, ≈11 KB including remote entry and share shims): loaded eagerly once per manifest to publish window.__STRALOS_ASSISTANT__ and let the toggle render.
  • Widget entry (assistant/widget, ≈135 KB): loaded once, on first open.
Both entries share one store. Whichever arrives first publishes the bridge; the second is a no-op.

Toggle state storage

The shell writes and reads only stralos.assistant.toggle. It no longer reads the legacy stralos.assistant.panel key: sessionStorage dies with the tab, and production first served users after the split shipped. The split exists to prevent the shell from destroying a conversationId the remote stores in the legacy key. The remote migrates the legacy key on first read.

User-menu entry

The user menu shows Talk with Doug (AI Assistant) only while useAssistantAvailable() returns true, so it never offers an item that opens nothing. The item calls openAssistant(), which loads the widget if needed and opens the panel; unlike the header button, it never closes it. The billing recovery menu does not show the item because the assistant panel is not mounted there.

Availability bridge

assistantBridge.ts subscribes to window.__STRALOS_ASSISTANT__ (version 1), a store the remote publishes when its availability module evaluates. useAssistantAvailable() returns:
  • undefined — bridge not yet arrived; render nothing.
  • true — assistant is available; show the toggle.
  • false — assistant is disabled; hide the toggle.
The bridge arrives after the toggle mounts on every render. notifyAssistantBridgeInstalled() is called by loadAssistantAvailability once the availability load resolves so that already-mounted readers re-subscribe and pick up the initial snapshot.

Assistant activity

Organisation admins can open Assistant activity in Settings. That panel is owned by the organisation feature remote, not the shell. The shell’s App.settingsHandoff.test.tsx covers the integration path — verifying that the activity and fatigue endpoints are called with the host’s bearer token after the remote mounts through the real organisation route. See AI copilot frontend for the ChatPanel component contract, Doug assistant frontend for the draft lifecycle, network calls, and kill switch, and Organisation settings frontend for the activity view.