Skip to content

Manifest contract

Every plugin repository must include shop-plugin.json at its root. The file is validated before install and runtime activation.

{
"schemaVersion": 1,
"id": "com.example.loyalty",
"name": "Loyalty Points",
"version": "1.0.0",
"shopCompatibility": ">=0.1.0",
"serverEntry": "dist/server/index.mjs",
"webEntry": "dist/web/index.mjs",
"permissions": ["storefront:extend", "mcp:extend", "events:subscribe", "users:read"],
"contributes": {
"storefrontSlots": [
{
"slot": "product.detail.after-price",
"module": "dist/web/product-badge.mjs",
"exportName": "ProductLoyaltyBadge"
}
],
"pages": [
{
"path": "/plugins/com.example.loyalty",
"module": "dist/web/loyalty-page.mjs",
"exportName": "LoyaltyPage",
"title": "Loyalty"
}
],
"events": ["orders.paid"],
"mcpTools": [
{
"name": "loyalty.points_preview",
"title": "Preview loyalty points",
"description": "Estimate loyalty points for a purchase amount.",
"permission": "users:read"
}
]
}
}
  • id should be reverse-DNS style and stable.
  • shopCompatibility declares the core version range.
  • Entry paths must be relative and stay inside the plugin package.
  • Runtime registration must match declared contributions exactly.
  • Plugin pages must live under /plugins/:pluginId.
  • MCP tool names should use a plugin namespace.
  • Event handlers must be idempotent.
  • Plugin SQL tables must use the guarded plugin table prefix.

Production installs should pin:

  • expectedCommitSha
  • expectedManifestSha256
  • requireSignedCommit

Unpinned server plugins are rejected in production unless the operator explicitly overrides that policy.