MisarMisar Docs
MisarMailMisarBlogMisarReachMisarPostMisarSEOMisarDevMisarCoderMisar PlatformMisar SSO
API Reference

Registry

The central catalog of coding capabilities — skills, agents, MCP servers, plugins, tools and models — at api.misar.io/coder/registry/*.

The registry is the one place coding capabilities are published, versioned, discovered and installed from. Misar Code, Misar.dev's Skill Center, and any other product read the same catalog over the same REST surface — there is no shared package to install and no database to connect to.

Base URL: https://api.misar.io/coder/registry Auth: reads are anonymous. Writes need a credential (see Publishing).

Kinds

Every item has exactly one kind, from a closed set:

KindWhat it is
skillA reusable instruction set the assistant can invoke
agentA specialised assistant with its own triggers and tools
mcp_serverA Model Context Protocol server that adds tools
pluginA bundle that extends the runtime, including lifecycle hooks
toolA single callable function
modelA model definition available for routing

Ignore kinds you do not recognise

The set is closed, but it can grow. A client must render the kinds it supports and skip the rest — a new kind should never break an older client. Do not switch on kind without a default branch.

Lifecycle hooks publish as kind: "plugin" carrying a hook:<name> capability, rather than as a kind of their own, so clients that predate them still handle them sensibly.

Reading the catalog

Reads are cacheable (Cache-Control: public, max-age=60, stale-while-revalidate=600) — the catalog changes when someone publishes, not per request.

GET/items

List public items, filtered and paginated.

kindstringquery

Restrict to one kind. Unknown values are ignored rather than erroring.

qstringquery

Free-text search across name, summary and description.

tagstringquery

Restrict to items carrying this tag.

productstringquery

Restrict to items installable in a given product (dev, coder, ai, …).

pageintegerquery

1-based page number. Default 1.

limitintegerquery

Items per page. Default 24, clamped to a server maximum.

sortstringquery

popular (default), recent, or name.

Response

{
  "data": [
    {
      "slug": "git-worktree",
      "kind": "skill",
      "name": "Git Worktree",
      "summary": "Work on several branches at once without stashing.",
      "description": "…",
      "version": "1.2.0",
      "publisher": { "id": "misar", "name": "Misar", "verified": true },
      "tags": ["git", "vcs"],
      "capabilities": ["worktree"],
      "products": ["dev", "coder"],
      "license": "MIT",
      "sourceUrl": "https://git.misar.io/misaradmin/MisarCoder",
      "icon": null,
      "installs": 128,
      "createdAt": "2026-08-01T10:00:00Z",
      "updatedAt": "2026-08-02T09:30:00Z"
    }
  ],
  "pagination": { "total": 42, "page": 1, "limit": 24, "totalPages": 2 }
}

pagination.total is the number of matching items, not the number on this page.

Visibility

Only public items appear in list results. An unlisted item is fetchable by its exact slug but never listed. A private item requires its publisher's credentials — to anyone else it returns 404, not 403, so the endpoint cannot be used to discover that a private slug exists.

GET/items/{slug}

One item, with its release history and the manifest of its latest version.

Response — the item shape above, plus:

{
  "versions": [
    { "version": "1.2.0", "changelog": "…", "yanked": false, "createdAt": "…" },
    { "version": "1.0.0", "changelog": null, "yanked": true, "createdAt": "…" }
  ],
  "manifest": { "…": "kind-specific" }
}

Yanked versions remain listed — a client that pinned one needs to know it was withdrawn — but must not be offered as an install target.

GET/items/{slug}/manifest

The raw installable manifest.

versionstringquery

A specific semver. Defaults to the latest non-yanked version.

GET/kinds

Counts per kind, for filter UIs: [{ "kind": "skill", "count": 8 }, …]

GET/tags

Counts per tag: [{ "tag": "git", "count": 3 }, …]

Publishing

Writes accept either credential:

  • x-registry-service-key: <key> — server-to-server, with an explicit publisherId in the body.
  • Authorization: Bearer <api key> — a MisarCoder API key.

Manifests must never contain secret values

A registry row is world-readable by design. Runtime configuration carries environment variable names, never their values — the server strips values at the storage boundary, including from nested objects, and consumers prompt for them at install time. A manifest that ships a key has published that key.

POST/items

Create or update an item. Matching is by slug, so re-posting updates in place.

slugstringbodyrequired

Lowercase, hyphen-separated. Stable forever — it is the item's identity.

kindstringbodyrequired

One of the six kinds above.

namestringbodyrequired

Display name.

summarystringbodyrequired

One line, 160 characters or fewer.

descriptionstringbody

Long form, markdown. Consumers render it as text, not HTML.

visibilitystringbody

public (default), unlisted, or private.

tagsstring[]body
capabilitiesstring[]body
productsstring[]body

Which products may install it. Defaults to all.

licensestringbody
sourceUrlstringbody
iconstringbody

verified cannot be self-asserted — a bearer caller requesting it gets false.

POST/items/{slug}/versions

Publish a version.

versionstringbodyrequired

Semver. Ordered numerically, so 1.10.0 is newer than 1.2.0.

manifestobjectbodyrequired

The installable payload. Validated against the schema for the item's kind.

runtimeobjectbody

Transport, command, args and environment variable names.

changelogstringbody

A version is immutable once published

Re-publishing the same (slug, version) returns 409. Fix a bad release with a new version or a yank — never by overwriting. Someone who installed 1.2.0 yesterday and someone who installs it today must get the same thing.

DELETE/items/{slug}/versions/{version}

Yank a version. The row is kept and stays visible in the release history; it is removed from install targets, and version falls back to the highest remaining non-yanked release. Nothing is ever hard-deleted.

POST/items/{slug}/install

Record an install. This is what makes the popular sort meaningful, so a client that installs without recording is under-reporting.

versionstringbodyrequired
productstringbodyrequired

Which product installed it (dev, coder, …).

This call must never block or fail an install. A registry-side fault returns 200 {"recorded": false} rather than an error, so a caller can fire it and move on. An unknown slug is still a 404, because that is a bug in the caller rather than an outage.

Errors

Errors carry a real status code and a body of { "error": string, "code"?: string } — never 200 with an error inside.

StatusMeaning
404Unknown slug, or a private item you cannot see
409That (slug, version) already exists
422The manifest failed its kind's schema
503The registry's storage is unavailable

503 means unavailable, not empty

When storage is down the registry returns 503. It never falls back to a local plugin list, because presenting one node's loaded plugins as "the catalog" is worse than an honest error. Clients should show "unavailable" rather than an empty catalog — an empty grid reads as there is nothing here, which is a different and wrong statement.

SDKs

Both SDKs expose the same surface under registry, with the same names and arguments as the REST endpoints.

import { MisarCoder } from "@misar/coder";

const coder = new MisarCoder({ apiKey: process.env.MISARCODER_API_KEY });

const { data, pagination } = await coder.registry.list({ kind: "skill", q: "git" });
const item = await coder.registry.get("git-worktree");
const manifest = await coder.registry.manifest("git-worktree", "1.2.0");

await coder.registry.recordInstall("git-worktree", {
  version: "1.2.0",
  product: "dev",
});
from misarcoder import MisarCoder

client = MisarCoder(api_key=os.environ["MISARCODER_API_KEY"])

items = client.registry.list(kind="skill", q="git")
item = client.registry.get("git-worktree")
manifest = client.registry.manifest("git-worktree", version="1.2.0")