# electron/electron — codebase unpack

> Canonical page: https://codevetter.com/unpack/electron

This is a deterministic Repo Unpack scan of electron/electron — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: 56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f (2026-09-22)
- Last upstream commit: test: collect orphaned MessagePortMain with a precise GC in the close-event spec (#54191)
- Generated by codevetter 1.12.0 on 2026-09-22
- 2937 files scanned · 16.0 MB

## Languages

- JavaScript: 526 files
- C: 438 files
- C++: 415 files
- Markdown: 324 files
- HTML: 264 files
- TypeScript: 214 files
- JSON: 138 files
- YAML: 78 files

## Repository structure

- shell/ — 932 files
- spec/ — 919 files
- docs/ — 474 files
- patches/ — 226 files
- script/ — 117 files
- lib/ — 98 files
- .github/ — 92 files
- .claude/ — 15 files

Probable source entrypoint: `lib/` (inferred from the tree, not upstream docs)

## Package

- package.json: @electron-ci/dev-root v0.0.0-development — 30 declared dependencies

## Structural health signals

Average score 6.2/10 across 96 files; 53 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- 56f681cfe08e (2026-09-21) test: collect orphaned MessagePortMain with a precise GC in the close-event spec (#54191)
- 8a6429e41408 (2026-09-21) build: upgrade to TypeScript 7 (#54172)
- 9baaed782e64 (2026-09-21) test: load specs as native ES modules (#54171)
- 2774d5761f6c (2026-09-21) test: keep spec sources to erasable syntax and explicit type imports (#54170)
- 1e93884db50f (2026-09-21) fix: remove read-only files with fs.rmSync on Windows (#54180)

## Overview

Electron is the framework that embeds Chromium and Node.js into a single binary so apps can be built with JavaScript, HTML, and CSS. This repo is the framework itself: a C++ core in shell/ layered on the Chromium content API, a per-process JavaScript API layer in lib/ that is bundled by rolldown and baked into the binary, ~200 maintained patches to Chromium/Node/V8 under patches/, and a Mocha-based spec suite in spec/ that runs inside the built binary.

## System map

Electron is a Chromium content-API embedder: platform entry points (shell/app/electron_main_*.cc) create an ElectronMainDelegate that plugs Electron's content clients into content::ContentMain. The browser (main) process lives in shell/browser, renderers in shell/renderer, shared code in shell/common, and a separate utility-process client in shell/utility plus shell/services/node. On top of the C++ core sits a TypeScript layer in lib/ that is bundled per execution context (browser, renderer, worker, webview, isolated_renderer, node, utility) and compiled into the binary. Build is GN/Ninja driven by BUILD.gn and filenames.gni, with dependency versions pinned in DEPS and upstream modifications carried as patch queues in patches/.
- Each platform has a thin main() — shell/app/electron_main_linux.cc line 49 — that hands off to content::ContentMain with an ElectronMainDelegate; the delegate implements BasicStartupComplete, PreSandboxStartup, PreBrowserMain and the CreateContent*Client factory methods. — [shell/app/electron_main_linux.cc#L49](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_linux.cc#L49) [shell/app/electron_main_delegate.cc#L216-L284](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L216-L284) [shell/app/electron_main_delegate.cc#L437-L470](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L437-L470)
- The browser-process composition root is ElectronBrowserMainParts: its constructor wires BrowserProcessImpl, NodeBindings, ElectronBindings and the Browser singleton, and PostEarlyInitialization() creates the V8 isolate via JavascriptEnvironment, initializes Node, and loads the app package. — [shell/browser/electron_browser_main_parts.cc#L200-L210](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L200-L210) [shell/browser/electron_browser_main_parts.cc#L290-L410](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L290-L410)
- ElectronMainDelegate::CreateContentRendererClient selects between ElectronSandboxedRendererClient and ElectronRendererClient based on IsSandboxEnabled(command_line), so the sandbox decision happens per child-process launch. — [shell/app/electron_main_delegate.cc#L454-L464](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L454-L464)
- The JS layer in lib/ is compiled into seven self-contained bundles (browser, renderer, worker, webview, isolated_renderer, node, utility) by build/bundle/bundle.mjs using rolldown, driven by the per-target flags in build/bundle/targets.mjs. — [build/bundle/bundle.mjs#L50-L60](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/bundle/bundle.mjs#L50-L60) [build/bundle/targets.mjs#L23-L54](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/bundle/targets.mjs#L23-L54) [build/bundle/bundle.gni](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/bundle/bundle.gni)
- Native modules are exposed to JS through process._linkedBinding: node_bindings.cc declares the binding names in the ELECTRON_BROWSER_BINDINGS / ELECTRON_COMMON_BINDINGS / ELECTRON_RENDERER_BINDINGS macros, and each C++ file registers itself with NODE_LINKED_BINDING_CONTEXT_AWARE (e.g. electron_browser_app in electron_api_app.cc). — [shell/common/node_bindings.cc#L68-L120](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/node_bindings.cc#L68-L120) [shell/browser/api/electron_api_app.cc#L2127](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/api/electron_api_app.cc#L2127)
- The 'electron' npm module object is assembled lazily: lib/browser/api/exports/electron.ts calls defineProperties over commonModuleList + browserModuleList, where each entry is { name, loader } with a deferred require(). — [lib/browser/api/exports/electron.ts#L1-L8](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/exports/electron.ts#L1-L8) [lib/browser/api/module-list.ts#L4-L48](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/module-list.ts#L4-L48) [lib/common/define-properties.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/define-properties.ts)
- require('electron'), 'electron/main', 'electron/renderer', 'electron/common' and 'electron/utility' are module aliases installed by lib/common/init.ts via fake entries in Module._cache and a Module._resolveFilename override. — [lib/common/init.ts#L79-L122](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/init.ts#L79-L122)
- Dependencies are pinned in DEPS: chromium_version 155.0.8046.0, node_version v24.21.0, plus squirrel.mac, sparkle, nan and others; gclient applies the patch queue because 'apply_patches': True. — [DEPS#L1-L40](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/DEPS#L1-L40)
- patches/config.json maps 13 patch directories (chromium, boringssl, devtools_frontend, ffmpeg, v8, node, nan, libaddressinput, perfetto, squirrel.mac, webrtc, sqlite, angle) onto target repos under src/. — [patches/config.json](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/patches/config.json)
- Build configuration is GN: BUILD.gn (~2200 lines) defines the electron targets including the electron_fuses action that generates fuses.h/fuses.cc from build/fuses/fuses.json5; per-build args live in build/args/{all,testing,release}.gn. — [BUILD.gn#L450-L457](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/BUILD.gn#L450-L457) [build/fuses/fuses.json5](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/fuses/fuses.json5) [build/args/all.gn](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/args/all.gn)
- If no app is supplied, resources/default_app.asar provides a fallback app (default_app/) that parses CLI args, can open a file/URL/package directory, prints --version/--abi, or starts a REPL with lazy Electron builtins. — [default_app/main.ts#L297-L341](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/default_app/main.ts#L297-L341) [default_app/main.ts#L174-L295](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/default_app/main.ts#L174-L295) [shell/browser/app_package.cc#L93-L98](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/app_package.cc#L93-L98)
- The published npm package (npm/) is a thin downloader: index.js reads path.txt for the executable name, supports ELECTRON_OVERRIDE_DIST_PATH, and runs install.js to fetch the binary. — [npm/index.js#L25-L52](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/npm/index.js#L25-L52)
- asar archives are supported at two levels: shell/common/asar implements the archive reader used by C++ (LoadAppPackage reads package.json through asar::ReadFileToString), and lib/node/asar-fs-wrapper.ts monkey-patches the fs module so Node can read inside .asar files. — [shell/common/asar/asar_util.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/asar/asar_util.cc) [shell/browser/app_package.cc#L102-L107](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/app_package.cc#L102-L107) [lib/node/asar-fs-wrapper.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/asar-fs-wrapper.ts) [lib/node/init.ts#L1-L3](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L1-L3)

## Feature catalog

Electron's public surface is a set of lazily-loaded modules on the 'electron' export, split by process: ~40 browser-process modules, 2 common modules, 6 renderer modules and a small utility-process set. Highlights include the windowing stack (BrowserWindow/BaseWindow/WebContentsView), ipcMain/ipcRenderer messaging, session/networking (net, protocol, session), OS integrations (Tray, Menu, Notification, globalShortcut, powerMonitor, autoUpdater), and newer additions like utilityProcess, ServiceWorkerMain, sharedTexture and a local-AI handler. Binary-level behavior toggles called fuses let distributors flip security-relevant features post-build.
- browserModuleList enumerates the main-process API surface: app, autoUpdater, BaseWindow, BrowserView, BrowserWindow, clipboard, contentTracing, crashReporter, desktopCapturer, dialog, globalShortcut, ipcMain, inAppPurchase, Menu/MenuItem, MessageChannelMain, nativeTheme, net, netLog, Notification, powerMonitor, powerSaveBlocker, protocol, pushNotifications, safeStorage, screen, ServiceWorkerMain, session, sharedTexture, ShareMenu, systemPreferences, TouchBar, Tray, utilityProcess, View, webContents, WebContentsView, webFrameMain and native-bound ImageView. — [lib/browser/api/module-list.ts#L4-L48](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/module-list.ts#L4-L48)
- The renderer-side module list is deliberately small — contextBridge, crashReporter, ipcRenderer, sharedTexture, webFrame, webUtils — while common modules (nativeImage, shell) load on both sides. — [lib/renderer/api/module-list.ts#L2-L9](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/api/module-list.ts#L2-L9) [lib/common/api/module-list.ts#L2-L5](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/api/module-list.ts#L2-L5)
- The net module exposes request() (ClientRequest), fetch() (delegated to session.defaultSession.fetch), resolveHost(), isOnline()/online and a WebSocket implementation, and refuses to run before app ready. — [lib/browser/api/net.ts#L9-L33](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/net.ts#L9-L33) [lib/browser/api/session.ts#L41-L43](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/session.ts#L41-L43) [lib/common/api/net-client-request.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/api/net-client-request.ts)
- protocol.handle() registers a Fetch-API-style handler per scheme — using registerProtocol for custom schemes and interceptProtocol for http/https/file — converting ProtocolRequest into a Request and the returned Response back to a Chromium loader callback. — [lib/browser/api/protocol.ts#L152-L200](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L152-L200)
- Global protocol functions (registerFileProtocol, interceptBufferProtocol, etc.) are deprecated-style shims that forward to session.defaultSession.protocol. — [lib/browser/api/protocol.ts#L214-L236](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L214-L236)
- session provides fromPartition/fromPath factories, a defaultSession getter, fetch(), setDisplayMediaRequestHandler (with a macOS native-picker fake source id window:-4:N), registerPreloadScript, extensions loading, and registerLocalAIHandler which unwraps a utilityProcess handle. — [lib/browser/api/session.ts#L24-L128](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/session.ts#L24-L128)
- utilityProcess.fork() spawns a child running a JS entry script via the native electron_browser_utility_process._fork binding, validating stdio ('pipe'|'inherit'|'ignore' triples, stdin must be 'ignore') and exposing postMessage/kill/pid/stdout/stderr. — [lib/browser/api/utility-process.ts#L7-L153](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/utility-process.ts#L7-L153) [shell/browser/api/electron_api_utility_process.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/api/electron_api_utility_process.cc)
- autoUpdater has three platform implementations under lib/browser/api/auto-updater/: auto-updater-native.ts (macOS Squirrel), squirrel-update-win.ts and auto-updater-msix.ts/msix-update-win.ts (Windows). — [lib/browser/api/auto-updater/auto-updater-native.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/auto-updater/auto-updater-native.ts) [lib/browser/api/auto-updater/squirrel-update-win.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/auto-updater/squirrel-update-win.ts) [lib/browser/api/auto-updater/auto-updater-msix.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/auto-updater/auto-updater-msix.ts) [shell/browser/auto_updater.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/auto_updater.cc)
- ElectronBindings::BindProcess extends the Node process object with Electron methods: crash(), hang(), getCreationTime, getHeapStatistics, getBlinkMemoryInfo, getSystemMemoryInfo, getCPUUsage, getProcessMemoryInfo (browser only), plus takeHeapSnapshot, setFdLimit (POSIX) and activateUvLoop. — [shell/common/api/electron_bindings.cc#L43-L84](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/api/electron_bindings.cc#L43-L84)
- Fuses are post-build toggles baked into the binary: run_as_node, cookie_encryption, node_options, node_cli_inspect, embedded_asar_integrity_validation, only_load_app_from_asar, load_browser_process_specific_v8_snapshot, grant_file_protocol_extra_privileges, wasm_trap_handlers — defined in build/fuses/fuses.json5 and consumed via electron::fuses::* (e.g. IsOnlyLoadAppFromAsarEnabled gates the app-search list). — [build/fuses/fuses.json5#L1-L14](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/fuses/fuses.json5#L1-L14) [shell/browser/app_package.cc#L91-L98](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/app_package.cc#L91-L98) [docs/tutorial/fuses.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/tutorial/fuses.md) [spec/fuses-spec.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/fuses-spec.ts)
- The utility process gets its own mini API set (net, local-ai-handler, language-model-utility) via lib/utility/api/module-list.ts, backed by the NodeService in shell/services/node. — [lib/utility/api/module-list.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/utility/api/module-list.ts) [lib/utility/init.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/utility/init.ts) [shell/services/node/node_service.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/services/node/node_service.cc)
- BrowserWindow forwards most content operations (loadURL, loadFile, reload, send, openDevTools, capturePage, setBackgroundThrottling, inspectElement/SharedWorker/ServiceWorker) straight to its webContents, and manages a _browserViews list via addBrowserView/setTopBrowserView. — [lib/browser/api/browser-window.ts#L118-L240](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/browser-window.ts#L118-L240)
- The <webview> tag is implemented by guest-view-manager.ts in the browser process responding to GUEST_VIEW_MANAGER_* internal IPC channels, tracking GuestInstance records keyed by guestInstanceId. — [lib/browser/guest-view-manager.ts#L1-L30](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/guest-view-manager.ts#L1-L30) [lib/common/ipc-messages.ts#L5-L11](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/ipc-messages.ts#L5-L11) [lib/isolated_renderer/init.ts#L4-L11](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/isolated_renderer/init.ts#L4-L11)

## Data flow

App code enters through a package.json discovered in resources/{app.asar,app,default_app.asar}; the browser process creates a Node environment, loads the bundled browser init script which in turn loads the app's main entry. Renderer↔browser communication rides a mojo interface (mojom::ElectronApiIPC) into a C++ dispatch layer that emits events on the JS ipcMain/ipcMainInternal objects; the reverse direction emits on ipcRenderer via a hidden 'ipcNative' context binding. Network data flows through Chromium URL loader factories, with protocol.handle() bridging Fetch-API Request/Response objects and net.fetch routing through the session's network context. Preload scripts are pushed to the renderer ahead of navigation in startup data rather than fetched by sync IPC.
- App discovery: LoadAppPackage() reads package.json from resources/app.asar, then resources/app, then resources/default_app.asar (only app.asar when the only_load_app_from_asar fuse is on), applies name/productName/version/desktopName, and returns {path, main, esm, v8Flags}. — [shell/browser/app_package.cc#L86-L134](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/app_package.cc#L86-L134)
- PostEarlyInitialization() stashes the AppPackage as a v8 private value 'appPackage' on the Node context global; lib/browser/init.ts retrieves it via getHiddenValue, calls app.setAppPath, then loads the entry with Module._load (CJS) or runEntryPointWithESMLoader (ESM, when type=module or .mjs). — [shell/browser/electron_browser_main_parts.cc#L349-L365](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L349-L365) [lib/browser/init.ts#L62-L121](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/init.ts#L62-L121)
- node_bindings_->JoinAppCode() blocks browser startup until init.ts signals process.appCodeLoaded(), which init.ts invokes after the main module loads (or after the ESM loader settles); this is what synchronizes Chromium startup with the app's JS. — [shell/browser/electron_browser_main_parts.cc#L378-L382](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L378-L382) [lib/browser/init.ts#L95-L120](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/init.ts#L95-L120)
- Renderer→main IPC: the mojom::ElectronApiIPC associated interface delivers Message/Invoke/MessageSync/ReceivePostMessage/MessageHost to ElectronApiIPCHandlerImpl, which resolves the Session from the RenderFrameHost's BrowserContext, builds an api::IpcMainEvent, and calls ipc_dispatch::Message/Invoke which emit on the JS objects registered via electron_browser_ipc_dispatch.setup({ipcMain, ipcMainInternal}). — [shell/browser/electron_api_ipc_handler_impl.cc#L48-L128](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L48-L128) [shell/browser/electron_api_ipc_handler_impl.cc#L152-L196](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L152-L196) [lib/browser/ipc-dispatch.ts#L1-L7](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-dispatch.ts#L1-L7) [shell/common/api/api.mojom](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/api/api.mojom)
- ipcMain.handle registrations live in IpcMainImpl._invokeHandlers (a Map keyed by channel) which throws on duplicate handlers; handleOnce wraps handle + removeHandler. — [lib/browser/ipc-main-impl.ts#L5-L35](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-main-impl.ts#L5-L35)
- Main→renderer IPC: EmitIPCEvent in electron_ipc_native.cc looks up a hidden 'ipcNative' private binding on the v8 context (set by the renderer IPC setup), wraps {sender, ports} into an event object, and emits the channel on ipcRenderer or ipcRendererInternal inside a node::CallbackScope when a Node env exists. — [shell/renderer/electron_ipc_native.cc#L21-L36](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_ipc_native.cc#L21-L36) [shell/renderer/electron_ipc_native.cc#L40-L99](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_ipc_native.cc#L40-L99)
- Internal control messages ride reserved channels in the IPC_MESSAGES const enum (e.g. BROWSER_PRELOAD_ERROR re-emitted as 'preload-error' on webContents, BROWSER_GET_PROCESS_MEMORY_INFO returning the calling frame's own renderer pid stats) handled by lib/browser/rpc-server.ts. — [lib/common/ipc-messages.ts#L1-L14](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/ipc-messages.ts#L1-L14) [lib/browser/rpc-server.ts#L4-L14](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/rpc-server.ts#L4-L14)
- Preload flow: the browser pushes preload paths into RendererStartupData ahead of navigation (WebContents::MaybeSendRendererStartupData); ElectronRendererClient::DidCreateScriptContext creates a per-frame Node environment, defers document loading (LoaderFreezeMode::kStrict), and lib/renderer/init.ts loads CJS preloads via Module._load and .mjs preloads via runEntryPointWithESMLoader, then calls appCodeLoaded which triggers UndeferLoad. — [shell/renderer/electron_renderer_client.cc#L133-L204](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_renderer_client.cc#L133-L204) [shell/renderer/electron_renderer_client.cc#L128-L131](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_renderer_client.cc#L128-L131) [lib/renderer/init.ts#L145-L180](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L145-L180)
- protocol.handle() converts the native ProtocolRequest into a WHATWG Request — rebuilding uploadData (rawData/file/stream/blob chunk types, blob data pulled via session.defaultSession.getBlobData) into a ReadableStream body — then converts the handler's Response back, with a fast path (relayUntouchedFetch) that hands an untouched net.fetch URL loader straight to Chromium instead of streaming through JS. — [lib/browser/api/protocol.ts#L58-L106](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L58-L106) [lib/browser/api/protocol.ts#L127-L150](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L127-L150) [lib/browser/api/protocol.ts#L175-L198](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L175-L198)
- net.fetch/session.fetch go through fetchWithSession in net-fetch.ts into Chromium's network stack under the session's NetworkContext (shell/browser/net/), so requests share the session's cookies, proxy and cache. — [lib/browser/api/net.ts#L16-L18](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/net.ts#L16-L18) [lib/browser/api/session.ts#L41-L43](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/session.ts#L41-L43) [lib/browser/api/net-fetch.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/net-fetch.ts) [shell/browser/net/network_context_service.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/net/network_context_service.cc)
- Node module resolution is fenced: lib/node/init.ts overrides Module._nodeModulePaths so modules inside process.resourcesPath can only resolve node_modules inside the app, and patches child_process.fork to set ELECTRON_RUN_AS_NODE=1 (refusing outright when the runAsNode fuse is off). — [lib/node/init.ts#L6-L41](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L6-L41) [lib/node/init.ts#L77-L93](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L77-L93)
- The uv loop is demand-driven: lib/common/init.ts wraps process.nextTick, setImmediate, setTimeout and setInterval to call process.activateUvLoop() (bound to ElectronBindings::ActivateUVLoop, which uv_async_sends to OnCallNextTick) so Node callbacks fire even though Chromium owns the main loop. — [lib/common/init.ts#L8-L61](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/init.ts#L8-L61) [shell/common/api/electron_bindings.cc#L90-L111](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/api/electron_bindings.cc#L90-L111)
- Guest <webview> data flow: a renderer frame registers the element, the browser's guest-view-manager maps guestInstanceId→GuestInstance (embedder WebContents + embedderFrame), and only the creating frame may drive the guest through GUEST_VIEW_MANAGER_* IPCs; webPreferences are parsed from the 'webpreferences' attribute string with security options force-inherited from the embedder. — [lib/browser/guest-view-manager.ts#L15-L30](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/guest-view-manager.ts#L15-L30) [lib/browser/guest-view-manager.ts#L32-L75](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/guest-view-manager.ts#L32-L75) [lib/common/ipc-messages.ts#L7-L11](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/ipc-messages.ts#L7-L11)

## Behavior traces

Three flows define the system's shape. (1) Cold start: platform main → ElectronMainDelegate hooks → ElectronBrowserMainParts builds V8+Node, loads the app package, runs the bundled init which loads the app's main script, then Chromium's BrowserMain continues. (2) ipcRenderer.invoke: mojo message → ElectronApiIPCHandlerImpl → IpcMainEvent → JS ipcMain handler → reply through a ReplyChannel. (3) protocol.handle: a renderer request hits the session's protocol registry, calls the JS handler with a Request, and streams the Response back to the loader.
- Browser-process startup order: main() → content::ContentMain → ElectronMainDelegate::BasicStartupComplete (env vars ELECTRON_ENABLE_STACK_DUMPING/ELECTRON_DISABLE_SANDBOX, RegisterPathProvider, root-without-sandbox fatal check on Linux) → PreSandboxStartup (logging, crash keys, ResourceBundle for subprocesses, --allow-file-access-from-files) → PreBrowserMain (FieldTrialList, InitializeFeatureList, InitializeMojoCore). — [shell/app/electron_main_linux.cc#L49](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_linux.cc#L49) [shell/app/electron_main_delegate.cc#L216-L284](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L216-L284) [shell/app/electron_main_delegate.cc#L286-L410](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L286-L410)
- Startup continued: ElectronBrowserMainParts::PostEarlyInitialization sets up WASM trap handlers (fuse-gated), creates JavascriptEnvironment, node_bindings_->Initialize → CreateEnvironment → sets unhandled_rejections='warn-with-error-code' → ElectronBindings::BindTo → LoadAppPackage → node_bindings_->LoadEnvironment (runs the browser bundle = lib/browser/init.ts) → JoinAppCode → re-initializes the FeatureList so app-set command-line switches take effect. — [shell/browser/electron_browser_main_parts.cc#L290-L410](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L290-L410)
- lib/browser/init.ts order: require common init (module aliases, uv-loop wrapping) → set EventEmitter prototype on the native binding → install uncaughtException→dialog.showErrorBox handler → map process.exit→app.exit → require ipc-dispatch, rpc-server, guest-view-manager → read 'appPackage' hidden value → app.setAppPath → pre-populate protocol/service-worker-main/web-contents/web-frame-main modules → default window-all-closed→app.quit handler → apply v8Flags → load main entry → appCodeLoaded. — [lib/browser/init.ts#L10-L121](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/init.ts#L10-L121)
- new BrowserWindow(): JS constructor reaches the native object from process._linkedBinding('electron_browser_window'), whose _init freeze-wraps id, merges setBounds args with getBounds, re-emits focus/blur on app as 'browser-window-focus/blur', debounces 'unresponsive' (50ms; 5s during close), tracks _browserViews, emits 'browser-window-created' on app, then loadURL etc. forward to webContents. — [lib/browser/api/browser-window.ts#L4-L82](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/browser-window.ts#L4-L82) [lib/browser/api/browser-window.ts#L118-L128](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/browser-window.ts#L118-L128)
- Renderer script-context flow: Blink creates a script context → ElectronRendererClient::DidCreateScriptContext → ShouldLoadPreload gate → first-time NodeBindings::Initialize/SetUpIsolate (then restores Blink's WASM streaming callback) → per-frame FrameEnvironment + node::InitializeContext → document load deferred (kStrict) → CreateEnvironment registers UndeferLoad callback → BindTo + BindProcess → preload paths stored as hidden 'preloadPaths'. — [shell/renderer/electron_renderer_client.cc#L133-L204](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_renderer_client.cc#L133-L204) [shell/renderer/renderer_client_base.cc#L389-L416](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/renderer_client_base.cc#L389-L416)
- Preload execution order in lib/renderer/init.ts: patch Module._load to warn on 'vm' → override Module.wrapper to keep process/global/Buffer for preloads → common init → read webPreferences (nodeIntegration) → set up node globals only if nodeIntegration → load cjsPreloads synchronously (errors → BROWSER_PRELOAD_ERROR IPC) → esmPreloads via runEntryPointWithESMLoader → onPreloadsLoaded deletes node globals when !nodeIntegration && !contextIsolated → appCodeLoaded → UndeferLoad unfreezes the document. — [lib/renderer/init.ts#L11-L41](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L11-L41) [lib/renderer/init.ts#L125-L180](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L125-L180)
- ipcRenderer.invoke('ch', ...args): the renderer binding sends ElectronApiIPC.Invoke over the associated mojo channel → ElectronApiIPCHandlerImpl::Invoke resolves api::Session from the frame's BrowserContext → MakeIPCEvent builds api::IpcMainEvent carrying the mojo InvokeCallback (ReplyChannel) → ipc_dispatch::Invoke looks up IpcMainImpl._invokeHandlers['ch'] → return value/promise serialized back through SerializedValue to the renderer promise. — [shell/browser/electron_api_ipc_handler_impl.cc#L66-L84](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L66-L84) [shell/browser/electron_api_ipc_handler_impl.cc#L158-L188](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L158-L188) [lib/browser/ipc-main-impl.ts#L15-L35](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-main-impl.ts#L15-L35) [lib/browser/ipc-dispatch.ts#L5-L7](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-dispatch.ts#L5-L7)
- If the Session or WebContents wrapper is gone when an Invoke arrives, MakeIPCEvent still invokes the reply callback with an error via ReplyChannel::SendError so the renderer promise rejects instead of hanging. — [shell/browser/electron_api_ipc_handler_impl.cc#L163-L184](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L163-L184)
- protocol.handle('app', handler) on a custom scheme: registerProtocol stores the callback → a request arrives as ProtocolRequest → convertToRequestBody rebuilds uploadData → a Request is constructed (initiatorOrigin attached as own prop, 'null' origin header stripped) → await handler(req) → validateResponse → if the Response is an untouched net.fetch result, relayUntouchedFetch holds the URL loader and streams prefix+remainder natively; otherwise res.body is wrapped with Readable.fromWeb → cb({data, headers, statusCode, statusText, mimeType}). — [lib/browser/api/protocol.ts#L152-L200](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L152-L200)
- utilityProcess.fork flow: JS validates options (execArgv array, serviceName string, stdio triple with stdin forced 'ignore') → native _fork launches a utility process → the returned handle emits 'stdout'/'stderr' events carrying fds that JS wraps in Socket→PassThrough pipes → 'exit' nulls the handle and tears down streams. — [lib/browser/api/utility-process.ts#L53-L117](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/utility-process.ts#L53-L117) [shell/services/node/node_service.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/services/node/node_service.cc)
- ELECTRON_RUN_AS_NODE flow: lib/node/init.ts patches child_process.fork to inject ELECTRON_RUN_AS_NODE=1 (and helperExecPath on macOS); on Linux, spawn/spawnSync are wrapped to forward CRASHDUMP_SIGNAL_FD/CRASHPAD_HANDLER_PID env pairs to such children; shell/app/node_main.cc detects the env var and runs plain Node instead of Chromium. — [lib/node/init.ts#L6-L75](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L6-L75) [shell/app/node_main.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/node_main.cc)
- V8 snapshot integrity: when the embedded_asar_integrity_validation fuse is on, a validator registered via gin::SetV8SnapshotValidator CHECK-fails startup unless the snapshot's SHA-256 equals the compiled-in snapshot_checksum::kChecksum. — [shell/app/electron_main_delegate.cc#L165-L177](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L165-L177) [shell/app/electron_main_delegate.cc#L202-L204](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L202-L204)

## Testing signals

Tests are Mocha specs in spec/ (api-*-spec.ts per module plus feature specs like asar/fuses/esm/crash) executed inside the built Electron binary — spec/index.js is literally run as the app's main script by script/spec-runner.js. Assertions use chai with dirty-chai and chai-as-promised; CI shards by per-file weights and records timing artifacts. Coverage is strongest on the JS-facing API surface; C++ internals are exercised indirectly, and there are no unit tests for shell/ outside the in-binary specs.
- npm test → script/spec-runner.js, which installs spec node_modules when the spec hash changed, generates electron.d.ts if missing, then launches the built Electron binary with spec/ as the app. — [package.json#L73](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L73) [script/spec-runner.js#L44-L120](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/script/spec-runner.js#L44-L120) [spec/index.js#L1-L8](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L1-L8)
- spec/index.js is the test app's main: it registers privileged test schemes ('app', 'zoom', 'sw', 'cors', 'stream', ...), appends js-flags=--expose_gc and enable-features switches, loads Mocha with forbidOnly+3 retries on CI, TAP reporter by default (MOCHA_REPORTER/MOCHA_MULTI_REPORTERS override), 30s default timeout (MOCHA_TIMEOUT). — [spec/index.js#L33-L80](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L33-L80) [spec/index.js#L208-L292](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L208-L292)
- Spec discovery picks files matching /-spec\.[tj]s$/ under spec/ via get-files.ts; MOCHA_GREP/MOCHA_INVERT and --files allow sharding; npm_config_match filters by name. — [spec/index.js#L294-L321](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L294-L321) [spec/get-files.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/get-files.ts)
- disabled-tests.json is a title-exact skip list enforced by a mocha beforeEach root hook; per-suite beforeAll kills orphaned Electron processes (pgrep/wmic/proc scan filtered by execPath and PID-descent) between spec files. — [spec/index.js#L249-L258](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L249-L258) [spec/index.js#L104-L206](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L104-L206) [spec/disabled-tests.json](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/disabled-tests.json)
- On CI the runner writes spec/artifacts/spec-timings.json (per-file wall time keyed by platform/arch/mas/sanitizer) consumed by script/gen-spec-weights.js; script/spec-weights.json already holds per-file shard weights. — [spec/index.js#L363-L394](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L363-L394) [script/spec-weights.json](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/script/spec-weights.json)
- spec/package.json pins the harness deps — mocha ^10, chai + chai-as-promised + dirty-chai, mocha-junit-reporter, ws, busboy — plus @electron-ci/* native-addon fixtures (dialog-helper, echo, is-valid-window, object-wrap, uv-dlopen, virtual-display) and @electron/fuses. — [spec/package.json#L10-L43](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/package.json#L10-L43)
- ELECTRON_REQUIRE_TESTING_BINDINGS=1 makes the run fail early if testing bindings are unavailable, distinguishing testing builds from release binaries. — [spec/index.js#L268-L271](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L268-L271) [spec/lib/spec-helpers.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/lib/spec-helpers.ts)
- electron.d.ts is generated from docs API markdown (create-api-json.mjs + @electron/typescript-definitions) and validated by a smoke test: spec/ts-smoke/runner.js compiles fixture TS against the definitions; the same generation runs as a docs lint step. — [package.json#L61-L63](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L61-L63) [spec/ts-smoke/runner.js](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/ts-smoke/runner.js) [script/create-api-json.mjs](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/script/create-api-json.mjs)
- Fixtures cover asar archives (test.asar, recursive-asar), crash-cases, devtools-extensions, native-addon builds, ESM variants and webview pages under spec/fixtures; helper modules live in spec/lib (http-server-helpers, codesign-helpers, window-helpers, ...). — [spec/fixtures](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/fixtures) [spec/lib/spec-helpers.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/lib/spec-helpers.ts)
- Linting is a first-class gate: npm run lint chains script/lint.js (oxlint for JS/TS, cpplint-style for C++/ObjC, python, gn), oxfmt format check, clang-format on shell/, and a docs pipeline that lints code blocks in markdown and validates api-history YAML blocks against docs/api-history.schema.json. — [package.json#L42-L60](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L42-L60) [script/lint.js](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/script/lint.js) [docs/api-history.schema.json](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/api-history.schema.json)
- CI splits work across pipeline workflows: pipeline-segment-electron-build.yml, pipeline-segment-electron-test.yml (plus a -64k variant), pipeline-electron-lint.yml, apply-patches.yml, and per-OS publish workflows (linux/macos/windows-publish.yml); audit workflows publish findings as an 'audit-results.md' artifact. — [.github/workflows/pipeline-segment-electron-test.yml](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/.github/workflows/pipeline-segment-electron-test.yml) [.github/workflows/apply-patches.yml](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/.github/workflows/apply-patches.yml) [.github/workflows/audit-branch-ci.yml](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/.github/workflows/audit-branch-ci.yml)
- default_app/ has no dedicated spec file — its CLI behaviors (REPL, --version, package loading) are only covered indirectly through specs that launch Electron with app paths; the argument parser itself is untested in isolation. (inferred) — [default_app/main.ts#L20-L70](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/default_app/main.ts#L20-L70) [spec/index.js](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js)
- spec/CLAUDE.md documents real test-authoring hazards: expect() inside stream/event listeners becomes an uncaught exception that kills the runner silently, utilityProcess drops stdio listeners at 'exit', and children must be registered with deferKillUtilityProcess — evidence that flaky child-process specs have been a recurring problem. — [spec/CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/CLAUDE.md)

## Risk map

The largest risks are the security boundary between web content and Node, the breadth of the IPC surface, and the patch-queue maintenance burden. Sandbox/safety defaults are computed from webPreferences in one place (web_contents_preferences.cc) so changes there have wide blast radius; several features (fuses, ELECTRON_RUN_AS_NODE, preload privilege, protocol handlers) deliberately trade security for capability; and ~200 patches to Chromium/Node/V8 must be re-applied and merged on every dependency roll.
- Sandbox defaults are derived, not explicit: RendererProcessPreferences::From marks a renderer sandboxed unless nodeIntegration or nodeIntegrationInWorker is set (or webPreferences.sandbox overrides), and AppendCommandLineSwitches injects --no-sandbox/--no-zygote for unsandboxed renderers — a single pref change flips process isolation. — [shell/browser/web_contents_preferences.cc#L86-L117](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/web_contents_preferences.cc#L86-L117) [shell/browser/web_contents_preferences.cc#L126-L159](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/web_contents_preferences.cc#L126-L159)
- ELECTRON_DISABLE_SANDBOX unconditionally appends --no-sandbox at BasicStartupComplete, and ELECTRON_RUN_AS_NODE turns the whole binary into Node — both are env-var-controlled capabilities attackers can sometimes influence. — [shell/app/electron_main_delegate.cc#L100-L103](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L100-L103) [shell/app/electron_main_delegate.cc#L235-L236](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/app/electron_main_delegate.cc#L235-L236) [lib/node/init.ts#L28-L41](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L28-L41)
- Preload scripts run with Node globals even in isolated worlds; the Module.wrapper hack in lib/renderer/init.ts must stay in sync with the bundle's inject list in build/bundle/bundle.mjs, and mistakes leak process/Buffer into the main world (the deletion path only runs for non-context-isolated renderers). — [lib/renderer/init.ts#L21-L41](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L21-L41) [lib/renderer/init.ts#L125-L141](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L125-L141) [build/bundle/bundle.mjs#L127-L141](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/bundle/bundle.mjs#L127-L141)
- The IPC surface trusts channel strings end-to-end: internal channels share the same wire as app channels (ipcMainInternal vs ipcMain separated only by the 'internal' bool on the mojo call), so a confused-deputy bug in ipc_dispatch or event.type checks (e.g. rpc-server.ts guards event.type !== 'frame') would let renderer content reach privileged handlers. — [shell/browser/electron_api_ipc_handler_impl.cc#L48-L84](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L48-L84) [lib/browser/rpc-server.ts#L4-L14](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/rpc-server.ts#L4-L14) [lib/browser/ipc-dispatch.ts#L5-L7](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-dispatch.ts#L5-L7)
- process._linkedBinding exposes the entire native binding table (ELECTRON_*_BINDINGS) to any code running with Node in the renderer when nodeIntegration is on — including process.crash() and process.hang() which deliberately crash/hang the process. — [shell/common/node_bindings.cc#L68-L120](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/node_bindings.cc#L68-L120) [shell/common/api/electron_bindings.cc#L113-L123](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/api/electron_bindings.cc#L113-L123)
- Fuses change security posture post-build without recompilation: grant_file_protocol_extra_privileges defaults to '1' (on) and run_as_node/node_options/node_cli_inspect default on; embedded_asar_integrity_validation and only_load_app_from_asar default off, so integrity guarantees are opt-in. — [build/fuses/fuses.json5#L5-L14](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/fuses/fuses.json5#L5-L14) [shell/browser/app_package.cc#L91-L98](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/app_package.cc#L91-L98) [docs/tutorial/fuses.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/tutorial/fuses.md)
- protocol.handle bridges raw request data into Fetch objects: uploadData chunk types (rawData/file/stream/blob) are reassembled by hand and blob bytes come from session.defaultSession regardless of the requesting session (noted in the code as relying on globals) — a subtle cross-session data path. — [lib/browser/api/protocol.ts#L58-L106](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L58-L106)
- <webview> webPreferences are parsed from a DOM attribute string via parse-features-string, and guest-view-manager merges them with embedder-inherited security prefs; malformed or malicious attribute values are a parsing/injection surface, mitigated by the inheritedWebPreferences allowlist. — [lib/browser/guest-view-manager.ts#L32-L75](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/guest-view-manager.ts#L32-L75) [lib/browser/parse-features-string.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/parse-features-string.ts)
- security_warnings.cc exists specifically to nag developers about insecure configurations (insecure content, disabled webSecurity, etc.) in devtools — implying the footguns are common enough to need runtime warnings, gated off in tests via ELECTRON_DISABLE_SECURITY_WARNINGS. — [shell/renderer/security_warnings.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/security_warnings.cc) [spec/index.js#L16](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L16)
- The uncaughtException handler in lib/browser/init.ts swallows main-process crashes into a GUI error box (showErrorBox) instead of exiting — a deliberate 'don't quit' policy that can mask fatal errors in production apps. — [lib/browser/init.ts#L14-L31](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/init.ts#L14-L31)
- patches/ carries ~200 patches across 13 upstream repos (chromium, node, v8, angle, sqlite, webrtc, boringssl, ffmpeg, ...); each Chromium roll (DEPS chromium_version) requires 3-way merging the queue, and patch rot in security-relevant files is a recurring fragility the repo's own docs warn about. — [patches/config.json](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/patches/config.json) [DEPS#L3-L8](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/DEPS#L3-L8) [docs/development/patches.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/development/patches.md)
- spec/index.js kills processes matching the Electron execPath between spec files — on macOS via pgrep -f and on Linux by scanning /proc/*/exe — which would terminate any co-located Electron app sharing the binary path if run outside CI. — [spec/index.js#L104-L206](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L104-L206)
- ElectronBrowserMainParts holds most browser-process singletons (node_bindings_, js_env_, node_env_, browser_, fake_browser_process_) with an enforced single self_ instance; ordering bugs in PostEarlyInitialization (env before LoadAppPackage, JoinAppCode before FeatureList re-init) are load-bearing and poorly isolated. (inferred) — [shell/browser/electron_browser_main_parts.cc#L198-L210](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L198-L210) [shell/browser/electron_browser_main_parts.cc#L290-L410](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L290-L410)

## Extension points

New APIs plug in at three layers: a C++ binding registered via NODE_LINKED_BINDING_CONTEXT_AWARE plus a name in the ELECTRON_*_BINDINGS macros, a JS wrapper added to the appropriate lib/<proc>/api/module-list.ts, and a docs/api/*.md page that generates the .d.ts. Apps extend Electron through protocol.handle/registerSchemesAsPrivileged, session partitions and preload-script registration, ipcMain/ipcRenderer channels, utilityProcess.fork, and (for embedders) build-time fuses and GN buildflags. docs/development/creating-api.md documents the recipe.
- To add a main-process module: add { name, loader } to browserModuleList in lib/browser/api/module-list.ts (alphabetical, with a matching module-keys update noted in the file's TODO), implement lib/browser/api/<name>.ts, and it appears on require('electron') via defineProperties. — [lib/browser/api/module-list.ts#L1-L5](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/module-list.ts#L1-L5) [lib/browser/api/exports/electron.ts#L5-L8](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/exports/electron.ts#L5-L8) [lib/common/define-properties.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/define-properties.ts)
- To add a native binding: register Initialize() with NODE_LINKED_BINDING_CONTEXT_AWARE(electron_<proc>_<name>, Initialize) at file scope and add the name to the matching ELECTRON_*_BINDINGS macro in node_bindings.cc; JS reaches it via process._linkedBinding('electron_<proc>_<name>'). — [shell/browser/api/electron_api_app.cc#L2099-L2127](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/api/electron_api_app.cc#L2099-L2127) [shell/common/node_bindings.cc#L68-L120](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/node_bindings.cc#L68-L120)
- docs/development/creating-api.md is the canonical recipe for new APIs; the docs page's YAML 'history' front-matter is schema-validated and feeds electron.d.ts generation via create-api-json.mjs + electron-typescript-definitions. — [docs/development/creating-api.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/development/creating-api.md) [docs/api-history.schema.json](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/api-history.schema.json) [package.json#L61-L62](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L61-L62)
- protocol.registerSchemesAsPrivileged (must run before app ready, per spec/index.js usage) + session.protocol.handle/unhandle/isProtocolHandled let apps mint custom URL schemes with privileges (standard, secure, stream, corsEnabled, supportFetchAPI, allowServiceWorkers). — [lib/browser/api/protocol.ts#L152-L212](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L152-L212) [spec/index.js#L62-L80](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L62-L80) [shell/browser/protocol_registry.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/protocol_registry.cc)
- session.fromPartition/fromPath create isolated storage/network contexts; registerPreloadScript registers frame- or service-worker-scoped preloads (superseding getPreloads/setPreloads which are deprecation shims). — [lib/browser/api/session.ts#L57-L85](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/session.ts#L57-L85) [lib/browser/api/session.ts#L122-L128](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/session.ts#L122-L128) [shell/browser/electron_browser_context.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_context.cc)
- session.extensions.loadExtension (Chromium extensions support, ENABLE_ELECTRON_EXTENSIONS buildflag) is the app-facing extension point for MV2-style extensions; old session.loadExtension calls are rerouted with deprecation warnings. — [lib/browser/api/session.ts#L87-L114](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/session.ts#L87-L114) [shell/browser/electron_browser_main_parts.cc#L114-L121](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L114-L121) [docs/api/extensions.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/api/extensions.md)
- ipcMain.handle/on and ipcRenderer.invoke/send are the app-level RPC extension point; MessageChannelMain/MessagePortMain support transferable ports, and ipcMainServiceWorker covers service-worker targets. — [lib/browser/ipc-main-impl.ts#L15-L35](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-main-impl.ts#L15-L35) [docs/api/ipc-main.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/api/ipc-main.md) [docs/api/ipc-main-service-worker.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/api/ipc-main-service-worker.md)
- utilityProcess.fork(modulePath, args, opts) is the supported way to run app JS in a dedicated process with postMessage messaging — replacing child_process.fork when the runAsNode fuse is off. — [lib/browser/api/utility-process.ts#L151-L153](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/utility-process.ts#L151-L153) [lib/node/init.ts#L28-L32](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L28-L32)
- GN buildflags (buildflags/buildflags.gni) gate major subsystems — ENABLE_ELECTRON_EXTENSIONS, ENABLE_BUILTIN_SPELLCHECKER, ENABLE_PDF_VIEWER, ENABLE_PRINTING, ENABLE_PLUGINS — and are exposed to JS at runtime via electron_common_features binding (features.cc). — [buildflags/buildflags.gni](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/buildflags/buildflags.gni) [shell/common/api/features.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/api/features.cc) [shell/browser/electron_browser_main_parts.cc#L114-L135](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L114-L135)
- Fuses are the distributor-facing extension mechanism: build/fuses/fuses.json5 is the schema (with a 'never remove, mark removed r' rule and _version field), generated into fuses.h/fuses.cc by build/fuses/build.py during the electron_fuses GN action; the @electron/fuses npm package flips them in shipped binaries. — [build/fuses/fuses.json5#L1-L4](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/fuses/fuses.json5#L1-L4) [BUILD.gn#L450-L457](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/BUILD.gn#L450-L457) [spec/fuses-spec.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/fuses-spec.ts)
- New webview-exposed behaviors plug into the GUEST_VIEW_MANAGER_* internal channels plus the syncMethods/asyncMethods/properties tables in lib/common/web-view-methods.ts and the event list in lib/browser/web-view-events.ts. — [lib/common/ipc-messages.ts#L5-L11](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/ipc-messages.ts#L5-L11) [lib/common/web-view-methods.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/web-view-methods.ts) [lib/browser/guest-view-manager.ts#L7-L11](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/guest-view-manager.ts#L7-L11)
- New patch targets are added by extending patches/config.json with a {patch_dir, repo} pair — the queue is applied by e sync / apply-patches.yml and exported by e patches <target>. — [patches/config.json](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/patches/config.json) [.github/workflows/apply-patches.yml](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/.github/workflows/apply-patches.yml)
- The bundle pipeline itself is extensible: adding a lib/<name>/init.ts plus a targets.mjs entry produces a new baked-in JS context, with knobs for Node availability, electron-module aliasing, node-globals capture and init wrapping. (inferred) — [build/bundle/targets.mjs#L5-L54](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/bundle/targets.mjs#L5-L54) [build/bundle/bundle.mjs#L50-L60](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/bundle/bundle.mjs#L50-L60)

## Contributor handoff

This is a Chromium-tree project, not a standalone repo: it lives at src/electron inside a Chromium checkout, builds with GN/Ninja via @electron/build-tools ('e' commands), and tests run the built binary against spec/. Follow the pinned rules: no npx, no force-push conventions, patches are fixed not recreated, C++ is Chromium-style, JS/TS is oxlint+oxfmt. Read the root CLAUDE.md and docs/development/* before editing; run lint-staged-adjacent checks (oxlint, clang-format, gen-filenames) since filenames.gni is generated.
- Read first: root CLAUDE.md (build commands, patch rules, cppgc/GC rules, PR conventions), docs/development/source-code-directory-structure.md, docs/development/creating-api.md, docs/development/testing.md, then BUILD.gn/DEPS/filenames.gni for build wiring. — [CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/CLAUDE.md) [docs/development/source-code-directory-structure.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/development/source-code-directory-structure.md) [docs/development/creating-api.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/development/creating-api.md) [docs/development/testing.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/development/testing.md)
- Never use npx — it can fetch arbitrary packages; run binaries via node_modules/.bin/<tool> or yarn <tool>. This applies to authored scripts too. — [CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/CLAUDE.md)
- Build/test loop: e init/e use/e sync/e build/e start/e test (from @electron/build-tools); inside the repo, npm test runs script/spec-runner.js and npm run lint runs the full lint chain (oxlint, oxfmt, clang-format, docs lint, gn check). — [CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/CLAUDE.md) [package.json#L42-L77](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L42-L77) [script/spec-runner.js#L1-L30](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/script/spec-runner.js#L1-L30)
- filenames.gni and filenames.auto.gni are generated: lint-staged runs script/gen-filenames.mts on *.{js,mjs,ts,mts,d.ts} changes, and bundle.mjs --print-graph produces the module list — hand-editing them is a trap. — [package.json#L94-L96](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L94-L96) [build/bundle/bundle.mjs#L8-L10](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/bundle/bundle.mjs#L8-L10) [script/gen-filenames.mts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/script/gen-filenames.mts) [filenames.gni](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/filenames.gni)
- Patch workflow: fix existing patches rather than adding new ones, preserve TODO(name) attribution, edit the target repo then 'e patches <target>' to export; for CI patch conflicts fetch the update-patches.patch artifact from the Apply Patches run instead of a local e sync --3. — [CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/CLAUDE.md) [docs/development/patches.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/development/patches.md) [.github/workflows/apply-patches.yml](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/.github/workflows/apply-patches.yml)
- Spec-writing rules (spec/CLAUDE.md): never expect() inside 'data'/'message'/'exit' listeners, wait for expected output not 'exit', accumulate stdout before asserting (stderr races), and register forked children with deferKillUtilityProcess so the global afterEach reaps them. — [spec/CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/CLAUDE.md)
- C++ conventions follow Chromium style enforced by clang-format (script/run-clang-format.py); cppgc/Oilpan rules are strict — cppgc::MakeGarbageCollected only, Member/WeakMember edges, no destructors touching other GC objects, GCPA-managed callbacks via WeakCellFactory. — [CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/CLAUDE.md) [package.json#L46](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L46)
- API changes need synchronized updates across lib/<proc>/api/module-list.ts (+module-keys), the C++ binding registration, docs/api/*.md with YAML history blocks (lint:api-history validates against docs/api-history.schema.json), docs/breaking-changes.md for removals, and regenerated electron.d.ts. — [lib/browser/api/module-list.ts#L1-L3](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/module-list.ts#L1-L3) [docs/CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/docs/CLAUDE.md) [package.json#L59-L62](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L59-L62)
- PR conventions: body must end with a 'Notes:' consumer-facing line ('Notes: none' if internal); label semver/{none,patch,minor,major} and target/{N}-x-y backports — bug fixes to all active branches except oldest, security fixes including oldest, features main-only. — [CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/CLAUDE.md)
- Known traps: the renderer's Module.wrapper hack must mirror build/bundle/bundle.mjs inject entries; the 'vm' module is unusable in renderers; process.exit is remapped to app.exit; renderer node globals are deleted unless nodeIntegration/contextIsolation; unhandled rejections are set to 'warn-with-error-code' not crash. — [lib/renderer/init.ts#L11-L41](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L11-L41) [lib/browser/init.ts#L40-L50](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/init.ts#L40-L50) [lib/renderer/init.ts#L125-L141](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L125-L141) [shell/browser/electron_browser_main_parts.cc#L343-L344](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L343-L344)
- Safe edit boundaries: lib/ changes are self-contained TS that get bundled — run build/bundle/typecheck.mjs and oxlint; shell/ C++ changes need clang-format and a full build; spec/ changes should mirror the api-<module>-spec.ts naming convention and use spec/lib helpers. (inferred) — [build/bundle/typecheck.mjs](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/build/bundle/typecheck.mjs) [spec/lib/spec-helpers.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/lib/spec-helpers.ts) [package.json#L76](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/package.json#L76)
- CI artifacts worth knowing: audit workflows upload 'audit-results.md' unarchived (archive_download_url returns raw markdown); the Apply Patches workflow uploads 'update-patches.patch'; spec-timings.json feeds shard balancing. — [CLAUDE.md](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/CLAUDE.md) [.github/workflows/audit-branch-ci.yml](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/.github/workflows/audit-branch-ci.yml) [spec/index.js#L376-L394](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/spec/index.js#L376-L394)

Source repository: https://github.com/electron/electron
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/electron.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
