Use when building or maintaining Electrobun desktop apps in TypeScript, including electrobun.config.ts, electrobun/bun or electrobun/view imports, BrowserWindow/BrowserView usage, updater flows, and distribution artifacts.
How this skill is triggered — by the user, by Claude, or both
Slash command
/engineering-practices:electrobun-best-practicesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Electrobun builds cross-platform desktop apps with TypeScript and Bun. This skill gives safe defaults, typed RPC patterns, and operational guidance for build/update/distribution.
Electrobun builds cross-platform desktop apps with TypeScript and Bun. This skill gives safe defaults, typed RPC patterns, and operational guidance for build/update/distribution.
Docs: https://blackboard.sh/electrobun/docs/
Always load typescript-best-practices alongside this skill.
Electrobun APIs evolve quickly. Before relying on advanced options or platform-specific behavior, verify against current docs and CLI output.
Electrobun apps run as Bun apps:
electrobun/bunelectrobun/viewIPC between bun and browser contexts uses postMessage, FFI, and (in some paths) encrypted WebSockets.
bunx electrobun init
bun install
bun start
Recommended scripts:
{
"scripts": {
"start": "electrobun run",
"dev": "electrobun dev",
"dev:watch": "electrobun dev --watch",
"build:dev": "bun install && electrobun build",
"build:canary": "electrobun build --env=canary",
"build:stable": "electrobun build --env=stable"
}
}
Use this baseline for untrusted or third-party content:
import { BrowserWindow } from "electrobun/bun";
const win = new BrowserWindow({
title: "External Content",
url: "https://example.com",
sandbox: true, // disables RPC, events still work
partition: "persist:external",
});
win.webview.setNavigationRules([
"^*", // block everything by default
"*://example.com/*", // allow only trusted domain(s)
"^http://*", // enforce HTTPS
]);
win.webview.on("will-navigate", (e) => {
console.log("nav", e.data.url, "allowed", e.data.allowed);
});
Security checklist:
sandbox: true for untrusted content.partition values for isolation.host-message payloads from <electrobun-webview> preload scripts.PATHS.RESOURCES_FOLDER at runtime; use Utils.paths.userData.// src/shared/types.ts
import type { RPCSchema } from "electrobun/bun";
export type MyRPC = {
bun: RPCSchema<{
requests: {
getUser: { params: { id: string }; response: { name: string } };
};
messages: {
logToBun: { msg: string };
};
}>;
webview: RPCSchema<{
requests: {
updateUI: { params: { html: string }; response: boolean };
};
messages: {
notify: { text: string };
};
}>;
};
// bun side
import { BrowserView, BrowserWindow } from "electrobun/bun";
import type { MyRPC } from "../shared/types";
const rpc = BrowserView.defineRPC<MyRPC>({
handlers: {
requests: {
getUser: ({ id }) => ({ name: `user-${id}` }),
},
messages: {
logToBun: ({ msg }) => console.log(msg),
},
},
});
const win = new BrowserWindow({
title: "App",
url: "views://mainview/index.html",
rpc,
});
await win.webview.rpc.updateUI({ html: "<p>Hello</p>" });
// browser side
import { Electroview } from "electrobun/view";
import type { MyRPC } from "../shared/types";
const rpc = Electroview.defineRPC<MyRPC>({
handlers: {
requests: {
updateUI: ({ html }) => {
document.body.innerHTML = html;
return true;
},
},
messages: {
notify: ({ text }) => console.log(text),
},
},
});
const electroview = new Electroview({ rpc });
await electroview.rpc.request.getUser({ id: "1" });
electroview.rpc.send.logToBun({ msg: "hello" });
Use before-quit for shutdown cleanup instead of relying on process.on("exit") for async work.
import Electrobun from "electrobun/bun";
Electrobun.events.on("before-quit", async (e) => {
await saveState();
// e.response = { allow: false }; // optional: cancel quit
});
Important caveat:
before-quit. Programmatic quit via Utils.quit()/process.exit() is reliable.ApplicationMenu with role-based items.runtime.exitOnLastWindowClosed: false, then drive UX from Tray.partition values per account.bundleCEF: true and defaultRenderer: "cef" in platform config.sandbox: true disables RPC).setNavigationRules ordering; last match wins.^* first only when you intentionally run strict allowlist mode.release.baseUrl and uploaded artifacts/ naming ({channel}-{os}-{arch}-...).canary vs stable).Session.fromPartition(...).ELECTROBUN_BUILD_ENV, ELECTROBUN_OS, ELECTROBUN_ARCH).npx claudepluginhub alleneubank/agent-profile --plugin engineering-practicesGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.