Skip to main content

App manifest

Use manifest.json to describe your extension for Kittl: listing fields, the embed HTML entrypoint, requested SDK scopes, and optional OAuth providers. The Kittl CLI validates this file with the same shape as below when you create or update a draft version.

Manifest schema

Field names are camelCase in JSON (for example authorizationUrl, not authorization_url).

type Scope =
| 'design:state:read'
| 'design:state:write'
| 'uploads:create'
| 'fonts:read'
| 'fonts:write'
| 'fonts:read:global'
| 'fonts:write:global'
| 'uploads:global:read'
| 'data:mockups:read'
| 'ai:credit:spend'
| 'workspace:state:read'
| 'workspace:state:write';

type OAuthProvider = {
authorizationUrl: string;
clientId: string;
tokenUrl: string;
scope?: string;
accessType?: string;
customFieldMappings?: Record<string, unknown>;
};

type ExtensionManifest = {
$schema?: string;
displayName: string;
icon: string;
tagline: string;
installPage: {
description: string;
coverImage: string;
termsAndConditionsLink: string;
privacyPolicyLink: string;
};
config: {
scopes: Scope[];
embed: {
// Either editorContentPanel or mainAppPanel is required (not both)
editorContentPanel?: {
path: string;
};
/** @deprecated Use editorContentPanel instead */
mainAppPanel?: {
path: string;
};
editorScriptRunner?: {
path: string;
};
/** @deprecated Use editorScriptRunner instead */
scriptRunner?: {
path: string;
};
sharedFileBrowser?: {
path: string;
};
};
appDevelopment?: {
local: {
requireHTTPS?: boolean;
port?: number;
};
};
oauthProviders?: Record<string, OAuthProvider>;
};
};

config.scopes is required. If you want no permissions, set it to an empty array ([]). With an empty scope set, many SDK calls will be denied by scope checks.

Deprecated field names

The mainAppPanel and scriptRunner fields are deprecated. Use editorContentPanel and editorScriptRunner instead.

  • mainAppPaneleditorContentPanel
  • scriptRunnereditorScriptRunner

The CLI will emit warnings if you use the deprecated names. Both names are currently accepted for backwards compatibility, but you cannot specify both the old and new names simultaneously.

Complete example

{
"$schema": "https://api.kittl.com/extensions/manifest/schema.json",
"displayName": "My extension",
"icon": "icon.svg",
"tagline": "My extension for Kittl.",
"installPage": {
"description": "Install My extension to use it in Kittl.",
"coverImage": "icon.svg",
"termsAndConditionsLink": "https://example.com/terms",
"privacyPolicyLink": "https://example.com/privacy"
},
"config": {
"scopes": ["design:state:read", "design:state:write"],
"embed": {
"editorContentPanel": {
"path": "index.html"
}
},
"appDevelopment": {
"local": {
"requireHTTPS": true,
"port": 5173
}
},
"oauthProviders": {
"myProvider": {
"authorizationUrl": "https://provider.example.com/oauth2/authorize",
"clientId": "client-id-from-provider",
"scope": "assets.read assets.write",
"accessType": "offline",
"tokenUrl": "https://provider.example.com/oauth2/token"
}
}
}
}

Manifest location

Place manifest.json at the root of your app project (same level as the output/ directory), not inside output/.

Field notes

  • displayName, tagline, icon: short listing fields for your extension.
  • installPage: longer description, cover art, and links shown in the install flow (termsAndConditionsLink and privacyPolicyLink are required).
  • config.embed.editorContentPanel.path: HTML entrypoint for the main panel in the editor content area (next to the canvas). Either this or the deprecated mainAppPanel is required. The path is interpreted relative to the built artifact root (the contents you upload), for example index.html next to your bundled assets.
  • config.embed.mainAppPanel.path: Deprecated — use editorContentPanel instead. HTML entrypoint for the main panel.
  • config.embed.editorScriptRunner.path: optional HTML entrypoint for a headless runner — a hidden iframe that runs background logic (AI pipelines, data sync, etc.) with full SDK access but no visible UI.
  • config.embed.scriptRunner.path: Deprecated — use editorScriptRunner instead.
  • config.embed.sharedFileBrowser.path: optional HTML entrypoint for a file browser panel. Extensions can register custom tabs in the Kittl upload panel to show their own file browsing UI. See the File Browser guide for implementation details.
  • config.scopes: SDK permissions your extension requests. See SDK scopes.
  • config.oauthProviders: map of provider id to OAuth endpoints; the key is the provider string you pass to kittl.auth. scope and accessType are optional in the manifest if your provider does not need them.
  • config.appDevelopment.local: optional local-dev hints (requireHTTPS is useful when a provider expects a secure origin; port can match your dev server).

Development helpers

JSON Schema for editors

The canonical JSON Schema for extension manifests is published at https://api.kittl.com/extensions/manifest/schema.json.

Add a $schema field in manifest.json so your editor can validate and autocomplete against it:

{
"$schema": "https://api.kittl.com/extensions/manifest/schema.json"
}