Manifest
The timon field in package.json declares the plugin contract. The npm package uses type: "module"; main points to host code, when present, and exports["./client"] points to the browser entry.
| Field | Contract |
|---|---|
id | Required; 3–40 lowercase letters, digits or hyphens in the current third-party validator |
apiVersion | Required positive integer; minimum supported API contract |
kind | One kind or a nonempty list; inferred from slots when absent |
label, description, author | Optional nonempty display strings |
cover | Optional package-relative image path, not a remote URL |
screenshots | Additional package-relative images; default [] |
permissions | Requested capabilities; default [] |
client.slots | Admitted UI surfaces; default [] |
client.external | External module declarations; default [] |
client.mode | esm by default; schema also accepts iframe |
declares | Slots opened for other components, mapped to single, list or keyed |
route | Page route; required for a page, forbidden otherwise |
modifies | Informational list of affected surfaces; default [] |
contains | Child manifest IDs for bundles only |
settings | Declarative fields: key, type, label, optional default |
license.required | Whether the licence must explicitly permit the plugin; default false |
Slot names have lowercase alphanumeric dot-separated segments beginning with a letter. Routes start with /, use lowercase alphanumeric or hyphenated segments and contain no query or traversal. Covers and screenshots are confined to the package and accept PNG, WebP, JPG, JPEG or SVG paths.
Unknown manifest keys are ignored. Known fields with invalid values, incompatible kinds/slots or an API version newer than the daemon are refused. Use the real templates' ESM mode for browser plugins; an accepted schema option alone does not demonstrate an alternate runtime integration.
Shared browser modules
Keep these imports external to a browser bundle:
react
react-dom
@timon/ui
@timon/api
@timon/theme
@timon/navigate
For esbuild, use format: 'esm', bundle: true and an external array containing those exact specifiers. Do not embed another React instance. Include the built browser file in the published package: installation does not run lifecycle scripts.
Host entry
Export apply(ctx) and register routes or effects through the context. ctx.router() mounts routes beneath /api/plugins/<encoded-id>/ and removes them when the plugin unloads. The /-/ path prefix is reserved for platform endpoints.
If you export inject, it may name only kanban, missions, notify, storage, settings, events, http and host. It may not name db, bus or another internal service. Requested permissions are separate from dependency injection.