一键导入
add-plugin
Step-by-step workflow for creating a new Baseplate plugin package, including root configuration files, source structure, and platform modules.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Step-by-step workflow for creating a new Baseplate plugin package, including root configuration files, source structure, and platform modules.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Workflow for adding a new UI component to ui-components (with Storybook + optional tests) and optionally to the react-generators template system.
Workflow for modifying generated code in Baseplate, including template extraction, generator updates, and project synchronization.
Systematic approach for upgrading packages in the Baseplate monorepo, ensuring consistency between monorepo dependencies and generated project code.
基于 SOC 职业分类
| name | add-plugin |
| description | Step-by-step workflow for creating a new Baseplate plugin package, including root configuration files, source structure, and platform modules. |
Use this skill when creating a new Baseplate plugin package from scratch.
This skill guides you through creating a new plugin by copying plugin-queue as a template and customizing it. Plugins support two architectures:
cp -r plugins/plugin-queue plugins/plugin-<name>
Edit plugins/plugin-<name>/package.json:
"name" to "@baseplate-dev/plugin-<name>""description""version" to "0.1.0""keywords" to match the new pluginChange the federation name:
federation({
name: 'plugin-<name>', // <-- Update this
filename: 'remoteEntry.js',
...
})
Replace content with appropriate description for the new plugin.
Create a fresh changelog:
# @baseplate-dev/plugin-<name>
Run from the repository root to auto-configure tsconfig.build.json references:
pnpm metadata:sync
This command automatically updates TypeScript project references based on package dependencies.
Update packages/project-builder-common/package.json to include the new plugin:
{
"dependencies": {
"@baseplate-dev/plugin-<name>": "workspace:*"
}
}
STOP HERE and inform the user:
The new plugin directory has been created. Before continuing:
- Run
pnpm installto register the new package in the workspace- Restart your watch process (
pnpm watchor similar) to pick up the new plugin- The pnpm workspace needs to recognize
plugins/plugin-<name>before we can continue- Restart Claude Code plugin (the MCP server needs to be restarted to pick up the new plugin)
Once you've restarted the watch process, let me know and we'll continue with the src/ customization.
Do NOT proceed until user confirms they have restarted the watch process.
Remove the template implementation directories (we'll create fresh ones):
rm -rf plugins/plugin-<name>/src/queue
rm -rf plugins/plugin-<name>/src/pg-boss
rm -rf plugins/plugin-<name>/src/bullmq
rm -rf plugins/plugin-<name>/src/common
mkdir -p plugins/plugin-<name>/src/<plugin-name>/core
mkdir -p plugins/plugin-<name>/src/<plugin-name>/core/schema
mkdir -p plugins/plugin-<name>/src/<plugin-name>/core/components
mkdir -p plugins/plugin-<name>/src/<plugin-name>/core/generators
mkdir -p plugins/plugin-<name>/src/<plugin-name>/static
Update the CSS prefix in plugins/plugin-<name>/src/styles.css:
@layer theme, base, components, utilities;
@import 'tailwindcss/theme.css' layer(theme) prefix(<plugin-name>);
@import 'tailwindcss/utilities.css' layer(utilities) prefix(<plugin-name>);
@import '@baseplate-dev/ui-components/theme.css';
Create exports for your plugin:
export * from './<plugin-name>/index.js';
Create plugins/plugin-<name>/src/<plugin-name>/plugin.json:
{
"name": "<plugin-name>",
"displayName": "<Plugin Display Name>",
"icon": "icon.svg",
"description": "Description of what this plugin does",
"version": "0.1.0",
"moduleDirectories": ["core"]
}
Create or copy an SVG icon to plugins/plugin-<name>/src/<plugin-name>/static/icon.svg
common.ts - Schema registration:
import {
createPluginModule,
pluginConfigSpec,
} from '@baseplate-dev/project-builder-lib';
import { create<PluginName>PluginDefinitionSchema } from './schema/plugin-definition.js';
export default createPluginModule({
name: 'common',
dependencies: {
pluginConfig: pluginConfigSpec,
},
initialize: ({ pluginConfig }, { pluginKey }) => {
pluginConfig.schemas.set(pluginKey, create<PluginName>PluginDefinitionSchema);
},
});
web.ts - UI registration:
import {
createPluginModule,
webConfigSpec,
} from '@baseplate-dev/project-builder-lib';
import { <PluginName>DefinitionEditor } from './components/<plugin-name>-definition-editor.js';
import '../../styles.css';
export default createPluginModule({
name: 'web',
dependencies: {
webConfig: webConfigSpec,
},
initialize: ({ webConfig }, { pluginKey }) => {
webConfig.components.set(pluginKey, <PluginName>DefinitionEditor);
},
});
node.ts - Generator registration:
import {
appCompilerSpec,
backendAppEntryType,
createPluginModule,
pluginAppCompiler,
} from '@baseplate-dev/project-builder-lib';
import { <pluginName>Generator } from './generators/<plugin-name>/<plugin-name>.generator.js';
export default createPluginModule({
name: 'node',
dependencies: {
appCompiler: appCompilerSpec,
},
initialize: ({ appCompiler }, { pluginKey }) => {
appCompiler.compilers.push(
pluginAppCompiler({
pluginKey,
appType: backendAppEntryType,
compile: ({ appCompiler }) => {
appCompiler.addRootChildren({
<pluginName>: <pluginName>Generator({}),
});
},
}),
);
},
});
index.ts - Barrel exports:
export * from './core/index.js';
core/index.ts:
// Re-export schema types
export type * from './schema/plugin-definition.js';
Create plugins/plugin-<name>/src/<plugin-name>/core/schema/plugin-definition.ts:
import { definitionSchema } from '@baseplate-dev/project-builder-lib';
import { z } from 'zod';
export const create<PluginName>PluginDefinitionSchema = definitionSchema(() =>
z.object({
// Add your plugin configuration fields here
// For spec-implementation pattern:
// implementationPluginKey: z.string().min(1, 'Implementation must be selected'),
}),
);
export type <PluginName>PluginDefinition = z.infer<
ReturnType<typeof create<PluginName>PluginDefinitionSchema>
>;
Create plugins/plugin-<name>/src/<plugin-name>/core/components/<plugin-name>-definition-editor.tsx:
import type { WebConfigProps } from '@baseplate-dev/project-builder-lib';
import {
useProjectDefinition,
useResettableForm,
} from '@baseplate-dev/project-builder-lib/web';
import { Button } from '@baseplate-dev/ui-components';
import { zodResolver } from '@hookform/resolvers/zod';
import React from 'react';
import {
create<PluginName>PluginDefinitionSchema,
type <PluginName>PluginDefinition,
} from '../schema/plugin-definition.js';
export function <PluginName>DefinitionEditor({
definition: pluginMetadata,
metadata,
onSave,
}: WebConfigProps): React.ReactElement {
const { saveDefinitionWithFeedback } = useProjectDefinition();
const schema = create<PluginName>PluginDefinitionSchema();
const form = useResettableForm<<PluginName>PluginDefinition>({
resolver: zodResolver(schema),
values: pluginMetadata?.config as <PluginName>PluginDefinition,
});
const onSubmit = form.handleSubmit((data) =>
saveDefinitionWithFeedback(
(draftConfig) => {
// Update plugin config
},
{
successMessage: 'Plugin settings saved!',
onSuccess: () => onSave(),
},
),
);
return (
<form onSubmit={onSubmit} className="<plugin-name>:space-y-4 <plugin-name>:max-w-4xl">
{/* Add form fields here */}
<Button type="submit" disabled={form.formState.isSubmitting}>
Save
</Button>
</form>
);
}
IMPORTANT: All CSS classes must use the <plugin-name>: prefix (e.g., <plugin-name>:flex, <plugin-name>:space-y-4).
Skip this phase for standalone plugins.
mkdir -p plugins/plugin-<name>/src/<implementation-name>/core
mkdir -p plugins/plugin-<name>/src/<implementation-name>/core/schema
mkdir -p plugins/plugin-<name>/src/<implementation-name>/core/components
mkdir -p plugins/plugin-<name>/src/<implementation-name>/core/generators
mkdir -p plugins/plugin-<name>/src/<implementation-name>/static
Create plugins/plugin-<name>/src/<implementation-name>/plugin.json:
{
"name": "<implementation-name>",
"displayName": "<Implementation Display Name>",
"icon": "icon.svg",
"description": "Description of this specific implementation",
"version": "0.1.0",
"moduleDirectories": ["core"],
"managedBy": "@baseplate-dev/plugin-<name>:<plugin-name>"
}
The managedBy field links this implementation to the base plugin.
Follow the same pattern as the base plugin, but with implementation-specific logic.
Add exports for each implementation:
export * from './<plugin-name>/index.js';
export type * from './<implementation-name>/index.js';
pnpm install
cd plugins/plugin-<name>
pnpm build
pnpm typecheck
pnpm lint --fix
plugin.json exists in each plugin directorymoduleDirectories points to valid directories with module filespnpm-workspace.yaml scope (plugins/*)<plugin-name>: prefixstyles.css has the correct prefix configurationvite.config.ts has the correct federation namepnpm typecheck to identify issues.js extensions for ESM compatibilityexport type * for type-only exports