| name | electron-ipc |
| description | Electron IPC communication patterns between main and renderer processes. Use when implementing IPC handlers, sending events between processes, or working with the preload script. |
Electron IPC & UI (MVP)
Files
src/main/index.ts - Main process, BrowserWindow config
src/main/ipc.ts - IPC handlers
src/preload/index.ts - Context bridge API
src/renderer/styles.css - Global styles (Tailwind + custom)
src/renderer/components/ - React UI components
Preload API (window.api)
interface API {
startRun(prompt: string, credentials: Credentials): Promise<void>
selectWinner(agentId: string): Promise<void>
cancelRun(): Promise<void>
previewAll(): Promise<PreviewResult[]>
onAgentOutput(cb: (data: { agentId: string; chunk: string }) => void): () => void
onAgentStatus(cb: (data: { agentId: string; status: AgentStatus }) => void): () => void
onError(cb: (error: string) => void): () => void
}
interface Credentials {
daytonaApiKey: string
claudeOAuthToken?: string
anthropicApiKey?: string
}
interface PreviewResult {
agentId: string
url: string | null
error?: string
}
type AgentStatus = 'idle' | 'running' | 'completed' | 'failed'
IPC Communication
Main → Renderer Events
sendToRenderer('agent-output', { agentId, chunk })
sendToRenderer('agent-status', { agentId, status })
sendToRenderer('error', errorMessage)
Renderer → Main Handlers
ipcMain.handle('start-run', async (_event, { prompt, credentials }) => { ... })
ipcMain.handle('select-winner', async (_event, { agentId }) => { ... })
ipcMain.handle('cancel-run', async () => { ... })
ipcMain.handle('preview-all', async () => { ... })
Output Buffering
const buffer = new OutputBuffer((agentId, data) => {
sendToRenderer('agent-output', { agentId, chunk: data })
})
buffer.append(agentId, chunk)
buffer.flush(agentId)
buffer.flushAll()
BrowserWindow Configuration
Current config in src/main/index.ts:
const mainWindow = new BrowserWindow({
width: 1400,
height: 900,
minWidth: 1000,
minHeight: 700,
show: false,
autoHideMenuBar: true,
backgroundColor: '#171717',
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false,
contextIsolation: true,
nodeIntegration: false
}
})
UI Beautification Options
Custom Title Bar (Frameless Window)
const win = new BrowserWindow({
titleBarStyle: 'hidden',
trafficLightPosition: { x: 15, y: 15 }
})
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: {
color: '#171717',
symbolColor: '#ffffff',
height: 40
}
})
const win = new BrowserWindow({
titleBarStyle: 'hiddenInset'
})
const win = new BrowserWindow({
titleBarStyle: 'customButtonsOnHover'
})
Platform Vibrancy Effects
win.setVibrancy('sidebar')
win.setVibrancy('under-window')
const win = new BrowserWindow({
backgroundColor: '#00000000',
})
win.setBackgroundMaterial('mica')
win.setBackgroundMaterial('acrylic')
Transparent Window
const win = new BrowserWindow({
frame: false,
transparent: true,
resizable: false,
backgroundColor: '#00000000'
})
Window Controls Overlay API
Exposes native controls area to web content:
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: true
})
In CSS, use safe area insets:
.titlebar {
padding-top: env(titlebar-area-y, 0);
padding-left: env(titlebar-area-x, 0);
height: env(titlebar-area-height, 40px);
}
.drag-region {
-webkit-app-region: drag;
}
.no-drag {
-webkit-app-region: no-drag;
}
Tailwind CSS Patterns
Current setup uses Tailwind with dark theme. Key patterns:
Color Palette (neutral-based)
bg-neutral-900
bg-neutral-800
bg-neutral-700
text-neutral-100
text-neutral-400
text-neutral-500
Status Colors
bg-yellow-500/20 text-yellow-400 animate-pulse
bg-green-500/20 text-green-400
bg-red-500/20 text-red-400
border-green-500 bg-green-500/5
Interactive Elements
bg-blue-600 hover:bg-blue-500 disabled:bg-neutral-700
bg-red-600/20 text-red-400 hover:bg-red-600/30
bg-neutral-800 border-neutral-700 focus:ring-2 focus:ring-blue-500
rounded-lg border border-neutral-700 bg-neutral-800
Useful Effects for Beautification
backdrop-blur-md bg-white/10
bg-gradient-to-br from-neutral-800 to-neutral-900
shadow-lg shadow-blue-500/20
transition-all duration-200
hover:-translate-y-0.5 hover:shadow-lg
xterm.js Theme
Current terminal theme in Terminal.tsx:
const terminal = new XTerm({
theme: {
background: '#1e1e1e',
foreground: '#d4d4d4',
cursor: '#d4d4d4',
selectionBackground: '#264f78',
black: '#1e1e1e',
red: '#f44747',
green: '#6a9955',
yellow: '#dcdcaa',
blue: '#569cd6',
magenta: '#c586c0',
cyan: '#4ec9b0',
white: '#d4d4d4'
},
fontSize: 12,
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
scrollback: 10000,
cursorBlink: false,
disableStdin: true
})
Alternative themes to consider:
theme: {
background: '#282a36',
foreground: '#f8f8f2',
cursor: '#f8f8f2',
red: '#ff5555',
green: '#50fa7b',
yellow: '#f1fa8c',
blue: '#bd93f9',
magenta: '#ff79c6',
cyan: '#8be9fd'
}
theme: {
background: '#282c34',
foreground: '#abb2bf',
cursor: '#528bff',
red: '#e06c75',
green: '#98c379',
yellow: '#e5c07b',
blue: '#61afef',
magenta: '#c678dd',
cyan: '#56b6c2'
}
Component Architecture
App.tsx # State: phase, credentials, agents, winner
├── SetupWizard.tsx # Credentials input form
└── GridView.tsx # Header bar + 2x2 grid
└── AgentCard.tsx # Card with status badge + terminal
└── Terminal.tsx # xterm.js instance
App Phases
setup - Show SetupWizard
ready - Show prompt input + idle grid
running - Agents executing, cancel available
completed - All done, select winner
Cleanup
Always return unsubscribe function and call on unmount to prevent memory leaks:
useEffect(() => {
const unsub = window.api.onAgentOutput(({ agentId, chunk }) => {
terminals[agentId].write(chunk)
})
return () => unsub()
}, [])