Every widget has a manifest — the metadata the hub stores alongside its HTML. You don’t write it directly; the hub builds it when you publish. But knowing the fields helps when you list widgets or debug versioning.
Manifest fields
| Field | Type | Meaning |
|---|---|---|
id | string | Stable widget id (returned by publish_widget). |
name | string | Human-readable name (switcher + Mac list). |
refreshMs | int | Native poll interval for this widget’s feed. |
htmlHash | string | SHA-256 (hex) of the HTML, for integrity. |
version | int | Bumped on every update so the phone knows to refetch. |
publishedAt | double? | First-published time (Unix seconds). Optional. |
icon | WidgetIcon? | Switcher / Mac list / Lock Screen icon. Optional. |
builtInSlug | string? | If installed from a shipped template, its stable slug (e.g. "soundbar"). nil for custom widgets. |
builtInVersion | int? | The template version it was installed from (drives “update available”). |
list_widgets returns an array of these plus the activeWidgetId.
Icons
A WidgetIcon has a kind and a value:
{ "kind": "sfSymbol", "value": "thermometer" }
{ "kind": "emoji", "value": "🎵" }
{ "kind": "png", "value": "<base64-encoded PNG bytes>" }
| Kind | value | Notes |
|---|---|---|
sfSymbol | SF Symbol name | Best default — crisp, tint-safe, desaturates cleanly on the Lock Screen. |
emoji | one emoji | Colorful in-app; flattens to a tinted silhouette on the Lock Screen. |
png | base64 PNG on input | ~256px, transparent background, monochrome silhouette, ≤256 KiB. |
For a png, the hub stores the bytes, computes their SHA-256, and rewrites
value to that hash (a cache key); the raw bytes are served at
GET /widget/:id/icon. So a manifest you read back will show the hash, not the
base64 you sent.
Set or change an icon without touching the HTML via set_widget_icon:
{ "id": "wgt_abc123", "icon": { "kind": "sfSymbol", "value": "thermometer.sun" } }