.agents/skills/plate-plugin-creator/SKILL.md
Repo-specific companion to Plate's core plugin APIs.
Before shaping a reusable public API, architecture decision, builder/factory pattern, naming convention, runtime/service boundary, or perf-sensitive public surface, read north-star first. This skill is the execution companion, not the constitutional source of truth.
Use this skill for Plate-specific plugin authorship: semantic ownership, authoring order, type-contract fidelity, and React/Plate wrapper boundaries.
Use docs-plugin for public plugin docs.
Binary contract:
north-star updatednorth-star reaffirmed: <section-name>Owner map:
| Owner | Scope |
|---|---|
north-star | doctrine, API shape, runtime boundaries, perf law |
plate-plugin-creator | plugin mechanics, typing, wrappers, file placement |
Do not restate long-form north-star law, precedence, or anti-pattern prose
here. Keep only the routing gate, short derived checklist, and execution
mechanics.
Derived checklist from north-star:
packages/*/src/lib — semantic base plugins, transforms, parsers, rulespackages/*/src/react — Plate/React wrappers, hooks, node props, componentspackages/core/src/lib/plugin — Slate-first authoring primitivespackages/core/src/react/plugin — Plate wrapper primitivespackages/core/type-tests — plugin contract source of truthsrc/lib.createT* only when explicit
contract control buys something real.toPlatePlugin or toTPlatePlugin instead of re-authoring it in React.packages/utils/src/lib/plate-keys.ts, not random string literals.index.ts / index.tsx barrel files. Treat
them as generated output only.pnpm brl after the file work and before final
verification.pnpm brl produces a broken barrel, fix the barrel generator/config or
file placement. Do not patch the generated index.ts by hand after brl.internal/
directory.internal/ unless the user-facing API genuinely needs the file to
be importable.createSlatePlugin / createTSlatePlugin own semantic base plugins.toPlatePlugin / toTPlatePlugin lift a semantic base into the React/Plate
surface.createPlatePlugin / createTPlatePlugin are for real React/Plate-native
plugins or bundles of existing Plate plugins.editor, plugin, type, api, tf,
getOptions, setOption, and friends. Use them.any in source files. The only acceptable exception is non-type test
code where the looseness is intentional and local to the test.SlateEditor through callbacks, options, or helper signatures
when plugin context already has the editor.KEYS from packages/utils/src/lib/plate-keys.ts for shipped/shared
plugin keys and cross-plugin references. Use editor.getType(KEYS.foo) when
you need the resolved node type.createTSlatePlugin and createTPlatePlugin are explicit-contract tools, not
default ceremony.packages/core/type-tests/* over stale package precedent.extendApi / extendTransforms are plugin-specific surfaces.extendEditorApi / extendEditorTransforms feed the merged editor surface.configurePlugin to override nested child plugins instead of cloning
their config by hand.overrideEditor when the real ownership is editor behavior, not random
event glue.inject.nodeProps.transformProps before inventing wrapper components or
heavier node plumbing. This is especially right when the augmentation needs
hooks.Slate-first, Plate-second.
If a plugin has meaningful document semantics without React, author the base in
packages/*/src/lib first. Add the React/Plate layer only when rendering,
hooks, or Plate-only editor integration is actually needed.
Named exceptions:
useHooks pluginssrc/react just because the consumer eventually uses React.createPlatePlugin just to add a
component or small wrapper config.KEYS already owns that
contract.({ editor }: { editor: SlateEditor }) => ... callback
annotations when inference already knows the editor type.internal/ is enough.transformProps like a universal replacement for
node.component, render, or useHooks. Use it when the real job is prop
augmentation.// Good: semantic base first, thin Plate wrapper second.
export const BaseCommentPlugin = createTSlatePlugin<BaseCommentConfig>({
key: KEYS.comment,
}).extendApi(...);
export const CommentPlugin = toPlatePlugin(BaseCommentPlugin);
// Good: wrapper adds Plate-only child wiring without re-authoring semantics.
export const CodeBlockPlugin = toPlatePlugin(BaseCodeBlockPlugin, {
plugins: [CodeLinePlugin, CodeSyntaxPlugin],
});
// Good: direct Plate plugin when the job is React/editor integration.
export const EventEditorPlugin = createPlatePlugin({
key: 'eventEditor',
handlers: { ... },
});
// Good: bundle existing Plate plugins without fake base-plugin theater.
export const BasicBlocksPlugin = createPlatePlugin({
plugins: [BlockquotePlugin, HeadingPlugin, HorizontalRulePlugin],
});
packages/*/src/lib, packages/*/src/react,
and packages/core/type-tests.