definePlugin() the same way any third-party extension would be, and it has the same capabilities. The only thing that makes the main application special is the uiEntrypoint in defineConfig(), which tells the framework which plugin’s code to load in the renderer process first.
Defining a plugin
Plugins are declared withdefinePlugin() from @zenbujs/core/config:
zenbu.config.ts
Scaffolding a plugin
create-zenbu-app can scaffold a plugin folder from anywhere on disk:
The command scaffolds the plugin folder and installs its dependencies.
Adding a plugin
Plugins can be inlined withdefinePlugin() or referenced by path to a zenbu.plugin.ts file:
zenbu.config.ts is a hot-reloadable change that takes effect without restarting the app.
Local-only plugins (localPlugins)
A zenbu.config.ts can opt into a per-developer overlay file that’s gitignored and loaded only if it exists. Use this when you want to wire a local plugin (e.g. one cloned into ~/.zenbu/plugins/...) into your app without committing the path:
zenbu.local.ts
- The default export is a plugin entry, or an array of entries. Same shape as
plugins. - Relative paths inside the overlay anchor to the overlay file’s directory, not the project root.
localPluginsaccepts a single string or an array of strings (multiple overlays).- If the overlay file doesn’t exist, the field is silently ignored.
- Editing the overlay file hot-reloads exactly like editing
zenbu.config.ts. zen build:source/zen build:electron/zen publish:sourceskiplocalPluginsentirely, so a developer’s overlay can never ship in a build artefact.
Plugin capabilities
A plugin has the same capabilities as the host application:- Services run in the main process and expose methods via RPC.
- Database schemas define sections of the shared database.
- Events can be emitted and listened to across plugins.
- Injections are the unified renderer-side surface. One primitive (
this.inject(...)/useRegisterInjection(...)) covers React components other plugins can render via<View>, plain side-effect modules (the old “content script” pattern), plain functions/values, and advice (sugar for wrapping or replacing an existing export).
Type dependencies
If a plugin needs to call another plugin’s RPC methods, read its database, or subscribe to its events, it needs that plugin’s type definitions. You declare this withdependsOn:
zenbu.plugin.ts
name is the plugin you depend on, and from is the path to the file that defines it. With this in place, you get typed access to that plugin’s API:
dependsOn tells zen link where to find the other plugin’s service, schema, and event definitions so it can generate TypeScript types under <plugin>/.zenbu/types/. The generated files are import type pointers to the actual source on disk, and the entire .zenbu/types/ directory is gitignored.
zen link runs automatically inside zen dev. Outside dev, run it manually before typechecking:

