How to create plugins
This guide shows you how to build stagewise plugins that add additional features or enhance framework compatibility.
stagewise plugins let you extend the browser toolbar with custom UI, actions, and context for your AI-powered code workflows. Plugins can provide new buttons, panels, and even custom tools that your AI agent can call via MCP (Multi-Context Protocol).
1. Getting Started
Scaffold a Plugin
The fastest way to start is with our CLI:
npx create-stagewise-plugin
This will generate a new plugin project using our template, including all required configuration and example code.
Project Structure
A typical plugin project looks like this:
my-plugin/
src/
index.tsx # Main plugin entry point
component.tsx # Example UI component
build.config.ts
package.json
tsconfig.json
...
2. Anatomy of a Plugin
A stagewise plugin is an object that implements the ToolbarPlugin
interface from @stagewise/toolbar
. Here's a minimal example:
// src/index.tsx
import type { ToolbarPlugin } from '@stagewise/toolbar';
import { ExampleComponent } from './component';
const ExamplePlugin: ToolbarPlugin = {
displayName: 'Example',
description: 'Example Plugin',
iconSvg: null, // You can provide a VNode for a custom SVG icon
pluginName: 'example',
onActionClick: () => <ExampleComponent />,
};
// It's super important to default-export the plugin!
export default ExamplePlugin;
Key Fields
displayName
: Shown to users in the toolbarpluginName
: Internal unique namedescription
: Short summaryiconSvg
: (optional) Monochrome SVG icon as a Preact VNodeonActionClick
: (optional) Returns a VNode to render when the plugin is activated
See the full interface in the codebase for advanced hooks and MCP integration.
3. Building Plugin UI with @stagewise/plugin-sdk
stagewise provides a set of UI primitives for building plugin panels:
Available Components
Panel
: Card-like container with optionalHeader
,Content
, andFooter
Button
: Styled button with variantsBadge
: Colored label for status/info
Example Usage
// src/component.tsx
import { Panel, PanelHeader, PanelContent, Button, useToolbar } from '@stagewise/plugin-sdk';
export const ExampleComponent = () => {
const toolbar = useToolbar();
return (
<Panel>
<PanelHeader title="Example Plugin" />
<PanelContent>
<Button onClick={() => toolbar.sendPrompt('Hello world!')}>
Send "Hello world!" to Cursor!
</Button>
</PanelContent>
</Panel>
);
};
The useToolbar
Hook
This hook gives you access to the toolbar context, including the sendPrompt
method to send messages to your AI agent or the window object of the main web app.
4. Advanced Plugin Features
Context Snippets & Annotations
Plugins can provide extra context for prompts or annotate selected elements. Implement these hooks in your plugin:
onPromptSend
: Add context before a prompt is sentonContextElementSelect
: Annotate selected DOM elements
MCP Integration
Expose custom tools, resources, or prompts to your AI agent by implementing the mcp
property. See the ToolbarPlugin
interface for details.
5. Development & Build
- Use
pnpm dev
to start development - Use
pnpm build
to produce a distributable package
There are two main approaches to test your plugin during development, depending on your project structure:
Option A: Using workspace:* in a Monorepo
If your plugin is part of a monorepo setup, the simplest approach is to use workspace dependencies:
- In your test project's
package.json
, add your plugin as a workspace dependency:
{
"dependencies": {
"@stagewise/plugin-example": "workspace:*"
}
}
- Run
pnpm install
to set up the workspace dependency
This approach automatically makes your plugin available to other packages in your workspace, and changes will be reflected immediately after rebuilding the plugin.
Option B: Using Local NPM Linking with pnpm
If you're developing your plugin outside of a monorepo, you can use pnpm's linking feature to test it locally:
Step-by-step: Local Linking with pnpm
- Build your plugin (from the plugin directory):
pnpm build
- Link your plugin locally:
pnpm link --global
- Link the plugin in your example project:
Navigate to your example app (e.g.,
examples/next-example/
):
pnpm link --global @stagewise/plugin-example
-
Use your plugin in the example app: Import and add your plugin to the toolbar config as you would with a published package.
-
Develop and test:
- Changes to your plugin source will be reflected after you rebuild (
pnpm build
) in the plugin directory - Restart your example app's dev server if needed
Tip: When you're done with local linking, you can unlink with
pnpm unlink --global @stagewise/plugin-example
in your example app andpnpm unlink --global
in your plugin directory.
Once your plugin is ready, you can publish it to npm or continue using it locally with either of the above approaches.
6. Full Example
The plugin:
// src/index.tsx
import type { ToolbarPlugin } from '@stagewise/plugin-sdk';
import { ExampleComponent } from './component';
const ExamplePlugin: ToolbarPlugin = {
displayName: 'Example',
description: 'Example Plugin',
iconSvg: null,
pluginName: 'example',
onActionClick: () => <ExampleComponent />,
};
export default ExamplePlugin;
// src/component.tsx
import { Panel, PanelHeader, PanelContent, Button, useToolbar } from '@stagewise/plugin-sdk';
export const ExampleComponent = () => {
const toolbar = useToolbar();
return (
<Panel>
<PanelHeader title="Example Plugin" />
<PanelContent>
<Button onClick={() => toolbar.sendPrompt('Hello world!')}>
Send "Hello world!" to Cursor!
</Button>
</PanelContent>
</Panel>
);
};
To test and integrate your plugin into stagewise, add it as a plugin with a path-location.
For more advanced examples and API details, see the stagewise repository and the ToolbarPlugin interface.