# Lynn v0.79.9 UX Maintenance Plan

Date: 2026-05-28

v0.79.9 should stay focused on stability, recovery, and discoverability. Do not add new model surfaces or major product features. The goal is to make existing workflows harder to misuse and easier to recover from.

## Release Boundary

- Base: v0.79.8 stable release.
- Do not change the local-model policy: 9B MTP remains the default local onboarding model, 35B APEX-MTP remains the high-end manual upgrade, and 4B remains the low-config downgrade with thinking-on risk copy.
- Keep download links on ModelScope-first MTP repositories and preserve the legacy-model upgrade window.
- Run the full release gate before packaging: typecheck, runtime typecheck, tests, build, release regression, Electron UI smoke.

## Sprint A: Immediate UX Polish

### UX-2: Attachment Capability Warning

Problem: when the current provider does not support images or audio, pasted or dropped multimodal attachments can be ignored or rejected too late.

Plan:
- Add a toast or inline warning in `InputArea.tsx` and related drop zones when the active model lacks the required capability.
- Offer two explicit actions: switch to MiMo, or send text only.
- Keep server-side `capability_required` as the last line of defense.

Acceptance:
- Pasting an image into a text-only provider shows a visible warning.
- The user can switch to MiMo without opening Settings.
- The attachment is never silently discarded.

### UX-3: Cmd+? Shortcut Help

Problem: existing shortcuts and slash commands are not discoverable.

Plan:
- Add a Cmd+? / Ctrl+? help modal from `SidebarLayout.tsx`.
- Include keyboard shortcuts and core slash commands in two compact columns.
- Add a first-run hint line that points to Cmd+?.

Acceptance:
- Cmd+? opens the modal from the main chat surface.
- Escape closes it.
- Existing shortcut behavior is unchanged.

## Sprint B: Recovery UX

### UX-1: Error Recovery Bar

Problem: provider-chain failures, max-iteration failures, and tool-storm limits can leave users with only an error message.

Plan:
- Add `ErrorRecoveryBar` for recoverable assistant-message failures.
- Actions: retry, retry with local Qwen, retry with a specific fallback provider when available.
- Surface the actual failure class: all providers failed, max iterations, tool storm, capability mismatch, or transport failure.

Acceptance:
- `tool_storm_limit`, `max_iterations_reached`, and provider exhaustion all show recovery actions.
- Local fallback retry switches model and replays the last turn.
- Error text remains copyable and inspectable.

### UX-4: Edit Previous User Message And Regenerate

Problem: a bad prompt currently requires appending another user turn, which pollutes context.

Plan:
- Add edit affordance on user messages.
- Inline edit followed by confirm removes later turns and regenerates from the edited message.
- Keep the behavior explicit because it changes conversation history.

Acceptance:
- Editing an earlier user turn clearly warns that later turns will be replaced.
- Regeneration uses the edited text and preserves turns before that message.
- Undo or cancel leaves the session untouched.

## Sprint C: Transparency And App Handoff

### UX-5: Token, Cost, And Cache Visibility

Plan:
- Extend provider telemetry chunks to carry prompt tokens, completion tokens, cache hits, and approximate cost when available.
- Render a compact footer: `1.2k tokens · cached 87% · ~$0.006`.
- Add a session-level context usage indicator when the model exposes a context limit.

### UX-6: Background Completion Notifications

Plan:
- Add a setting for long-task completion notifications.
- Use native Electron notifications when the window is unfocused and a long-running turn completes.
- Avoid notification spam by rate limiting per session.

### UX-7: Cross-Window File And URL Jump

Plan:
- Add `Open in editor` to file output cards and inline file references.
- Add `Open in browser view` for URL references when the browser viewer is available.
- Keep normal copy/open-external actions intact.

## Sprint D: Search

### UX-8: Global Message Search

Problem: sidebar search only matches session title, first message, and labels.

Plan:
- Build a separate global search surface for message bodies.
- Start with lazy local indexing; evaluate SQLite FTS only if the simple index is too slow.
- Show matches with session name and surrounding context.

## Main Refactor: InputArea Split

`InputArea.tsx` is still the largest active UI file and should be the main structural task for this version.

Target modules:

- `input/useVoicePrefix.ts`: voice-mode prompt prefix assembly.
- `input/useDeepResearchState.ts`: deep-research state machine and transitions.
- `input/ModelPickerInline.tsx`: compact model selector and capability copy.
- `input/ComposerTextarea.tsx`: textarea, IME, cursor, and submit-key behavior.
- `input/SlashCommandHints.tsx`: slash command discovery and hint rendering.
- `input/SubmitArea.tsx`: send, stop, join, thinking mode, and execution-mode controls.

Targets:

- Reduce `InputArea.tsx` to under 900 lines in the first pass.
- Do not change user-visible behavior during extraction.
- Add focused tests for pure hooks and state transitions before any visual changes.

## Order Of Work

1. Sprint A: capability warning + Cmd+? help.
2. InputArea split pass 1: extract voice prefix and deep-research state.
3. Sprint B: error recovery + edit/regenerate.
4. InputArea split pass 2: model picker and submit area.
5. Sprint C: telemetry, notifications, and cross-window jumps.
6. Sprint D: global search.

## Gate

Every batch must pass:

- `npm run typecheck`
- `npm run typecheck:runtime`
- targeted vitest for touched files
- `npm run build`

Before release:

- `npm run release:gate`
- package macOS Apple Silicon, macOS Intel, and Windows
- notarize/staple/validate macOS DMGs
- verify GitHub Release and Tencent mirror links
