Milady Electrobun RPC
Use when working with Electrobun's RPC system — defineElectrobunRPC, Electroview.defineRPC, ElectrobunRPCSchema types, bun-to-renderer and renderer-to-bun communication. Activates automatically when RPC code is present.
install
source · Clone the upstream repo
git clone https://github.com/milady-ai/milady
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/milady-ai/milady "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/plugins/electrobun-dev/skills/electrobun-rpc" ~/.claude/skills/milady-ai-milady-electrobun-rpc && rm -rf "$T"
manifest:
.claude/plugins/electrobun-dev/skills/electrobun-rpc/SKILL.mdsource content
Electrobun RPC System
Type-safe bidirectional communication between the Bun process and webview renderers. Uses WebSockets for transport with AES-GCM encryption. Two call types:
requests (expects a response) and messages (fire-and-forget).
Schema Definition (shared type)
Define the schema in a shared file both sides import:
// src/shared/rpc-schema.ts import type { ElectrobunRPCSchema, RPCSchema } from "electrobun/view"; // bun: what the BUN process handles (requests from renderer, messages from renderer) // webview: what the WEBVIEW handles (requests from bun, messages from bun) export type AppRPC = { bun: RPCSchema<{ requests: { getNotes: { args: {}; response: Note[] }; saveNote: { args: { id: string; title: string; content: string }; response: { success: boolean } }; deleteNote: { args: { id: string }; response: void }; }; messages: { userIdleDetected: {}; }; }>; webview: RPCSchema<{ requests: { getSelectedText: { args: {}; response: string }; }; messages: { menuAction: { action: string; role?: string }; noteUpdatedExternally: { id: string }; }; }>; } & ElectrobunRPCSchema;
Bun Side — BrowserView.defineRPC
import { BrowserView } from "electrobun/bun"; import type { AppRPC } from "../shared/rpc-schema"; const appRPC = BrowserView.defineRPC<AppRPC>({ maxRequestTime: 10000, // ms — set higher for file dialogs, heavy DB ops handlers: { requests: { getNotes: async () => { return await db.getAllNotes(); }, saveNote: async ({ id, title, content }) => { await db.saveNote({ id, title, content }); return { success: true }; }, deleteNote: async ({ id }) => { await db.deleteNote(id); }, }, messages: { userIdleDetected: () => { console.log("User idle, saving state..."); }, }, }, }); // Pass rpc to BrowserView const view = new BrowserView({ url: "...", rpc: appRPC }); // Send a message to renderer view.rpc.send.menuAction({ action: "file-new" }); // Make a request to renderer const selectedText = await view.rpc.request.getSelectedText({});
Renderer Side — Electroview.defineRPC
// src/mainview/index.ts import { Electroview } from "electrobun/view"; import type { AppRPC } from "../shared/rpc-schema"; const rpc = Electroview.defineRPC<AppRPC>({ maxRequestTime: 10000, handlers: { requests: { getSelectedText: () => { return window.getSelection()?.toString() ?? ""; }, }, messages: { menuAction: ({ action, role }) => { handleMenuAction(action ?? role ?? "unknown"); }, noteUpdatedExternally: ({ id }) => { reloadNote(id); }, }, }, }); // Make a request to bun const notes = await rpc.request.getNotes({}); // Send a message to bun rpc.send.userIdleDetected({});
Key Rules
: bidirectional, async, returns a value. Use for: data fetching, file I/O, native dialogs.requests
: fire-and-forget, no return value. Use for: notifications, state updates, events.messages
: always set explicitly. Default may be too low for:maxRequestTime- File save dialogs: set ≥ 30000
- Database operations: set ≥ 10000
- Quick in-memory ops: 5000 is fine
- Type safety: the schema type is shared — import it on both sides. Never duplicate the type definition.
- Encryption: RPC uses AES-GCM. Keys are auto-generated per session. Don't bypass this.
Common Gotchas
- RPC not available yet: Wait for
event before callingdom-ready
.view.rpc.request.* - maxRequestTime timeout: Error message is generic. If you see "RPC timeout", increase
.maxRequestTime - sandbox: true: Disables RPC entirely. Don't set sandbox on windows that need RPC.
- Schema mismatch: If bun and renderer import different schema types, calls silently fail. Use a single shared type file.
- Renderer not initialized:
must be called before anyElectroview.defineRPC
calls.rpc.request.*