---
phase: 33-persistent-memory
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - ui/src/pages/PersonalAssistant.tsx
  - ui/src/api/assistantMemory.ts
  - ui/src/hooks/useNexusMode.ts
  - ui/src/App.tsx
  - ui/src/components/Layout.tsx
autonomous: true
requirements: [ASST-04]

must_haves:
  truths:
    - "PersonalAssistantPage is visible when mode is personal_ai or both"
    - "PersonalAssistantPage is hidden (route redirects) when mode is project_builder"
    - "User can navigate to assistant page from sidebar"
    - "Assistant page renders the existing ChatPanel component for chat functionality"
  artifacts:
    - path: "ui/src/pages/PersonalAssistant.tsx"
      provides: "Personal assistant page component"
      exports: ["PersonalAssistant"]
    - path: "ui/src/hooks/useNexusMode.ts"
      provides: "React Query hook for nexus settings mode"
      exports: ["useNexusMode"]
    - path: "ui/src/api/assistantMemory.ts"
      provides: "API client for memory endpoints"
      exports: ["assistantMemoryApi"]
  key_links:
    - from: "ui/src/pages/PersonalAssistant.tsx"
      to: "ui/src/hooks/useNexusMode.ts"
      via: "useNexusMode hook"
      pattern: "useNexusMode"
    - from: "ui/src/App.tsx"
      to: "ui/src/pages/PersonalAssistant.tsx"
      via: "Route element"
      pattern: "PersonalAssistant"
    - from: "ui/src/components/Layout.tsx"
      to: "assistant route"
      via: "NavLink in sidebar"
      pattern: "assistant"
---

<objective>
Create the Personal Assistant page, mode-gating hook, and memory API client. Wire the route and sidebar navigation.

Purpose: ASST-04 requires assistant and project builder modes to work standalone or together. The PersonalAssistantPage is the entry point for assistant mode.
Output: Working assistant page with mode-gated visibility, sidebar link, and memory API client.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/33-persistent-memory/33-RESEARCH.md
@ui/src/App.tsx
@ui/src/components/Layout.tsx
@ui/src/api/hardware.ts
@ui/src/components/ChatPanel.tsx
</context>

<interfaces>
<!-- Existing code the executor needs -->

From ui/src/api/hardware.ts:
```typescript
export type NexusMode = "personal_ai" | "project_builder" | "both";
export interface NexusSettings { mode: NexusMode; }
export function fetchNexusSettings(): Promise<NexusSettings>;
```

From ui/src/App.tsx (route pattern):
```typescript
// Board routes at line 122-180
function boardRoutes() {
  return <>
    <Route index element={<Navigate to="dashboard" replace />} />
    <Route path="dashboard" element={<Dashboard />} />
    // ... more routes
  </>;
}
```

From ui/src/components/Layout.tsx (sidebar pattern):
```typescript
// ChatPanel rendered at line 463
// Sidebar NavLinks with icons (lucide-react)
```

From ui/src/components/ChatPanel.tsx:
```typescript
// Existing chat panel component — renders conversation list + message list
// Used as slide-over panel in Layout
```
</interfaces>

<tasks>

