How to Build and Contribute to PI-Desktop Plugins: A Complete Developer Guide
To build a PI-Desktop plugin, create a folder containing a manifest.json and main.js, declare permissions and contributions, then use the Plugin DevKit CLI to validate and pack it into a .piplug file for distribution.
PI-Desktop exposes a full-featured plugin system that lets developers extend the application with custom commands, panels, agent tools, skills, themes, and MCP servers. Whether you want to build and contribute to PI-Desktop plugins for private use or share them with the community, the repository provides a complete development toolchain and strict security architecture. All plugin capabilities are governed by the Plugin Specification defined in spec/07-plugins/ and the runtime API exposed through the global pi object.
Understanding the Plugin Architecture
PI-Desktop uses a multi-process architecture that isolates plugin code from the main application while maintaining rich integration capabilities.
The Plugin Process and Sandbox Model
Every plugin runs in a dedicated Node process that loads the entry script (main.js) specified in the manifest. This process has access to the global pi API for registering contributions such as commands, tools, and services. When a plugin declares UI contributions like panels or views, PI-Desktop launches sandboxed Electron windows that contain only the HTML/CSS/JS assets. These renderer processes communicate with the plugin host through window.pluginBridge, never directly with the Node API.
According to the source code in docs/plugin-development.md, this separation ensures that UI code cannot access the filesystem or network without explicit permission granted through the bridge.
Permission Gateway and Security
Every API call—whether pi.fs.*, pi.net.fetch, or pi.agent.*—passes through a permission gateway defined in spec/07-plugins/13-plugin-permissions-matrix.md. The manifest.json must declare all required permissions in the permissions array (e.g., ui.panel, fs.read, net.fetch). At install time, PI-Desktop prompts the user to grant each permission, and any missing permission causes the corresponding API call to fail with PERMISSION_DENIED.
Creating Your First Plugin
A minimal plugin requires three components: a manifest, an entry script, and optional UI assets.
The Manifest File
The manifest.json declares the plugin's identity, contributions, and required permissions. Refer to spec/07-plugins/02-plugin-manifest-schema.md for the formal JSON schema.
{
"schemaVersion": 1,
"id": "local.my-first-plugin",
"name": "My First Plugin",
"version": "0.1.0",
"description": "Opens a panel and shows a greeting.",
"main": "main.js",
"ui": {
"panel": "renderer/index.html",
"title": "My First Plugin",
"width": 480,
"height": 360
},
"contributes": {
"commands": [
{
"id": "my-first-plugin.open",
"title": "My First Plugin: Open Panel",
"keywords": ["hello", "panel"]
}
]
},
"permissions": ["ui.panel"],
"engines": { "piDesktop": ">=0.1.0" },
"activationEvents": ["onCommand:my-first-plugin.open", "onStartup"]
}
The Entry Script
The main.js file exports lifecycle hooks (onLoad and onUnload) that the runtime calls when activating or deactivating the plugin.
async function onLoad() {
await pi.commands.register({
id: "my-first-plugin.open",
title: "My First Plugin: Open Panel",
keywords: ["hello", "panel"],
run: async () => {
await pi.ui.openPanel({ title: "My First Plugin" });
await pi.ui.showToast("Hello from My First Plugin");
},
});
}
async function onUnload() {
await pi.commands.unregister("my-first-plugin.open");
}
module.exports = { onLoad, onUnload };
UI Assets and Renderer Communication
Place HTML files under a renderer/ subfolder. The frontend communicates with the plugin process via window.pluginBridge.invoke().
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My First Plugin</title>
</head>
<body>
<h1>My First Plugin</h1>
<button id="hello">Show toast</button>
<script>
document.getElementById("hello").addEventListener("click", async () => {
await window.pluginBridge.invoke("ui.showToast", {
message: "Hello from the panel",
});
});
</script>
</body>
</html>
Development Workflow and Tooling
The repository includes a Plugin DevKit workspace package (@pi-desktop/plugin-devkit) that provides CLI utilities for scaffolding, validating, and packaging plugins.
Scaffolding and File Structure
After installing repository dependencies (pnpm install), use the CLI to generate a new plugin from a template:
pnpm pi-plugin init panel-basic ../my-first-plugin \
--id local.my-first-plugin \
--name "My First Plugin"
This creates the folder structure defined in docs/plugin-development.md, including the manifest, main script, and renderer assets.
Hot Reload and Debugging
PI-Desktop automatically reloads plugins during development after a 300ms debounce. The runtime performs an unload → validate → load cycle whenever it detects file changes in the plugin directory. This allows rapid iteration without restarting the application.
Validation and Packaging
Before distribution, validate your plugin against the schema and permission matrix:
# Verify manifest, file scopes, and size limits
pnpm pi-plugin check ../my-first-plugin
# Create distributable .piplug ZIP
pnpm pi-plugin pack ../my-first-plugin
The check command references spec/07-plugins/02-plugin-manifest-schema.md to ensure all required fields are present and that declared permissions match the actual API usage detected in main.js.
Contributing Plugins to the Repository
To contribute a plugin to the main vastsa/PI-Desktop repository:
- Fork the repository and create a new feature branch.
- Place your plugin under
examples/plugins/<your-plugin>to serve as a reference implementation. - Run validation and packaging steps to ensure CI compliance.
- Open a pull request that adds your plugin folder.
- Update the marketplace catalog in the
pi-desktop-pluginsrepository if you intend to publish it for public installation.
The examples/plugins/hello directory provides a real-world reference showing view contributions, commands, tools, and skills working together. For end-to-end validation, see scripts/e2e/plugin.mjs, which tests registration, UI rendering, and permission enforcement.
Summary
- PI-Desktop plugins run in isolated Node processes with sandboxed UI windows, communicating through
window.pluginBridge. - Every plugin requires a
manifest.jsondeclaring contributions (commands, panels, agent tools, etc.) and explicit permissions. - The
main.jsentry script uses the globalpiAPI to register capabilities and exportsonLoad/onUnloadlifecycle hooks. - The Plugin DevKit CLI (
pnpm pi-plugin) handles scaffolding, validation againstspec/07-plugins/, and packaging into.piplugfiles. - Contributions should be placed in
examples/plugins/and validated before submitting a pull request.
Frequently Asked Questions
What file structure is required for a PI-Desktop plugin?
A valid plugin folder must contain a manifest.json file and a main.js entry script at minimum. UI contributions require additional assets, typically placed in a renderer/ subdirectory. The manifest's main field points to the entry script, while ui.panel or contributes.views reference HTML files relative to the plugin root.
How does the permission system work in PI-Desktop plugins?
Permissions are declared in the manifest.json permissions array (e.g., fs.read, net.fetch, ui.panel). At installation, PI-Desktop prompts the user to grant each permission. The runtime enforces these permissions through a gateway layer; any API call lacking the corresponding permission returns PERMISSION_DENIED. The complete mapping of permissions to APIs is documented in spec/07-plugins/13-plugin-permissions-matrix.md.
Can I contribute my plugin to the official repository?
Yes. Fork the vastsa/PI-Desktop repository, place your plugin in examples/plugins/<your-plugin-name>, and ensure it passes validation via pnpm pi-plugin check. The CI pipeline runs scripts from scripts/e2e/plugin.mjs to verify registration, UI functionality, and permission compliance. After merging, you may submit the plugin to the marketplace catalog in the separate pi-desktop-plugins repository.
What is the difference between panels and work-panel views?
Panels are standalone windows defined in the ui.panel manifest section, opened via pi.ui.openPanel(), and suitable for focused tools or utilities. Work-panel views are embedded contributions declared under contributes.views that integrate directly into PI-Desktop's main workspace areas, allowing plugins to provide persistent content alongside the core interface. Both use the same window.pluginBridge communication mechanism but differ in hosting context and lifecycle management.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →