Skip to main content

Marketplace V2 — find sections by intent

The classic content_list_marketplace_components filters by category (hero, features, pricing, …). Marketplace V2 turns the same catalog into something an agent searches by what they actually want — "calm cinematic for a luxury hotel," "energetic conversion-focused for ecommerce" — across all three marketplace tables (bg-videos / components / site-templates) in one query.

Live since 2026-05-05. Available in @spideriq/cli@1.5.0+, @spideriq/mcp-publish@1.5.0+, and the public Starter Kit.

Why this exists

Categories tell you the shape ("it's a hero"); they don't tell you whether the hero matches a luxury hotel brief or a fintech dashboard brief. Four universal axes do:

AxisVocabulary (subset)What it picks
moodcalm, energetic, bold, dreamy, futuristic, urban, minimal, warm, editorial, professional, friendly, clear, technical, credibleThe emotional register
palettemonochrome, deep-blue, cream, neutral-warm, nature-green, neon-accent, cinematicThe visual signature
brand_fit_tagssaas, agency, ecommerce, fintech, hospitality, restaurant, wellness, blog, publication, real-estateThe industry vertical
scene_typehero-bold, conversion-cta, social-proof (components); city-aerial, nature-landscape (bg-videos); marketing-site, docs-site (site-templates)The semantic shape

marketplace_search matches any-of within an axis ("mood includes calm OR editorial") and and-of across axes ("calm-mood AND saas-brand-fit"). For tighter narrowing, pass single values per axis.

Quick start — find a calm bg-video, insert it as hero

# 1. Search
spideriq marketplace search --mood calm --asset-types bg_video --limit 5
# → results: [{
# slug: "alpine-wildflowers",
# asset_type: "bg_video",
# video_url: "https://media.cdn.spideriq.ai/bg-videos/alpine-wildflowers.mp4",
# mood: ["calm","dreamy"],
# scene_type: "nature-landscape",
# ...
# }, ...]

# 2. Insert as the first block on the homepage
spideriq content insert-section \
--page-id <homepage-uuid> \
--component-slug sys-bg-video \
--props '{"video_slug": "alpine-wildflowers"}' \
--position start \
--confirm

Same flow via MCP (marketplace_searchcontent_insert_section) — see the Starter Kit recipe for the full preview-token + confirm dance.

The 6 Marketplace V2 tools

Available in CLI (spideriq marketplace …), MCP (@spideriq/mcp-publish), opvsHUB skill (content-platform v1.6.0+), and the public Starter Kit.

ToolAuthUse case
marketplace_searchpublicCross-table discovery by mood / palette / brand_fit / scene_type / agent_meta / asset_types
list_data_sourcespublicDiscover internal source IDs for binding kind="dynamic" blocks (posts, authors, IDAP×4, idap.lead)
set_component_kindgatedPromote a custom component into the 4-class taxonomy (static / interactive / dynamic / extension)
set_component_agent_metagatedCurate axes + ComponentAgentMeta on a component so other agents can find it
set_bg_video_agent_metasuper_admin, gatedCurate bg-video discoverability (pace, time_of_day, weather, aspect_ratio, …)
set_site_template_agent_metasuper_admin, gatedCurate site-template discoverability (page_count, has_blog, style_aesthetic, …)

All four destructive set_* tools default dry_run=true — first call returns a preview envelope with confirm_token; second call (same args + confirm_token) actually mutates. See Deploy safely for the broader two-step flow.

The 4-class component taxonomy

marketplace_search filters across three asset tables, but components themselves split into four behavioural classes:

KindProps?Reads data?Renders where?Needs secrets?Examples
staticcomponent HTMLnohero-headline, faq-accordion, pricing-3tier (44 existing)
interactivecomponent HTML + JSnosys-timer-fixed-date, sys-popup-exit-intent, sys-bar-promo
dynamiccomponent HTML + fetchnoList of posts, Item Details for IDAP business, sys-proof-recent-purchase
extensionrenderer / worker / hookYESsys-tracking-fb-capi, sys-geo-md-mirror, sys-geo-mcp-server

