Summary
Implement a comprehensive notification system that allows users to stay informed about Levante's activity, especially for long-running tasks. Users can configure their preferred notification style through Settings.
Problem
When users leave Levante running in the background (e.g., waiting for AI to complete a complex task), they have no way to know when:
- A chat response has completed
- An MCP tool has finished executing
- An error has occurred
- A background process needs attention
Solution
Multi-layered notification system with granular user control.
Notification Levels
| Level |
Description |
Visual |
| None |
No notifications |
- |
| In-App Only |
Bell icon with badge counter |
🔔 (3) |
| OS Notification |
System notification center |
Native toast |
| OS + Sound |
System notification with audio |
Native toast + sound |
Requirements
1. Notification Types & Events
type NotificationEvent =
| 'chat_complete' // AI finished responding
| 'chat_error' // AI response failed
| 'mcp_tool_complete' // MCP tool finished
| 'mcp_tool_error' // MCP tool failed
| 'mcp_server_disconnected' // MCP server lost connection
| 'export_complete' // File export finished
| 'update_available' // New app version available
| 'announcement'; // New announcement (see #133)
interface NotificationPayload {
id: string;
event: NotificationEvent;
title: string;
body: string;
icon?: string;
timestamp: Date;
read: boolean;
action?: {
type: 'navigate' | 'open_url' | 'dismiss';
target?: string;
};
}
2. Settings Configuration
interface NotificationPreferences {
enabled: boolean; // Master switch
// Per-event configuration
events: {
[key in NotificationEvent]: {
level: 'none' | 'in_app' | 'os' | 'os_sound';
sound?: string; // Custom sound file (optional)
};
};
// Global options
showBadge: boolean; // App icon badge (dock/taskbar)
badgeCount: 'all' | 'unread'; // What to count
playSound: boolean; // Global sound toggle
soundVolume: number; // 0-100
// Do Not Disturb
quietHours: {
enabled: boolean;
start: string; // "22:00"
end: string; // "08:00"
};
}
3. In-App Notification Center (Bell Icon)
┌─────────────────────────────────────┐
│ 🔔 Notifications Clear All │
├─────────────────────────────────────┤
│ ● Chat completed │
│ "Análisis de código finalizado" │
│ hace 2 minutos │
├─────────────────────────────────────┤
│ ● MCP Tool finished │
│ filesystem: read_file completed │
│ hace 5 minutos │
├─────────────────────────────────────┤
│ ○ Export complete │
│ chat_export.json saved │
│ hace 1 hora │
└─────────────────────────────────────┘
● = unread ○ = read
Bell Icon States:
- 🔔 Normal (no unread)
- 🔔 (3) Badge with count
- 🔔 Animated shake on new notification
4. OS-Level Notifications
macOS:
import { Notification } from 'electron';
new Notification({
title: 'Levante - Chat Complete',
body: 'Your AI response is ready',
icon: path.join(__dirname, 'icon.png'),
silent: \!preferences.playSound
}).show();
Windows: Native Windows notifications via Electron
Linux: libnotify integration
5. App Icon Badge
macOS Dock:
app.dock.setBadge('3'); // Show count
app.dock.setBadge(''); // Clear
app.dock.bounce('informational'); // Bounce once
Windows Taskbar:
mainWindow.setOverlayIcon(
nativeImage.createFromPath('badge.png'),
'New notifications'
);
mainWindow.flashFrame(true); // Flash taskbar
Linux: Unity/GNOME badge support where available
6. Sound System
Built-in Sounds:
notification.wav - Default notification
success.wav - Task completed
error.wav - Error occurred
subtle.wav - Low priority
Custom Sounds:
- Allow users to select custom audio files
- Validate file format (wav, mp3, ogg)
- Preview sound in settings
Settings UI
┌─────────────────────────────────────────────────┐
│ ⚙️ Notification Settings │
├─────────────────────────────────────────────────┤
│ │
│ [✓] Enable notifications │
│ │
│ ─── Notification Style ─── │
│ │
│ Chat Responses: │
│ [▼ OS Notification + Sound] │
│ │
│ MCP Tool Execution: │
│ [▼ In-App Only] │
│ │
│ Errors & Warnings: │
│ [▼ OS Notification + Sound] │
│ │
│ Updates & Announcements: │
│ [▼ In-App Only] │
│ │
│ ─── Sound ─── │
│ │
│ [✓] Play notification sounds │
│ Volume: [━━━━━━━●━━━] 70% │
│ Sound: [▼ Default] [▶ Preview] │
│ │
│ ─── App Badge ─── │
│ │
│ [✓] Show badge on app icon │
│ Badge shows: (•) All ( ) Unread only │
│ │
│ ─── Quiet Hours ─── │
│ │
│ [ ] Enable quiet hours │
│ From: [22:00] To: [08:00] │
│ │
└─────────────────────────────────────────────────┘
Suggestions
Phase 1 (MVP)
Phase 2 (Enhanced)
Phase 3 (Advanced)
Phase 4 (Polish)
Technical Considerations
Notification Service Architecture
// Main process
class NotificationService {
private history: NotificationPayload[] = [];
private unreadCount = 0;
async notify(event: NotificationEvent, data: Partial<NotificationPayload>) {
const prefs = await preferencesService.getNotifications();
// Check quiet hours
if (this.isQuietHours(prefs)) return;
// Get event-specific settings
const eventConfig = prefs.events[event];
if (eventConfig.level === 'none') return;
const notification: NotificationPayload = {
id: generateId(),
event,
timestamp: new Date(),
read: false,
...data
};
// Store in history
this.history.unshift(notification);
this.unreadCount++;
// In-app notification (always if enabled)
if (eventConfig.level \!== 'none') {
this.sendToRenderer('notification:new', notification);
this.updateBadge();
}
// OS notification
if (eventConfig.level === 'os' || eventConfig.level === 'os_sound') {
this.showOSNotification(notification, eventConfig.level === 'os_sound');
}
}
private updateBadge() {
// macOS
if (process.platform === 'darwin') {
app.dock.setBadge(this.unreadCount > 0 ? String(this.unreadCount) : '');
}
// Windows
if (process.platform === 'win32' && this.mainWindow) {
// Set overlay icon or flash
}
}
}
Focus-Aware Notifications
// Don't show OS notification if app is focused
private shouldShowOSNotification(): boolean {
const focused = BrowserWindow.getFocusedWindow();
return \!focused || \!focused.isFocused();
}
Integration Points
Hook notifications into existing services:
Persistence
// Store notification preferences in ui-preferences.json
// Store notification history in memory (clear on app restart)
// Optional: persist history to SQLite for analytics
UX Considerations
Smart Defaults
- First-time users: In-app notifications only
- Power users can enable OS notifications
- Sound off by default (respect user focus)
Notification Fatigue Prevention
- Group rapid notifications ("5 tools completed")
- Rate limit: max 1 OS notification per 10 seconds
- Auto-collapse similar notifications
Accessibility
- Screen reader support for notifications
- Visual + audio feedback options
- High contrast badge for visibility
Related Issues
Labels: enhancement, feature, ux, electron
Summary
Implement a comprehensive notification system that allows users to stay informed about Levante's activity, especially for long-running tasks. Users can configure their preferred notification style through Settings.
Problem
When users leave Levante running in the background (e.g., waiting for AI to complete a complex task), they have no way to know when:
Solution
Multi-layered notification system with granular user control.
Notification Levels
Requirements
1. Notification Types & Events
2. Settings Configuration
3. In-App Notification Center (Bell Icon)
Bell Icon States:
4. OS-Level Notifications
macOS:
Windows: Native Windows notifications via Electron
Linux: libnotify integration
5. App Icon Badge
macOS Dock:
Windows Taskbar:
Linux: Unity/GNOME badge support where available
6. Sound System
Built-in Sounds:
notification.wav- Default notificationsuccess.wav- Task completederror.wav- Error occurredsubtle.wav- Low priorityCustom Sounds:
Settings UI
Suggestions
Phase 1 (MVP)
Phase 2 (Enhanced)
Phase 3 (Advanced)
Phase 4 (Polish)
Technical Considerations
Notification Service Architecture
Focus-Aware Notifications
Integration Points
Hook notifications into existing services:
AIService: Emit on stream complete/errorMCPService: Emit on tool execution complete/errorExportService: Emit on export completeAnnouncementService: Emit on new announcement (feat: Add Startup Announcements Modal with External API Integration #133)Persistence
UX Considerations
Smart Defaults
Notification Fatigue Prevention
Accessibility
Related Issues
Labels:
enhancement,feature,ux,electron