Actions and replies
At most 4 actions survive on a payload. The runtime keeps the first 4 and drops the rest, so put the important ones first: smaller spaces (an ear, a tile, a peek) show only the first one or two.
actions: [ { id: "stop", label: "Stop", role: "destructive" }, { id: "reply", label: "Reply", input: "text", placeholder: "Send a message…" },]| Field | Notes |
|---|---|
id |
Routed back to your onAction as action.actionId. Yours to name. |
label |
Button text. |
role |
"default", "primary" (called out visually: use it for the one action you want someone to notice), or "destructive" (asks first, with a hold or a second press, so it never fires on a stray press). Keep destructive for what can’t be taken back (stopping an agent, cancelling a deploy): anything your extension can undo should act on one press. |
icon |
An SF Symbol name. |
input |
"text" swaps the button for a reply field; the typed text comes back as action.input. |
placeholder |
Shown in that reply field. |
url |
Opened by the host directly, with no round trip to your onAction. Use it for “open the dashboard”, not for anything that needs your code to run first. |
quick |
true makes it one of a set of small choices (“5 min”, “+1 min”), shown only when the item is opened in place, as a line of chips under its buttons; never in a row, a tile or a peek. Counted in the 4 actions a payload keeps. |
on |
Makes the first button a switch, and says whether it’s on (keep awake, mute, deploys paused). Its icon names the switch, not the press; a tile keeps it in reach and lights it while on, and quiets the item’s value while off. |
confirm |
true asks first, a hold or a second press, like destructive but without its red: for what’s consequential rather than harmful (Merge, Publish). |
dismisses |
On a list item’s button: true takes the item out of the list the moment it’s pressed (Done, Snooze, Mute). It stays out while your onAction runs; your next update decides, and it’s back at once if your action throws. Use the kit’s TRIAGE buttons rather than your own. |
copy |
Text the host copies with no round trip to you, saying “Copied” under the notch (“Copy branch”). At most 1,000 characters; not with url or input. |
Handling one in onAction:
async onAction(ctx, action) { switch (action.actionId) { case "stop": ctx.end(action.key, { state: "failure", dismissAfter: 5 }); await ctx.notify("Blipbar", `Stopped ${action.key}`); return; case "reply": ctx.log.info(`reply for ${action.key}: ${action.input ?? ""}`); // … send action.input wherever it needs to go. return; }}action is { blipId, key, actionId, input?, itemId? }. itemId says which list
item’s button it was (see “Items with buttons” in Builders: one per layout); key is the blip’s own key (the
part of blipId after the /), which is what you pass back into ctx.end,
ctx.remove or another ctx.emit for the same item.