5.5 KiB
5.5 KiB
03 — Continuity Moments (Auto-Resume Banner)
Author: CC (Block B design pass) Date: 2026-05-01 Status: AWAITING_RATIFICATION Estimate: ~120 LOC + ~2-3h wall-clock Touches: apps/web (1 file: ChatApp.tsx OR new ContinuityBanner.tsx), packages/server (1 endpoint extension)
User story
When I open Chat after closing it for hours/days, I want a 1-line banner reminding me where I left off — what I last decided, what's still open — and a one-click way to continue or start fresh, so I don't have to re-orient myself manually.
Acceptance criteria
- When ChatApp mounts AND
messages.length === 0AND last session for the workspace was within the past 7 days, render a "Picking up where you left off" banner at the top of the chat. - Banner content: 1-line headline ("Yesterday you decided X") + 2 buttons:
Continue(loads last session messages) +Start fresh(dismisses banner, opens empty input). - Banner suppressed for fresh workspaces (sessionCount=0) and for sessions older than 7 days (handoff to LoginBriefing's domain).
- Dismissing banner via
Start freshsets a per-workspace flagcontinuity:dismissed:{wsId}so the banner doesn't re-render same session. - Continuity banner replaces neither WorkspaceBriefing nor LoginBriefing — it's a third surface specific to "between-session" memory.
UI sketch
ChatApp top, above message list:
┌──────────────────────────────────────────────────────────┐
│ ⟳ Picking up where you left off ✕ │
│ Yesterday you decided: ship migrations Wednesday. │
│ 2 open follow-ups · last session 16h ago │
│ │
│ [ Continue conversation ] [ Start fresh ] │
└──────────────────────────────────────────────────────────┘
After click Continue: banner fades, last session messages stream into the chat.
After click Start fresh: banner removed for this session, input focused.
Data model
No new tables. Extends existing endpoints:
GET /api/workspaces/:id/context— already returnsrecentThreads[]. PullrecentThreads[0]if itslastActive≤ 7 days. AddlastDecisionfield (top decision content from yesterday) — drawable from existingrecentDecisions[0].- New endpoint
POST /api/sessions/:id/load— already exists conceptually asgetHistory(workspaceId, sessionId). Confirm wire-up.
Frontend localStorage:
continuity:dismissed:{wsId} = ISO timestamp
Set on Start-fresh click. Banner suppressed for that workspace until next mount where lastActive moves forward (i.e. user has actually had new activity).
Implementation notes
- Existing
WorkspaceBriefingalready showsrecentThreads[]as a list. Continuity banner is a focused alternative: ONE thread, biggest decision, action-oriented buttons. - Decision: keep WorkspaceBriefing for the "browse" affordance (5 recent threads + memories + decisions list) and add ContinuityBanner as the "resume" affordance (1 thread, 1 click to continue). They co-exist, both above chat list, ContinuityBanner above WorkspaceBriefing.
- Continue button: calls existing session load mechanism —
setActiveSession(threadId)thenloadSessionHistory(threadId). - Decision extraction:
recentDecisions[0]from workspace-context already filtered for last 24h elsewhere; reuse.
Estimate
- ContinuityBanner component: ~70 LOC
- ChatApp wire-up + localStorage logic: ~30 LOC
- Server context extension (lastDecision field): ~10 LOC
- Tests: ~30 LOC (banner render conditions, dismissal flag, time-window logic)
- Total ~140 LOC, ~2-3h with verification.
Risks + open questions
- Three surfaces collide — ContinuityBanner + WorkspaceBriefing + LoginBriefing all surface "what you did last" content. Need clear visual hierarchy: LoginBriefing (cross-workspace), WorkspaceBriefing (this workspace overview), ContinuityBanner (one-click resume).
- Stale banner — user opens Chat at 2am after a 12-hour break. Banner says "Yesterday you...". Linguistic edge case (was it really yesterday?). Use existing
timeAgo()helper. - Continue vs new session — clicking Continue should load the OLD session's messages OR start a NEW session that references them? v1: load old session messages so user sees full context.
- Multiple workspaces — banner only fires for the active workspace. Cross-workspace continuity prompts are LoginBriefing's job.
- Fresh user — sessionCount=0 → banner suppressed. But what about a returning user with one stub workspace and no real sessions? Same: suppress.
Out of scope (v1)
- Voice continuity ("Resume our conversation where I asked about X").
- Multi-thread continuity (continue the most-impactful thread, not just newest).
- Smart "you might want to follow up on X" suggestion engine. (That's the Daily Brief's domain.)
- Cross-device continuity sync (already handled by server-side session storage; no client work needed).
PM decisions needed
- GO / MODIFY / SKIP
- Time window — 7 days reasonable? or shorter (3 days)? or 30 days?
- Dismissal scope — per-session (re-show next mount) or per-day?
- Continue button behavior — load old messages vs new session w/ context inject
- Co-existence with WorkspaceBriefing — both above chat OR Continuity replaces Briefing for last-7-day case?