Skip to content

spec: marketplace asset types and YAML schemas #25

@andrewchumchal

Description

@andrewchumchal

Overview

This issue defines the canonical schema for every asset type in the OpenConduit marketplace registry (OpenConduit/marketplace). It serves as the implementation reference for the registryStore, marketplace UI components, and the CI build pipeline.

Each asset lives as a single .yaml file in registry/<type>/. A CI step compiles all files in a folder into a flat index.json served at registry.openconduit.ai/v1/<type>/index.json.


Shared fields (all asset types)

Every entry must include these top-level fields:

Field Type Description
id string Unique kebab-case identifier. Must be stable — used as a key in local stores.
name string Display name shown in the marketplace card.
type string Asset type discriminator (see per-type values below).
author string GitHub handle of the author. openconduit for official entries.
verified boolean Set to true by maintainers after review. Community submissions use false.
description string One-line description shown in the marketplace card.
content object Type-specific payload (see per-type schemas below).

Asset types

1. Persona — type: persona

Stored in registry/personas/.
Installed into personasStore via addPersona(content).

id: code-reviewer
name: Code Reviewer
type: persona
author: openconduit
verified: true
description: Senior engineer reviewing code for correctness, security, and style.
content:
  name: Code Reviewer        # string — display name (can differ from top-level name)
  color: "#6366f1"           # string — hex colour for the avatar dot
  systemPrompt: |            # string — injected as the system message
    You are a senior software engineer...

TypeScript type (content):

interface PersonaContent {
  name: string;
  color: string;
  systemPrompt: string;
}

Install behaviour: calls usePersonasStore().addPersona(entry.content) — assigns a new UUID unless the entry id matches an existing starter-* ID (those use fixed IDs to prevent duplicates).


2. Prompt Template — type: prompt-template

Stored in registry/prompts/.
Installed into templatesStore (new store, see #21).

id: blog-post-draft
name: Blog Post Draft
type: prompt-template
author: openconduit
verified: true
description: Draft a blog post from a topic and key points.
content:
  template: |                # string — prompt body with {{variable}} placeholders
    Write a blog post about {{topic}}.

    Key points: {{key_points}}
    Tone: {{tone}}.
    Length: {{word_count}} words.
  variables:                 # array — defines the fill-in form
    - name: topic            # string — matches {{placeholder}} in template
      label: Topic           # string — form field label
      type: text             # enum: text | textarea | select | number
    - name: key_points
      label: Key Points
      type: textarea
    - name: tone
      label: Tone
      type: select
      options: [professional, casual, technical]   # required when type is select
    - name: word_count
      label: Word Count
      type: number
      default: 800           # optional — pre-filled value

TypeScript types (content):

type VariableType = 'text' | 'textarea' | 'select' | 'number';

interface TemplateVariable {
  name: string;
  label: string;
  type: VariableType;
  options?: string[];   // required when type === 'select'
  default?: string | number;
}

interface PromptTemplateContent {
  template: string;
  variables: TemplateVariable[];
}

Render behaviour: replace all {{name}} occurrences with the filled-in values, then insert the rendered string into InputBar.


3. Routing Profile — type: routing-profile

Stored in registry/profiles/.
Installed into settingsStore routing config.

id: cost-optimised
name: Cost Optimised
type: routing-profile
author: openconduit
verified: true
description: Routes simple tasks to cheap models, complex reasoning to premium.
content:
  tiers:                     # object — model IDs per tier
    fast: gpt-4o-mini        # string — model ID for fast/simple tasks
    balanced: gpt-4o         # string — model ID for balanced tasks
    powerful: claude-opus-4-5  # string — model ID for complex tasks
  taskOverrides:             # object — optional per-task tier overrides
    code: balanced           # task key → tier name
    research: powerful
    summary: fast

TypeScript types (content):

type RoutingTier = 'fast' | 'balanced' | 'powerful';
type TaskKey = 'code' | 'research' | 'summary' | 'chat' | 'creative' | string;

interface RoutingProfileContent {
  tiers: Record<RoutingTier, string>;        // tier → model ID
  taskOverrides: Partial<Record<TaskKey, RoutingTier>>;
}

Install behaviour: saves the profile to settingsStore.routingProfiles[]; user selects the active profile separately.


4. Theme — type: theme

Stored in registry/themes/.
Installed into themesStore (new store, see #22).

id: midnight-navy
name: Midnight Navy
type: theme
author: openconduit
verified: true
description: Deep navy dark theme with cyan accents.
content:
  colors:                            # object — CSS variable overrides
    --color-primary: "#22d3ee"       # accent / interactive colour
    --color-surface: "#0f1729"       # card / panel background
    --color-background: "#0a1120"    # app background
    --color-muted: "#1e2d45"         # subtle backgrounds / dividers
    --color-text: "#e2e8f0"          # primary text
    --color-border: "#1e3a5f"        # borders and outlines

Required CSS variables (all must be present):

Variable Purpose
--color-primary Accent, buttons, active states
--color-surface Cards, panels, sidebar background
--color-background App background
--color-muted Subtle fills, dividers, hover states
--color-text Primary text
--color-border Borders and outlines

TypeScript types (content):

interface ThemeContent {
  colors: {
    '--color-primary': string;
    '--color-surface': string;
    '--color-background': string;
    '--color-muted': string;
    '--color-text': string;
    '--color-border': string;
    [key: string]: string;  // allow additional variables
  };
}

Apply behaviour: Object.entries(content.colors).forEach(([k, v]) => document.documentElement.style.setProperty(k, v)) — no rebuild required.


5. Provider — type: provider

Stored in registry/providers/.
Integrated with the existing provider marketplace (currently uses provider-registry.json in core).

Schema TBD — will be migrated from the existing in-app registry format when the hosted registry ships (#23).


6. MCP Server — type: mcp

Stored in registry/mcp/.
Integrated with the existing MCP marketplace (currently uses mcp-registry.json in core).

Schema TBD — will be migrated from the existing in-app registry format when the hosted registry ships (#23).


RegistryEntry union type

type RegistryEntry =
  | { type: 'persona';          content: PersonaContent }          & SharedFields
  | { type: 'prompt-template';  content: PromptTemplateContent }   & SharedFields
  | { type: 'routing-profile';  content: RoutingProfileContent }   & SharedFields
  | { type: 'theme';            content: ThemeContent }            & SharedFields
  | { type: 'provider';         content: unknown }                 & SharedFields
  | { type: 'mcp';              content: unknown }                 & SharedFields;

interface SharedFields {
  id: string;
  name: string;
  author: string;
  verified: boolean;
  description: string;
}

CI schema validation

A GitHub Actions workflow in OpenConduit/marketplace should validate each .yaml file on PRs:

  • All shared fields present and correctly typed
  • type matches the folder it's in
  • content matches the schema for the declared type
  • id is kebab-case and unique within the folder
  • color fields (personas, themes) are valid hex strings

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions