Logostagewise

Plugins

stagewise Plugins

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
  package.json
  vite.config.ts
  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';
 
export const ExamplePlugin: ToolbarPlugin = {
  displayName: 'Example',
  description: 'Example Plugin',
  iconSvg: null, // You can provide a VNode for a custom SVG icon
  pluginName: 'example',
  onActionClick: () => <ExampleComponent />,
};

Key Fields

  • displayName: Shown to users in the toolbar
  • pluginName: Internal unique name
  • description: Short summary
  • iconSvg: (optional) Monochrome SVG icon as a Preact VNode
  • onActionClick: (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 @plugin-ui

stagewise provides a set of UI primitives for building plugin panels:

Available Components

  • Panel: Card-like container with optional Header, Content, and Footer
  • Button: Styled button with variants
  • Badge: Colored label for status/info

Example Usage

// src/component.tsx
import { Panel, Button, useToolbar } from '@stagewise/toolbar/plugin-ui';
 
export const ExampleComponent = () => {
  const toolbar = useToolbar();
 
  return (
    <Panel>
      <Panel.Header title="Example Plugin" />
      <Panel.Content>
        <Button onClick={() => toolbar.sendPrompt('Hello world!')}>
          Send "Hello world!" to Cursor!
        </Button>
      </Panel.Content>
    </Panel>
  );
};

The useToolbar Hook

This hook gives you access to the toolbar context, including the sendPrompt method to send messages to your AI agent.

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 sent
  • onContextElementSelect: 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:

  1. In your test project's package.json, add your plugin as a workspace dependency:
{
  "dependencies": {
    "@stagewise/plugin-example": "workspace:*"
  }
}
  1. 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

  1. Build your plugin (from the plugin directory):
pnpm build
  1. Link your plugin locally:
pnpm link --global
  1. Link the plugin in your example project: Navigate to your example app (e.g., examples/next-example/):
pnpm link --global @stagewise/plugin-example
  1. Use your plugin in the example app: Import and add your plugin to the toolbar config as you would with a published package.

  2. 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 and pnpm 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/toolbar';
import { ExampleComponent } from './component';
 
export const ExamplePlugin: ToolbarPlugin = {
  displayName: 'Example',
  description: 'Example Plugin',
  iconSvg: null,
  pluginName: 'example',
  onActionClick: () => <ExampleComponent />,
};
 
// src/component.tsx
import { Panel, Button, useToolbar } from '@stagewise/toolbar/plugin-ui';
 
export const ExampleComponent = () => {
  const toolbar = useToolbar();
  return (
    <Panel>
      <Panel.Header title="Example Plugin" />
      <Panel.Content>
        <Button onClick={() => toolbar.sendPrompt('Hello world!')}>
          Send "Hello world!" to Cursor!
        </Button>
      </Panel.Content>
    </Panel>
  );
};

Using the plugin in your next-app:

// app/layout.tsx
import type { Metadata } from 'next';
import { StagewiseToolbar } from '@stagewise/toolbar-next';
import { ExamplePlugin } from '@stagewise/plugin-example'; // <-- replace this with your plugin-name
 
export const metadata: Metadata = {
  title: 'My Next.js App',
  description: 'An app using stagewise plugins',
};
 
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
        <StagewiseToolbar config={{ plugins: [ExamplePlugin] }} />
        {children}
      </body>
    </html>
  );
}

For more advanced examples and API details, see the stagewise repository and the ToolbarPlugin interface.