<task type="auto">
  <name>Task 1: Create useNexusMode hook, memory API client, and PersonalAssistantPage</name>
  <files>
    ui/src/hooks/useNexusMode.ts,
    ui/src/api/assistantMemory.ts,
    ui/src/pages/PersonalAssistant.tsx
  </files>
  <action>
    Create `ui/src/hooks/useNexusMode.ts`:
    - Export `useNexusMode()` hook that calls `useQuery` with key `["nexus", "settings"]` fetching `fetchNexusSettings()` from `../api/hardware`
    - Return `{ mode, isLoading, isAssistantEnabled }` where `isAssistantEnabled = mode !== "project_builder"`
    - Default mode to `"both"` while loading

    Create `ui/src/api/assistantMemory.ts`:
    - Export `assistantMemoryApi` object with:
      - `getMemory(companyId: string)` — GET `/assistant-memory/${companyId}` using `api.get`
      - `appendFact(companyId: string, fact: string)` — PATCH `/assistant-memory/${companyId}` with `{ fact }`
      - `clearMemory(companyId: string)` — DELETE `/assistant-memory/${companyId}`
    - Import `api` from `./client`

    Create `ui/src/pages/PersonalAssistant.tsx`:
    - Export default `PersonalAssistant` component
    - Use `useNexusMode()` — if `!isAssistantEnabled`, render `<Navigate to="/dashboard" replace />`
    - Render a full-page chat layout:
      - Use `useCompany()` to get `selectedCompany`
      - Create or retrieve an assistant conversation (use existing `chatApi.listConversations` with a dedicated agent filter, or create a new one)
      - Render `ChatPanel`-style UI: conversation list on left, messages on right
      - Include a header with "Personal Assistant" title and a "Turn this into a project" button (wired in Plan 03)
    - Styling: Use existing Tailwind patterns from Layout.tsx. Full height (`h-full`), flex layout, clean assistant-focused design.
    - The "Turn this into a project" button should be present but disabled with tooltip "Coming soon" — Plan 03 wires the actual handoff.
  </action>
  <read_first>
    ui/src/api/hardware.ts,
    ui/src/api/client.ts,
    ui/src/components/ChatPanel.tsx,
    ui/src/context/CompanyContext.tsx,
    ui/src/hooks/useStreamingChat.ts,
    ui/src/components/ChatMessageList.tsx
  </read_first>
  <verify>
    <automated>pnpm --filter @paperclipai/ui tsc --noEmit</automated>
  </verify>
  <acceptance_criteria>
    - grep -q "useNexusMode" ui/src/hooks/useNexusMode.ts
    - grep -q "isAssistantEnabled" ui/src/hooks/useNexusMode.ts
    - grep -q "fetchNexusSettings" ui/src/hooks/useNexusMode.ts
    - grep -q "assistantMemoryApi" ui/src/api/assistantMemory.ts
    - grep -q "appendFact" ui/src/api/assistantMemory.ts
    - grep -q "PersonalAssistant" ui/src/pages/PersonalAssistant.tsx
    - grep -q "useNexusMode" ui/src/pages/PersonalAssistant.tsx
    - grep -q "project_builder\|isAssistantEnabled" ui/src/pages/PersonalAssistant.tsx
  </acceptance_criteria>
  <done>
    PersonalAssistant page renders full-page chat when mode allows, redirects to dashboard when project_builder only. Memory API client ready. Mode hook available for any component.
  </done>
</task>

<task type="auto">
  <name>Task 2: Wire assistant route in App.tsx and sidebar link in Layout.tsx</name>
  <files>
    ui/src/App.tsx,
    ui/src/components/Layout.tsx
  </files>
  <action>
    In `ui/src/App.tsx`:
    - Add lazy import: `const PersonalAssistant = React.lazy(() => import("./pages/PersonalAssistant"));` (or direct import if lazy loading is not used in this codebase — check existing import pattern)
    - Add route inside `boardRoutes()` function, after the dashboard route: `<Route path="assistant" element={<PersonalAssistant />} />`
    - Also add `<Route path="assistant/:conversationId" element={<PersonalAssistant />} />` for direct conversation linking

    In `ui/src/components/Layout.tsx`:
    - Add a sidebar NavLink for the assistant page
    - Use `MessageCircle` or `Bot` icon from lucide-react (check which icons are already imported)
    - Place it prominently — after Dashboard in the nav order
    - Gate visibility using `useNexusMode()` — only show when `isAssistantEnabled` is true
    - NavLink target: `/assistant`
    - Label: "Assistant"
  </action>
  <read_first>
    ui/src/App.tsx,
    ui/src/components/Layout.tsx
  </read_first>
  <verify>
    <automated>pnpm --filter @paperclipai/ui tsc --noEmit</automated>
  </verify>
  <acceptance_criteria>
    - grep -q "PersonalAssistant" ui/src/App.tsx
    - grep -q "assistant" ui/src/App.tsx
    - grep -q "assistant" ui/src/components/Layout.tsx
    - grep -q "useNexusMode\|isAssistantEnabled" ui/src/components/Layout.tsx
  </acceptance_criteria>
  <done>
    /assistant route exists and renders PersonalAssistant page. Sidebar shows Assistant link when mode is personal_ai or both, hidden when project_builder. TypeScript compiles clean.
  </done>
</task>

</tasks>

<verification>
pnpm --filter @paperclipai/ui tsc --noEmit
</verification>

<success_criteria>
- PersonalAssistantPage renders chat interface when mode allows
- Route /assistant exists in board routes
- Sidebar link visible only when assistant mode enabled
- Mode redirect works (project_builder -> dashboard)
- TypeScript compiles without errors
</success_criteria>

<output>
After completion, create `.planning/phases/33-persistent-memory/33-02-SUMMARY.md`
</output>
