Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate secure main process and preload script boilerplate with proper context isolation, IPC patterns, and security best practices for Electron applications
.claude/skills/a5c-ai-electron-main-preload-generator/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 53% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 61% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 92% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 107% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 29% | 0% |
Generate secure Electron main process and preload scripts with proper context isolation, secure IPC patterns, and comprehensive security best practices. This skill creates production-ready boilerplate that follows Electron security guidelines.
main.js/main.ts) with proper window configurationjson{ "type": "object", "properties": { "projectPath": { "type": "string", "description": "Path to the Electron project root" }, "language": { "enum": ["javascript", "typescript"], "default": "typescript" }, "features": { "type": "array", "items": { "enum": [ "contextIsolation", "sandbox", "csp", "ipcChannels", "permissionHandler", "protocolHandler", "deepLinking", "autoUpdater", "tray", "multiWindow" ] }, "default": ["contextIsolation", "sandbox", "csp", "ipcChannels"] }, "ipcChannels": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "direction": { "enum": ["toMain", "toRenderer", "bidirectional"] }, "description": { "type": "string" }, "requestSchema": { "type": "object" }, "responseSchema": { "type": "object" } }, "required": ["name", "direction"] }, "description": "Define IPC channels for the application" }, "windowConfig": { "type": "object", "properties": { "width": { "type": "number", "default": 1200 }, "height": { "type": "number", "default": 800 }, "minWidth": { "type": "number" }, "minHeight": { "type": "number" }, "frame": { "type": "boolean", "default": true }, "transparent": { "type": "boolean", "default": false }, "titleBarStyle": { "enum": ["default", "hidden", "hiddenInset", "customButtonsOnHover"] } } }, "cspPolicy": { "type": "object", "properties": { "defaultSrc": { "type": "array", "items": { "type": "string" } }, "scriptSrc": { "type": "array", "items": { "type": "string" } }, "styleSrc": { "type": "array", "items": { "type": "string" } }, "imgSrc": { "type": "array", "items": { "type": "string" } }, "connectSrc": { "type": "array", "items": { "type": "string" } } } } }, "required": ["projectPath"] }
json{ "type": "object", "properties": { "success": { "type": "boolean" }, "files": { "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string" }, "type": { "enum": ["main", "preload", "types", "utils"] }, "description": { "type": "string" } } } }, "securityChecklist": { "type": "array", "items": { "type": "object", "properties": { "check": { "type": "string" }, "status": { "enum": ["implemented", "recommended", "optional"] }, "details": { "type": "string" } } } }, "warnings": { "type": "array", "items": { "type": "string" } } }, "required": ["success", "files"] }
src/
main/
main.ts # Main process entry point
ipc-handlers.ts # IPC handler implementations
window-manager.ts # Multi-window management (optional)
protocol-handler.ts # Custom protocol registration (optional)
permission-handler.ts # Permission request handling
preload/
preload.ts # Preload script with contextBridge
api.ts # Exposed API definitions
shared/
ipc-channels.ts # IPC channel definitions
types.ts # Shared TypeScript typestypescriptimport { app, BrowserWindow, session, ipcMain } from 'electron'; import path from 'path'; // Security: Disable remote module (deprecated but check) app.disableHardwareAcceleration(); // Optional: for headless environments function createWindow(): BrowserWindow { const mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { // Security settings nodeIntegration: false, // Never enable in production contextIsolation: true, // Always enable sandbox: true, // Enable sandbox webSecurity: true, // Keep enabled allowRunningInsecureContent: false, preload: path.join(__dirname, 'preload.js'), }, }); // Content Security Policy session.defaultSession.webRequest.onHeadersReceived((details, callback) => { callback({ responseHeaders: { ...details.responseHeaders, 'Content-Security-Policy': [ "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'" ] } }); }); // Permission handling session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => { const allowedPermissions = ['clipboard-read', 'notifications']; callback(allowedPermissions.includes(permission)); }); return mainWindow; }
typescriptimport { contextBridge, ipcRenderer } from 'electron'; // Define allowed channels const VALID_CHANNELS = { toMain: ['save-file', 'open-dialog', 'app-settings'], fromMain: ['file-saved', 'update-available', 'settings-changed'], } as const; type ToMainChannel = typeof VALID_CHANNELS.toMain[number]; type FromMainChannel = typeof VALID_CHANNELS.fromMain[number]; // Expose protected methods via contextBridge contextBridge.exposeInMainWorld('electronAPI', { // Send to main process (one-way) send: (channel: ToMainChannel, data: unknown) => { if (VALID_CHANNELS.toMain.includes(channel)) { ipcRenderer.send(channel, data); } }, // Invoke main process and wait for response invoke: async <T>(channel: ToMainChannel, data?: unknown): Promise<T> => { if (VALID_CHANNELS.toMain.includes(channel)) { return ipcRenderer.invoke(channel, data); } throw new Error(`Invalid channel: ${channel}`); }, // Subscribe to main process events on: (channel: FromMainChannel, callback: (...args: unknown[]) => void) => { if (VALID_CHANNELS.fromMain.includes(channel)) { const subscription = (_event: Electron.IpcRendererEvent, ...args: unknown[]) => callback(...args); ipcRenderer.on(channel, subscription); // Return unsubscribe function return () => { ipcRenderer.removeListener(channel, subscription); }; } return () => {}; }, // One-time listener once: (channel: FromMainChannel, callback: (...args: unknown[]) => void) => { if (VALID_CHANNELS.fromMain.includes(channel)) { ipcRenderer.once(channel, (_event, ...args) => callback(...args)); } }, });
typescript// types/electron-api.d.ts export interface ElectronAPI { send: (channel: string, data: unknown) => void; invoke: <T>(channel: string, data?: unknown) => Promise<T>; on: (channel: string, callback: (...args: unknown[]) => void) => () => void; once: (channel: string, callback: (...args: unknown[]) => void) => void; } declare global { interface Window { electronAPI: ElectronAPI; } }
| Security Measure | Status | Details | |-----------------|--------|---------| | Context Isolation | Required | Always set contextIsolation: true | | Node Integration | Required | Always set nodeIntegration: false | | Sandbox | Recommended | Set sandbox: true for renderer | | Web Security | Required | Never disable webSecurity | | CSP Headers | Recommended | Strict Content Security Policy | | Remote Module | Required | Ensure enableRemoteModule: false | | IPC Validation | Required | Whitelist and validate all IPC channels | | Protocol Handlers | Recommended | Register custom protocols securely | | Permission Handler | Recommended | Control permission requests | | Navigation Guard | Recommended | Restrict navigation to trusted origins |
ipcRenderer directly - Always use channel whitelistingelectron-builder-config - Build configurationelectron-ipc-security-audit - Audit IPC implementationselectron-auto-updater-setup - Auto-update configurationelectron-architect - Electron architecture expertisedesktop-security-auditor - Security auditing| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 16,845 | 14,119 | -16% | 1 | 1 | 0% | 3,992 | 6,116 | +53% | 0 | 0 | — |
case-02 | fail→pass | 16,104 | 13,433 | -17% | 1 | 1 | 0% | 3,656 | 5,868 | +61% | 0 | 0 | — |
case-03 | fail→pass | 13,833 | 18,039 | +30% | 1 | 1 | 0% | 3,092 | 5,930 | +92% | 0 | 0 | — |
case-04 | pass→pass | 9,057 | 10,513 | +16% | 1 | 1 | 0% | 2,121 | 4,979 | +135% | 0 | 0 | — |
case-05 | pass→pass | 14,874 | 16,561 | +11% | 1 | 1 | 0% | 1,554 | 4,283 | +176% | 0 | 0 | — |
case-06 | pass→pass | 9,494 | 9,349 | -2% | 1 | 1 | 0% | 2,022 | 4,782 | +136% | 0 | 0 | — |
case-07 | pass→pass | 9,841 | 13,490 | +37% | 1 | 1 | 0% | 1,796 | 5,689 | +217% | 0 | 0 | — |
case-08 | pass→pass | 13,113 | 15,403 | +17% | 1 | 1 | 0% | 3,017 | 6,099 | +102% | 0 | 0 | — |
case-09 | pass→pass | 13,108 | 16,584 | +27% | 1 | 1 | 0% | 3,159 | 6,511 | +106% | 0 | 0 | — |
case-10 | fail→fail | 8,190 | 13,286 | +62% | 1 | 1 | 0% | 1,759 | 5,597 | +218% | 0 | 0 | — |
case-11 | fail→pass | 11,786 | 16,552 | +40% | 1 | 1 | 0% | 2,799 | 5,784 | +107% | 0 | 0 | — |
case-12 | pass→pass | 4,792 | 12,730 | +166% | 1 | 1 | 0% | 1,098 | 5,735 | +422% | 0 | 0 | — |
case-13 | fail→fail | 8,649 | 25,987 | +200% | 1 | 1 | 0% | 1,654 | 7,203 | +335% | 0 | 0 | — |
case-14 | fail→pass | 21,453 | 15,293 | -29% | 1 | 1 | 0% | 5,113 | 6,596 | +29% | 0 | 0 | — |
case-15 | pass→pass | 7,894 | 9,072 | +15% | 1 | 1 | 0% | 1,605 | 4,490 | +180% | 0 | 0 | — |
case-16 | fail→pass | 9,193 | 17,098 | +86% | 1 | 1 | 0% | 2,012 | 6,656 | +231% | 0 | 0 | — |
case-17 | fail→fail | 5,651 | 14,105 | +150% | 1 | 1 | 0% | 1,110 | 5,039 | +354% | 0 | 0 | — |
case-18 | pass→pass | 9,882 | 10,645 | +8% | 1 | 1 | 0% | 2,321 | 5,200 | +124% | 0 | 0 | — |
case-19 | pass→pass | 7,132 | 12,901 | +81% | 1 | 1 | 0% | 1,595 | 5,939 | +272% | 0 | 0 | — |
case-20 | pass→pass | 11,833 | 13,963 | +18% | 1 | 1 | 0% | 2,473 | 5,849 | +137% | 0 | 0 | — |
case-21 | fail→fail | 13,207 | 22,878 | +73% | 1 | 1 | 0% | 3,269 | 8,865 | +171% | 0 | 0 | — |
case-22 | pass→pass | 17,436 | 13,708 | -21% | 1 | 1 | 0% | 4,235 | 5,971 | +41% | 0 | 0 | — |
case-23 | pass→pass | 5,711 | 8,992 | +57% | 1 | 1 | 0% | 1,202 | 4,578 | +281% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +26 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.