Use set_component_kind to promote a custom component into the taxonomy. The kind drives the renderer (whether to fetch data, whether to ship JS, whether to require a worker route).

Per-asset agent_meta

Beyond the 4 universal axes, each table has its own JSONB agent_meta with extra filters:

# Calm bg-video, slow pace, night scene, no people
spideriq marketplace search \
--mood calm \
--asset-types bg_video \
--agent-meta '{"pace": "slow", "time_of_day": "night", "has_people": false}'

The full vocabulary lives in template_get_help (or GET /content/help) — search for BgVideoAgentMeta / ComponentAgentMeta / SiteTemplateAgentMeta.

BgVideoAgentMeta keys (subset)

pace, time_of_day, weather, has_people, aspect_ratio, has_audio, music_tempo_bpm, transcript

ComponentAgentMeta keys (subset)

interaction_pattern, trigger_kind, placement, motion_safety, accessibility_notes, conversion_strategy

SiteTemplateAgentMeta keys (subset)

page_count, has_blog, has_pricing, has_directory, has_booking, conversion_strategy, style_aesthetic, component_set

Anti-patterns

  • Don't bind idap.lead to a List block — it's a singleton (is_collection=false); only Item Details accepts it.
  • Don't pass mood as a comma-string in the JSON body — it's string[]. The CLI accepts --mood calm,editorial, the API expects ["calm","editorial"].
  • agent_meta is extra="forbid" — typos return 422. Use template_get_help if a key isn't in the table above.
  • Universal axes are NOT inside agent_metamood / palette / brand_fit_tags / scene_type are sibling top-level fields. Putting them inside agent_meta silently no-ops.

Internal data sources (for kind=dynamic components)

The 9 sources currently exposed via list_data_sources:

Source IDShapeNotes
postscollectionBlog posts (status=published, ordered by published_at desc)
authorscollectionAuthor profiles (active=true)
categoriescollectionBlog categories (hierarchical)
tagscollectionTags with post counts
idap.countriescollectionIDAP geo — countries
idap.citiescollectionIDAP geo — cities (parent: countries)
idap.streetscollectionIDAP geo — streets (parent: cities)
idap.businessescollectionIDAP geo — businesses (parent: streets)
idap.leadsingletonPer-request lead (request-scoped, not a collection)

Bind a List or Item Details component to any of these via block.data_binding:

{
"type": "component",
"component_slug": "list",
"layout": "stacked",
"data_binding": {
"source_id": "posts",
"filter": { "category": "tutorials" },
"sort": "-published_at",
"limit": 10,
"field_select": ["title", "excerpt", "cover_image"]
}
}

External connectors (Airtable, Postgres, custom URLs) plug into the same content_data_sources registry shape — deferred to a future initiative.

Coverage caveat

The seed migration (178) backfilled best-guess universal-axis defaults from the legacy marketplace_category field. agent_meta (the per-type keys above) is sparse on existing assets as of 2026-05-05. Search recall today is bounded by what's in the DB.

A "Fill the Bank" initiative is in flight to populate agent_meta on every existing asset via SpiderGate-powered inference + a Suggest agent_meta button in the dashboard editors + a CLI/MCP marketplace_suggest_agent_meta tool. Until that ships, narrow your search to universal axes for best results, and ask template_get_help to see which agent_meta keys are populated for the asset type you're searching.

See also

  • Starter Kit recipe — runnable end-to-end with auth + page lookup
  • agents.mdx — full agent integration guide (@spideriq/cli, @spideriq/mcp-publish)
  • deploy-safely.mdx — preview → confirm pattern that gates every destructive set_* tool
  • sessions.mdx — Phase 11+12 multi-tenant session binding
  • template_get_help (or GET /api/v1/content/help?format=yaml) — canonical vocabulary reference