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.
The mainAppPanel and scriptRunner fields are deprecated. Use editorContentPanel and editorScriptRunner instead.
mainAppPanel→editorContentPanelscriptRunner→editorScriptRunner
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 (termsAndConditionsLinkandprivacyPolicyLinkare required).config.embed.editorContentPanel.path: HTML entrypoint for the main panel in the editor content area (next to the canvas). Either this or the deprecatedmainAppPanelis required. The path is interpreted relative to the built artifact root (the contents you upload), for exampleindex.htmlnext to your bundled assets.config.embed.mainAppPanel.path: Deprecated — useeditorContentPanelinstead. 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 — useeditorScriptRunnerinstead.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 theproviderstring you pass tokittl.auth.scopeandaccessTypeare optional in the manifest if your provider does not need them.config.appDevelopment.local: optional local-dev hints (requireHTTPSis useful when a provider expects a secure origin;portcan match your dev server).
Development helpers
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"
}