PlutocracyMercury developer docs

Collection Kit

Mercury's collection grid as a Svelte widget where every visible part and every client-side decision is a slot you can replace.

The Collection Kit is the collection and search page widget Mercury ships in its theme app extension. It renders a complete grid (filters, sort, product cards, campaign tiles, pagination) from the storefront API. When a store needs something different, you don't fork it: you override slots. Every visible part and every client-side decision has a stable name, and an override bundle replaces just the ones you name.

How it fits together

  • The SDK, @mercury/collection-sdk, is the contract: the slot catalog, the models, defineSlot and defineOverrides. Its major version is the compatibility axis.
  • The host is the widget itself (<mercury-kit>), loaded by the theme block. It renders the default slots and calls the storefront API.
  • An override bundle is your code: an ES module that exports defineOverrides({ ui, logic }). Published bundles are hosted on Shopify Files and listed in the store's MERCURY.KIT metafield, which the theme block reads.

Write an override

// src/index.ts
import { defineOverrides } from '@mercury/collection-sdk';
import { defineSlot } from '@mercury/collection-sdk/svelte';
import Price from './Price.svelte';

export default defineOverrides({
  ui: { 'card.price': defineSlot(Price) },
  logic: { 'merch.arrange': ({ items }) => items }, // page-level pin/boost hook
});
<!-- Price.svelte -->
<script lang="ts">
  import type { SvelteSlotProps } from '@mercury/collection-sdk/svelte';
  let { product, ctx }: SvelteSlotProps<'card.price'> = $props();
</script>
<strong>{ctx.utils.formatPrice(product.min_price)}</strong>

Every UI slot gets its own props plus ctx: ctx.state (the grid's reactive state), ctx.actions (toggleFilter, setSort, loadMore, addToCart...), ctx.config, ctx.utils, and ctx.render.slot() to render another slot inside yours. Inside a Svelte slot, <Slot name="card.badge" props={{ product }} /> does the same. Rendering your own slot's name gets the default implementation, like calling super.

The full list is the slot catalog, generated from the SDK.

Overrides may import their own files, svelte, svelte/* and the SDK; anything else is a build error. A bundle carries its own Svelte runtime, so the host's Svelte version never matters.

Build, preview and publish

The Mercury admin has a Collection Kit page: a live preview of the store's collection with a code editor over it. Every edit compiles in the browser and swaps into the preview. Preview on storefront opens the real theme with your draft (?mercury_kit_preview=<key>); Publish makes it live and records a numbered version you can diff, restore, or roll back to.

Coding agents can do the same over MCP. In the editor, Connect an agent creates a kit-scoped token and shows the command:

claude mcp add --transport http mercury-kit https://mercury.plutocracy.io/api/mcp \
  --header "Authorization: Bearer mkt_…"

Start with the kit_overview tool; kit_slots, kit_docs and kit_examples explain the contract, kit_write_file and kit_build edit and preview, and kit_publish ships with a message for the history.

What keeps a published bundle working

A published bundle is frozen for months while the widget and the API move on. Three promises keep it working:

  1. The SDK major. Adding a slot or an optional prop is a minor release; renaming or removing is a new major, and the host keeps accepting the old one until no live version uses it.
  2. The storefront contract, versioned and frozen: the API routes, query parameters and response fields a bundle reads, plus the theme config and the manifest. See contract versions and freezing and the v1 contract.
  3. Rebuilds. Every version keeps its source, so a store can be rebuilt on the latest kit (Rebuild on latest kit) without anyone touching its code.

When an override throws, the slot falls back to the default and reports once; the manifest's flags.strict makes it a visible error instead, for development.