/desktop-ipc-electron
Type-safe Electron IPC patterns with typed channels, electron-trpc, MessagePort, and utility process communication
$ npx -y skills add agents-inc/skills --skill desktop-ipc-electron --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/desktop-ipc-electron
Context preview
The summary Claude sees to decide when to auto-load this skill.
Type-safe Electron IPC patterns with typed channels, electron-trpc, MessagePort, and utility process communication
SKILL.md
desktop-ipc-electron.SKILL.mdname: desktop-ipc-electron
description: Type-safe Electron IPC patterns with typed channels, electron-trpc, MessagePort, and utility process communication
Electron Type-Safe IPC Patterns
> **Quick Guide:** All Electron IPC flows through a preload script using `contextBridge.exposeInMainWorld()`. Make it type-safe by defining a shared channel map that constrains channel names, payloads, and return types across main, preload, and renderer. For end-to-end type safety with minimal boilerplate, use `electron-trpc` (tRPC over IPC). For high-throughput streaming or renderer-to-renderer communication, use `MessageChannelMain`/`MessagePort`. For CPU-intensive background work, use `utilityProcess` with `parentPort`. Always validate IPC input in the main process -- treat renderer messages as untrusted.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST validate and sanitize ALL data received via IPC in the main process -- treat renderer messages as untrusted input)**
**(You MUST use `contextBridge.exposeInMainWorld()` in preload scripts -- never expose `ipcRenderer` directly)**
**(You MUST define IPC channel names and payload types in a single shared file -- never use untyped string literals for channel names)**
**(You MUST use `ipcMain.handle()` / `ipcRenderer.invoke()` for request-response IPC -- `sendSync` blocks the renderer)**
**(You MUST clean up IPC listeners when components unmount or windows close -- listener leaks cause memory issues and duplicate handlers)**
</critical_requirements>
---
**Auto-detection:** Electron IPC, ipcMain, ipcRenderer, contextBridge, preload, type-safe IPC, electron-trpc, ipcLink, createIPCHandler, exposeElectronTRPC, MessageChannelMain, MessagePortMain, MessagePort, utilityProcess, parentPort, typed channels, IPC channel map, postMessage, webContents.send, ipcMain.handle, ipcRenderer.invoke
**When to use:**
- Adding type safety to Electron IPC communication
- Setting up electron-trpc for end-to-end typed IPC
- Defining shared channel/payload types between main and renderer
- Building typed preload APIs with contextBridge
- Using MessagePort for high-throughput or renderer-to-renderer communication
- Implementing utility process IPC for background tasks
- Validating and sanitizing IPC input in main process handlers
**When NOT to use:**
- Choosing a UI framework for the renderer (use the appropriate framework skill)
- General Electron app setup, packaging, or native APIs (use the Electron framework skill)
- Simple IPC that does not need type safety beyond basic JavaScript
**Key patterns covered:**
- Shared IPC channel map with typed payloads and return types
- Typed preload API via contextBridge with declaration augmentation
- electron-trpc for end-to-end type safety (queries, mutations, subscriptions)
- Request-response (`handle`/`invoke`) with typed wrappers
- Fire-and-forget (`on`/`send`) with typed channels
- Main-to-renderer push (`webContents.send`) with typed events
- MessagePort for high-throughput and renderer-to-renderer communication
- Utility process IPC with `parentPort` and MessagePort transfer
- IPC input validation and channel allowlisting
---
**Detailed Resources:**
- [examples/core.md](examples/core.md) - Shared channel map, typed preload, typed wrappers, declaration augmentation
- [examples/electron-trpc.md](examples/electron-trpc.md) - electron-trpc setup, queries, mutations, subscriptions
- [examples/message-ports.md](examples/message-ports.md) - MessagePort patterns, renderer-to-renderer, utility process IPC
- [reference.md](reference.md) - IPC method quick reference, decision framework, security checklist
---
<philosophy>
Philosophy
Electron IPC is stringly typed by default -- channel names are plain strings, payloads are `any`, and there is no compile-time guarantee that the main process handler matches what the renderer sends. Type-safe IPC solves this by defining a single source of truth for channel names, argument types, and return types, then threading those types through typed wrapper functions.
**Three levels of type safety, pick one:**
1. **Shared channel map + typed wrappers** (DIY) -- define an `IpcChannelMap` interface, create thin typed wrappers around `ipcMain`/`ipcRenderer`. Zero dependencies, full control. 2. **electron-trpc** (library) -- tRPC over Electron IPC. Define a router in main with Zod-validated procedures, get a fully typed client in the renderer. Best DX for complex apps. 3. **MessagePort with typed messages** -- for high-throughput streaming or renderer-to-renderer communication where standard IPC overhead matters.
**When to use each:**
- **Shared channel map:** Most apps. Simple, no dependencies, covers `handle`/`invoke`, `send`/`on`, and `webContents.send`.
- **electron-trpc:** Apps with many IPC endpoints, complex input validation, or subscription needs. Worth the dependency when you have 10+ IPC channels.
- **MessagePort:** Real-time data feeds, large binary transfers, or direct renderer-to-renderer communication. Not a replacement for standard IPC -- an addition for specific high-throughput needs.
**When NOT to use type-safe IPC:**
- Prototyping where speed matters more than safety
- Apps with 1-2 trivial IPC calls where the overhead of typed infrastructure is not justified
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Shared IPC Channel Map
Define all channel names, argument types, and return types in a single shared file. Both main and renderer import from this file.
// shared/ipc-channels.ts
export interface IpcHandleChannels {
"file:read": (filePath: string) => { content: string };
"file:write": (filePath: string, content: string) => { success: boolean };
"dialog:open": (options: OpenDialogOptions) => string | null;
"app:version": () => string;
}
export inteRead more
name: desktop-ipc-electron description: Type-safe Electron IPC patterns with typed channels, electron-trpc, MessagePort, and utility process communication
Electron Type-Safe IPC Patterns
> **Quick Guide:** All Electron IPC flows through a preload script using `contextBridge.exposeInMainWorld()`. Make it type-safe by defining a shared channel map that constrains channel names, payloads, and return types across main, preload, and renderer. For end-to-end type safety with minimal boilerplate, use `electron-trpc` (tRPC over IPC). For high-throughput streaming or renderer-to-renderer communication, use `MessageChannelMain`/`MessagePort`. For CPU-intensive background work, use `utilityProcess` with `parentPort`. Always validate IPC input in the main process -- treat renderer messages as untrusted.
---
<critical_requirements>
CRITICAL: Before Using This Skill
> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)
**(You MUST validate and sanitize ALL data received via IPC in the main process -- treat renderer messages as untrusted input)**
**(You MUST use `contextBridge.exposeInMainWorld()` in preload scripts -- never expose `ipcRenderer` directly)**
**(You MUST define IPC channel names and payload types in a single shared file -- never use untyped string literals for channel names)**
**(You MUST use `ipcMain.handle()` / `ipcRenderer.invoke()` for request-response IPC -- `sendSync` blocks the renderer)**
**(You MUST clean up IPC listeners when components unmount or windows close -- listener leaks cause memory issues and duplicate handlers)**
</critical_requirements>
---
**Auto-detection:** Electron IPC, ipcMain, ipcRenderer, contextBridge, preload, type-safe IPC, electron-trpc, ipcLink, createIPCHandler, exposeElectronTRPC, MessageChannelMain, MessagePortMain, MessagePort, utilityProcess, parentPort, typed channels, IPC channel map, postMessage, webContents.send, ipcMain.handle, ipcRenderer.invoke
**When to use:**
- Adding type safety to Electron IPC communication
- Setting up electron-trpc for end-to-end typed IPC
- Defining shared channel/payload types between main and renderer
- Building typed preload APIs with contextBridge
- Using MessagePort for high-throughput or renderer-to-renderer communication
- Implementing utility process IPC for background tasks
- Validating and sanitizing IPC input in main process handlers
**When NOT to use:**
- Choosing a UI framework for the renderer (use the appropriate framework skill)
- General Electron app setup, packaging, or native APIs (use the Electron framework skill)
- Simple IPC that does not need type safety beyond basic JavaScript
**Key patterns covered:**
- Shared IPC channel map with typed payloads and return types
- Typed preload API via contextBridge with declaration augmentation
- electron-trpc for end-to-end type safety (queries, mutations, subscriptions)
- Request-response (`handle`/`invoke`) with typed wrappers
- Fire-and-forget (`on`/`send`) with typed channels
- Main-to-renderer push (`webContents.send`) with typed events
- MessagePort for high-throughput and renderer-to-renderer communication
- Utility process IPC with `parentPort` and MessagePort transfer
- IPC input validation and channel allowlisting
---
**Detailed Resources:**
- [examples/core.md](examples/core.md) - Shared channel map, typed preload, typed wrappers, declaration augmentation
- [examples/electron-trpc.md](examples/electron-trpc.md) - electron-trpc setup, queries, mutations, subscriptions
- [examples/message-ports.md](examples/message-ports.md) - MessagePort patterns, renderer-to-renderer, utility process IPC
- [reference.md](reference.md) - IPC method quick reference, decision framework, security checklist
---
<philosophy>
Philosophy
Electron IPC is stringly typed by default -- channel names are plain strings, payloads are `any`, and there is no compile-time guarantee that the main process handler matches what the renderer sends. Type-safe IPC solves this by defining a single source of truth for channel names, argument types, and return types, then threading those types through typed wrapper functions.
**Three levels of type safety, pick one:**
1. **Shared channel map + typed wrappers** (DIY) -- define an `IpcChannelMap` interface, create thin typed wrappers around `ipcMain`/`ipcRenderer`. Zero dependencies, full control. 2. **electron-trpc** (library) -- tRPC over Electron IPC. Define a router in main with Zod-validated procedures, get a fully typed client in the renderer. Best DX for complex apps. 3. **MessagePort with typed messages** -- for high-throughput streaming or renderer-to-renderer communication where standard IPC overhead matters.
**When to use each:**
- **Shared channel map:** Most apps. Simple, no dependencies, covers `handle`/`invoke`, `send`/`on`, and `webContents.send`.
- **electron-trpc:** Apps with many IPC endpoints, complex input validation, or subscription needs. Worth the dependency when you have 10+ IPC channels.
- **MessagePort:** Real-time data feeds, large binary transfers, or direct renderer-to-renderer communication. Not a replacement for standard IPC -- an addition for specific high-throughput needs.
**When NOT to use type-safe IPC:**
- Prototyping where speed matters more than safety
- Apps with 1-2 trivial IPC calls where the overhead of typed infrastructure is not justified
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Shared IPC Channel Map
Define all channel names, argument types, and return types in a single shared file. Both main and renderer import from this file.
// shared/ipc-channels.ts
export interface IpcHandleChannels {
"file:read": (filePath: string) => { content: string };
"file:write": (filePath: string, content: string) => { success: boolean };
"dialog:open": (options: OpenDialogOptions) => string | null;
"app:version": () => string;
}
export inteShowing the first part of this file.
The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?
Repo: agents-inc/skills
Other skills on agents-inc-skills.
- /ai-infrastructure-huggingface-inference
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints
Open skill - /ai-infrastructure-litellm
LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment
Open skill - /ai-infrastructure-modal
Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns
Open skill - /ai-infrastructure-ollama
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint
Open skill - /ai-infrastructure-replicate
Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training
Open skill - /ai-infrastructure-together-ai
Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints
Open skill

