ui/goose2/ui_improvements/state_management/phase-4-store-boundaries.md
Phase 4: Split The Clearest Store Boundaries
Status
Goal
Scope
ui/goose2/src/features/agents/stores/agentStore.tsui/goose2/src/features/agents/stores/agentSelectors.ts if Phase 2 adds itui/goose2/src/features/agents/stores/agentUiStore.tsui/goose2/src/features/chat/stores/chatSessionStore.tsui/goose2/src/features/chat/stores/chatSessionSelectors.tsui/goose2/src/features/chat/stores/chatSelectors.ts if chatStore boundaries are revisitedui/goose2/src/features/chat/stores/chatSessionUiStore.tsOut Of Scope
activeSessionId unless this phase's boundary review proves it is safe.chatStore immediately.Execution Steps
Split agentStore UI state first.
agentStore as mixing personas, agents, providers, selected provider, active agent, and persona editor UI state.agentUiStore:
personaEditorOpeneditingPersonapersonaEditorModeagentUiStore:
openPersonaEditorclosePersonaEditoragentStore.Update agent UI consumers.
AgentsView.tsx and related components to read editor state from agentUiStore.agentStore.agentSelectors.ts contains only state that remains in agentStore. If UI selectors were avoided in Phase 2, this should be a small verification step.Validate the agentStore split.
agentUiStore tests if behavior is not trivially covered by UI tests.agentStore.isLoading. Phase 2 found it may be a legacy/general loading flag because personas, agents, and providers already have specific loading fields. Remove or defer it only after confirming consumers and tests do not depend on it.getActiveAgent, getAgentsByPersona, getBuiltinPersonas, and getCustomPersonas. Keep them for imperative getState() usage if useful, but React consumers should prefer selectors or pure helpers.Split chatSessionStore UI state second.
chatSessionStore as mixing session records, hydration/loading, active selection, creation/archive/mutation actions, context-panel state, and workspace UI state.chatSessionUiStore:
contextPanelOpenBySessionactiveWorkspaceBySessionchatSessionUiStore:
setContextPanelOpensetActiveWorkspaceclearActiveWorkspacechatSessionStore.Update chat UI consumers.
ChatView.tsx, ContextPanel.tsx, useChatSessionController.ts, and useChat.ts if they read the moved fields/actions.chatSessionSelectors.ts so selectors for moved UI state live with chatSessionUiStore or are removed. Keep session record selectors with chatSessionStore.sessions + activeSessionId or sessions + homeSessionId; do not add duplicate stored session objects.Re-evaluate chatStore only after the two safe splits.
chatStore as mixing messages, runtime, drafts, queue, loading, scroll targets, and cleanup.chatStore and chatSessionStore store activeSessionId. Decide which store should own active session selection, or explicitly document why both must remain synchronized.chatStore state moves later, update chatSelectors.ts in the same change so selector files continue to reflect real store boundaries.Record remaining domain-model questions.
chatStore.getActiveMessages, chatSessionStore.getActiveSession, and chatSessionStore.getArchivedSessions. Prefer pure helpers/selectors for React reads, but keep imperative helpers if they are still useful in callbacks or non-React code.Recheck component responsibility after the UI-store splits.
AgentsView should be simpler after persona editor UI state moves out of agentStore; if it still mixes list filtering, editor orchestration, import/export, delete confirmation, and mutation flows too heavily, record a focused component-decomposition follow-up.useChatSessionController, ChatView, and context-panel consumers should be rechecked after context panel and workspace UI state move out of chatSessionStore.AppShell and prop-drilled through multiple surfaces, especially rename from SidebarChatRow and SessionCard.Validation
rg "personaEditorOpen|editingPersona|personaEditorMode|openPersonaEditor|closePersonaEditor" ui/goose2/srcrg "contextPanelOpenBySession|activeWorkspaceBySession|setContextPanelOpen|setActiveWorkspace|clearActiveWorkspace" ui/goose2/srccd ui/goose2 && pnpm test -- agentStore chatSessionStore useChatSessionControllerSuccess Criteria
agentStore.chatSessionStore.