KB LabsDocs

Marketplace

Last updated April 7, 2026


Install, manage, and discover entities (plugins, adapters, workflows) via npm.

The marketplace service is how plugins, adapters, and other entities get installed into a KB Labs workspace. It wraps npm (today — a native registry is on the roadmap) behind a unified HTTP API and writes the resolved installations into .kb/marketplace.lock, which is then read by the discovery layer at CLI and service startup.

It's a small Fastify service. Source: platform/kb-labs-marketplace/apps/marketplace/.

Service manifest

TypeScript
{
  schema: 'kb.service/1',
  id: 'marketplace',
  name: 'Marketplace',
  version: '1.0.0',
  description: 'Unified entity marketplace — install, manage, discover',
  runtime: {
    entry: 'dist/index.js',
    port: 5070,
    healthCheck: '/health',
  },
  env: {
    PORT: { description: 'HTTP port', default: '5070' },
    NODE_ENV: { description: 'Environment mode', default: 'development' },
  },
}

Source: apps/marketplace/src/manifest.ts.

Why a service?

Install, uninstall, and upgrade operations all have to:

  • Resolve the package from a registry.
  • Verify integrity and (eventually) signatures.
  • Update .kb/marketplace.lock.
  • Surface progress events so Studio can show a spinner.
  • Trigger a registry refresh in any running services (CLI, REST API, workflow daemon).

Doing all that from inside every consumer (CLI, REST, Studio) would mean duplicating the install logic and coordinating concurrent writes to the lock file. Centralizing it in a single service solves both problems — everyone else becomes a client of the marketplace HTTP API.

Architecture

    CLI / Studio / REST


    Marketplace HTTP :5070

    ┌────┴─────┐
    ▼          ▼
 Fastify    MarketplaceService


           NpmPackageSource


              pnpm / npm


          .kb/marketplace.lock

From bootstrap.ts:

  1. Detect repo root via findRepoRoot(cwd).
  2. Load env from .env in the repo root.
  3. createServiceBootstrap({ appId: 'marketplace', repoRoot }) — init the platform singleton.
  4. Construct MarketplaceService with an NpmPackageSource.
  5. Create a Fastify server via @kb-labs/marketplace-api.
  6. Listen on port (default 5070).
  7. Wire SIGTERM / SIGINT for graceful shutdown.

The service is deliberately thin. MarketplaceService holds the business logic; the Fastify layer is pure HTTP wrapping.

Packages

The marketplace is a small monorepo in itself — the daemon lives alongside the libraries it consumes:

PackagePurpose
@kb-labs/marketplace-coreThe MarketplaceService class and PackageSource interface
@kb-labs/marketplace-npmNpmPackageSourcepnpm wrapper that installs, resolves, and introspects packages
@kb-labs/marketplace-apiFastify routes (createServer())
@kb-labs/marketplace-appThe daemon binary that wires everything together

Only marketplace-npm depends on execa / pnpm — everything else is vendor-agnostic, so a future RegistryPackageSource can be dropped in without touching the core or API.

PackageSource interface

NpmPackageSource is the current implementation; the interface exists so that other sources (internal registry, OCI registry, local link) can be added without changing core behavior. The contract is in @kb-labs/marketplace-contracts.

The source is responsible for:

  • Resolving — turning a package spec (name, version) into a concrete downloadable artifact.
  • Installing — fetching the artifact into node_modules.
  • Inspecting — reading the installed package's package.json + manifest.
  • Uninstalling — removing the artifact from node_modules.

Entity kinds

The marketplace is unified — it handles more than just plugins. The entity kinds come from @kb-labs/core-discovery:

TypeScript
type EntityKind =
  | 'plugin'
  | 'adapter'
  | 'cli-command'
  | 'rest-route'
  | 'ws-channel'
  | 'workflow'
  | 'webhook'
  | 'job'
  | 'cron'
  | 'studio-widget'
  | 'studio-menu'
  | 'studio-layout'
  | 'skill'
  | 'hook'
  | (string & {});

When a package is installed, the marketplace inspects its manifest and records primaryKind (the discriminator) plus provides (all kinds it contributes) in the lock file. This lets clients filter — "list all installed plugins" or "list everything that provides a workflow".

Lock file format

Every install writes to .kb/marketplace.lock:

TypeScript
interface MarketplaceLock {
  schema: 'kb.marketplace/2';
  installed: Record<string, MarketplaceEntry>;
}
 
interface MarketplaceEntry {
  version: string;
  integrity: string;               // SRI hash of package.json (sha256-...)
  resolvedPath: string;            // relative to repo root
  installedAt: string;             // ISO 8601
  source: 'marketplace' | 'local';
  signature?: EntitySignature;
  primaryKind: EntityKind;
  provides: EntityKind[];
  enabled?: boolean;               // default true
}

The lock file is the single source of truth for the discovery layer. Every CLI startup and every service bootstrap reads this file via DiscoveryManager.discover() (core-discovery) and loads the manifests it points at.

  • source: 'marketplace' — installed via kb marketplace install. Integrity mismatches are fatal.
  • source: 'local' — linked via kb marketplace link. Integrity mismatches are silently refreshed, because local packages change on every build.

See Plugins → Overview → Discovery for the full discovery flow.

HTTP API

The API is mounted by createServer() in @kb-labs/marketplace-api. The surface covers:

  • InstallPOST /install with a package spec; returns the resolved entry.
  • UninstallDELETE /packages/<name>.
  • UpdatePOST /packages/<name>/update.
  • LinkPOST /link with a local path for dev mode.
  • UnlinkDELETE /packages/<name>/link.
  • ListGET /packages with optional kind filter.
  • InspectGET /packages/<name> returns the entry plus the parsed manifest.
  • Enable/DisablePATCH /packages/<name> with { enabled: boolean }.
  • Health / Readiness / OpenAPI — standard @kb-labs/shared-http endpoints at /health, /ready, /openapi.json, /docs.

The CLI commands (kb marketplace install, kb marketplace list, etc.) are thin HTTP clients that call this API.

Port 5070

The service binds to port 5070 by default. Override via KB_MARKETPLACE_PORT or PORT in env. The bind host is 0.0.0.0 by default; override via KB_MARKETPLACE_HOST.

kb-dev launches it on the default port and kb-dev status will show it under the backend group.

Starting the service

Bash
kb-dev start marketplace

Or directly:

Bash
cd platform/kb-labs-marketplace/apps/marketplace
node ./dist/index.js

The service reads kb.config.json from the repo root for platform configuration (logger, cache). There's no marketplace-specific config file.

CLI and lock cache

After an install, running services (CLI, REST API, workflow daemon) each have their own registry cache in memory. Freshly installed entities don't appear until those caches are refreshed:

Bash
pnpm kb marketplace clear-cache

This is the #1 source of "my plugin built but doesn't show up" confusion. The rule is: after any marketplace install, link, or rebuild of a linked plugin, clear the cache.

Graceful shutdown

On SIGTERM / SIGINT:

  1. Log receipt of the signal.
  2. Close the Fastify server.
  3. Exit with code 0.

No in-flight operation draining — installs are typically fast, and the npm subprocess (if one is running) is left to finish or fail on its own. If an install gets interrupted in the middle of writing the lock file, the lock is left in whatever state it was in and you may need to recover manually.

Marketplace — KB Labs Docs