Marketplace and Addons
The Shoehorn Marketplace lets you browse, install, and manage extensions that add widgets, integrations, and functionality to the platform. Addons are self-contained bundles that run inside Shoehorn with their own routes, frontend components, and webhook handlers. alpha
Browsing the Marketplace
Section titled “Browsing the Marketplace”Navigate to Admin > Addons to browse available items.
You can filter by:
- Kind: widget, integration, addon
- Category: monitoring, ci-cd, project-management, security, etc.
- Tier: declarative, scripted, full
- Search: free-text search across name and description
Each item shows its name, description, author, tier, and whether it is installed.
Installing an Addon
Section titled “Installing an Addon”- Find the addon in the marketplace catalog
- Click the addon card to see details
- Click Install
- Configure any required settings (API keys, URLs, etc.)
- The addon is activated for your tenant
Installed addons appear under Admin > Addons with their status (enabled/disabled).
Managing Installed Addons
Section titled “Managing Installed Addons”For each installed addon you can:
- Enable / Disable, toggle the addon on or off without uninstalling
- Configure, update settings like API keys or connection URLs
- View logs, check addon execution logs for debugging
- View status, see health and last execution info
- Uninstall, remove the addon and its data
Addon Secrets
Section titled “Addon Secrets”Some addons need credentials (API tokens, passwords). Set these in Admin > Addons > [addon] > Secrets. Secrets are stored encrypted and injected into the addon runtime. They are never exposed in the UI after being saved.
Addon Types
Section titled “Addon Types”| Tier | What it can do | Example |
|---|---|---|
| declarative | Configuration-only, no custom code | Dashboard widget pulling from an API |
| scripted | JavaScript/TypeScript with SDK helpers, webhook handlers | Jira issue sync, PagerDuty integration |
| full | Complete control over rendering, routing, data | Custom portal pages |
Widgets
Section titled “Widgets”Addons can provide dashboard widgets. Once installed, widgets appear in the widget picker when customizing your dashboard or team dashboards.
Installed widgets are available at Admin > Addons > Installed Widgets or via the API:
GET /api/v1/marketplace/installed/widgetsImporting Addons
Section titled “Importing Addons”There are three ways to get addons into your instance:
From the marketplace registry, click Install on any catalog item.
Import from manifest, paste an addon manifest JSON to install a custom addon not in the registry:
POST /api/v1/marketplace/import-manifestUpload a bundle, upload a built addon bundle (.tar.gz or .zip) directly:
POST /api/v1/marketplace/{slug}/bundleAddon Capabilities
Section titled “Addon Capabilities”Scripted and full-tier addons run in a sandboxed QuickJS VM with access to platform services via the ctx global. Capabilities are permission-gated, addons only receive what they declare in their manifest.
Core capabilities (always available or via basic scopes)
Section titled “Core capabilities (always available or via basic scopes)”| Capability | Description |
|---|---|
ctx.log | Structured logging (info, warn, error, debug) |
ctx.config | Read-only text configuration set by admins |
ctx.secrets | Read-only encrypted secrets (AES-256-GCM) |
ctx.http | Synchronous HTTP client (restricted to declared URLs) |
ctx.entities | Catalog entity CRUD (list, get, upsert, delete) |
ctx.addon | Addon metadata (id, version, tier) |
Adapter capabilities (optional, permission-gated)
Section titled “Adapter capabilities (optional, permission-gated)”These are injected into the addon VM only when the corresponding permission scope is declared in manifest.json. They provide direct access to platform backing services.
| Capability | Backing Service | Permission Scopes | Use Case |
|---|---|---|---|
ctx.cache | Valkey (Redis) | cache:read, cache:write | Cache API responses, deduplication, rate limiting |
ctx.events | Redpanda (Kafka) | events:publish, events:subscribe | Emit events for other services, react to platform changes |
ctx.db | PostgreSQL | db:read | Custom read-only queries against tenant-scoped platform data |
ctx.search | Meilisearch | search:read | Full-text search over indexed platform data |
ctx.kv | PostgreSQL JSONB | kv:read, kv:write | Persistent addon state (sync cursors, per-entity data) |
ctx.notifications | Platform push | notifications:send | Send in-app notifications to users or broadcast to teams |
To use an adapter, add its permission scopes to the manifest:
{ "addon": { "permissions": { "shoehorn": ["entities:read", "cache:read", "cache:write", "kv:read", "kv:write"] } }}See the Addon SDK documentation for full API reference and examples.
Building Your Own Addons
Section titled “Building Your Own Addons”Use the Addon SDK to create custom addons:
npx @shoehorn-dev/addon-sdk init my-addoncd my-addonnpm installnpm run buildshoehorn addon publish --dir .See Ecosystem and Tools for SDK details and the jira-sync addon for a production example.
Permissions
Section titled “Permissions”Marketplace permissions
Section titled “Marketplace permissions”| Scope | What it allows |
|---|---|
marketplace:read | Browse marketplace, view installed items |
marketplace:write | Install, enable, disable addons |
marketplace:admin | Publish addons, upload bundles, manage secrets |
Addon runtime permissions
Section titled “Addon runtime permissions”Declared in the addon’s manifest.json under permissions.shoehorn:
| Scope | What it unlocks |
|---|---|
secrets:read | Access to encrypted secrets via ctx.secrets |
entities:read | Read catalog entities via ctx.entities.get/list |
entities:write | Create/update/delete entities via ctx.entities.upsert/delete |
cache:read | Read from cache via ctx.cache.get/has |
cache:write | Write to cache via ctx.cache.set/delete |
events:publish | Publish events via ctx.events.publish |
events:subscribe | Subscribe to events via ctx.events.subscribe |
db:read | Run read-only SQL queries via ctx.db.query |
search:read | Search indexed data via ctx.search.search |
kv:read | Read from persistent KV store via ctx.kv.get/list/has |
kv:write | Write to KV store via ctx.kv.set/delete |
notifications:send | Send notifications via ctx.notifications.send/broadcast |