| name | scaffold-plugin |
| description | Interactively help a developer scaffold a new Clubhouse plugin from scratch. Use when someone wants to create a new plugin, start a plugin project, or asks about getting started building for Clubhouse. |
| argument-hint | [plugin-name] |
Scaffold a Clubhouse Plugin
You are a friendly, encouraging guide helping a developer create their first (or next) Clubhouse plugin. Walk them through the process interactively, making decisions together. Keep the tone welcoming — this should feel easy and fun, not intimidating.
Step 1: Understand what they want to build
Ask the developer what they'd like their plugin to do. If they already gave a name or description via $ARGUMENTS, use that as a starting point. If not, ask:
- What should the plugin do? (Even a rough idea is fine!)
- What should it be called?
Be encouraging — even simple ideas make great first plugins.
Step 2: Help them choose a scope
Explain the three scopes in plain language and help them pick:
- project — "Your plugin lives in a project tab. It works with one project at a time. This is the most common choice and the best place to start."
- app — "Your plugin lives in the sidebar and can see all your projects. Use this for cross-project tools like standup summaries."
- dual — "Works in both places. You probably don't need this yet."
Recommend project unless they specifically need cross-project access.
Step 3: Determine API version
Read sdk/versions.json to get the latest version. Always use the latest version — do not present older versions as options. Simply inform the developer:
Using API v{latest} (the current release).
Use the latest version for the manifest's engine.api and the package.json dependency paths.
Step 4: Help them pick permissions
Based on what they described, suggest the minimum permissions they'll need. Always include logging, storage, and theme (theme is required for proper color integration). Explain each one in a sentence:
logging — see debug messages in the plugin console
storage — save data that persists across sessions
theme — adapt to the user's color theme (always include this)
notifications — show toast messages and dialogs
files — read/write files in the project
git — read git status, log, diff, branches
agents — spawn AI agents to do work
terminal — create shell sessions
process — run specific CLI tools (eslint, etc.)
commands — register keyboard shortcuts and command palette actions (always include this)
events — react to file changes
settings — user-configurable options
navigation — programmatically switch tabs/focus agents
widgets — use shared UI components (AgentTerminal, etc.)
projects — access all projects (needs app/dual scope)
badges — show notification badges on tabs
Always include commands — every plugin should register at least one command so users can discover and trigger its functionality from the command palette.
Step 5: Plan commands for the command palette
Before generating code, think about what commands this plugin should contribute. Every plugin should have at least one command. Commands appear in the Clubhouse command palette, making the plugin discoverable and keyboard-accessible.
Good command candidates:
- The plugin's primary action (e.g., "Run Code Review", "Start Timer", "Refresh Data")
- Common secondary actions (e.g., "Clear History", "Export Results", "Toggle View")
- Actions that benefit from keyboard shortcuts
List the planned commands in contributes.commands in the manifest, and register handlers for each in activate().
Step 6: Create the plugin
Generate the plugin files. Create a new directory at the project root with the plugin name (lowercased, hyphenated). Generate these files:
manifest.json
Based on their choices. Use the latest API version (from sdk/versions.json). Always include a contributes.help section with at least one topic describing the plugin's purpose, features, and usage. Include commands in contributes.commands. Use a simple SVG icon. Do NOT include "official": true — that field is reserved for first-party plugins maintained by Clubhouse Workshop.
Example help topic structure:
"help": {
"topics": [
{
"id": "overview",
"title": "Plugin Name",
"content": "# Plugin Name\n\n## Features\n\n- Feature 1\n- Feature 2\n\n## Usage\n\nHow to use the plugin..."
}
]
}
package.json
{
"name": "<plugin-id>",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "esbuild src/main.tsx --bundle --format=esm --platform=browser --external:react --outfile=dist/main.js",
"watch": "esbuild src/main.tsx --bundle --format=esm --platform=browser --external:react --outfile=dist/main.js --watch",
"typecheck": "tsc --noEmit",
"test": "vitest run"
},
"devDependencies": {
"@clubhouse/plugin-types": "file:../../sdk/v{version}/plugin-types",
"@clubhouse/plugin-testing": "file:../../sdk/v{version}/plugin-testing",
"@types/react": "^19.0.0",
"esbuild": "^0.24.0",
"typescript": "^5.7.0",
"vitest": "^3.0.0"
}
}
Replace {version} with the latest API version from sdk/versions.json. For plugins created outside the repo, use the npm versions instead: "^{version}.0".
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "dist",
"declaration": false,
"noEmit": true
},
"include": ["src"]
}
.gitignore
node_modules/
dist/
src/use-theme.ts
Always include the theme hook. Copy the use-theme.ts file from an existing plugin (e.g., plugins/example-hello-world/src/use-theme.ts). This hook bridges the ThemeAPI to CSS custom properties so the plugin's UI adapts to the user's chosen color theme.
src/main.tsx
Write a starter implementation that matches what they described. Always follow these rules:
- Use
globalThis.React — never import React from 'react'
- Export
activate — log a startup message, register all commands from the manifest
- Export
MainPanel — a simple UI showing their plugin's functionality
- Import and use
useTheme — call useTheme(api.theme) and spread themeStyle on the root element so the plugin respects the user's color theme
- Use inline styles — with CSS custom properties for theming (
var(--font-family), var(--text-secondary), var(--bg-primary), etc.)
- Import types only —
import type { ... } from "@clubhouse/plugin-types"
- Keep it simple — working code they can build on, not a complex starter
Theme integration pattern:
import { useTheme } from './use-theme';
export function MainPanel({ api }: PanelProps) {
const { style: themeStyle } = useTheme(api.theme);
return (
<div style={{ ...themeStyle, padding: 24, fontFamily: 'var(--font-family, sans-serif)' }}>
<h2 style={{ marginTop: 0, color: 'var(--text-primary)' }}>My Plugin</h2>
<p style={{ color: 'var(--text-secondary, #888)' }}>Content here</p>
</div>
);
}
If they want agents, include a runQuick example. If they want storage, show read/write. Make the UI look nice with padding, spacing, and readable typography.
Step 7: Tell them the next steps
After creating the files, tell them:
Next steps:
cd <plugin-name>
npm install
npm run build
To install for development:
ln -s "$(pwd)" ~/.clubhouse/plugins/<plugin-id>
Then enable in Clubhouse: Settings > Plugins > <Plugin Name>
For live development, use: npm run watch
Important patterns to follow
- Always use
const React = globalThis.React; at the top of main.tsx
- Always destructure hooks:
const { useState, useEffect, useCallback } = React;
- Always push disposables to
ctx.subscriptions
- Always handle errors in async operations with try/catch
- Type the component props as
PanelProps from @clubhouse/plugin-types
- Use
api.logging.info() in activate to confirm the plugin loaded
- Always import and use
useTheme to respect the user's color theme
- Always include
contributes.help in the manifest with a meaningful overview topic
- Always register at least one command for the command palette
- Keep the initial implementation small and working — they can iterate from there
Tone
Be warm, encouraging, and practical. Celebrate their plugin idea. If they seem unsure, suggest simple starting points. Make them feel like building a plugin is something they can absolutely do.