Addon Manifests
Addon manifests are JSON files that define an addon’s metadata, permissions, runtime configuration, and UI extensions. Every addon requires a manifest.json in its project root.
For service catalog manifests (YAML), see Manifests.
Structure
Section titled “Structure”{ "schemaVersion": 1, "kind": "addon", "metadata": { ... }, "addon": { ... }}Root Fields
Section titled “Root Fields”| Field | Type | Required | Description |
|---|---|---|---|
schemaVersion | integer | Yes | Must be 1 |
kind | string | Yes | Must be "addon" |
metadata | object | Yes | Addon identity and marketplace information |
addon | object | Yes | Runtime and feature configuration |
metadata
Section titled “metadata”| Field | Type | Required | Description |
|---|---|---|---|
slug | string | Yes | Kebab-case identifier (3-50 chars). Pattern: ^[a-z][a-z0-9-]{1,48}[a-z0-9]$ |
name | string | Yes | Display name |
version | string | Yes | Semver version (e.g., 0.1.0) |
description | string | Yes | Short description (shown in marketplace) |
author | object | Yes | Author info: name (required), email, url |
category | string | Yes | Category: integrations, analytics, cloud, custom |
tier | string | Yes | Marketplace tier: free, pro, enterprise |
tags | array | No | Lowercase tags for discoverability |
icon | string | No | Icon name or SVG string |
Core Fields
Section titled “Core Fields”| Field | Type | Required | Description |
|---|---|---|---|
tier | string | Yes | Runtime tier: declarative, scripted, full |
runtime | string | Yes | Runtime engine: quickjs |
permissions | object | Yes | Capabilities the addon requires |
sync | object | No | Scheduled sync configuration |
config | object | No | Admin-configurable settings |
frontend | object | No | Browser UI extensions |
Runtime Tiers
Section titled “Runtime Tiers”| Tier | Description |
|---|---|
declarative | Configuration-only, no code execution |
scripted | Backend code in QuickJS sandbox, optional frontend |
full | Full runtime access (databases, events, notifications) |
permissions
Section titled “permissions”Declares what resources the addon can access at runtime.
"permissions": { "network": [ { "url": "https://*.atlassian.net/*" } ], "shoehorn": [ "secrets:read", "entities:read", "entities:write" ]}Network Permissions
Section titled “Network Permissions”URL patterns the addon can reach via ctx.http.request(). Wildcards supported:
*matches any single path segment- Patterns are matched against the full URL
Shoehorn Permission Scopes
Section titled “Shoehorn Permission Scopes”| Scope | API | Description |
|---|---|---|
secrets:read | ctx.secrets.get() | Read encrypted secrets |
entities:read | ctx.entities.get(), .list() | Read catalog entities |
entities:write | ctx.entities.upsert(), .delete() | Create/update/delete entities |
cache:read | ctx.cache.get(), .has() | Read ephemeral cache |
cache:write | ctx.cache.set(), .delete() | Write ephemeral cache |
events:publish | ctx.events.publish() | Publish to event bus |
events:subscribe | ctx.events.subscribe() | Subscribe to events |
db:read | ctx.db.query() | Read-only SQL queries |
search:read | ctx.search.search() | Full-text search |
kv:read | ctx.kv.get(), .list(), .has() | Read persistent KV store |
kv:write | ctx.kv.set(), .delete() | Write persistent KV store |
notifications:send | ctx.notifications.send() | Send notifications |
Configures periodic background synchronization.
"sync": { "schedule": "*/5 * * * *", "function": "sync"}| Field | Type | Required | Description |
|---|---|---|---|
schedule | string | Yes | Cron expression (5-field) |
function | string | Yes | Exported function name to call |
Common schedules:
| Expression | Frequency |
|---|---|
*/5 * * * * | Every 5 minutes |
*/15 * * * * | Every 15 minutes |
0 * * * * | Every hour |
0 0 * * * | Daily at midnight |
config
Section titled “config”Declares admin-configurable settings. These appear as form fields in the addon admin UI.
"config": { "api_url": { "label": "API URL", "type": "text", "required": true, "placeholder": "https://api.example.com" }, "api_token": { "label": "API Token", "type": "secret", "required": true }, "sync_mode": { "label": "Sync Mode", "type": "select", "default": "full", "options": ["full", "incremental"] }}Config Field Types
Section titled “Config Field Types”| Type | Description | Access |
|---|---|---|
text | Plain text input, stored unencrypted | ctx.config.get(key) |
secret | Password input, stored AES-256-GCM encrypted | ctx.secrets.get(key) (requires secrets:read) |
select | Dropdown with predefined options (requires options array) | ctx.config.get(key) |
Config Field Properties
Section titled “Config Field Properties”| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | UI label |
type | string | Yes | text, secret, or select |
required | boolean | No | Whether the field must be set |
placeholder | string | No | Hint text |
default | string | No | Default value |
options | array | No | Valid values (for select type) |
frontend
Section titled “frontend”Declares browser UI extensions: dashboard widgets and entity tabs.
Widgets
Section titled “Widgets”"frontend": { "widgets": [ { "id": "jira-issues", "label": "Jira Issues", "componentName": "JiraIssuesWidget", "size": { "default": { "w": 4, "h": 3 }, "min": { "w": 2, "h": 2 }, "max": { "w": 6, "h": 6 } } } ]}| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique widget identifier (scoped to addon) |
label | string | Yes | Display name in widget picker |
componentName | string | Yes | Exported component from frontend bundle |
size.default | object | Yes | Default grid size: { w, h } |
size.min | object | Yes | Minimum grid size |
size.max | object | No | Maximum grid size |
Grid dimensions are in dashboard grid units (typically ~60px each). Width range: 1-12, height range: 1-8.
Entity Tabs
Section titled “Entity Tabs”"frontend": { "entityTabs": [ { "id": "runbooks", "label": "Runbooks", "componentName": "RunbooksTab", "entityTypes": ["service", "api"], "priority": 10 } ]}| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique tab identifier |
label | string | Yes | Tab label |
componentName | string | Yes | Exported component from frontend bundle |
entityTypes | array | No | Entity types this tab applies to (omit for all) |
priority | number | No | Sort order (lower = first, default: 0) |
Complete Example
Section titled “Complete Example”{ "schemaVersion": 1, "kind": "addon", "metadata": { "slug": "jira-sync", "name": "Jira Sync", "version": "0.1.0", "description": "Syncs Jira issues into the Shoehorn catalog.", "author": { "name": "Shoehorn Team" }, "category": "integrations", "tier": "free" }, "addon": { "tier": "scripted", "runtime": "quickjs", "permissions": { "network": [{ "url": "https://*.atlassian.net/*" }], "shoehorn": ["secrets:read", "entities:read", "entities:write"] }, "sync": { "schedule": "*/5 * * * *", "function": "sync" }, "config": { "jira_base_url": { "label": "Jira Base URL", "type": "text", "required": true, "placeholder": "https://yourorg.atlassian.net" }, "jira_email": { "label": "Jira Email", "type": "text", "required": true, "placeholder": "user@company.com" }, "jira_api_token": { "label": "Jira API Token", "type": "secret", "required": true }, "jira_project": { "label": "Jira Project Key", "type": "text", "required": false, "placeholder": "PROJ" } }, "frontend": { "widgets": [ { "id": "jira-issues", "label": "Jira Issues", "componentName": "JiraIssuesWidget", "size": { "default": { "w": 4, "h": 3 }, "min": { "w": 2, "h": 2 }, "max": { "w": 6, "h": 6 } } } ] } }}Validation
Section titled “Validation”Slug Rules
Section titled “Slug Rules”- 3-50 characters
- Lowercase letters, numbers, and hyphens only
- Must start with a letter, end with letter or digit
- Must be unique per Shoehorn instance
Version Format
Section titled “Version Format”Semantic versioning: MAJOR.MINOR.PATCH (e.g., 0.1.0, 1.2.3)
Size Constraints
Section titled “Size Constraints”minwidth and height must be >= 1defaultmust be >=minand <=max(ifmaxis set)
See Also
Section titled “See Also”- Manifests - Service catalog manifests (YAML)
- Manifest Validation - Validation rules
- Marketplace - Publishing addons