Skip to content
OpenSmartRoute
Documentation
Hosted platform

Marketplace

Find, install, buy and publish agents, skills, personas, prompts and stack templates; ratings and the review lifecycle.

Hosted platform 17 min read

The marketplace is the part of the hosted platform where routing building blocks are shared: agents, skills, personas, prompts, tools, model profiles and stack templates, with versions, ratings and a short review lifecycle. Every listing is a plain YAML or JSON document that the OpenSmartRoute SDK, CLI and hosted API understand, so what you install is what you run; there is no marketplace-only format.

Browsing, installing, rating and publishing prompts and personas work from the website without writing code. Templates, skills and agents come with copy-paste snippets for the CLI and the SDK.

What is on it

KindWhat it isManifest
Template (stack)A complete routing setup - models, rules, weights - in one file. Apply it and you have a working router.kind: stack document (opensmartroute.stack)
AgentA multi-step worker the router can hand a whole task to.Open Capability Manifest (spec)
SkillAn Agent-Skills package (SKILL.md) that is also a routable target.OCM, generated from the SKILL.md
PersonaA system prompt with a voice, a domain and a complexity band.OCM with kind: persona
ToolA function or MCP tool with typed parameters.OCM with kind: tool
Model profile (llm)A model with cost, latency, context window and quality prior.OCM with kind: llm
PromptA reusable prompt with {{variables}}.{"prompt": "...", "variables": [...]}

Every listing has a slug (its address, /marketplace/<slug>), a version (1.2.3), a publisher, a licence, tags, a Markdown description, an install count and a star rating.

Finding and installing

  1. Open Marketplace in the top navigation. Filter by kind, tag, price or search; sort by popular, top rated, newest or name.
  2. Open a listing. The About tab is the publisher's description; Use it shows ready-made snippets (CLI, Python, HTTP); Manifest is the raw document; Reviews lists ratings.
  3. Click Install (free) or Buy (paid). You need an account - signing up is free. Free installs complete at once; paid ones go through the checkout and are recorded on your account when the payment completes.
  4. Everything you installed is listed under Dashboard -> Marketplace -> Installed by you, together with the version you installed and whether a newer one exists.

Installing records the listing on your account and returns the manifest and snippets. Nothing is executed on your behalf.

Using an installed template

osr stack apply registry://support-desk@1.0.0                      # build and summarise (hosted marketplace)
osr stack apply registry://support-desk --route "Refund for order 42?"
osr stack apply registry://support-desk --out stack.yaml             # flatten & keep
osr stack apply registry://support-desk --registry https://<platform>  # a self-hosted marketplace

registry:// references resolve against the marketplace the CLI is configured for (OSR_MARKETPLACE_URL, by default the hosted platform); --registry points one command at another deployment.

Or reference it from your own stack and let imports do the work:

osr: "1"
kind: stack
name: my-desk
imports:
  - registry://support-desk@1.0.0
targets:
  - id: llm-onprem
    kind: llm

osr stack validate my-desk.yaml, osr stack plan my-desk.yaml --against deployed.yaml and osr stack apply my-desk.yaml are the Terraform-style verbs: check, diff, apply.

Using an installed agent, skill, persona, tool or model

On the hosted platform nothing more is needed. Installing an agent, skill, persona, tool, subagent or command puts it into your workspace's routing pool: from the next request on, POST /api/v1/route with plan: true (and the OpenAI-compatible endpoints with plan composition) picks the installed skill or persona for the matching slot when it fits the request better than the catalogue's, and an installed primary competes for the answer itself. GET /api/v1/targets lists your installs with source: marketplace; plan_mode (sequential / parallel) decides whether several installed skills run one after another or at the same time (platform guide). Other workspaces never see your installs. Try it in the playground: install a skill, ask a matching question with Build a plan on, and the plan's prepare stage names it. An install is seen by every API replica on the very next request - no waiting for a cache.

