PluginManifest
export default definePlugin({ /* … */ });Identity
Section titled “Identity”| Field | Type | Notes |
|---|---|---|
id |
string |
Globally unique, kebab-case, 2–40 chars. It’s the key everything is stored under: renaming it is a new app. |
apiVersion |
number |
Extension API targeted. The host refuses versions it can’t run. |
version |
string |
Semver of the app. Bump it when the settings change shape. |
name |
string |
Shown in the storefront and the panel. |
summary |
string |
One line for the storefront card. |
description |
string? |
Longer text for the detail page. |
icon |
PluginIcon? |
A name from a closed list, never a URL or an SVG. |
accent |
PluginAccent? |
A tint from a closed list, used where the app’s work shows. |
highlights |
string[]? |
Three or four terse lines: what someone reads before installing. |
verticals, audience |
string[]?, string? |
Who it’s for, in the words a business uses about its own trade. Used to sort and suggest. |
The closed lists for icon and accent are the same idea as everything else
here: an app declares which one to draw, not how. The day manifests
come from third parties, that’s what stops a storefront card from loading
resources from outside or injecting markup into the panel.
What it needs
Section titled “What it needs”| Field | Type | Notes |
|---|---|---|
allowedHosts |
string[]? |
The only hosts ctx.http may reach. Absent or empty means no network at all. |
capabilities |
("image-input" | "document-input")[]? |
Chat abilities switched on while installed. Each costs tokens the customer pays for, so they’re opt-in. |
secrets |
string[]? |
Names of the host’s environment variables readable through ctx.secrets. Reserved for core apps. |
What it adds
Section titled “What it adds”| Field | Type | Notes |
|---|---|---|
settingGroups |
PluginSettingGroup[]? |
Sections of the panel, in drawing order. |
settings |
PluginSettingField[]? |
The fields. See Setting fields. |
onboarding |
PluginOnboardingStep[]? |
Guided setup after install, one step per screen. |
tools |
PluginTool[]? |
Functions the model can call. |
jobs |
PluginJob[]? |
Daily work, once for the whole platform. |
prompt |
(ctx) => string | null |
Synchronous, cheap: it’s rebuilt on every request. |
migrateSettings |
(stored, fromVersion) => stored |
Rewrites saved values into the shape today’s fields expect. Pure and synchronous. |
Guided setup
Section titled “Guided setup”onboarding: [ { key: "trade", // stable: it's stored as how far they got title: "Which items are yours", body: "A general bill has more of other trades' work than yours…", fields: ["trade", "ownWorks"], // or `group: "…"` for a whole section tryPrompt: "I have the client's bill of quantities as a PDF…", },]Renaming a key restarts everyone who was midway. And a guide that never asks
for a required field is rejected: it would declare itself finished while the
panel still reads “needs configuring”.
What definePlugin rejects
Section titled “What definePlugin rejects”It runs when the module loads, so these are startup failures rather than customer-facing ones: malformed id, unknown API version, non-semver version, missing name or summary, unknown icon or accent, duplicate tool or job names, a tool without a handler, duplicate setting keys, a field pointing at an undeclared section, a field both hideable and required, empty options, an illustration that doesn’t cover every choice, an invalid job time or an unknown time zone.