
Desktop
Implement new Electron desktop capabilities in LobeHub using the Controller–IPC–renderer pattern without breaking main vs renderer boundaries.
Overview
Desktop is an agent skill for the Build phase that implements LobeHub Electron features via Controller modules, typed IPC, and renderer service integration.
Install
npx skills add https://github.com/lobehub/lobehub --skill desktopWhat is this skill?
- Documents main-process Controller modules with grouped IPC handlers (@IpcMethod)
- Maps Renderer service layer and store actions against main-process system APIs
- Step-by-step pattern for features like desktop notifications with typed electron-client-ipc params
- Architecture diagram for Controller ↔ Service Layer ↔ fs/network boundaries
- Fails safely when OS capabilities (e.g. Notification.isSupported) are unavailable
- Two-process architecture diagram: Main Process Controller layer and Renderer Service/Store layer
Adoption & trust: 1.2k installs on skills.sh; 78.4k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need to add a desktop-only feature but are unsure how LobeHub splits main-process controllers, IPC contracts, and renderer state.
Who is it for?
Developers extending the LobeChat/LobeHub Electron app who already work in the monorepo and need IPC-safe desktop APIs.
Skip if: Teams building a greenfield desktop app outside LobeHub’s ControllerModule and @lobechat/electron-client-ipc conventions.
When should I use this skill?
Implementing or extending LobeHub Electron desktop features that require main-process controllers and IPC to the renderer.
What do I get? / Deliverables
You get a controller implementation pattern with typed IPC params, capability checks, and clear main/renderer responsibilities for the new desktop feature.
- New or updated ControllerModule under apps/desktop with @IpcMethod handlers
- Typed IPC client usage from renderer/services
Recommended Skills
Journey fit
Desktop feature work happens while you are actively building the product shell and wiring system APIs to the chat UI. The guide centers on IPC bridges, controllers, and system API access—the classic integration layer between Electron main and renderer.
How it compares
Use instead of generic Electron tutorials that do not match LobeHub’s controller grouping and typed IPC client package.
Common Questions / FAQ
Who is desktop for?
It is for solo builders and contributors implementing features in the LobeHub Electron desktop client, especially when touching notifications, filesystem, or other main-process APIs.
When should I use desktop?
Use it during Build when you add or refactor desktop-only behavior—wiring a new Controller, IPC method, and renderer-side calls after the feature is scoped in the app architecture.
Is desktop safe to install?
Review the Security Audits panel on this Prism page and treat any skill that guides filesystem or system API access as requiring your own code review before shipping.
SKILL.md
READMESKILL.md - Desktop
# Desktop Feature Implementation Guide ## Architecture Overview ```plaintext Main Process Renderer Process ┌──────────────────┐ ┌──────────────────┐ │ Controller │◄──IPC───►│ Service Layer │ │ (IPC Handler) │ │ │ └──────────────────┘ └──────────────────┘ │ │ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ System APIs │ │ Store Actions │ │ (fs, network) │ │ (UI State) │ └──────────────────┘ └──────────────────┘ ``` ## Step-by-Step Implementation ### 1. Create Controller ```typescript // apps/desktop/src/main/controllers/NotificationCtr.ts import type { ShowDesktopNotificationParams, DesktopNotificationResult, } from '@lobechat/electron-client-ipc'; import { Notification } from 'electron'; import { ControllerModule, IpcMethod } from '@/controllers'; export default class NotificationCtr extends ControllerModule { static override readonly groupName = 'notification'; @IpcMethod() async showDesktopNotification( params: ShowDesktopNotificationParams, ): Promise<DesktopNotificationResult> { if (!Notification.isSupported()) { return { error: 'Notifications not supported', success: false }; } try { const notification = new Notification({ body: params.body, title: params.title }); notification.show(); return { success: true }; } catch (error) { console.error('[NotificationCtr] Failed:', error); return { error: error instanceof Error ? error.message : 'Unknown error', success: false }; } } } ``` ### 2. Define IPC Types ```typescript // packages/electron-client-ipc/src/types.ts export interface ShowDesktopNotificationParams { title: string; body: string; } export interface DesktopNotificationResult { success: boolean; error?: string; } ``` ### 3. Create Service Layer ```typescript // src/services/electron/notificationService.ts import type { ShowDesktopNotificationParams } from '@lobechat/electron-client-ipc'; import { ensureElectronIpc } from '@/utils/electron/ipc'; const ipc = ensureElectronIpc(); export const notificationService = { show: (params: ShowDesktopNotificationParams) => ipc.notification.showDesktopNotification(params), }; ``` ### 4. Implement Store Action ```typescript // src/store/.../actions.ts showNotification: async (title: string, body: string) => { if (!isElectron) return; const result = await notificationService.show({ title, body }); if (!result.success) { console.error('Notification failed:', result.error); } }, ``` ## Best Practices 1. **Security**: Validate inputs, limit exposed APIs 2. **Performance**: Use async methods for heavy operations 3. **Error handling**: Always return structured results 4. **UX**: Provide loading states and error feedback # Desktop Local Tools Implementation ## Workflow Overview 1. Define tool interface (Manifest) 2. Define related types 3. Implement Store Action 4. Implement Service Layer 5. Implement Controller (IPC Handler) 6. Update Agent documentation ## Step 1: Define Tool Interface (Manifest) Location: `src/tools/[tool_category]/index.ts` ```typescript // src/tools/local-files/index.ts export const LocalFilesApiName = { RenameFile: 'renameFile', MoveFile: 'moveFile', } as const; export const LocalFilesManifest = { api: [ { name: LocalFilesApiName.RenameFile, description: 'Rename a local file', parameters: { type: 'object', properties: { oldPath: { type: 'string', description: 'Current file path' }, newName: { type: 'string', description: 'New file name' }, }, required: ['oldPath', 'newName'], }, }, ], }; ``` ## Step 2: Define Types ```typescript // packages/electron-client-ipc/src/types.ts export interface RenameLocalFileParams { oldPath: string; newName: str