Skills, personas and prompts you never installed can help too. Every plan also offers the router the published skills, personas and prompts whose listing matches the request - the same vocabulary the router extracts (its domains and salient words) is searched in the listing's name, summary, tags and domains, and only a listing that works in one of the request's domains qualifies - so the marketplace shapes an answer without anyone browsing it first. A prompt joins as an instructions-only skill when it takes its input through at most one {{variable}} (the placeholder stands for the user's message); one with several variables is a template for a person to fill. The router's own strategies and quality floor still decide whether such a companion is used; a discovered one never answers on its own, and the decision names it under marketplace with installed: false. What may be discovered is a matter of trust: by default only listings an operator has marked verified (the deployment's own seeded skills, personas and prompts are), because a discovered skill's instructions reach the prompt of a workspace that did not choose it. A workspace widens or narrows that with the marketplace_discovery policy key - verified (default), all (every published listing) or off (installs only) - and the operator sets the deployment default with OSR_PLATFORM_MARKETPLACE_DISCOVERY. Agents and tools are never discovered: they execute (a call to the publisher's endpoint with the request in it), so they join the pool through an install only.

Installed agents and tools do not only get picked, they run: when a listing's manifest declares a public https endpoint with protocol a2a (an agent card), http (a JSON agent or workflow endpoint) or mcp (a Streamable-HTTP MCP server), the platform binds it - an executed request that lands on the listing calls the agent, or lists the MCP server's tools once and runs the one the request names (context.tool), the only one there is, or the closest match, with context.tool_arguments as its arguments. GET /api/v1/targets shows executable: true for those; a listing whose endpoint the platform may not call (a private address, a protocol that needs credentials such as openai or queue) stays routable but not executable and carries the reason in metadata.endpoint_unbound, which the dashboard's Installed tab shows as a badge. Skills and personas need no endpoint: their instructions run through the model that answers. An installed model card (an llm listing) needs your own key: map it to one of your providers on the Providers page - it is offered there next to the catalogue with the listing's upstream model id prefilled - and it runs on your account like any other target; /v1/models lists it and a chat may name it (model: <slug>).

In your own code an OCM manifest becomes a target with one call:

from opensmartroute import Router
from opensmartroute.ocm import bind_endpoint, target_from_capability

manifest = {...}  # GET /api/v1/registry/<slug>/manifest
router = Router([bind_endpoint(target_from_capability(manifest))])  # http / a2a / mcp endpoints get a handler

Prompts are text: read manifest["prompt"] and fill in manifest["variables"].

The package has a client for the whole loop - search, load, keep in sync - so a router follows the marketplace (which itself refreshes from its public sources every day) without manual downloads:

from opensmartroute import Router, TargetRegistry
from opensmartroute.adapters import MarketplaceClient

mk = MarketplaceClient()  # https://api.opensmartroute.ai
skills = mk.targets("sql reporting", kind="skill", limit=5)  # RouteTargets from the listings' manifests
agents = mk.targets(kind="agent", tag="a2a", limit=10)  # A2A agent cards, endpoints attached
router = Router(TargetRegistry([*my_models, *skills, *agents]))

report = mk.sync(router.registry, kind="skill", tag="skill-md", limit=50)  # run daily: adds new, updates changed
print(report.added, report.updated)

MarketplaceClient.search returns Listing rows (slug, kind, version, installs, rating, source); target(slug) loads one manifest; sync upserts by id and replaces a target when its version, text, instructions or endpoints changed upstream. Only routable kinds (agent, skill, persona, tool, llm) become targets; templates are stacks - import them with registry://slug@version.

sync is safe to run forever: the SyncReport lists added, updated, skipped (no loadable manifest), removed, kept and seen. A followed listing the marketplace answers 404 / 410 for is removed from the registry; a synced target you edited locally (the sync stamps a fingerprint in metadata["marketplace"]) is kept as it is until you pass force=True; prune=True also removes the targets this marketplace delivered earlier that no longer match the search (OSR_MARKETPLACE_PRUNE=1 does the same for the server-side MarketplaceSync below). The same from the CLI:

osr marketplace search "sql reporting" --kind skill            # list matching listings
osr marketplace pull acme-skills-sql-reporting --out skills.json # manifests as an OCM catalogue file
osr marketplace sync --kind skill --tag skill-md --limit 50 --targets-file marketplace.json   # daily cron job
osr --targets marketplace.json route "Write the monthly revenue report" --plan

sync --targets-file creates or updates a catalogue file every routing command loads with --targets, so a scheduled osr marketplace sync keeps a self-hosted router on the marketplace's daily state. The file keeps each manifest's endpoints, and load_targets binds them again on the next start (http, a2a, mcp), so an agent or MCP tool the router picks from that catalogue runs - the process restart loses nothing.

Following the marketplace from osr serve

A running server can follow the marketplace by itself - no cron, no restart: MarketplaceSync upserts the followed listings into the served catalogue every OSR_MARKETPLACE_REFRESH_S seconds, so a skill published (or re-versioned) upstream is routable on the next tick.

osr -t targets.yaml serve --marketplace-refresh 86400                    # once a day
OSR_MARKETPLACE_REFRESH_S=86400 OSR_MARKETPLACE_KINDS=skill,tool osr -t targets.yaml serve
OSR_MARKETPLACE_QUERY="sql reporting" OSR_MARKETPLACE_SLUGS=acme-skills-sql-reporting ...

OSR_MARKETPLACE_URL, OSR_MARKETPLACE_KINDS (default skill,tool), OSR_MARKETPLACE_QUERY, OSR_MARKETPLACE_TAG, OSR_MARKETPLACE_LIMIT (per kind) and OSR_MARKETPLACE_SLUGS choose what is followed (MarketplaceSettings). GET /stats reports the sync (marketplace: last run, added / updated, last error) and POST /marketplace/sync runs one now (a write path; read-only tokens are refused). In Python, MarketplaceSync(router.registry).start() does the same in any process.

From the IDE (MCP)

The local MCP server (osr -t targets.yaml mcp) carries marketplace_search and marketplace_get backed by the marketplace in OSR_MARKETPLACE_URL (--marketplace-url to point elsewhere, --no-marketplace to leave them out). marketplace_get with install: true also loads the listing into the running router's catalogue, so an assistant can find a skill and route to it in the same conversation. To try a listing without installing it, route takes marketplace: [slug, ...]: those listings join the candidates for that one request (and fill the plan's slots) and the result names them under marketplace_candidates. When something in the catalogue can run - a model behind OSR_LLM_BASE_URL, an agent or MCP server with a bound endpoint - the local server also offers ask, which routes and runs in one call.

The HTTP endpoints are public for published listings:

GET /api/v1/registry?kind=template&q=support&sort=popular
GET /api/v1/registry/{slug}
GET /api/v1/registry/{slug}/manifest?version=1.0.0
GET /api/v1/registry/{slug}/reviews

GET /api/v1/registry filters with q (free text, 80 characters), kind, tag (one exact tag, 64 characters), price=free|paid, featured=true|false and orders with sort=popular|newest|name|rating; q and tag are matched literally. Pages are limit (1-100) and offset (at most 10 000); the whole catalogue is paged through GET /api/v1/registry/sitemap instead. Each page carries the kind counts and top tags of the catalogue, refreshed every few minutes.

Ratings and reviews

Anyone with an account can rate a listing from 1 to 5 stars and leave a short review. One review per account per listing (writing again replaces the previous one). Reviews from accounts that installed the listing are marked as such. A listing shows its average rating, the number of ratings and a star histogram.

Leaderboard

/rankings/marketplace ranks the published listings per kind - most installed, best rated or newest - from GET /api/v1/rankings/listings?kind=<kind>&sort=installs|rating|newest. Best rated is a Bayesian average: the mean rating shrunk towards 3.5 by the weight of five ratings, so a listing with one five-star review sits below one with forty four-star reviews until more ratings arrive. GET /api/v1/rankings/listings/kinds gives the published listings, installs and reviews per kind. Publishers appear by display name only.

Publishing

Marketplace -> Publish walks through four steps: choose the kind, describe it, paste or write the manifest, review and submit. Prompts and personas need no code at all; for templates the wizard offers a starter you can edit. You can also post the same payload to POST /api/v1/registry.

The lifecycle

draft  ->  review  ->  published  ->  archived
  ^          |
  +--- rejected
  • Draft - only you can see it. Edit anything, including the manifest.
  • Submit - the manifest is validated (OCM schema, stack schema or prompt shape). Free listings are published immediately; paid listings go to review. (Operators can require review for everything with OSR_PLATFORM_REGISTRY_AUTO_PUBLISH=false.)
  • Review - a platform reviewer approves or rejects with a note. Rejected listings go back to you with the note; fix and submit again.
  • Published - live. Name, summary, description, tags, price and licence stay editable. The manifest is frozen: ship a new version instead, with a changelog. Old versions remain downloadable (?version=).
  • Archived - hidden from the marketplace; existing installs keep working. You can restore it as a draft.

Your listings, their status and any reviewer note are under Dashboard -> Marketplace -> Published by you; each one has an edit page with the version form.

Set a price in USD when publishing (paid plans, Pro and above). Buyers pay through the platform's checkout; the purchase is confirmed by the payment webhook and the listing is then recorded on their account. Free plans can publish a limited number of free listings.

Writing a good listing

  • A one-line summary that says what it does and for whom.
  • A description that covers what it needs (models, keys, data) and how to use it - Markdown, no raw HTML or images.
  • Tags people would search for (support, pii, sql, on-prem).
  • Test templates locally first: osr stack validate stack.yaml.
  • Skills: keep SKILL.md front matter complete (name, description); osr skills validate checks it.

Built-in content

Every platform ships seeded with the repository's own Agent-Skills packages, a starter template, the examples/stack.yaml support-desk template, a persona and a couple of prompts, all published by OpenSmartRoute and marked verified. Set OSR_PLATFORM_REGISTRY_SEED=false to run an empty marketplace.

Imported catalogue

The hosted marketplace also carries the public agentic ecosystem - Agent Skills, agent instructions, prompt files, slash commands and workflows, chat modes, act-as roles and Fabric patterns, custom agents and subagents, A2A agent cards, stack files, MCP servers, the reference LLM catalogue and routing stacks generated from it - harvested and refreshed every day by the platform itself, so every marketplace kind fills from public sources:

SourceWhat is importedListing kind
skills.shevery SKILL.md in each repository on the leaderboard (about 2 400 repositories)skill
GitHub code searchthe long tail of SKILL.md files (needs a GitHub token; optional)skill
GitHub code search (github-agents)every public AGENTS.md file - the cross-tool agent-instruction standard (needs a GitHub token; optional)skill
GitHub code search (github-instructions, github-cursor-rules).github/instructions/*.instructions.md (Copilot custom instructions, applyTo kept as metadata.applies_to) and .cursor/rules/*.mdc (Cursor project rules, globs) (needs a GitHub token; optional)skill
GitHub code search (github-prompts).github/prompts/*.prompt.md reusable prompt files: the frontmatter's description, mode, model and tools, the body as the prompt with ${input:name} / ${selection} turned into {{name}} placeholders declared as variables (needs a GitHub token; optional)prompt
GitHub code search (github-claude-commands).claude/commands/**/*.md Claude Code slash commands: description, argument-hint, allowed-tools, model; $ARGUMENTS becomes {{arguments}} and $1 ... $9 become {{arg1}} ... (needs a GitHub token; optional)prompt
GitHub code search (github-cursor-commands, github-windsurf-workflows, github-codex-prompts).cursor/commands/*.md (Cursor custom commands), .windsurf/workflows/*.md (Windsurf workflows) and .codex/prompts/*.md (Codex custom prompts), same conversion; slugs end in -cursor-command, -workflow, -codex-prompt (needs a GitHub token; optional)prompt
GitHub code search (github-chatmodes).github/chatmodes/*.chatmode.md - a voice, rules and tool set layered on a model (needs a GitHub token; optional)persona
Awesome ChatGPT Prompts (awesome-prompts)every "Act as ..." role of the CC0 prompts.csv (the prompt is the persona's instructions, the first sentence its description); slugs persona-<role>persona
Fabric (fabric-patterns)every pattern's system.md (identity and purpose, steps, output format; MIT) from one repository tarball; slugs fabric-<pattern>persona
GitHub code search (github-custom-agents).github/agents/*.agent.md custom agent definitions: instructions, tools, model, handoffs (needs a GitHub token; optional)agent
GitHub code search (github-claude-agents).claude/agents/*.md Claude Code subagents: name, description, comma-separated tools, model; slugs owner-repo-<name>-subagent (needs a GitHub token; optional)agent
GitHub code search (github-a2a)public A2A agent cards (.well-known/agent.json): name, skills, capabilities and the a2a endpoint the router can call (needs a GitHub token; optional)agent
GitHub code search (github-stacks)OpenSmartRoute stack files anywhere on GitHub (osr: "1", kind: stack, at least one target or import; Docker / Pulumi stacks and invalid documents are dropped by the stack validator); the manifest is the stack, so registry://<slug>@<version> imports it; slugs stack-owner-repo-<file> (needs a GitHub token; optional)template
Generated from the model catalogue (catalogue-stacks)ready-made routing stacks the platform derives from the reference LLM catalogue: one tiers stack per vendor with at least three priced models (cheapest / middle / strongest by intelligence index, complexity rules, cost-aware objective) and themed stacks - free models, reasoning, vision, open weights (up to four models each). The targets are the catalogue's llm capabilities with their OpenRouter endpoint, so a stack installs with no mapping; regenerated as the line-up and prices change; slugs stack-<vendor> / stack-free-models ...template
MCP registrythe latest active version of every server, with its remote endpoints and packagestool
Reference model catalogue (models)every hosted LLM of the platform's model catalogue (the OpenRouter listing snapshot, <data dir>/models.json when the rankings loop has refreshed it): vendor, prices per million tokens (cost.usd_per_1k_tokens is the input/output average), context window, modalities, tool calling, open weights, the OpenAI-compatible endpoint https://openrouter.ai/api/v1 and a quality prior from the Artificial Analysis intelligence index when publishedllm

Imported listings are published under the upstream owner's name, are not marked verified, and carry metadata.source in their manifest (provider, repository, path, ref, url) so the listing page links back to the original file; the readme starts with the upstream install command (npx skills add owner/repo --skill name). Copyright and licence stay with the author (license is taken from the frontmatter when present). Domains are inferred from the description with the router's own lexicon; the skill-md / mcp tags and the source name are added to the author's tags.

The harvest runs inside the platform on its own schedule (OSR_PLATFORM_MARKETPLACE_REFRESH_S; operators can run it now from the console): it only fetches what the catalogue does not have yet, re-checks stale rows, and publishes each source's new listings as soon as that source finishes. Slugs are owner-repo-skill (mcp-<server name> for tools, model-<vendor>-<name> for models, owner-repo-<file>-<convention> such as acme-app-deploy-prompt for prompt / chat-mode / agent / instruction files, so two conventions sharing a file name stay distinct), truncated with a short hash when longer than 63 characters.

Imported text is screened before it is stored: control characters are dropped and credential-shaped strings an author left in a file (AWS access keys, GitHub / OpenAI / Slack / Stripe / Google API keys, platform keys, JWTs, PRIVATE KEY blocks) are replaced with [REDACTED <kind>], including documentation placeholders - the original stays one click away upstream. Repositories that publish attack corpora (poisoned, malicious or prompt-injection skill datasets) are never mirrored: the harvester skips them, the cache replay drops rows cached earlier, and the admin import endpoint rejects them (source: repository publishes attack corpora and is not mirrored).

For a platform whose SQLite file lives on a network share (the Azure Container Apps deployment mounts Azure Files), publish tens of thousands of rows offline: build the database locally with publish --data-dir, stop the API, replace platform.sqlite3 on the share, start it again. Sustained bulk writes through the HTTP endpoint over SMB have corrupted the listings table before; the endpoint is meant for incremental updates of a few hundred rows.

The hosted marketplace stays current from inside the platform process - no CI job or cron is involved. OSR_PLATFORM_MARKETPLACE_REFRESH_S is the interval (default 86400 = daily; 0 = only from the console) and the process that owns the marketplace runs every source in OSR_PLATFORM_MARKETPLACE_REFRESH_SOURCES (default: every source - skills.sh,mcp-registry,models,catalogue-stacks,awesome-prompts,fabric-patterns,github,github-agents,github-instructions,github-cursor-rules,github-prompts,github-chatmodes,github-custom-agents,github-claude-agents,github-claude-commands,github-cursor-commands,github-windsurf-workflows,github-codex-prompts,github-a2a,github-stacks; OSR_PLATFORM_MARKETPLACE_REFRESH_LIMIT new rows per source per run, default 2000) into <data dir>/harvest/, publishes the listings the catalogue lacks in batches of 100, and re-fetches the oldest cached rows older than OSR_PLATFORM_MARKETPLACE_STALE_DAYS (default 7; at most OSR_PLATFORM_MARKETPLACE_STALE_LIMIT = 500 per source per run) so listings whose upstream file changed are republished with the new text, version and endpoints. After harvesting, each cache file is compacted to the newest line per key (re-fetched rows are appended, so the files would otherwise grow without bound), and the publish step reads bodies back from the cache one batch at a time - a catalogue of a hundred thousand rows costs the process tens of megabytes, not the size of the caches. Every run publishes what the caches already hold before it harvests and again after each source, so a run interrupted by a deploy or an eviction loses nothing: the next run puts out the rows it had fetched and carries on. The first run after a (re)start waits five minutes, or until the interval has passed since the last run finished; a run that started and never finished is resumed after five minutes, then three times longer for every further interruption in a row, capped at one hour (a crash loop backs off to hourly attempts; a deploy costs five minutes, and a service deployed several times a day still completes its harvest). When the marketplace runs on several replicas, one of them takes a Redis lease (osr:marketplace:leader) per run and the others skip it, so the shared cache files are written by one process at a time. The lease lives ten minutes and the leader renews it while it works and releases it when done, so a leader killed mid-run (a deploy, an eviction) frees the slot within ten minutes; a replica that found the lease taken records the skip (refresh.last_skipped in the status) and looks again after fifteen minutes instead of waiting a whole interval. The console's Refresh now bypasses the lease. Sources that need GitHub code search are skipped - and reported as such - until OSR_PLATFORM_GITHUB_TOKEN is set (on Azure: the OSR_PLATFORM_GITHUB_TOKEN deployment input becomes the github-token secret of every API app; a token with the public_repo scope is enough). GET /api/v1/admin/registry/import reports the schedule, the sources, the last run (new, updated and invalid rows per source) and the next run time under refresh; POST /api/v1/admin/registry/import/refresh runs it now. From a machine, publish --url ... --only-new does the same: it asks POST /api/v1/admin/registry/import/check {"slugs": [...]} which slugs already exist and sends only the rest.

For operators

SettingDefaultEffect
OSR_PLATFORM_REGISTRY_AUTO_PUBLISHtrueFree listings go live on submit; false sends everything to review.
OSR_PLATFORM_REGISTRY_SEEDtrueSeed built-in skills, templates, personas and prompts at startup.

Moderation uses the admin token (X-Admin-Token):

GET  /api/v1/admin/registry?status=review
POST /api/v1/admin/registry/{slug}/approve      {"note": "..."}
POST /api/v1/admin/registry/{slug}/reject       {"note": "why"}
POST /api/v1/admin/registry/{slug}/flags        {"featured": true, "verified": true}
POST /api/v1/admin/registry/{slug}/unpublish    {"note": "..."}
GET  /api/v1/admin/registry/import              published listings per source
POST /api/v1/admin/registry/import              {"items": [...], "refresh": false}  (up to 500 harvested rows)
POST /api/v1/admin/registry/import/check        {"slugs": [...]} -> {"existing": [...]}  (up to 2000 slugs)
POST /api/v1/admin/registry/import/refresh      run the scheduled harvest now (202; 409 while running)

Paid purchases need billing to be configured (Stripe keys); without it POST .../install on a paid listing answers 402.

Security notes

  • Manifests are validated against the OCM / stack schemas and size-limited; descriptions are rendered without raw HTML, scripts or images and external links carry rel="nofollow".
  • Installing never runs anything: it returns a document. Review what a template or agent points at (endpoints, tools) before applying it, the same way you would review a Terraform module.
  • Slugs are stable; a new version never changes the slug, so pin @version in production stacks.
  • Platform guide - authentication, routing, plans, organizations and the dashboard.
  • REST API reference - the Marketplace group lists every endpoint.
  • User guide - stack files, osr stack and the Open Capability Manifest.

Something wrong or out of date on this page? Tell us - the page is named for you, so a one-line note is enough.