Plugin code: patch in place; scaffold only when requested or absent. A project's plugin installation is CMA data, not plugin code — install, enable/disable, switch marketplace package ↔ private URL or version, edit global parameters → datocms-cma plugin operations. Local testing without touching the working installation: development copy.
Workflow
- Inspect silently:
package.json, package manager, scripts, plugin metadata, and installed SDK/UI versions- top-level
connect()call, usuallysrc/main.tsxorsrc/index.tsx - touched hook pair, render component, helper, CSS file, and current UI pattern
- plugin-local
AGENTS.mdif present
- Classify the request:
- Existing plugin: package already exists and user asks to patch, add, maintain, fix, release-prep, or restyle. Default here.
- New plugin: user asks to create/scaffold/bootstrap a plugin folder, or no plugin project exists.
- Design pass: request mentions styling, layout, density, spacing, theme, dark mode, Canvas tokens, legacy CSS variables, hardcoded colors, forms, tables, panels, controls, or matching DatoCMS UI patterns.
- Mixed: combine hook/scaffold work with design changes in one pass.
- Ask only when inspection cannot resolve a behavior-changing choice:
- plugin/folder name for a new scaffold
- private vs marketplace plugin when package metadata changes
- target model/field/surface when several are plausible
- whether a new permission or dependency is allowed
- whether direct browser CMA calls are required instead of SDK helpers
- Load references after file inspection. Use the reference for the touched surface; do not load the full bundle.
- Patch in place:
- keep the existing file layout, package manager, scripts, naming, and UI structure
- update paired hooks together: declaration + render, trigger + modal, dropdown declaration + execute handler
- update permissions and package metadata in the same patch when the code path needs them
- add dependencies only when the implementation imports them
- Verify with the plugin's existing command. Prefer the build script; add typecheck, lint, or tests only when the project already defines them and they cover the change.
- Report the patch, command result, and remaining DatoCMS check: config save, field render, modal resolve, asset select, permission branch, page navigation, or resize behavior.
Reference map
Common
| Need | Load |
|---|---|
| Follow-up maintenance shortcuts | references/rapid-patterns.md |
Exact connect(), hook pairs, render helper, Canvas, frame sizing |
references/sdk-connect-and-frames.md |
Base ctx, entity repos, form values, browser CMA, endpoints, async errors |
references/sdk-context-and-cma.md |
| Target code has no clear precedent | references/current-plugin-patterns.md |
| Plugin permission changes | references/permissions.md |
| Localized values, field paths, Structured Text Slate form values | references/form-values.md |
New plugin
| Need | Load |
|---|---|
| Project files and package baseline | references/project-scaffold.md |
| First hook pair selection | references/surface-starters.md |
Surfaces
| Surface | Load |
|---|---|
| Config screen | references/config-screen.md |
| Field extension | references/field-extensions.md |
| Sidebar panel or full record sidebar | references/sidebar-panels.md |
| Custom page | references/custom-pages.md |
| Dropdown action | references/dropdown-actions.md |
| Lifecycle hook | references/lifecycle-hooks.md |
| Modal | references/modals.md |
| Outlet | references/outlets.md |
| Inspector | references/inspectors.md |
| Asset source | references/asset-sources.md |
| Upload sidebar or upload panel | references/upload-sidebars.md |
| Structured Text customization | references/structured-text.md |
| Record presentation or picker query | references/record-presentation.md |
Design
| Need | Load |
|---|---|
| Dark-mode-only migration | references/dark-mode-upgrade.md |
| First design pass | references/design-foundations.md + references/design-datocms-react-ui-bridge.md |
| Token/variable lookup | references/design-tokens.md |
| Layouts, pages, split views, toolbars | references/design-layouts.md |
| Forms, controls, settings | references/design-forms-and-controls.md |
| Dropdowns, tabs, tables, lists, notices | references/design-navigation-feedback-and-data-display.md |
| Surface shell rules | references/design-plugin-surfaces.md |
| Raw CSS fallback snippets | references/design-raw-css-fallbacks.md |
For design work, prefer public datocms-react-ui components when they match the required shape. Fall back to local React/CSS only when public components do not express the layout cleanly. Use Canvas tokens and variables directly; customize beyond them only for explicit product styling, vendor widgets, media treatments, data visualization, or effects they cannot express.
Guardrails
- Keep exactly one top-level
connect()call. - Inspect existing
connect()before adding hooks. - Import
datocms-react-ui/styles.cssonce in the plugin entry file; keepsrc/vite-env.d.ts(/// <reference types="vite/client" />) or TS rejects it. - Wrap every rendered surface in
<Canvas ctx={ctx}>. - Use
<Canvas ctx={ctx} noAutoResizer>for pages, inspectors, and full-width sidebars. - Use
switchfor ID-dispatched render hooks. - Use
import type { ... }for SDK types. - Guard
ctx.itembefore reading saved-record data. - Use
get(ctx.formValues, ctx.fieldPath)in field extensions; use localized-value helpers elsewhere. - Use deep-compare effects when depending on
ctxobject properties. - Keep
ctx.openModal()parameters andctx.resolve()values JSON-serializable. - Normalize stored plugin parameters at read/save boundaries.
- Use
ctx.setParameters()directly inrenderManualFieldExtensionConfigScreen. - Modular Content is
rich_textinFieldTypeand APIfield_type. Do not create editor field extensions for Modular Content, single block, or Structured Text fields; use addons (Modular Content:fieldTypes: ['rich_text']; single block has noFieldType:overrideFieldExtensions, orfieldTypes: 'all'if every field type may offer it). - Prefer SDK helpers before browser CMA calls. If browser CMA is required, use
@datocms/cma-client-browser, add only required permissions, and guard missingctx.currentUserAccessToken. - Keep modals, sidebars, and config screens compact.
Routing
-
DAST analysis, validation, or transforms → datocms-structured-text: document model, editing, or conversion. Keep Slate form values and editor hooks here; never pass DAST to
ctx.setFieldValue. Load the specialist only for DAST work. Missing sibling reference → install that skill fromdatocms/agent-skillsor update the full bundle. -
Website preview, Content Link, draft mode, cache tags, frontend rendering, or framework wiring ->
datocms-frontend-integrations; guided multi-part website setup ->datocms-setup. -
Content modeling decisions ->
datocms-content-modeling. -
Content delivery GraphQL query work ->
datocms-cda.